Git Product home page Git Product logo

Comments (81)

simen avatar simen commented on May 28, 2024

Thanks! I have used that script for complex, hour long milling jobs with no problems, yet I do occationally introduce bugs. I'll have a go as fast as I can.

from grbl.

jgeisler0303 avatar jgeisler0303 commented on May 28, 2024

Hi, maybe your problem is due to the arc commands. They do not currently support acceleration management. So when you try to run arcs with a feedrate that your motors cannot immediately jump to they will stall. I had a similar problem.

I started a fork, and when my mill (http://www.youtube.com/watch?v=6DoqTpJEfDE) is finished, I will try to implement a faster arc algorithm that allows acceleration management. I have already a concept working in MATLAB. But it will probably take some time since we just got started buying a house :-)

from grbl.

jjg avatar jjg commented on May 28, 2024

That makes sense because I've had luck running shapes that don't have curves (stars, boxes, etc.) but others such as this file (the letter "J") and another that has an ellipse seem to be the ones it chokes on.

Is there anything I can do to address this, perhaps different grbl config settings, etc.? I'm working with a 2-axis laser that I built and I'm stilling experimenting with feed rates, etc.

Thanks for taking a look and I'll be sure to post any successful changes I make!

from grbl.

jgeisler0303 avatar jgeisler0303 commented on May 28, 2024

As for now, you could add a very low feedrate to each arc command. For me this worked.

from grbl.

jjg avatar jjg commented on May 28, 2024

I've been doing a few experiments and I have some more details on the issue.

I upgraded my controller to the "edge" firmware and I'm able to do shapes consisting of straight lines reliably using the ruby script. However, I'm still having trouble with arcs.

I generated some gcode to draw a circle:

G90
G21
G0 X22.8783 Y11.8311

M03
G1F30.000000
G02 X19.9515 Y4.9224 I-9.6173 J0.
G02 X12.722 Y1.9956 I-7.2294 J7.4652
G02 X5.4926 Y4.9224 I0. J10.392
G02 X2.5658 Y11.8311 I6.6905 J6.9087
G02 X5.4926 Y18.7398 I9.6173 J-0.
G02 X12.722 Y21.6666 I7.2294 J-7.4652
G02 X19.9515 Y18.7398 I0. J-10.392
G02 X22.8783 Y11.8311 I-6.6905 J-6.9087
G1  X22.8783 Y11.8311
M05

G0 X0.000 Y0.000
M05
M02

When I stream this to grbl using the ruby script, the first half of the circle goes well. As we enter the third-quarter of the circle however, the laser begins to slow down (is this acceleration kicking in?), until it comes to a complete stop when the circle is 3/4 complete.

Now if I feed grbl each line by hand using a terminal, the same slow-down occurs however once the 3/4 point is reached, the speed slowly increases again until it's back to normal speed around the time it completes the circle.

I'm going to see if I can change/disable acceleration to see if this has any bearing (perhaps I'm even looking in the wrong direction) but if this information provides any insight into the issue or if you have any suggestions please pass them along.

Thank-you!

p.s. here's my current grbl configuration:

$0 = 53.330 (steps/mm x)
$1 = 53.333 (steps/mm y)
$2 = 755.906 (steps/mm z)
$3 = 30 (microseconds step pulse)
$4 = 30.0 (mm/min default feed rate)
$5 = 480.0 (mm/min default seek rate)
$6 = 0.100 (mm/arc segment)
$7 = 0 (step port invert mask. binary = 0)
$8 = 25.0 (acceleration in mm/sec^2)
$9 = 50.0 (max instant cornering speed change in delta mm/min)

from grbl.

jgeisler0303 avatar jgeisler0303 commented on May 28, 2024

As far as I know, arcs are always drawn without acceleration. They should jump to and run at the specified speed (your F30), maybe with a little hiccup between each gcode line. They are actually composed of very short lines. I really cant see why your arcs slow down. You could check if its really the stepping that slows or if the line segments are drawn with breaks in-between. Try playing with $6 (mm/arc segment). Maybe start with 3mm.
Cheers, Jens

from grbl.

simen avatar simen commented on May 28, 2024

You are right about the arcs. They were somewhat hard to get right with acceleration management, and personally I find that I don't use the arc-commands at all. I'll rather have my CAM software generate approximations with lines as they would have to do for any other curved shape anyway.

I intended to run arcs in a safe speed that should never exceed the set jerk limit. This might be to conservative, but to be honest I haven't had much time to use Grbl for production after I finished the acceleration-version because of several happy personal circumstances. I look forward to getting back in the lab soon and do some hands on tuning. Until then: Feel free to feed me detailed suggestions on how to remedy these problems.

from grbl.

dirktheeng avatar dirktheeng commented on May 28, 2024

I just tried running this code, but I run it with a feedrate of F1000. My steppers have a resolution of about 157 stepps per milimeter. All of the arcs run the same for me. My problem comes in that there is a definate pause between arc segments. It isn't noticeable when the feed rates are low, but I am sure it still occurs. I'm not confident in this, but I think ther is a pause when the command line gets sent. It seems to stop the motion until the line is read. That is definately not good and it makes arcs unusable. I am not confident that this soesnt' happen with strait lines yet either, but I will continue to experiment.

from grbl.

jgeisler0303 avatar jgeisler0303 commented on May 28, 2024

The behaviour you observe is correct. Currently grbl waits for the buffer to be cleared before a new arc is started. Also, after the line is sent, it takes some more complicated floating point math before the motion commands can be generated.
In my fork I am working on some modifications that hopefully will make arcs faster and smoother. But for now the code is totally unusable. Only the MATLAB folder shows the basic Idea in some simple script files. And the Wiki lays out the planed modifications.
@simen: I'm sorry that we get in contact in this indirect way. I have great respect for your work and always meant to write to you to share some ideas and maybe contribute to grbl. But then I don't like to share unfinished stuff and since I don't know when I'll have something ready, I didn't want to make any promises too early. I hope to talk to you more often soon.

from grbl.

simen avatar simen commented on May 28, 2024

No problem! I used to have a proper integer circle interpolator in an old versjon of grbl. It took a lot of code space and ess really complex and I realised I never used the arc commands, bit rather had the CAM-tool generate an approximation. I agree that if the arcs are important in day to day use, the code needs some love. I would welcome a well crafted patch or any suggestions that may lead to a simpler Interpolator than I used the last time.

But seeing as arcs are just one very special case of curved feature, I were thinking it should be deprecated. I may be wrong about that.

from grbl.

chamnit avatar chamnit commented on May 28, 2024

I have run into a similar issue with arcs, as well (UNO w/ grbl edge). I had written a python script similar to simen's ruby streaming script. When I would send g-code blocks and always wait for an 'ok' acknowledgement before sending another block, anytime an arc block was being processed, the serial port would freeze. Once finished, the serial port would opened again to allow more data. It was strange. This would only happen when processing arcs, consistently. This would cause an unintentional dwell, if the buffer was empty.

I had managed to patch the buffer waiting issue by forcing a prebuffer without waiting for acknowledgements, then resuming the wait for 'ok' (flushed read buffer before switching). As long as there was another g-code block in the buffer and my arc test g-code program worked smoothly without any problems. The g-code basically created 2 circles and 2 squares with internal fillets. Each arc was either 90deg or 180deg arcs. The serial port freeze would still occur when processing arcs, but the buffer would refill quickly when it was doing anything else.

Unrelated, I ran into an issue with arc mode's i and j commands. It doesn't do full-circle 360 blocks and does some strange things when processing it. It would occassionally accelerate up to infinite speed and crash the Arduino. Luckily, my steppers just stall out with a loud high pitched whine, when it happens. No damage to the motor or drivers so far.

from grbl.

simen avatar simen commented on May 28, 2024

I'm really sorry about the arcs. Truth is I really hate them. They introduce a lot of complexity in G-code and the parsers, yet represent only a very special case of curvy shapes. Personally I never use them, but have my CAM tool approximate any curvy shapes for me.

When it comes to 360 degree g-code, that might technically be a bug that should be fixed, but the standard recommends that you never render more than 180 degrees of an arc in a single command as rounding errors can yield unpredictable results on different machines.

The high level implementation of arcs in grbl is sound and nice, but the actual step generation is a bit shabby I have to admit. It is correct that an arc force a synchronization which precludes the nice pipelining that I have implemented for all other motion. As an arc-hater I am undecided on this: complete the support for arcs in a nice and sturdy way, or rip it all out and leave it to the code generators.

from grbl.

chamnit avatar chamnit commented on May 28, 2024

Yes. Technically you can do every movement you need with just G00 and G01. The only reasons one would use G02/03 is for readability, ease of hand-writing, and directly editing g-code. Although handy to have, it's not essential, because it's basically a simple canned cycle. Also, like you said, you can have a capable CAM system do the translation for you, or even a pre-processor Python/Ruby script that would translate and stream the G02/03 block to grbl.

After reading through your code base, I can see why it would be difficult to make it streamlined and efficient, especially considering the number of calculations required, integrating it into your acceleration planners, and the space limitations of the Arduino. I would vote for a complete removal of the arc motion from the microcontroller. Instead, I would use that CPU and memory savings on improving the acceleration planners and implementing those features you had mentioned adding: 4th-axis, PCM output to feedrate, and status/progress feedback.

I'm fairly fluent at Python and would give it shot at writing a pre-processor for grbl, if it's something that would be useful for your project. One of the good things with this type of approach is that it would be then possible to do a more complete implementation of the g-code standard, i.e. canned cycles, adjustable feedrates, single block execution, etc, and yet keep grbl simple, efficient, and flexible for many applications.

from grbl.

jjg avatar jjg commented on May 28, 2024

Thanks for following up on this everyone.

Just for reference, I'm using g-code generated from a plugin for Inkscape (I believe the plug-in is written in python). Since I'm not generating the g-code directly I don't know that I can control what it uses to generate arcs, etc. but I could use a post-processor as you have discussed to convert the code coming out of the plug-in into something that grbl likes better.

Of course I could re-write the plug-in as well, but I'm not very familiar with python, at least not yet.

