Currently Unrecognized G-Codes

Well, if you are approaching a curve, could you not issue the $15 prior to entering the curve to reduce the max feedrate and then after you leave the curve you issue a $15 to raise the max feedrate? Since the controller won’t exceed the max feedrate, it’s a way to accomplish some rudimentary level of acceleration planning. Correct? If so, you could run max feed rate on long straight cuts and slow down when you hit the corners… However, I am curious about the dynamics and if it would cause a problem having such an impulse (48 ipm to 20 ipm as an example)

The deal is, the feedrate is set at the start of a gcode movement. You could put a lower feedrate in the gcode for the curve - no need to change the maximum. Maybe best would be to put a “G4 Pnnn” line in just before the turn to pause nnn milliSeconds before proceeding.

1 Like

So, if I understand it correctly, it’s possible to write software/function to take a gcode file, figure out where acceleration may exceed a certain limit, and put in some feed rate changes to slow it down. It wouldn’t be simple to do, but I’d think its possible… assuming such a gcode post-processor hasn’t already been developed.

With respect to “grbl”, this acceleration planning is normally done by the controller, correct?

Where is acceleration planning normally handled? Is it in the gcode sender or in the controller?

in the controller

Would I be correct in stating that its technically possible to generate gcode that includes feed rate changes when needed?

not quite, but you can do a rough approximation in the g-code

true acceleration planning has the speed as a trapazoid, ramping up smoothly
(limited by whichever axis has the lowest acceleration limit) to the desired
feed rate, and then ramping down at the end (not necessarily to zero, depending
on the allowed acceleration, a joint doesn’t require coming to a complete halt,
which is a huge benefit when dealing with curves that are submitted as many line
segments, such as lettering would be)

grbl does this by breaking every movement down into the different phases, and as
it gets the next g-code command, it looks back at what it’s already got queued
and modifies the planned movement based on what is needed to interface cleanly
with the next movement.

David Lang

without acceleration planning in the controller, you are always asking for
infinate acceleration as you go from zero to any feed rate, because the g-code
is telling it to be at the full feed rate at the instant it starts moving.
You can accept some amount of error, so if you were to step up the feed rate
through lots of short movements [1] then you would simulate the acceleration
limit by keeping each step to an acceptable error

[1] but then you run into the problem of the rate that the arduino can process
commands, and if you aren’t careful you can easily end up with the situation
where instead of a steady acceleration, you end up with a jerky start-stop
movement instead.

David Lang

I used to work at a place where the software architect would call that a “SMOP” - a simple matter of programming. Also “anything is possible with software”. Anything can be trivialized, making it work is…

I believe the current release of grbl ‘looks ahead’ a couple of lines of gcode to evaluate acceleration, and works to limit it. Note that it is highly crafted hand-written code, optimized over years for its singular task. If I remember right, he’s taking a different approach with the next version, but that’s still pretty far in the future, I don’t think any of that is out for public view.

That’s the case, grbl is controller firmware, no GUI or gcode sender. Just serial in/out and open-loop motor control. But very good motor control…

as the SMOP, I’ll repeat my appeal/plan

rather than trying to port the acceleration planning from grbl to maslow,
instead take the approach of making a fork of grbl that supports the maslow.

This is a couple ‘simple’ steps

  1. modify grbl so that instead of precisely timed stepper pulses, make a version
    of the motor driver routine that can drive servos with PID loops (the timing is
    far less critical, so the loop does not have to run as frequently)

make sure you keep the encoder routine separate (so the pid loop makes a
function call to get the current position). This will allow you to support
different types of encoders (absolute vs quad)

If these are compile time options, then code and binary size are much easier to
deal with.

note that this would make building large format coreXY machines very easy.

  1. add an additional kinematics model to grbl to handle the maslow motion type.

This is probably the harder part

David Lang

I agree with the approach, but is probably sometilhing that is beyond my personal skill and availability to implement . So, I was wondering if we could at least mimic in gcode to some extent. I agree things can become jerky unless the spees step down/up increment is not kept to a small size… what that size is, I don’t know, and it’s possible that it will be too small to be practical.

However (and this would tie ground control to the firmware even more) I was wondering if we could precompute beginning and ending feed rates for each gcode line and send then to the controller (I don’t think sending an ending gcode rate is part of the gcode standard) and then the coordinated move would calculate the steps based upon a linearly increasing/decreasing feed rate… i think this would be simpler to implement than to send blocks of gcode to the controller and have the controller figure it since ground control/firmware, I think, is currently based on sending/executing gcode lines one at a time.

The thing is, a line of gcode gets decompiled into a lot of little steps for a long move. What you really want is for only the first few steps or the last few steps to be affected.

That would happen in either Motion::coordinatedMove() for a straight line, or Motion::arc() which take a gcode movement command apart into steps for the PID loops. If you keep track of your most recent position, these routines can look ahead at the next few steps of and limit the feedrate based on the change of direction or distance of the upcoming steps. I think that would capture at least part of the idea of motion planning.