If you come up with something to do this conversion and need help testing please let me know, thanks!

from grbl.

bobgates avatar bobgates commented on May 28, 2024

Hi all

I guess one of the problems with open source is keeping up with everyone. I haven't done any work on grbl in nearly a year, but I did spend a bit of time on the arc stalling problem. The bulk of my contribution is in this commit:

bobgates@e4b7919

I had earlier made a change to grbl, in that I'd introduced a small command interpreter, and I'd tried to move totally away from blocking. Grbl is already non-blocking on lines, as you're all aware, but stalls on arcs because they're not queued as arcs. My code marks an arc, then queues all its subsegments. If the queue is, say, 10 commands, when there are less than 10 segments left in the arc, it will allow another g-code instruction onto the queue, with the result that the next command starts immediately after the arc.

I can't guarantee the above commit is the only thing that needs to change, there was some later debugging, but take a look at the ideas for organising how the arcs are drawn. It worked for me! I did this before Simen introduced acceleration, so no guarantees on what might be necessary to get it to work with acceleration.

from grbl.

chamnit avatar chamnit commented on May 28, 2024

Hi Bob. Unless your modifications are significant, I can't see why your approach wouldnt work with Simen's acceleration profile calculations. You would just have to insert the new interpolations into the queue before they go into the acceleration code. This isn't different from what I'm implying with doing this off the Arduino with a Python post(pre)-processor to translate it into what runs most efficiently on grbl.

My concern is that the Arduino isn't the best at multitasking or very fast. I would suspect that if you start to add a lot of new capabilities, like 4th axis and status reports, with an internal gcode translator for arcs and other things, you will begin to limit how fast grbl can run multiple stepper pulse trains. I would propose to minimize everything grbl has to do internally, yet add features only that it needs, as Simen has already been doing.

If everything is efficient, I couldn't see why grbl couldn evolve to run 5-axis or 6-axis machines or hexapods. The question is: what are the bare minimum features you need to have the most flexibility and utility?

from grbl.

chamnit avatar chamnit commented on May 28, 2024

First it looks like grbl tries to do what Bob states, but I'm not sure why it's disabled, except for maybe it's not friendly to the acceleration planner in terms of speed or something else. Can't be sure until I'm back home and try it.

FYI. I spent some time looking at current research into optimal feedrate generation, trying to keep myself busy while out traveling for work. It looks to be problem with g-code interpolation and planning by nature. It's difficult to plan on the fly with limited and constantly changing look-ahead, especially for linearly-interpolated curves. Researchers are now using b-spline curve approximations with constrained optimization methods to solve for the curves in a pre-processor and sending the curves to the controllers as short sets of parameters to efficiently rebuild them on the fly in the controllers. (See Timar & Farouki, 2005, Algorithms for time-optimal control of CNC machines along curved tool paths.) There is an updated one that also accounts for lower motor torque at higher speeds.

from grbl.

simen avatar simen commented on May 28, 2024

That is correct: chamnit. The circles are generated by buffering a lot of tiny line segments. The reason that management is disabled is because the tiny processor just choked on planning all the tiny lines. One robust solution is to just increase the segment size and re-enable planning.

There are lots of more advanced ways of implementing acceleration management. I picked a simple approach that I think is more than adequate for the kind of feed rates and tool inertia you see with typical home milling. The manager in Grbl guarantees a constant linear acceleration and constrains all speed changes to that specific constant acceleration. Additionally it allows the user to accepts a certain sudden "jump" in speed which seems to yield more reasonable cornering. Given that the planner only looks about 10 commands into the future (because of memory constraints) it might miss oportunities where it could have kept going at a higher speed. On these occasions the planner will err on the low side to be able to guarantee never to exceed the set acceleration. In my experience using Grbl for milling this is of no practical consequence.

Ideally you want to manage 'jerk' (the change in acceleration over time (acceleration derived)), but i decided this approach was not a good fit for the limited platform and would be very hard to express in the terse and simple kind of code i prefer for this project.

from grbl.

chamnit avatar chamnit commented on May 28, 2024

Fair enough. Most of the literature I've read on advanced feedrate planning is still pretty infant in terms of implementing into the real world or only applies to high speed machining for large volume production. It would be interesting to see something like this as open-source, perhaps at some point I'll give this Pythagorean-hodograph method a shot as a side project.

Also, I just noticed the other day that jgeisler0303's fork just posted a re-written planner that supports arcs. It looks like it removes the sin() and cos() calculations and replaces them with more computationally efficient calculations to get it to work with the planner. I'm not sure how much he has changed from the current grbl master/edge, but I'll try giving it a look.

from grbl.

jgeisler0303 avatar jgeisler0303 commented on May 28, 2024

The code I committed is very raw again (lots of commented printf debugging lines and not very tested). I committed it anyway so perfectionism doesn't lead to never doing it. I already know of two minor bugs, but a first run on my now finished mill showed very satisfying results.

The code is a major rework with many new features (better homing, e-stop on limit switch tripping, instant abort with deceleration, jog-wheel mode) and - apart from the arc routine - a totally new and hope fully faster planner. Pulling this back upstream will be a pain, but it's not yet the time to thing about that.

Apart from my efforts to get arcs with acceleration management, I totally agree that the atmega should primarily run the real-time code and in the future should get a front-end like EMC2 that does preprocessing, GUI and stuff. Directly integrating something like grbl or teacup in EMC2 is probably not possible because of its whole architecture (it is very universal and carries the huge overhead for feedback control of dc motors).

For now I did the arcs because I wanted some kind of "hand operated" cnc mill to get a better feel for milling and gcode.

from grbl.

aldenhart avatar aldenhart commented on May 28, 2024

I implemented a controlled jerk acceleration solution for the tinyG project - it's open source and found at https://github.com/synthetos/TinyG. Simen and I have discussed this at various times - the math in the jerk equations is not that compatible with the Arduino ATmetas. TinyG runs an Xmega chip. Look-back replanning is 16 moves - again for memory space. I've been working on the physics behind optimal cornering and will post that as I have results to show.

from grbl.

chamnit avatar chamnit commented on May 28, 2024

Hi Alden. Can you elaborate on what you mean by the math is not compatible with the Arduino ATmegas?

I've been looking into the physics of optimal feedrates as well. The feedrate/acceleration problem is highly nonlinear and path dependent, which generally requires an constrained nonlinear optimization method for a true solution, which the Arduino cannot do on-board realtime. I have seen other algorithms in literature that do more robust versions of Simen's approach, but still these cannot be done on the Arduino realtime. Although, if you make some assumptions, there may be a simpler and more efficient method than the one Simen has now, but I haven't found a decent solution as of yet.

from grbl.

jgeisler0303 avatar jgeisler0303 commented on May 28, 2024

Do stepper motors have a problem with infinite jerk?Jerk usually is an issue with flexible structures, where it induces oscillations. The "jerk" in grbl is rather an instant change of velocity that is allowed to occur at line joints. So its more like the discrete version of curvature induced acceleration. The planner in grbl is already very good for its purpose (stepper and thread driven mill axes). IMHO, anything more sophisticated should include rounding of corners.
BTW Alden, I started to read the tinyG code. Very impressive work!There is probably one or the other feature to port to grbl.Do you have any more notes on the inner workings of the planner?

from grbl.

aldenhart avatar aldenhart commented on May 28, 2024

Hi Chamnit and J - My comment on the math was just that there are not enough cycles on a little Arduino to do the algorithms justice. You have 16 MIPS and 8 bits to work with. The xmega is somewhat faster at 32 MIPS, but I'm looking around for more cycles. You prettymuch answered the maths question in your second paragraph.

That said, the xmega is able to do some fairly complex math, but I have to be mindful of the cycle budget. GCC -Os is a wonderful thing. The TinyG planner uses 3rd order equations to solve the jerk equations in real-time. The jerk in this case is the amount of instantaneous change in velocity and it really just makes for smoother motion as the machine bangs around less.

I'm working on cornering (tangential jerk) now. I have a somewhat different target than Simen, or I'd just use the heuristic in grbl and be done. The problem comes in when there are rotational axes that have totally different velocity, acceleration, and jerk characteristics than the linear axes. There are also machines (e.g. makerbot) that have belts for X and Y, and screws for Z - same issue. So you really want the equations to be axis aware and driven from the unit vectors of the individual moves. The model I've been using is derived from the jerk equations of motion, and synthesizes a "jerk transition region" in which the tangential jerk is managed. This paves the way for corner splining - as what that really does is increase the size of the transition region to the diameter of the spline. This comes later. First I just have to get it to work. Once I get the transitions working correctly I'll update the github. Also, there will be more notes in the code as to how it works.

As for simpler and more efficient that Simen's code...? I feel like a logger with a chainsaw compared to the Bonsai work Simen's done. I doubt I could have gotten all this this to run in that small a footprint. I did something like this a few years back and programmed 192 channels of PWM LED control and a pattern generating language on a 5 MIPS pic (in assembly). I'm ready to let the compiler do some of the work.

BTW - our first actual production run of TinyG is done! There are 24 boards made. We'll be building more.

from grbl.

chamnit avatar chamnit commented on May 28, 2024

Alden- I would agree with you that one solution for this problem is to use a faster processor, but I think the main attraction of grbl is that it's on a unintimidating platform, the Arduino, which can introduce CNC to a lot of new people. I just posted something on this on my blog, which you are already aware of. (http://onehossshay.wordpress.com) Basically, I'm all for making grbl as good as it can get, within the Arduino limitations. Creating an easy-to-understand and solid code-base for people to use can really let loose people's imaginations on what CNC/robotics can do.

I totally agree with you with Simen's efficient coding. It's awesome to see that much attention to detail. It's been pretty difficult to try to come up with a new algorithm that is more compact and efficient, but I'm still going to try. :) And, good to hear that the TinyG is in production! Power to the makers, I say.

J- I like your approach on computationally simplifying the arc function by removing the sin() and cos() calculations for each line segment. Have you come across any compounding error problems with it? Especially for large circles?

from grbl.

jgeisler0303 avatar jgeisler0303 commented on May 28, 2024

Hi, as I just learned the other day that double = float on the atmega, I find/replaced that in my pc-test code. Ran the following test: full circle (should not be done in gcode but works anyway) 100mm radius came out x: 0.014664, y: 0.099866 off starting point. Same magnitude for variations in radius. That is well below the precision of my mill. With quarter arcs I'd say 400mm radius should be no problem.
@chamnit: you seem to be quite familiar with the source code. Maybe you could have a look at my planner modification. I would be really grateful for some feedback as my capabilities for testing are currently very limited.

from grbl.

aldenhart avatar aldenhart commented on May 28, 2024

I take your point completely on the accessibility of the Arduino and the value of introducing CNC and robotics to the widest possible audience. That's why we built the grblshield - to make it as easy as possible. (Unless we sell 100,000 of them we won't quit our day jobs!).

TinyG is an open-source exploration of something else. The mission for TinyG is laid out in What is TinyG and Why (https://www.synthetos.com/blog/what-is-tinyg-and-why/). We are going for a networkable, all-in solution where we can drive the cost per axis to negligible levels. Picture a hexapod as 2 networked boards feeding from the same command stream. Production is all about getting to lot sizes that I can job out. I am getting them hand assembled in Virginia right now, but I've used an assembly house in Serbia in the past - but that's only good for 250+ boards.

from grbl.

chamnit avatar chamnit commented on May 28, 2024

jgeisler0303: Sorry! I've been a little distracted in trying to write a Python preprocessor script for grbl, but I will definitely take a look at your planner probably sometime this weekend.

jjg: Here's a grbl pre-processor that should work for you. I had basically took Simen's code and converted the logic to keep track of what's going on and then translates any G02/03 arc it encounters into linear segments. It also removes all extra characters, comments, and unsupported commands, if desired. Don't be surprised with the output g-code file becomes huge, especially if there are a lot of arcs.

But... it's beta. There are some known problems and still working on them, but it should work fine as is for most things. I tested it on my machine without any issues, running in inch mode only. Let me know if it works for you.

#!/usr/bin/env python
"""\
G-code preprocessor for grbl
- Converts G02/03 arcs to G01 linear interpolations
- Removes comments, block delete characters, and line numbers
- Removes spaces and capitalizes commands
- Minor input error checking
- OPTIONAL: Remove unsupported grbl G and M commands

TODO: 
- More robust error checking
- Improve interface to command line options
- Improve g-code parsing to NIST standards
- Fix problem with inverse feed rates
- Positioning updates may not be correct on grbl. Need to check.

Version: 20100825
"""
import re
from math import *
from copy import *

# -= SETTINGS =-
filein = 'test.gcode'   # Input file name
fileout = 'grbl.gcode'  # Output file name
ndigits_in = 4 # inch significant digits after '.'
ndigits_mm = 2 # mm significant digits after '.'
mm_per_arc_segment = 0.1 # mm per arc segment      
inch2mm = 25.4 # inch to mm conversion scalar
verbose = False  # Verbose flag to show all progress
remove_unsupported = True   # Removal flag for all unsupported statements

# Initialize parser state
gc = { 'current_xyz' : [0,0,0], 
       'feed_rate' : 0,         # F0
       'motion_mode' : 'SEEK',  # G00
       'plane_axis' : [0,1,2],  # G17
       'inches_mode' : False,   # G21
       'inverse_feedrate_mode' : False, # G94
       'absolute_mode' : True}  # G90

def unit_conv(val) : # Converts value to mm
    if gc['inches_mode'] : val *= inch2mm
    return(val)

def fout_conv(val) : # Returns converted value as rounded string for output file.
    if gc['inches_mode'] : return( str(round(val/inch2mm,ndigits_in)) )
    else : return( str(round(val,ndigits_mm)) )

# Open g-code file
fin = open(filein,'r');
fout = open(fileout,'w');

# Iterate through g-code file
l_count = 0
for line in fin:
    l_count += 1 # Iterate line counter

    # Strip comments/spaces/tabs/new line and capitalize. Comment MSG not supported.
    block = re.sub('\s|\(.*?\)','',line).upper() 
    block = re.sub('\\\\','',block) # Strip \ block delete character
    block = re.sub('%','',block) # Strip % program start/stop character

    if len(block) == 0 :  # Ignore empty blocks

        print "Skipping: " + line.strip()

    else :  # Process valid g-code clean block. Assumes no block delete characters or comments

        g_cmd = re.findall(r'[^0-9\.\-]+',block) # Extract block command characters
        g_num = re.findall(r'[0-9\.\-]+',block) # Extract block numbers

        # G-code block error checks
        # if len(g_cmd) != len(g_num) : print block; raise Exception('Invalid block. Unbalanced word and values.')
        if 'N' in g_cmd :
            if g_cmd[0]!='N': raise Exception('Line number must be first command in line.')
            if g_cmd.count('N') > 1: raise Exception('More than one line number in block.')
            g_cmd = g_cmd[1:]  # Remove line number word
            g_num = g_num[1:]
        # Block item repeat checks? (0<=n'M'<5, G/M modal groups)

        # Initialize block state
        blk = { 'next_action' : 'DEFAULT',
                'absolute_override' : False,
                'target_xyz' : deepcopy(gc['current_xyz']),
                'offset_ijk' : [0,0,0],
                'radius_mode' : False, 
                'unsupported': [] }

        # Pass 1
        for cmd,num in zip(g_cmd,g_num) :
            fnum = float(num)
            inum = int(fnum)
            if cmd is 'G' :
                if   inum is 0 : gc['motion_mode'] = 'SEEK'
                elif inum is 1 : gc['motion_mode'] = 'LINEAR'
                elif inum is 2 : gc['motion_mode'] = 'CW_ARC'
                elif inum is 3 : gc['motion_mode'] = 'CCW_ARC'
                elif inum is 4 : blk['next_action'] = 'DWELL'
                elif inum is 17 : gc['plane_axis'] = [0,1,2]    # Select XY Plane
                elif inum is 18 : gc['plane_axis'] = [0,2,1]    # Select XZ Plane
                elif inum is 19 : gc['plane_axis'] = [1,2,0]    # Select YZ Plane
                elif inum is 20 : gc['inches_mode'] = True      
                elif inum is 21 : gc['inches_mode'] = False
                elif inum in [28,30] : blk['next_action'] = 'GO_HOME'
                elif inum is 53 : blk['absolute_override'] = True
                elif inum is 80 : gc['motion_mode'] = 'MOTION_CANCEL'
                elif inum is 90 : gc['absolute_mode'] = True
                elif inum is 91 : gc['absolute_mode'] = False
                elif inum is 92 : blk['next_action'] = 'SET_OFFSET'
                elif inum is 93 : gc['inverse_feedrate_mode'] = True
                elif inum is 94 : gc['inverse_feedrate_mode'] = False
                else : 
                    print 'Unsupported command ' + cmd + num + ' on line ' + str(l_count) 
                    if remove_unsupported : blk['unsupported'].append(zip(g_cmd,g_num).index((cmd,num)))
            elif cmd is 'M' :
                if   inum in [0,1] : pass   # Program Pause
                elif inum in [2,30,60] : pass   # Program Completed
                elif inum is 3 : pass   # Spindle Direction 1
                elif inum is 4 : pass   # Spindle Direction -1
                elif inum is 5 : pass   # Spindle Direction 0
                else : 
                    print 'Unsupported command ' + cmd + num + ' on line ' + str(l_count) 
                    if remove_unsupported : blk['unsupported'].append(zip(g_cmd,g_num).index((cmd,num)))
            elif cmd is 'T' : pass      # Tool Number

        # Pass 2
        for cmd,num in zip(g_cmd,g_num) :
            fnum = float(num)         
            if   cmd is 'F' : gc['feed_rate'] = unit_conv(fnum)   # Feed Rate
            elif cmd in ['I','J','K'] : blk['offset_ijk'][ord(cmd)-ord('I')] = unit_conv(fnum) # Arc Center Offset
            elif cmd is 'P' : p = fnum  # Misc value parameter
            elif cmd is 'R' : r = unit_conv(fnum); blk['radius_mode'] = True    # Arc Radius Mode
            elif cmd is 'S' : pass      # Spindle Speed
            elif cmd in ['X','Y','Z'] : # Target Coordinates
                if (gc['absolute_mode'] | blk['absolute_override']) :
                    blk['target_xyz'][ord(cmd)-ord('X')] = unit_conv(fnum)
                else :
                    blk['target_xyz'][ord(cmd)-ord('X')] += unit_conv(fnum)

        # Execute actions
        if   blk['next_action'] is 'GO_HOME' : 
            gc['current_xyz'] = deepcopy(blk['target_xyz']) # Update position      
        elif blk['next_action'] is 'SET_OFFSET' : 
            pass 
        elif blk['next_action'] is 'DWELL' :
            if p < 0 : raise Exception('Dwell time negative.')
        else : # 'DEFAULT'
            if gc['motion_mode'] is 'SEEK' : 
                gc['current_xyz'] = deepcopy(blk['target_xyz']) # Update position
            elif gc['motion_mode'] is 'LINEAR' :
                gc['current_xyz'] = deepcopy(blk['target_xyz']) # Update position
            elif gc['motion_mode'] in ['CW_ARC','CCW_ARC'] :
                axis = gc['plane_axis']

                # Convert radius mode to ijk mode
                if blk['radius_mode'] :
                    x = blk['target_xyz'][axis[0]]-gc['current_xyz'][axis[0]]
                    y = blk['target_xyz'][axis[1]]-gc['current_xyz'][axis[1]]
                    if not (x==0 and y==0) : raise Exception('Same target and current XYZ not allowed in arc radius mode.') 
                    h_x2_div_d = -sqrt(4 * r*r - x*x - y*y)/hypot(x,y)
                    if isnan(h_x2_div_d) : raise Exception('Floating point error in arc conversion')
                    if gc['motion_mode'] is 'CCW_ARC' : h_x2_div_d = -h_x2_div_d
                    if r < 0 : h_x2_div_d = -h_x2_div_d
                    blk['offset_ijk'][axis[0]] = (x-(y*h_x2_div_d))/2;
                    blk['offset_ijk'][axis[1]] = (y+(x*h_x2_div_d))/2;

                # Compute arc center, radius, theta, and depth parameters
                theta_start = atan2(-blk['offset_ijk'][axis[0]], -blk['offset_ijk'][axis[1]])
                theta_end = atan2(blk['target_xyz'][axis[0]] - blk['offset_ijk'][axis[0]] - gc['current_xyz'][axis[0]], \
                                  blk['target_xyz'][axis[1]] - blk['offset_ijk'][axis[1]] - gc['current_xyz'][axis[1]])
                if theta_end < theta_start : theta_end += 2*pi
                radius = hypot(blk['offset_ijk'][axis[0]], blk['offset_ijk'][axis[1]])
                depth = blk['target_xyz'][axis[2]]-gc['current_xyz'][axis[2]]
                center_x = gc['current_xyz'][axis[0]]-sin(theta_start)*radius
                center_y = gc['current_xyz'][axis[1]]-cos(theta_start)*radius

                # Compute arc incremental linear segment parameters
                angular_travel = theta_end-theta_start
                if gc['motion_mode'] is 'CCW_ARC' : angular_travel = angular_travel-2*pi
                millimeters_of_travel = hypot(angular_travel*radius, fabs(depth))
                if millimeters_of_travel is 0 : raise Exception('G02/03 arc travel is zero')
                segments = int(round(millimeters_of_travel/mm_per_arc_segment))
                if segments is 0 : raise Exception('G02/03 zero length arc segment')
#        ???    # if gc['inverse_feedrate_mode'] : gc['feed_rate'] *= segments
                theta_per_segment = angular_travel/segments
                depth_per_segment = depth/segments

                # Generate arc linear segments
                if verbose: print 'Converting: '+ block + ' : ' + str(l_count)
                fout.write('G01F'+fout_conv(gc['feed_rate']))
                if not gc['absolute_mode'] : fout.write('G90')    
                arc_target = [0,0,0]
                for i in range(1,segments+1) :
                    if i < segments : 
                        arc_target[axis[0]] = center_x + radius * sin(theta_start + i*theta_per_segment)
                        arc_target[axis[1]] = center_y + radius * cos(theta_start + i*theta_per_segment)
                        arc_target[axis[2]] = gc['current_xyz'][axis[2]] + i*depth_per_segment
                    else : 
                        arc_target = deepcopy(blk['target_xyz']) # Last segment at target_xyz
                    # Write only changed variables. 
                    if arc_target[0] != gc['current_xyz'][0] : fout.write('X'+fout_conv(arc_target[0]))
                    if arc_target[1] != gc['current_xyz'][1] : fout.write('Y'+fout_conv(arc_target[1]))
                    if arc_target[2] != gc['current_xyz'][2] : fout.write('Z'+fout_conv(arc_target[2]))
                    fout.write('\n')            
                    gc['current_xyz'] = deepcopy(arc_target) # Update position
                if not gc['absolute_mode'] : fout.write('G91\n')    

        # Rebuild original gcode block sans line numbers, extra characters, and unsupported commands
        if gc['motion_mode'] not in ['CW_ARC','CCW_ARC'] :
            if remove_unsupported and len(blk['unsupported']) : 
                for i in blk['unsupported'][::-1] : del g_cmd[i]; del g_num[i]
            out_block = "".join([i+j for (i,j) in zip(g_cmd,g_num)]) 
            if len(out_block) : 
                if verbose : print "Writing: " + out_block + ' : ' + str(l_count)
                fout.write(out_block + '\n')

print 'Done!'

# Close files
fin.close()
fout.close()

from grbl.

jjg avatar jjg commented on May 28, 2024

What a coincidence Chamnit, I'm doing a demo of the laser I built tomorrow. I'll give this a test this afternoon and see if it does the trick. Thanks!

from grbl.

chamnit avatar chamnit commented on May 28, 2024

jjg: How did the test go? I had some issues with the acceleration planner trying to plan the small linear interpolations and they would audibly create a hitching sound when trying to accelerate and decelerate all the time. Aside from that, it seems to improve how it ran for me, especially coming out of the arcs.

jgeisler: Took some time to look at your planner today. I really like how you stop the planner from over computing by back computing to a known good point. From what I can tell, grbl currently plans the whole buffer with every new incoming block. This is the same approach I have seen in the path optimization literature I've been reading. This seems to be the right way to go and should improve the planner speed tremendously.

Also, I noticed that you compute the maximum junction velocity initially, but don't recompute it in the planner when the junction velocities change. Is there as reason for this or did I misread it?

from grbl.

jgeisler0303 avatar jgeisler0303 commented on May 28, 2024

Hi chamnit, and thanks for taking the time!
I wrote some comments Friday at word in the web interface and it all got lost because github claimed someone did a commit since i started editing. Its a known issue, so beware. And sorry for the badly commented code. I will rewrite the comments soon.
max_junction_speed is is computed only once because all variables that go into the computation don't change - or did i miss some thing? This is something i already noticed in simens code and it should also save some time since it involves float multiplications and the sqrt. Apart from the nominal speeds of the adjacent lines, the max junction speed is the absolute maximum physical speed (in mm/min) that the junction can be traveled. It results from the discrete approximation of the curvature which is represented by the difference of the unit vectors (scaled to steps: delta_steps_per_mm). For circles it is an approximation of v_max= sqrt(a * radius). While simen does actually use the 2-norm which results exactly in this formula for infinitively short line segments, I opted for the max-Norm cause I felt it represents the actual machine limits better (each axis separately).Also, I use a float representation for the unit vectors instead of using the quantized step lengths, because these introduce the unsteady acceleration and deceleration for short lines you mention to jjg!

from grbl.

aldenhart avatar aldenhart commented on May 28, 2024

chamnit: I've been refactoring the tinyg planner and have worked out some solutions to the issues you mention. I have a "replannable" flag in each block that is used to limit the depth of the backplanning chain. It is set TRUE when the block is new. It gets set FALSE when either the block is running (can't replan it any more), or if the back planning algorithm finds that the block has already been optimally planned - i.e. the target entry, exit and cruise velocities are met. This happens a lot.