Yes, that makes sense. Basically, accelerate/decelerate at a set maximum limit for the beginning/end portions then go constant velocity for anything in the middle. I don’t think that tweak would be hard to implement if everything else can be figured out. At the start of both of those routines, you know the number of steps, the distance of each step and the feed rate, so I think the controller could pre-plan the move (assuming ground control sends it appropriate start/end feed rates).

It’s certainly not the ideal way of doing it and acceleration planning has been something desired for a long time, but as far as I know, no one is working on it.

By this I think you mean GroundControl would send start/end feed rates (or some scaling figure) as an AdvancedSetting. Those Motion.cpp routines use feedrate when creating the steps, that’s where to do the magic.

Well, actually ground control would parse the gcode, preprocess each line and add append a “non-gcode standard compliant” start/end feed rate and send it to the controller. This way we don’t have to completely rework the interface between ground control and the controller in order to send blocks of gcode for the controller to do the processing. The motion.cpp routines would use those feed rates (along with a new maximum acceleration setting for each axis) in creating the steps.

That would require re-writing GC as well as Motion.cpp that sounds like a pretty big rewrite to me…

Re-writing blocks of gcode seems overkill. The controller has the knowledge of the most recent position, angle and speed, and those two Motion routines can determine whether the gcode being converted into steps needs a special feedrate. The destination angle and distance required by the gcode command are already calculated in those routines, you just need to decide whether they the upcoming steps are greatly different in size or at a greatly different angle from the previous one(s) and use the acceleration scalar if so. Carrying along the most recent values of distance and angle between calls would make that possible.

I might be missing something… but how does the controller know what the acceleration needs to be at the end of the gcode line without it knowing what the next gcode line or being told what to end at? For example, first first gcode is a straight line G1 X50 and the next is a hard right turn G1 Y50. When processing G1 50, it doesn’t know it will receive a G1 Y50 so runs at max speed. Then it sees the G1 Y50 and you’re already going to fast.

An alternative (which still requires pre-processing) is for anything that needs acceleration planning is add a G1 Fxxx statement where xxx is the start feed rate and then on the next gcode, append the Fyyy where yyy is the end feed rate. The controller, when it receives a Fxxx statement, sets a flag and if when processing the next gcode sees an appended Fyyy statement, it computes using acceleration planning. My concern in doing this is if some gcode generator mimics this, that it will be wrongly interpretted, that’s why I proposed something like:

G1 X50 F3000 F2000

When the controller sees a second F, it knows to interpet that as an end feed rate and then performs acceleration planning for that move.

I don’t think it would be all that big of a rewrite. Not saying its easy, but the pre-processing would be done by ground control when the gcode. Maybe there’s a few extra parses needed in the firmware to extract a second F statement, but that doesn’t seem too hard. I don’t think you’d be touching many different files.

You’re right, of course. I plead coffee deficiency. grbl queues up the steps before they get to the routine that does motor control, so it can adjust things in the queue. To handle it in a similar manner, we would have to either read a line ahead of the one we’re processing.

I’ve been wondering though, shouldn’t a properly tuned PID loop handle this without need for special acceleration planning? Too, have you personally seen instances of sled position error that were unquestionably caused by acceleration issues and not friction or PID tuning? Not sure that I have. What would a simple gcode program look like that consistently produces these errors? It would be good to be able to reliable reproduce the error before creating solutions…

Maslow acelleration is trickier than a Cartesian machine. Rather than being concerned about just x and y (ignoring z, a, b, c, etc for now) the Maslow’s polar architecture means that the motor forces are in constantly changing directions towards the corners, and gravity and friction throw in some interesting twists.

I think @blurfl is close, the PID loops and encoder feedback could be solving a fair part of the problem by controlling motor forces based on position error

1 Like

Sure, but I think that if you slam into a 90 degree right turn at full speed, it’s too late to make any correction based upon position error. I think you have to look ahead. Either we preprocess things before they are sent or the firmware buffers multiple lines and does the processing itself.

Have you seen errors on squares? Some of the calibration tests use squares, I haven’t run those in a while, but I don’t remember seeing errors in the corners.

Personally? No… but I run slow and not near full feed rate… but I would like to run at 48 ipm on straight and long runs and slow down when the sled enters a curve… like a race car. Isn’t that what acceleration planning is about?

no, don’t do non-standard g-code, do one of two things

  1. set acceleration limits with $ settings (they don’t change from line to line
    after all)

  2. instead of one long move at a feed rate of 40 ipm, do a short move at 10 ipm,
    another short move at 20 ipm, another short move at 30 ipm, a long move at 40
    ipm, a short move at 30 ipm, a short move at 20 ipm, and finally a short move at
    10 ipm (or whatever stepping works well)

#2 can be done in your CAM program (I understand that fusion 360 has an option
for this sort of thing)

#1 is the right long term answer (if we don’t convert over to grbl derived
firmware)

David Lang