Also, I found that the variables for the optimal junction velocity do not change as new moves are added, but the cumulative braking velocity of the chain will change, and this may be the minimum (limiting) term. So I keep that separate from the pre-computed minimum derived from the acceleration and jerk values.

Can you provide pointers to the literature you are finding useful?

Sorry I don't have any code to post on this yet - hopefully today or this week if I'm productive. The code is a major refactor over the code on the tinyg github and really simplifies things, but it's in bits and pieces right now. In any case, I'll let you know when it is up there. - Alden

from grbl.

jgeisler0303 avatar jgeisler0303 commented on May 28, 2024

Hi Alden, thats funny: we commented about the same things at the same time :-)
What do you mean by "cumulative braking velocity"? It seems to be something I didn't consider. I wander if it would be useful for grbl. Cheers, Jens

from grbl.

chamnit avatar chamnit commented on May 28, 2024

jgeisler: Ahhh! This clarifies the junction velocity. I wasn't completely sure on what this parameter truly meant. Thanks! In a way, it's a junction radius parameter. At the junction of two line segments, the centripetal acceleration is infinite, but by introducing the junction velocity, this defines a finite circular joining segment between the two dependent on the maximum acceleration. So for clarity, is it better to define this as junction velocity or junction radius, even though radius may be confusing as well?

You are correct. I misread the max junction velocity in Simen's code. In his approach, it only needs to be updated once, but as Alden implies, you aren't guaranteed to be traveling at the nominal velocities for each line segment. It seems to be a good enough approximation, but I suppose it really only depends on if problems occur in some extreme planning cases. It would be hard to tell without some thorough testing.

For the 2-norm vs max-norm, I would have to agree that it's more representative of a 3-axis machine, but I would also say that separating the max acceleration into 3-axes is more representative as well. The 2-norm and universal max acceleration approach provides a uniform 3DOF path response but not time optimal, while the max-norm would provide a more time optimal but non-uniform 3DOF path response. I think this is more of a operator preference.

Interesting note on fixing the integer math problem of the step lengths, integer math can get really messy and inaccurate quickly. And no worries on the comments, your code was very readable and straightforward!

alden: I had noticed you implement true jerk (3rd derivative of position) into TinyG. Have you noticed significant improvement in performance with a stepper motor based machine? Most of the references to jerk indicate this is as a problem associated with servo motors, but don't say anything about steppers (since they don't use them for large machines). Just curious!

Here's a list of journal articles that seem to be the most cited on this topic in the last 20 years, usually meaning that they are regarded as the most correct or promising by consensus. These are mostly from accredited institutions, except for the '*' ones. These are noteable articles that I found helpful.

Timar 2005 - Algorithms for time-optimal control of CNC machines along curved tool paths
Timar 2007 - Time-optimal traversal of curved paths by Cartesian CNC machines under both constant and speed-dependent axis acceleration bounds
Chou 1991 - Command generation for three-axis CNC machining
Chou 1992 - On the generation of coordinated motion of five-axis CNC machines
Shiller 1990 - Robust computation of path constrained time optimal motions
Shiller 1994 - On singular time-optimal control along specified paths
Slotine 1989 - Improving the efficiency of time-optimal path-following algorithms

*Sir 2007 - Rounding spatial g-code tool paths using pythagoream hodograph curves
*Dong 2007 - Feed-rate optimization with jerk constraints for generating minimum-time trajectories

from grbl.

aldenhart avatar aldenhart commented on May 28, 2024

Jens, yes, we commented at the same time.

For cumulative braking, here's what I mean. I've been doing planning to controlled jerk, not acceleration, so some of the specifics will be different, but the concepts are the same. When a new move comes in it's stuck on the end of the current move chain. The move has to plan to a zero exit velocity, so one of the limiting factors on the entry velocity is the maximum speed the move can start and still decelerate to zero - given the max jerk and the length of the move. (I think grbl computes this factor as well, but I don't remember the specifics of the code). For backplanning I then work backwards in the chain, accumulating the braking velocities for each move. These are stored as the cumulative braking velocity at each entry point. No move should have an entry velocity higher than the cumulative braking velocity at that point in the move chain. So these factors change with each new move added, whereas all the others are static and only need t be computed once. An efficient way to deal with this is just to compute the braking velocity for each move and then sum them during the backwards pass of backplanning.

I asked Simen about the grbl planning assumptions a while back - he said that grbl assumes that the moves are pretty close to the same speeds and that changes that would cause that assumption to do sub-optimal planning are rare and therefore acceptable. Parameters apply to all axes and are not set individually per axis. Since tinyg is a 6 axis system (xyzabc) it can't make the same assumptions and am therefore doing things explicitly for each axis.

Chamnit - I defined the junction radius as well - I just called it the junction transition region. I've been using a jerk equation to determine the maximum velocity you can "shed" in a given axis: V = Vi + Jm_(T^2)/2. If you substitute the transition region for T: (S-Si)/(V-Vi) you get V = Jm_((S/V)^2)/2 (simplifying out the initial position and velocity and setting Vi to 0). This solves to an insane cube-root equation that gives you a nice constant Jm velocity-shedding curve that reduces as the V increases - because you are spending less time to get through the transition region. I've been able to do some testing of this, but I'm not really done yet. So far the results are very good. In order to determine the effective size of the transition region I solve the equation for position. V = Jm_((S/V)^2)/2 solved for S is S = sqrt(2)_V*sqrt(V/Jm). Entering a non-zero V (for a given Jm) gives you the transition region size for a given change in acceleration.

My theory is that you can use this to determine the region size experimentally by turning off planning and starting the stepper motors from standstill. At some point the motor will stall, and somewhere below this is the maximum jerk the machine can take (on acceleration). This velocity yields the S region size, which then can be plugged into the first equation to get the constant jerk curve. Anyway, that's the theory - I've been coding this for the past few weeks and am seeing good progress when I run it on the Zen Toolworks machine. It's also possible that this is a house of cards that will never work! I'll see.

As for true jerk - Transitions are noticeably smoother but the moves actually take the same time. TinyG runs a 5 segment jerk scheme not a 7 segment, so the ramp times are the same as an acceleration-only solution. I've crafted the code so I can drop in a 7 segment solution at some later date. Also, arguably if the jerk is controlled optimally around corners I might get some more speed, than I could get with a more approximate tangential jerk solution, but I'll also see about that

Thanks for the references! - Alden

from grbl.

chamnit avatar chamnit commented on May 28, 2024

Oops. I guess I was correct the first time. Simen calls the max_allowable_speed function during planning with the actual junction speeds (adjusted by the entry and exit factors). So they can change during planning. My bad.

from grbl.

jgeisler0303 avatar jgeisler0303 commented on May 28, 2024

Hi yall, here's a video showing the working of the planner: http://youtu.be/SqWd5xa_teY. There are also two more showing a feed-rate limited circle and varying feed-rate on my chanel.
I've been toying around a bit but maybe it can help to demonstrate the difference between nominal speed, max junction speed and acceleration/deceleration constraints.

from grbl.

aldenhart avatar aldenhart commented on May 28, 2024

Cool. Did you implement a way to limit replanning to just the latest blocks, or is the last 3-4 block effect just the effect of the math on the entire chain? I think it would be tough to implement a stop as the blocks are not able to get to the set speed (nominal), so I'm not sure how you determine where to stop the back-planning. - I should add, pretty impressive video that really shows the internals nicely.

from grbl.

chamnit avatar chamnit commented on May 28, 2024

Great work Jens! Looks like you're pretty much there. And, nice Matlab video. :) Just curious, what's the max feedrate limited by centripetal acceleration/max allowable acceleration of your system and how does it compare to what you are getting with your planner? Or in other words, are you seeing the same path speed by your planner compared to the closed-form solution?

I've been looking into trying to come up with a nice simple closed form path for an arc, but accounting for the tangential accel/decel in the beginning and end of an arc with the centripetal accel is causing some issues. Doesn't look like there is very simple way to define it. Still looking though.

from grbl.

jgeisler0303 avatar jgeisler0303 commented on May 28, 2024

@alden: there are three reasons why the planner might abort during the backwards loop before reaching the tail: the block is flagged as "full acceleration", the block has reached nominal speed or cumulated deceleration would allow for an entry speed higher than the max junction speed. This last rule is the one that applies in the video while cursing. Writing this, I start to wander if there are some strange cases that are not covered, though I haven't come across any.

@chamnit:I'm not sure how to compare the planner result to the theory: Theory gives: (150 mm/min/60 sec/min)^2/1 mm radius=6.25 mm/sec^2 centripetal acceleration. I thing I used 300 mm/min max_jerk but that's not an acceleration I could compare. Division by the time one line segment takes gives: (300 mm/min/60 sec/min)/(0.1 mm/(150 mm/min/60 sec/min))= 150 mm/sec^2. That's way higher. Dividing max_jerk by the even shorter time the transition takes (1 to 2 steps) leads to even higher values. So, I not quite sure how the change in velocity (max_jerk) and the centripetal acceleration can come together.
What do you mean by "simple closed form" path for an arc? Analytically describing the speed profile of an arc that possibly has to be accelerated into or e.g. all the way through or what ever tangential speed profile is given?

from grbl.

aldenhart avatar aldenhart commented on May 28, 2024

Jens - I'm trying to follow the math on the centripetal case. The jerk is the 3rd derivative so it's units are technically mm/min^3. The figure of 300 mm/min (ala grbl) I've always taken to be a velocity proxy for the jerk - i.e. the velocity at which the jerk is controlled. (A value of V=300 yields something on the order of a bit less than 50,000,000 mm/min^3 for the transition regions I've been working with). To compute the jerk itself you need to know the time over which the velocity changes hence the need for some sort of a radius or a region. The jerk itself is given by Jm = 4*(V-Vi)/T^2. T is in minutes, so T^2 is a very small number. As per my earlier post, it's getting the right value for T that I've been playing with.

I'm not sure this solves the centripetal question head-on, but it's a way to look at the problem - at least in cases where inertia is negligible. Planning the beginning end of an arc should be no different than planning any other curve. The elephant in the room is that to properly solve any of these cases you would need to introduce mass and understand the inertia matrix, perhaps dealing with tensor math. I've been trying to avoid this by pretending the system is massless (and I'm cutting a vacuum!).

from grbl.

jgeisler0303 avatar jgeisler0303 commented on May 28, 2024

Ahh, I never really thought about this: max_jerk in simen's code is a misleading name! It really should be "max_instantaneous_change_of_velocity" because that's how it's treated: when changing direction, the axis are allowed to make a one-time change of speed at the junction. So the units really are mm/min as stated. Sorry, I didn't detect this confusion earlier.

So what are the consequences? I did a little simulation to find the max_junction_speed of arcs from 1 to 100 mm radius. And guess what: max_junction_speed goes up linear with the radius instead of by the square root as theory would demand (constant centripetal acceleration rule).
Consequence: for small radii, the speed limit resulting from the liner relationship is smaller than that resulting from the square root. For very large radii, the speed limit resulting from the liner relationship is much higher than that allowed by the constant centripetal acceleration rule.
I have the following explanation: the arcs all have the same line segment length (0.1mm). So small diameter circles get very edgy and the junctions become more and more sharp corners. This deviation from the smoothness of circle results in lower speed limits. For large radii the junctions become almost straight, so there is no need to limit the cornering speed much (I got 15000mm/min for 100mm radius). But what is neglected is that when the line segments are travelled at this insanely high speed, the succession of instantaneous changes of velocity becomes very rapid thus increasingly invalidating the assumption of a one-time event.
Actions to take: additionally apply the constant centripetal acceleration rule to limit the nominal speed when processing arcs. But that wouldn't cover general curvy paths. So, either determine that max_jerk yields satisfactory results up to max machine speed or factor in some sort of line length and speed dependency.
Re intertia, friction and load:I wonder how "max_instantaneous_change_of_velocity" could be reliably determined.
Hope my writing doesn't cause to much pain :-) - Jens

from grbl.

aldenhart avatar aldenhart commented on May 28, 2024

I tried to figure out how to use the centripetal approach and did not come up with a solution. This is probably more a statement about my understanding of the problem and my (limited) math ability. The challenge is that the radius changes constantly based on the curvature defined between the joined lines [note: the "osculating circle"]. Perhaps this is what you are doing (computing the radius of curvature for each junction - in which case I'm really interested in how you did that).

I adopted an approach based more on the tangential component of the change in velocity in each axis as stated by the unit vectors of the joined lines. This also has the nice effect of being easily extensible to 6 axes. The approach is something like this: http://en.wikipedia.org/wiki/Acceleration#Tangential_and_centripetal_acceleration but not exactly. That still leaves the problem of determining the time interval over which the transition occurs, which looks to be the dominant factor in determining the jerk. So now I see that my "region" and your "radius" are not the same. Hmmm. Need to noodle this.

from grbl.

jgeisler0303 avatar jgeisler0303 commented on May 28, 2024

Hi Alden, I'm sure you have quite a deep understanding of the subject-matter, judging from the complexity of the tinyG code. It's probably more a case of misunderstandings, though I'm not sure what they might be (like for instance the "max_jerk" that isn't a jerk really). Also, I don't rely on any radius but rather go by the difference of the unit vectors, just like you. The whole trick then is - and this is base on simens work - to allow step changes in velocity at the junctions (limited in hight by "max_jerk" parameter). That circumvents the need to define a transition region.
As long as there are discrete line segments, there will be abrupt changes of direction making necessary abrupt changes of velocity (unless coming to a full stop at every junction). So what would really be needed is a path planning that smooths the paths (cutting corners) like i.e. splines do. But then Bresenham and the whole concept of feed forward control of steppers don't work any more and you get a more feedback control oriented scheme like EMC2 uses. Of course EMC2 can also drive steppers but the math behind it is MUCH more complicated. But then again an xmega might be able to do it.
I'd suggest to go by simen's junction approach, allowing abrupt changes in axis speeds - not tangential speed! - and have true jerk controlled planning only in the tangential direction because it is nice on the machine, especially belt driven machines. The abrupt changes in axis speeds that are needed to achieve sufficiently high cornering speed are not noticeable and shouldn't hurt the mechanics.

from grbl.

chamnit avatar chamnit commented on May 28, 2024

I think I can clarify this (hopefully). When traveling a path there are two acceleration components, tangential and normal to the path. These add up vectorally to a total acceleration. Right now, grbl really only looks at tangential by accelerating and decelerating along a linear segment. The normal or centripetal acceleration is assumed to only occur at a junction of two line segments and this is approximated by the max_jerk. This is not a true representation of actual centripetal acceleration, but a lightweight simple approximation. Inertia is a huge force (especially in the rotors and leadscrews) and you can't assume the system is massless. This directly translates to how much torque your system can output and whether or not it will skip steps when accelerating. This is why there is a max acceleration term.

Last night I completely replaced max_jerk (or instantaneous velocity change) with a more accurate maximum junction velocity based on centripetal acceleration. This significantly improved how well grbl behaves, particularly around curves and arcs. It really moved like you would feel like it should. Very smoothly into and out of every movement. The main drawback is that it involves some sine and cosine calculations, but I came up with a solution that removes them and simplifies the math significantly. This calculation only needs to be done once for each junction too. Here goes an attempt at an explanation:

First let's assume that at a junction we only look a centripetal acceleration to simply things. At a junction of two lines, let's place a circle such that both lines are tangent to the circle. The circular segment joining the lines represents the path for constant centripetal acceleration. This creates a deviation from the path (let's call this delta), which is the distance from the junction to the edge of the circular segment. Delta needs to be defined, so let's replace the term max_jerk with max_junction_deviation( or delta). This sets indirectly sets the radius of the circle, and hence limits the velocity by the centripetal acceleration. Think of the this as widening the race track. If a race car is driving on a track only as wide as a car, it'll have to slow down a lot to turn corners. If we widen the track a bit, the car can start to use the track to go into the turn. The wider it is, the faster through the corner it can go.

If you do the geometry in terms of the known variables, you get : sin(theta/2) = R/(R+delta) -> Re-arranging in terms of circle radius (R) -> R = delta_sin(theta/2)/(1-sin(theta/2). Theta is the angle between line segments given by: cos(theta) = dot(a,b)/(norm(a)_norm(b). Most of these calculations are already done in the planner. To remove the acos() and sin() computations, use the trig half angle identity: sin(theta/2) = +/- sqrt((1-cos(theta))/2). For our applications, this should always be positive. Now just plug and chug the equations into the centripetal acceleration equation: v_c = sqrt(a_max*R). You'll see that there are only two sqrt computations and no sine/cosines. Finally to compute the maximum junction velocity use: min(v_c, min( before->nominal_speed, after->nominal_speed)).

I need to polish the code a bit and find a bug where there is a velocity discontinuity when traveling the same path but changing feedrates. I'll post it on my fork as soon as I can.

Jens: For the closed-form solution for the arc path, I'm trying to come up with a way to treat the arcs the same way as a line in the planner, like being able to compute the intersection distances a priori. Basically to remove the need to plan each individual arc line segments that has an already known path and nominal velocity. The problem is that this involves a differential equation when trying to accelerate/decelerate the tangential component into and out of an arc. Right now, I'm putting it on the back burner until I finish replacing max_jerk with the max_junction_deviation.

from grbl.

aldenhart avatar aldenhart commented on May 28, 2024

Both you guys - This is great stuff. I look forward to the code.

from grbl.

chamnit avatar chamnit commented on May 28, 2024

To clarify a little more, this approach automatically takes care of any abrupt changes in direction (aka 'jerk'). For example, when entering a 90 degree junction, the max_junction_velocity will be nearly zero. For a junction at about 170 degrees, the max_junction velocity will be nearly at the nominal velocities.

In addition, the max_junction_deviation parameter does not have to be set very high. It seems to work fine at the level your machine's precision (0.001-0.002"). This also does not denote that there will be an actual deviation from the path. Instead, this should be considered a way to robustly compute the maximum junction velocity.

Alden: I agree with Jens. Taking on the challenge of TinyG with 6-axis control is very impressive.

from grbl.

aldenhart avatar aldenhart commented on May 28, 2024

So to put what you said in Gcode terms, the radius solution executes an exact-path path control mode (G61.1). A higher level trajectory planner (as opposed to line planner) routine that actually splines would be the G64 setting (continuous-mode path control mode). Very neat.

I'll post the tinyg code to the synthetos/tinyg github as soon as I get your changes incorporated and working satisfactorily on some real machines. Thanks for the props on the 6 axis stuff. There are a lot of changes that fell out of extending to 6 axes that are in the new code, including separation of the motors from the axes (EMC calls them "joints", which is technically correct, but I still call them "motors"), and independent configuration of motors from axes; mapping motors to axes (which is a really nice way of handling the Lumenlabs machine with a dual X gantry); the insertion of an inverse kinematics layer - which is currently a pass-through to handle cartesian coords. There is also all the rotary/linear conversion and alignment stuff. Yow. See the NIST RS274NGC_3 spec, section 2.1.2.5 "Feed Rate". But it opens up all kinds of nice rotary axis slave mode possibilities, some of which are implemented. Like the ability to set the extrusion rate as a rotary axis slaved to travel in the XY plane. I'll try to get the code working quickly so I can post it.

from grbl.

jgeisler0303 avatar jgeisler0303 commented on May 28, 2024

Wow, this thread is really sky-rocketing!
Chamnit: this seems like the perfect solution for the discrete line planning task. Great describing it too. I always find it kind of hard with out supporting graphics. I did think about pre-planning an arc like a single long line too. But the computational overhead doesn't seem to be worth the effort just for arcs. Especially with this new planner. Its a one-size-fits-all. Nothing more to add.

from grbl.

aldenhart avatar aldenhart commented on May 28, 2024

Progress update: I've coded Chamnit's approach into tinyg and have been testing it in a Zen Toolworks 7x12. Let's see if I got this right. I had to take the negative of the unit cosine value (dot product of the lineA and lineB unit vectors). The unit vector dot product for two lines which make a straight line with no bend is 1 (cos of zero degrees, as it should be), but the radius calculation really wants that to be 180 degrees - i.e. the radius of the osculating circle is infinite. Negating the cos value shifts the angle by 180 degrees, which I believe is what you want. Next, I had to trap 2 "blow up" conditions. (1) costheta = -1 (represents a straight line) blows up the radius equation, so return an arbitrary large number that's guaranteed to be larger than the nominal velocity of A or B (like a phone number). Blowup case (2) is where costheta = 1 (180 degree reversal). Return 0 velocity in this case. Perhaps this is what you are seeing with the discontinuity problem? By the way, the entire operation (extended to 6 dimension unit vectors) takes about 4300 machine cycles using doubles, which is about 268 uSec on a 16Mhz arduino. Not bad. I'll post more later - as I've got an entire 3 day weekend to work through this.
Out of curiosity, where are you guys located? I'm in Arlington, VA.

from grbl.

chamnit avatar chamnit commented on May 28, 2024

Alden: Yes, your math is correct. You will take the negative of the prior unit vector, since it is now pointing the opposite direction at the prior-current junction. If the bend is near 180 deg, this should give you a very large number, since it can fly through the junction only limited by the max nominal speeds of the two joining lines. In the reversal case, this velocity should be zero, and indicates that you must come to a complete stop.

I've coded everything, but I still couldn't figure out why grbl was acting weird with the discontinuities. Just this morning, I check with a fresh pair of eyes and found the problem. (Finally!) The exit_factors are not handled correctly. This is defined by the 'next' block's speed not the 'current' block, where the 'current' speed is always used to compute the exit speed. This fixed the discontinuity problem that I was seeing. I was also hoping that it would fix another one that showed up yesterday too. The rapid accel and decel in short line segments when traversing arcs. It shouldn't do this, but still looking for the bug.

I'm in Albuquerque, NM.

from grbl.

chamnit avatar chamnit commented on May 28, 2024

Jens: I remembered you stated a while back that you used the floating point representations of the unit vectors, rather than the rounded step length version, and this fixed your issue with rapid accel/decel in arcs. What exactly did you change? Is this updated in your fork? I'm thinking this is exactly what I've been seeing, as I can't seem to locate another reason why.

Also, I agree with your assessment with the closed-form solution of the arc, of it likely having a high overhead. I'll still attempt to come up to some simple solution, but looking at the math, don't hold your breath. For an on-board system, your approach is still the most efficient (just needs occasional error correction for large arcs). Or a pre-processor approach that I had sent jjg.

from grbl.

aldenhart avatar aldenhart commented on May 28, 2024

Glad you found the discontinuity bug. I've been spending the time trying to optimize trapezoid segment construction. The 2 segment case (head and tail only) is a bear requiring successive approximation. I'm probably missing some really obvious and elegant way to do this.

The cornering algorithm you described works well for me at low to moderate speeds, but I get problems at high speeds. The Zen grunches going around 90 degree bends. What speeds are you running, and on what kind of machine? I do fine at 350mm/min on the Zen, but I'm not doing so well at 600 mm/min or above. I'm not sure the Zen can do it - so I might just be hitting the limits of the machine. I'm going to try to get it running on the Lumenlabs MicRo3 this weekend which has a higher top speed, and possibly even the Probotix V90 which is the fastest of the 3. My issues might be simply that I don't have the parameters tuned well.

I'm exploring extending the algorithm to manage to controlled jerk - not just acceleration. It should be possible to solve for jerk by knowing the time the path spends in the transition region, which is the arc defined by the tangents of the circle, divided by the velocity through it. I did this by calculating "phi", the angle subtended by arc defined by the tangents. My early excel results are encouraging; the time falls of very slowly (relatively constant) from a zero to a 45 or 60 degree line, then falls off more and more rapidly as the angle becomes more acute. This would jibe with the observation that velocity reduction is OK at lower angles, but perhaps needs more correction at sharper angles. The time dropping off is what's needed to manage to jerk as J=a/t.

Hope the weather's nice in NM. It's good to know what time zone you are in. I think Jens is in Germany, but I'm not sure.

from grbl.

chamnit avatar chamnit commented on May 28, 2024

I'm running a Sherline 5400 mill with a DIY CNC upgrade via Pololu stepper drivers. It's posted on my blog. My seek rates are about 28ipm (~650 mm/m). My feedrates for the test program are about half that speed. Not sure what you mean by grunches (skipped steps?), but this is likely the limit of the machine. If you reduce the delta (path width) parameter, this should scale all of the junction velocities lower with respect to your acceleration parameter. You'll just have to tweak these two parameters to get the best response out of your machine(s).

from grbl.

aldenhart avatar aldenhart commented on May 28, 2024

Grunching is just the descriptive noise the machine makes when skipping steps. I'm probably running the machine too fast for its own limits - feed rates of 600mm/min. This is me just being impatient. However, I still see noticeable jerk at lower speeds around 90 degrees or greater corners. This is what's prompted the jerk exploration. I had developed some earlier algorithms that looked at the jerk contribution to each axis (since jerk has to be looked at as a vector) and scaled down the velocity to accommodate the limiting axis. This worked really well on sharp corners.

from grbl.

jgeisler0303 avatar jgeisler0303 commented on May 28, 2024

Chamnit: Yes the float vector math is in my fork (edge). The idea is this: With short segments and especially with larger radii the quantization has the effect that some lines have the exact same unit vector and then comes a (sudden) change often being different from the preceding by only one step. So the quantized radius constantly varies from inf to something finit and that is a huge difference! Using float math should result in roughly the same radius for every junction of an arc (and therefore a uniform junction speed).
Yes, I'm from Germany (Alden: how did you know?)
I'm really busy these days waterproofing the walls of the basement of my new home to be. That's digging a 2m deep trench and then applying a thick layer of nastily sticky bitumen. I get jealous at you really milling something. Guess I'll have to wait some 6 months, but then I'll have a whole basement room for myself :-) I'm expectantly following this thread!

from grbl.

chamnit avatar chamnit commented on May 28, 2024

Finally done and tested! The entry and exit factors were causing a lot of the bugs I was seeing. It took me a little longer than I'd like to admit to fix them. I had changed everything over to junction entry speeds to (1) remove unnecessary divides (2) and make things clearer. The entry and exit factors are only computed when converting to stepper rate info. Much like you have Jens. Now it's working beautifully. The code is posted on my edge fork. Fellas let me know what you think.

Alden: Now that I think about it 600mm/min sounds pretty fast for those little steppers on the Zen. NEMA 17 right? Stepper torque drops significantly at faster speeds and grbl doesn't account for it with its constant acceleration. For future mods, I suppose a scaling parameter could be introduced to account for motor torque reduction. I think I remember seeing that EMC2 does something like this too.

jjg: Still wondering how it went with the script. If you use the updated planner in my fork, it should fix everything! :)

from grbl.

aldenhart avatar aldenhart commented on May 28, 2024

Very good. I'm going out for some of those social festivities that take place when I'm not coding. Can't wait to try this out. Jens: it was a lucky guess.

from grbl.

aldenhart avatar aldenhart commented on May 28, 2024

I got the code running a Probotix V90. Using an acceleration value of 100,000 and a delta of 0.01 it handles a complicated draw (braid.gcode) at 600mm/min just fine. I'm continuing to push the speeds up. I think you were right about the little NEMA17s on the Zen conking out at those speeds due to torque drop-off.

from grbl.

chamnit avatar chamnit commented on May 28, 2024

Good to hear that it's working well! FYI, I just posted a bug fix I found this morning. The forward planner wasn't working quite right for some cases. Turned out the reverse planner was resetting the initial speed and would cause unintended jumps in speed when accelerating into short line segments. Should now work better.

from grbl.

aldenhart avatar aldenhart commented on May 28, 2024

Yes, it's also working quite well on the lumenlabs MicRo v3. So my conclusion is that the Zen is really finicky when it gets towards it's operating limit. That's nice in a way, as it's a good test of how far you can push the envelope. I can't wait to get the Grizzly 0619 mill converted so I can do some serious machining. (No, I don't just collect machine tools, I've kind of acquired all these as a test bed for the project). Did you see the video the John Knoll made of his Rong-Fu conversion using grblshield? http://www.youtube.com/watch?v=mHmDhi2u2BE Really nice work.

from grbl.

chamnit avatar chamnit commented on May 28, 2024

Great! I've been working on planner optimization and significantly increased the speed of the planner by an order of magnitude. Mainly by removing or limiting all expensive and unnecessary repetitive calculations (sqrts, trig, divides, repetitive trapezoid calcs). If I enable planning for the current arc implementation (with lots of trig computations), it now works for most cases, where it would completely choke before. Last night, I had a chance to implement and test Jens' arc approach by vector transformation. It flies through arcs with absolutely no problems. Tonight, I will test out the code some more and clean things up a bit. It should be posted later tonight or tomorrow. Overall the changes increase the size of the code a little, but the efficiency is much much higher.

Jens: I looked into the error propagation of your vector transformation approach. In a MATLAB script, I compared the norm () of the transformed circle vs. the known radius length. For a 1m radius circle and 0.1mm segments, the error was less than 1e-6mm. This was using MATLAB's doubles. It looks like there shouldn't be any issues with error propagation with this approach. Very nice work. Although, the error you did see maybe attributed to either numerical problems in converting from radius mode to offset mode, or the Arduino may not compute the sin() and cos() accurately enough. Not sure. Any ideas?

UPDATE: Ahh. Arduino only does single precision floating point calculations.

from grbl.

aldenhart avatar aldenhart commented on May 28, 2024

I've also been doing some work on the code. I've been experimenting with a sub-function to the corner planner to allow setting the delta value as the composite of per-axis deltas. The reason for this is to support machines with axes that have different characteristics. I've mentioned this case earlier - like a Z with different parameters than X and Y, and to support ABC axes. For example, the Probotix has 5 pitch X and Y (0.200" per rev), and a 12 pitch Z. Another example - if you use a rotary table for A then it's got totally different V, A and Jerk characteristics than X and Y.

The function looks at the unit vectors then computes the aggregate delta based on the contribution of each axis to the move. If all the deltas are the same then the geometry of the move has no effect. If Z (for example) requires a tighter delta (slower cornering) then moves with a Z component would be "downgraded" by the extent of the Z contribution to the move. All this in an effort to find the maximum speed you can run these machines.

from grbl.

jgeisler0303 avatar jgeisler0303 commented on May 28, 2024

Hi Chamnit, for the error value of the vector transform circle I stated here a while ago I actually used the relevant parts of the real grbl code wrapped in an s-function (code= strrep(code, 'double', 'float')). But I think there was a typo. The error was x: 0.014664, y: 0.0_0_99866 @100mm radius full circle (not y: 0.099866). Giving a norm of roughly 1/100mm. Not sure why that is. I would guestimate the difference between double and float could well half the exponent of the norm-error: 1e-3 instead of 1e-6 -- which is still no problem though. I'm really looking forward to try your code.

from grbl.

chamnit avatar chamnit commented on May 28, 2024

OK. The code is up on my fork. Full planner optimization and arc support now enabled. I use Jens' arc method with an additional error correction scheme and small angle approximation for the transformation matrix for speed purposes. Tested on my machine and works great. At first, I did run into arc hiccuping problems that didn't make much sense. I think they were related to running out of memory, but I'm not 100% sure. The problems were fixed after I did some memory cleanup and corrected some function variable types to pass and receive the correct variable types. Let me me know if it works with the arcs with you two.

Alden: Agreed. A separation of accelerations for each axis would be useful for CNC routers in particular. Right now, the single acceleration model works well, and I'm not sure how well it can handle too many other computations especially with arc now supported. I suppose you could compute the max acceleration in terms of the direction of junction centripetal acceleration, but that would change with direction... Hmm. Interesting problem.

Jens: You're right. I mistook the doubles as true double precision (I know you stated that before, but I guess I have a thick skull). In MATLAB, I looked at the error accumulated for single precision transformation matrices like you implemented. I got a path error on the order of what you did. So this makes sense. In most cases, the error will be less than the order of a CNC machine, as you stated, but not for all cases and all machines, like large CNC routers. So, I ended up creating a periodic path correction function. Now path error is guaranteed not to exceed 0.01mm. The path correction uses the same transformation matrix approach, so that I wouldn't have to compute the initial start angle with an atan2().

from grbl.

aldenhart avatar aldenhart commented on May 28, 2024

Pretty remarkable work, you guys. I've started reading through the enhancements. I'll get this onto an Arduino & grblshield as soon as I can get back to a work area, and do some testing.

from grbl.

chamnit avatar chamnit commented on May 28, 2024

Alden: How did the testing go? Still working on improving the planner. I was pretty conservative in some of the assumptions. I have to write a grbl simulator in MATLAB to really get a visual understanding of how the planner behaves, before implementing more computational efficiency logic into it.

from grbl.

aldenhart avatar aldenhart commented on May 28, 2024

I did some testing tonight. Things work OK for simple hand-entered moves, but I could not get it to run the "cornering torture test" that is braid_2d. I've updated github synthetos / tinyg with a gcode directory where I've put some of the files I've been using to test. Try running braid_300mm (300mm/min version). Instead of the loopy XY movement I get movement that's predominantly in the Y dimension with very little X - then Y crashes, so I shut it down. I just ran the same exact toolchain with a stock simen edge 0.7 and it worked on that file (as I've always seen). BTW I'm using the gctrl processing sketch to stream the file - github damellis / gctrl. In case you want to try it, I should point out that for some reason I can't get the JOptionPane Swing dialog to work to select the serial port, so I reverted to the v2 commit on the github which doesn't have that feature. I'm a noob to Processing, so perhaps there's something obvious that I'm missing.

Any ideas as to what's going on?

P.S. Any way to get Matlab for less than $2100? Yikes! I can't go there. but I'm not a student nor and educational institution nor a government, so I guess that makes me a professional by their logic - which is the only other choice. Professional hacker? No category for that. An INDIVIDUAL license was quoted as $2100. I'll be sticking with Excel and Wolfram Alpha.

from grbl.

chamnit avatar chamnit commented on May 28, 2024

That's strange. I just ran braid_300mm.gcode this morning before heading into work, and it ran just fine. I'm using a Python script to send grbl gcode blocks. I did notice at one point that my eeprom had changed on me suddenly and started to behave erratically. I'm not certain I had made the correct changes in the code to reset them. But once I did re-write them manually, it hasn't had that same problem since. This might be the weird response you got. I'll look into it some more, as I'm not finished with all of the changes in the planner code.

Yes MATLAB is pretty stupid expensive, especially if you're not a student. Fortunately my work has a license. I'm working on converting my general programming over to Python w/ SciPy for portability purposes and being nearly just as powerful and flexible. But I'm still a way faster coder in MATLAB.

from grbl.

aldenhart avatar aldenhart commented on May 28, 2024

Odd. Can you get me the script you use just so I can be as aligned as possible? I'll re-test over the weekend.

from grbl.

chamnit avatar chamnit commented on May 28, 2024

This is one that I have been using recently. It forces characters into the Arduino serial read buffer, so grbl doesn't have to wait for a serial send and response for the next block. You will need the pyserial library for it work. On a Mac, type 'sudo easy-install pyserial' at a terminal prompt.

Let me know if it turns out that settings are not compatible. Like I said before, a ways back I had to re-write them all because they had gone corrupt. I need to look into if just changing the settings version number will automatically reset the eeprom.

#!/usr/bin/env python
"""\
Stream g-code to grbl controller
"""

import serial
import re
import glob
import time
import sys
# import getopt

device_str = '/dev/tty.usbmodem*'  # Serial port device string. Wildcards OK.
filename = 'grbl.gcode'
RX_BUFFER_SIZE = 128
verbose = True
# TODO: Single block mode
# TODO: Complete command line interface

# Search for serial device and returns name(s).
def scan():
    return glob.glob(device_str)

# Search for and open Arduino port based on search string
portscan = scan()
if len(portscan) != 1 :
    print "No port or multiple ports found:",portscan
    sys.exit()
print "Grbl port found: ",
s = serial.Serial(portscan[0],9600)

# Open g-code file
f = open(filename,'r');

# Wake up grbl
print "Initializing grbl..."
s.write("\r\n\r\n")

# Wait for grbl to initialize and flush startup text in serial input
time.sleep(2)
s.flushInput()

# Stream g-code to grbl
print "Streaming [",filename,"] to grbl..."
l_count = 0
c_line = []
for line in f:
    l_count += 1 # Iterate line counter
#     l_block = re.sub('\s|\(.*?\)','',line).upper() # Strip comments/spaces/new line and capitalize
    l_block = line.strip()
    c_line.append(len(l_block))
    grbl_out = '' 
    while sum(c_line) > RX_BUFFER_SIZE | s.inWaiting() :
        grbl_out += s.readline().strip() # Wait for grbl response
        del c_line[0]
    if verbose: print "SND: " + l_block,
    s.write(l_block + '\n') # Send block to grbl
    if verbose : print "BUF:",str(sum(c_line)),"LN:", str(l_count),"REC:",grbl_out

# Wait for user input after streaming is completed
print "G-code streaming finished!\n"
print "WARNING: Wait until grbl completes buffered g-code blocks before exiting."
raw_input("  Press <Enter> to exit and disable grbl.") 

# Close file and serial port
f.close()
s.close()    

from grbl.

aldenhart avatar aldenhart commented on May 28, 2024

Sonny, I had a chance to run your script on my setup this morning (Arduino Duemilenova, grblshield, Zen Toolworks 7x12). I used the braid 300mm file you picked up earlier. I think there are some things in the planner that still need work. Have you run it side-by-side with stock grbl edge 0.7? I did this and got different results. This could be an error in my setup, but it would probably be good to verify that these 2 trace the same exact path.

from grbl.

chamnit avatar chamnit commented on May 28, 2024

Weird. I have checked against Simen's stock 0.7b grbl. It works exactly the same, as it should, since it is logically the same except for the G02/03 arc, max junction speed calculations, and some additional planner logic. I just noticed as I was typing that you are using a Duemilenova. I think this is the problem. From what I understand, Simen did a lot of things to try to fit grbl with acceleration planning onto an Atmega 168. The changes that I made probably now don't fit, plain runs out of memory (1k vs 2k), or you are seeing some problems from having a severely truncated buffer size (5 blocks from 16). I use an Arduino Uno and have been basing all of my test on it. Sorry, I don't have an Arduino Duemilenova.

From my matlab grbl simulator, you will want to have as large of a buffer size as possible, because this will allow the planner to plan for much higher overall speeds along the length of the path in the buffer. In other words, since the braid code has a lot of rapidly changing short blocks that eat up the buffer, there is not enough planned lengths to accelerate from zero speed at the end of buffer to the current running speed at the beginning. I would bet that Simen's max_jerk is hiding some of those issues on the Atmega 168 builds. Because of this, I wouldn't recommending using my code on one of these and use 328p or greater only, at least for now.

Also, I have recently done re-written some of the planner code to improve speed in some extreme and time critical cases. They should be posted here shortly after I test and validate the code. Probably later this week.

from grbl.

aldenhart avatar aldenhart commented on May 28, 2024

I'll run it on an Uno. This may be the issue. I'll look for your new code and do a pull from your fork when it's available.

from grbl.

aldenhart avatar aldenhart commented on May 28, 2024

So I'm running it on an Uno right now and it works great. The Duemilenova is actually an Atmega 328p, so I'm not sure what's up here. I'll continue to investigate.

from grbl.

chamnit avatar chamnit commented on May 28, 2024

Awesome, Alden! I really appreciate that you are taking the time to test the code. You're right. I thought all Duemilenove's were Atmega168's. That's strange that it works on the Uno but not the Duemilenove. From what I can tell, the only difference is the USB interface. If you find out anything, let me know, so I can look into it.

Just posted the planner improvements on my fork. The main changes are removing the modulo operators which is very expensive, considering how many times it is called, saving about 192bytes of run-time memory (increased the buffer size b/c of this to 18, could go to 20) and improving the planner logic. These changes seem to make grbl run smoother, but this could be just in my head. FYI, this update will reset your EEPROM settings, so don't forget to write down all of your settings beforehand, if you haven't already.

After this, I don't see much room for more improvement of the current system, now that arcs are fully planner-enabled and the planner is working fast and efficiently. So I'l likely start looking at some other features, like status reports and an e-stop.

from grbl.

jjg avatar jjg commented on May 28, 2024

Good news everyone!

This morning I was able to successfully cut a circle using the code from chamnit's fork. I ran into some trouble getting it to work using the ruby script (stream.rb) but when I "spoon-fed" the gcode line-by-line it worked perfectly!

I'm going to do some more complex tests to verify but I'll need to ether figure out why the ruby script is giving me trouble or find another way to stream the gcode first (I had written a little OSX app to send the code one line at a time awhile back, but I seem to have misplaced it...). Once I get that straightened out I'll see if I can cut some more complex shapes.

Thank-you all for your work on this, I can't wait to start making more stuff with my laser!

from grbl.

chamnit avatar chamnit commented on May 28, 2024

That's great to hear! What kind of trouble did you run across with the ruby script? In some of my tests, I found that the serial interface is the bottleneck now, especially when you have two arc motions concurrently. Once the first arc finishes, grbl has to send an ok then receive the next block and process it. The lag can cause the buffer to empty before it starts up the next arc.

Try the Python script that I posted for Alden about a few days back. You may have to hack it a bit to get it to work if you don't have a Mac. It forces 128 characters of g-code into the Arduino's serial receive buffer and keeps it there for grbl to access it immediately, no waiting for any serial handshaking. The script keeps sending more characters by tracking how many has been emptied from it, always trying to keep it full.

from grbl.

jjg avatar jjg commented on May 28, 2024

I was able to find the app I wrote to feed the gcode one line at a time (or rather, wait until it hears "OK" from grbl before sending the next line) and using this was able to cut the circle with no problems. I tried some more complex gcode files that I had handy and while they didn't turn out perfect I think the problem had more to do with the files (the both generated some "bad number format" errors while running) than grbl itself.

Hopefully tonight I'll have time to create some new drawings and try the whole process front-to-back, and debug the gcode number format errors if they come up again. Thanks again for working so hard on resolving this issue, it's very exciting to see the results and now I can move on to improving my hardware :)

BTW once I clean it up and debug it a bit I'll be posting the code for my OSX streamer app. It's probably overkill compared to the scripts but it provides some visual feedback and info that is helpful for debugging gcode files/scripts.

from grbl.

basics0603 avatar basics0603 commented on May 28, 2024

Wow you guys are smart. Just completed my CNC machine and fear my question doesn't warrant your expertise but here I go. I use phlatboys and Sketchup to generate Gcode, passing to m arduino via GCodesender. Phlatboys seems limited to cutting out 2D stencils. I have CamBam on trial but cannot get it to produce linear interpolation instead of circular. (hence m stumbling on this thread). My options are to look at different CAD and Flow software or post process the Cambam (which I don't own yet). You suggestions would be highly appreciated.

from grbl.

chamnit avatar chamnit commented on May 28, 2024

You can either use my fork of grbl, which supports arcs and has a
number of other improvements to grbl, or use the grbl preprocessor I
wrote, preGrbl, to convert the arcs to linear interpolations. The
first option is easiest.

On Oct 6, 2011, at 6:48 AM, basics0603
[email protected]
wrote:

Wow you guys are smart. Just completed my CNC machine and fear my question doesn't warrant your expertise but here I go. I use phlatboys and Sketchup to generate Gcode, passing to m arduino via GCodesender. Phlatboys seems limited to cutting out 2D stencils. I have CamBam on trial but cannot get it to produce linear interpolation instead of circular. (hence m stumbling on this thread). My options are to look at different CAD and Flow software or post process the Cambam (which I don't own yet). You suggestions would be highly appreciated.

Reply to this email directly or view it on GitHub:
https://github.com/simen/grbl/issues/26#issuecomment-2309338

from grbl.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.