Closed edwilliams16 closed 8 years ago
I'm not sure where this is documented.
The DEFAULT_MAX_ACCELERATION
values are used to limit the acceleration for each axis, so acceleration will go no higher than the given values. Depending on which axes are involved in a move, one or more of these values will be used.
The DEFAULT_ACCELERATION
value is the acceleration initially applied to all planner moves, which is then constrained by DEFAULT_MAX_ACCELERATION
for all the axes involved in the given move.
These acceleration settings are used when the planner sets acceleration for each stepper block. See the section of the planner.cpp
function buffer_line
starting with // Compute and limit the acceleration rate for the trapezoid generator.
for the relevant code.
I've got it, I think. DEFAULT_MAX_ACCELERATION
represents some per axis hardware limit - depending on mass, available torque etc. DEFAULT_ACCELERATION
is then the tweakable parameter - while the previous parameter prevents you from setting it higher than the hardware allows.
Thank you for taking the time to answer my questions.
The DEFAULT_MAX_ACCELERATION
values are used to initialize planner.max_acceleration_units_per_sq_second
. You can change the planner.max_acceleration_units_per_sq_second
array using the GCode command M201 Xn Yn Zn En
or the LCD menu options Amax X
, Amax Y
, Amax Z
, and Amax E
. If you save to EEPROM the values you set here will be preserved across reboots.
The DEFAULT_ACCELERATION
value is used to initialize planner.acceleration
. You can change planner.acceleration
using the GCode command M204 Pn
or the LCD menu option named Accel
. If you save to EEPROM the value you set here will be preserved across reboots.
I'd just like to confirm a few things before I drop this.
1) DEFAULT_ACCELERATION
and DEFAULT_MAX_ACCELERATION
(all axes) are all in mm/sec^2
(The code has reference to units/sec^2 - but I take it that somewhere unit=mm)
2) DEFAULT_ACCELERATION
refers motion in the x/y plane (at least for Cartesian 3D printers). (Comments imply x/y/z/e)
3) Acceleration in the E-axis in printing moves (neglecting advance) is scaled to the acceleration in the x-y plane, by essentially the ratio of the filament cross-sectional areas leaving and entering the extruder.
4) Given (3) and that typically DEFAULT_MAX_ACCELERATION
(E) > DEFAULT_MAX_ACCELERATION
(X,Y), DEFAULT_MAX_ACCELERATION
(E) is never limiting in a printing move.
5) Given (4), the effective range of adjustment is 0<DEFAULT_ACCELERATION
<max(DEFAULT_MAX_ACCELERATION
(X,Y).
Thanks for your patience in this.
You can cross #1 off your list. The units are mm/sec^2
Everywhere in the configs, where you read mm/s or mm/s^2 replace it by units/s or units/s^2. Where unit is the unit you used in DEFAULT_AXIS_STEPS_PER_UNIT
. Theoretically you can use inch, foot or km or nm, but because of the limited exactness of our calculations (float, long) you'll get the best results for something around mm, where the numbers are not too small and not to large..
So that has handled #1 nicely...
So that has handled #1 nicely...
Well, As Blue-Marlin says... The units can be anything. But I've only seen units specified as mm/sec^2.
2) DEFAULT_ACCELERATION refers motion in the x/y plane (at least for Cartesian 3D printers). (Comments imply x/y/z/e)
@edwilliams16 DEFAULT_ACCELERATION
is used to set the default value of planner.acceleration
. The current value of planner.acceleration
is applied to new planner blocks that include moves in X, Y, or Z, and also E.
DEFAULT_TRAVEL_ACCELERATION
is used to set the default value of planner.travel_acceleration
. The current value of planner.travel_acceleration
is applied to new planner blocks that include moves in X, Y, or Z but not E.
DEFAULT_RETRACT_ACCELERATION
is used to set the default value of planner.retract_acceleration
. The current value of planner.retract_acceleration
is applied to new planner blocks if they only include moves in E. (Not just retract moves, it appears.)
I'm obviously not explaining myself very well - or I don't understand how things work. Let's take a simple case where the trapezoid is just a triangle, accelerating from zero up to a velocity and then decelerating back to zero. Let's suppose we are making a printing move in the x direction, where we move a distance 2d while extruding a distance 2d_e of filament in a time 2t. Let the x-acceleration be a, and the extruder acceleration be a_e (all in mm, secs or your favorite units). Then d =a t^2/2 and d_e = a_e t^2/2 and so a_e = a (d_e/d). So the acceleration of the E-axis (in mm/sec^2) is much smaller than the acceleration of X-axis (in mm/sec^2), by the ratio of d_e/d, which is also the ratio of the extrusion cross-sectional area to the filament cross-sectional area. So the "default acceleration" cannot refer to both E and X because their values differ by a factor of 16 or so. I conclude that the number one assigns to DEFAULT_ACCELERATION is an x/y plane acceleration. It does however feed through in the code to determine the much smaller E (and Z) accelerations.
The code itself says it best. Here's what planner.buffer_line
does with the configured acceleration values…
// Compute and limit the acceleration rate for the trapezoid generator.
float steps_per_mm = block->step_event_count / block->millimeters;
long bsx = block->steps[X_AXIS], bsy = block->steps[Y_AXIS], bsz = block->steps[Z_AXIS], bse = block->steps[E_AXIS];
if (bsx == 0 && bsy == 0 && bsz == 0) {
block->acceleration_st = ceil(retract_acceleration * steps_per_mm); // convert to: acceleration steps/sec^2
}
else if (bse == 0) {
block->acceleration_st = ceil(travel_acceleration * steps_per_mm); // convert to: acceleration steps/sec^2
}
else {
block->acceleration_st = ceil(acceleration * steps_per_mm); // convert to: acceleration steps/sec^2
}
// Limit acceleration per axis
unsigned long acc_st = block->acceleration_st,
xsteps = axis_steps_per_sqr_second[X_AXIS],
ysteps = axis_steps_per_sqr_second[Y_AXIS],
zsteps = axis_steps_per_sqr_second[Z_AXIS],
esteps = axis_steps_per_sqr_second[E_AXIS],
allsteps = block->step_event_count;
if (xsteps < (acc_st * bsx) / allsteps) acc_st = (xsteps * allsteps) / bsx;
if (ysteps < (acc_st * bsy) / allsteps) acc_st = (ysteps * allsteps) / bsy;
if (zsteps < (acc_st * bsz) / allsteps) acc_st = (zsteps * allsteps) / bsz;
if (esteps < (acc_st * bse) / allsteps) acc_st = (esteps * allsteps) / bse;
block->acceleration_st = acc_st;
block->acceleration = acc_st / steps_per_mm;
block->acceleration_rate = (long)(acc_st * 16777216.0 / (F_CPU / 8.0));
The code itself says it best.
Joao won't like this: But the code is the ultimate documentation! :) But of course, that only works if you can read the code.
We're talking past each other. I've read that code already. It calculates an acceleration, using the default and the limits. I'm hoping I don't have to read stepper.cpp to figure how it is really used. block->acceleration is a physical quantity, measured in mm/sec^2. WHAT IS IT THE ACCELERATION OF? - given, if you believe my argument above, that, for instance, the acceleration in the E-axis is much smaller than in the x/y plane. Perhaps I'm just supposed to treat DEFAULT_ACCELERATION as a number to be plucked out of the air - not representing any physical motion? But that seems unlikely.
block->acceleration … WHAT IS IT THE ACCELERATION OF?
It is the acceleration rate of the whole move, already constrained to the lowest acceleration of all the axes involved.
Indeed it is... But as a value, it is representative of the acceleration in the X/Y plane or what? The code is the embodiment of some physical model. In that model DEFAULT_ACCELERATION is a physical quantity (in mm/sec^2) representing acceleration of something. What? I'm really not that interested in trying to trace it all through the code. I want to know what it represents in the physical model. I assume the code authors know what that is. When I set it to a value, it helps if I know what physical quantity it represents. Making all the max accelerations infinite, if I print a straight line along the x-axis, what is the relation between DEFAULT_ACCELERATION and the acceleration of my extruder along the x-axis at the beginning and end of the trapezoid? I don't know how to make the question any clearer.
What? I'm really not that interested in trying to trace it all through the code. I want to know what it represents in the physical model.
@edwilliams16 I am absolutely insisting on a more polite tone here. I'm not gong to compromise on that. Please be respectful even if you are frustrated.
I apologize if I came over as impolite. I realize you are all volunteers and don't have to tell me anything. I just seem to be going around in circles, asking the same question in as many different ways as I can come up with. It's fine if you don't know the answer. Tell me that, and I'll stop asking the question.
@edwilliams16 https://github.com/edwilliams16 I have been through the code a thousand times and even had a look at other firmware like Sailfish, and Sprinter. The all use the same base code from Grbl with small changes.
The code is the embodiment of some physical model. In that model DEFAULT_ACCELERATION is a physical quantity (in mm/sec^2) representing acceleration of something. What?
Since you can set the acceleration for each axis, I always assumed that the trapezoid calculations use the assigned acceleration per Axis. The code in this issue trail seems to do that within an array (4 axis x,y,z and e).
Does that answer your question? Is the question, are the calculations for the axis all based on one default acceleration figure or are the calculations based on specific acceleration setting per axis? (I think the latter is the answer)
On 8 June 2016 at 15:00, edwilliams16 notifications@github.com wrote:
I apologize if I came over as impolite. I realize you are all volunteers and don't have to tell me anything. I just seem to be going around in circles, asking the same question in as many different ways as I can come up with. It's fine if you don't know the answer. Tell me that, and I'll stop asking the question.
— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/MarlinFirmware/Marlin/issues/3961#issuecomment-224487731, or mute the thread https://github.com/notifications/unsubscribe/AIOTKc-tyN_7GEDC8ooGCF57iXMw53mbks5qJkyGgaJpZM4IuM55 .
I'm not having much success finding out how the Grbl/Marlin planner code actually works. The code is dense and I've found virtually nothing in the way of documentation. I'm delighted to talk to someone who has dug into this.
Since you can set the acceleration for each axis, I always assumed that the trapezoid calculations use the assigned acceleration per Axis. The code in this issue trail seems to do that within an array (4 axis x,y,z and e).
I don't see how this can be true. Suppose we print a single straight line in the x-direction - one block - with the x-velocity a trapezoid as a function of time. We want even deposition along the line, so the extrusion rate has to follow the same trapezoidal shape as a function of time, with the extrusion rate at every point on the trapezoid directly proportional to the x-velocity. Thus the accelerations on the X and E axes also are directly proportional, and not independently specifiable. (At the risk of derailing the thread, "advance" breaks this proportionality, making the extruder velocities greater in the acceleration phase and smaller during deceleration, by an amount proportional to the acceleration.) So DEFAULT_MAX_ACCELERATION is a vector (over X,Y,Z,E). The code quoted above forces the accelerations finally used to not exceed the maximum values for each axis, one by one. However, DEFAULT_ACCELERATION is a scalar - once this is limited, if required, by the axis limits, only a single value should be required in (and is provided to) the stepper routine, because the accelerations used by each axis are direct multiples of this single value. My question is which, if any, of the proportional accelerations for the four axes is the acceleration passed to the stepper (which in turn derived from DEFAULT_ACCELERATION). My guess it is in fact none of them, but is the acceleration in the X/Y plane (i.e. the derivative of the speed in the X/Y plane) - at least that's how I would have done it.
@edwilliams16 I could not find a description on how it works via google either. So i went to Github/grbl to look it up. The code is very detailed described in github/grbl. From what I read in the code comments (see an extract from grbl/stepper.c) the multiple axis are synced with each other through a smoothing algorithm which implies that each axis has its own trapezoid calculation but I might be wrong.
The Stepper Driver Interrupt" - This timer interrupt is the workhorse of Grbl. Grbl employs the venerable Bresenham line algorithm to manage and exactly synchronize multi-axis moves. Unlike the popular DDA algorithm, the Bresenham algorithm is not susceptible to numerical round-off errors and only requires fast integer counters, meaning low computational overhead and maximizing the Arduino's capabilities. However, the downside of the Bresenham algorithm is, for certain multi-axis motions, the non-dominant axes may suffer from un-smooth step pulse trains, or aliasing, which can lead to strange audible noises or shaking. This is particularly noticeable or may cause motion issues at low step frequencies (0-5kHz), but is usually not a physical problem at higher frequencies, although audible. To improve Bresenham multi-axis performance, Grbl uses what we call an Adaptive Multi-Axis Step Smoothing (AMASS) algorithm, which does what the name implies. At lower step frequencies, AMASS artificially increases the Bresenham resolution without effecting the algorithm's innate exactness. AMASS adapts its resolution levels automatically depending on the step frequency to be executed, meaning that for even lower step frequencies the step smoothing level increases. Algorithmically, AMASS is acheived by a simple bit-shifting of the Bresenham step count for each AMASS level.
I wouldn't have read it that way. Bresenham is a venerable fast algorithm for drawing diagonal lines across a computer screen at slopes incommensurate with the screen resolution. It generalizes in an obvious way to multiple dimensions and to a counter that is not tied to an axis pixel position. I presume this applies to the stepper algorithm in that for each tick of an ISR you to look to see if it is time to send a stepper pulse to each of the axes. We are "drawing straight lines" in (X,Y,Z,E,t) space in that the ratio of the step rates is constant at each point on the discrete time axis (same trapezoid, but digitized differently depending on the scale!). AMASS I take to be a smoothing scheme that dithers the steps in some clever way - not calculating multiple trapezoids, but digitizing multiples of the same trapezoid. The purpose of AMASS is to get rid of undesired artifacts created by more straightforward digitization. But it may take some digging and math to confirm this. Thanks for the reference. Though I'm not much closer to an answer to my question...
If I just want to try to figure this out for myself, it looks like I can put SERIAL_* commands of various kinds in the code to dump info to serial output. Is there a debugging primer somewhere?
No primer...
But on the SERIAL_ commands to print stuff to the host... Don't go crazy and print too much. You will lose a lot of output. You can put a delay(100); after each line to make sure you don't over burden the host program when printing a lot. Lastly... Don't use too many of the macros that end in PGM because that puts the text in the program memory. At some point, the text won't really be there. There seems to be some limit to how much PGM text you can declare.
SERIAL_ECHO_START;
SERIAL_ECHOPAIR(varname1,var1);
delay(100);
SERIAL_ECHOPAIR(varname2,var2);
...
would do it? I start up the host, then send individual G-CODES and look at the serial output? One SERIAL_ECHO_START? SERIAL_ECHOPAIR is overloaded with different data-types?
Thanks
@Roxy-3DPrintBoard The limit is 64k.
The limit is 64k.
In the past... I've had problems when I had a bunch of debug messages stored in program memory. I don't know what I had, but it was well under 8KB. I don't know what was going wrong. But I do know just deleting some of the messages let me add other messages.
My guess it is in fact none of them, but is the acceleration in the X/Y plane
If your move includes the X or Y plane, but not the Z or E plane, then your acceleration will only be constrained by the max acceleration and max rates of the X and Y planes.
But if you include Z or E you will find that your acceleration may differ, if the default acceleration for Z or E is lower than that for X and Y.
Consider:
DEFAULT_MAX_ACCELERATION {3000,3000,100,10000}
DEFAULT_ACCELERATION
: Default for a move with X, Y, and EDEFAULT_ACCELERATION
: Default for a move with Z only, alsoDEFAULT_RETRACT_ACCELERATION
: Default for a move with E onlyDEFAULT_TRAVEL_ACCELERATION
: Default for a move with X and Y only but not EIf you include the Z axis in a move, the acceleration will be constrained to no more than 100mm/s/s. If a move only includes the E
axis, its acceleration will be (essentially) unconstrained, since E
accelerates at 10000mm/s/s.
There is only a single trapezoid for each linear move. Once we know which axes are moving together, and the target movement rate, then a single trapezoid is generated which applies to the whole move. As for chaining moves together, again, the acceleration part, which determines the "slope" of the trapezoid, is always constrained by the lowest acceleration value of the axes that are involved in the move.
Similarly, the max feedrate constrains the speed of a given move based on all the axes involved in the move, making sure that none of the axes exceeds its own maximum.
SERIAL_ECHO_START
Where in the code do you intend to insert these print commands? If you want to see what's going on in the planner and stepper functions, which need to run quite fast, I would suggest not inserting echo commands into the code at those points. And there's no need to use delay()
so long as you aren't printing things out continually.
If you want to debug the planner and stepper functions, you can't just insert echo commands into the code at any arbitrary point. Instead, you will need to make an array for the data you want to examine, write to that array in the stepper and planner functions, and then set a flag. Add some code into the idle()
function to check that flag, and if it's set print out the contents of the buffer and clear the flag.
@Roxy-3DPrintBoard http://www.nongnu.org/avr-libc/user-manual/group__avr__pgmspace.html - a bit further down (Detailed Description - Note), makes perfect sense to me, but there may be further limitations. However - if you don't use the _P functions you will have the strings always in RAM and Progmem. That's really limiting.
It is confusing, because distances are converted to steps. The axis with the most number of steps is used as the control axis in the Bresenham algorithm. So I think the DEFAULT_ACCEL will be applied to whichever axis is the control axis.
To check some code I implemented the algorithm on a PC, much easier to trace the operation.
If your move includes the X or Y plane, but not the Z or E plane, then your acceleration will only be constrained by the max acceleration and max rates of the X and Y planes.
But if you include Z or E you will find that your acceleration may differ, if the default acceleration for Z or E is lower than that for X and Y.
I see that, but suppose the maximum acceleration rates are set high enough that they do not constrain the move, so that DEFAULT_ACCELERATION is used as is. Consider a printing move in X, Y and E. A single trapezoid is constructed which generates coordinated motion in all three axes. Each axis will have its own acceleration, as for instance, the E-axis moves slower than the spatial axes will. The question I had is what is the relationship between DEFAULT_ACCELERATION and the accelerations generated by the move in the three axes X, Y and E, which will all be different. Perhaps it is the maximum of the three?
EDIT bobc has just suggested it is the axis with the largest number of steps. Though I have not got my head around the implications of that yet.
I was looking at the (commented) code
/**
SERIAL_ECHO_START;
SERIAL_ECHOPGM("advance :");
SERIAL_ECHO(block->advance/256.0);
SERIAL_ECHOPGM("advance rate :");
SERIAL_ECHOLN(block->advance_rate/256.0);
*/
in planner.cpp as a template. It looks like there is more to it.
BTW, what about moves with X, Y, Z and E? I'm pretty sure Cura started a print by gradually lowering to the bed as it printed.
Perhaps it is the maximum of the three?
The minimum. Whenever Marlin makes a move, it must defer to the lowest acceleration.
bobc has just suggested it is the axis with the largest number of steps
No, it is not. The largest number of steps simply defines the "ceiling" for the Bresenham algorithm. An axis whose "addend" is the same as the "ceiling" will step every time. An axis whose "addend" is 1/2 of the ceiling will step once for every 2 times that the longest axis does.
Each axis will have its own acceleration
Each axis has a preferred acceleration. But a single move, regardless of how many axes are involved, has only a single acceleration, culled from the preferred accelerations of the involved axes. The final acceleration for the move will be constrained to the lowest of the preferred accelerations of the involved axes.
I said:
"The question I had is what is the relationship between DEFAULT_ACCELERATION and the accelerations generated by the move in the three axes X, Y and E, which will all be different. Perhaps it is the maximum of the three?" and "suppose the maximum acceleration rates are set high enough that they do not constrain the move, so that DEFAULT_ACCELERATION is used as is"
You said "The minimum. Whenever Marlin makes a move, it must defer to the lowest acceleration."
I specified that the move was unconstrained. So it doesn't have to defer to any axis constraints. It just takes DEFAULT_ACCELERATION in some way.
If I can ask yet again: If none of the per axis DEFAULT_MAX_ACCELERATION's come into play, what axis does the DEFAULT_ACCELERATION refer to? We've agreed it's a physical quantity, measured in mm/sec^2. It makes a big difference whether that refers to a spatial axis or the extruder axis as the extruder has much lower physical accelerations in any given printing move.
Maybe explaining how "each axis has a preferred acceleration" relates to the input DEFAULT_ACCELERATION (in the absence of any per axis maximum constraint) would end up answering my question.
Studying the code is the only way you will be able to comprehend it. English isn't working.
So far, it is not. Maybe someone else understands the question I am asking. Or I'll try to trace the code myself.
That was my next plan, to follow the code and paste snippets here for your benefit. But I'm sure you can do that yourself easily enough. If you discover a concise answer, please post it here.
OK. Here is how it works - assuming a printing move, with, in principle, all 4 axes active:
DEFAULT_ACCELERATION
is a scalar quantity it represents the user-desired acceleration along a segment in 3-space. Since z-motions are tiny compared those in x and y, it is essentially the desired acceleration in the x/y plane in mm/sec^2.
If there are no limitations put on it, it is passed to the stepper routine as block->acceleration
(Which answers my long standing question of what does it represent)
Checks are made to ensure that the components of DEFAULT_ACCELERATION
in the x/y/z directions
do not exceed the three corresponding spatial components of DEFAULT_MAX_ACCELERATION
.
So, for instance if I print a 45 degree line, DEFAULT_ACCELERATION
can exceed the x/y components of DEFAULT_MAX_ACCELERATION
by sqrt(2)
before triggering a reduction. (Which all makes good physical sense.)
In addition, a check is made to make sure the maximum extruder acceleration is not exceeded - but given typical values, it appears this won't happen in practice - and the coding gets intricate it did. So, I'll pass on that.
The stepper wants to work in steps. There ends up being a "primary axis" on which there is the largest number of steps. The key internal appears to be block->acceleration_st
(also acc_st) which is related to the physical (x/y)-plane acceleration by
block_acceleration_st = block_acceleration *steps_per_mm
where steps_per_mm
is the no of steps in the primary direction divided by the physical 3D path length in mm.
If I have it wrong, please let me know.
So I believe the answers to my questions of two days ago were: 1) yes 2) yes - strictly along the 3D path. Except for z-only moves effectively in the X/Y plane 3) yes 4) yes 5) Approximately. Actually 0 < DEFAULT_ACCELERATION < sqrt(DEFAULT_MAX_ACCELERATION(X)^2 +DEFAULT_MAX_ACCELERATION(Y)^2 +DEFAULT_MAX_ACCELERATION(Z)^2)
I'm happy that you sorted it out. Incidentally, we are always looking for more contributors who can help with Marlin documentation. https://github.com/MarlinFirmware/MarlinDocumentation
A minor change that would make the code more readable would be to rename'
axis_steps_per_sqr_second
to max_acceleration_steps_per_sq_sec
to make its relation to max_acceleration_units_per_sq_second
transparent.
(in planner.cpp
)
that would make the code more readable
Always a welcome thing. I'm not too fond of "per_sqr_second
" and "per_sq_second
" as a suffix for "per-second-per-second" either. I might just go for "per_s2
" since we know what it means in this context.
Great. Shorter is better. More descriptive is better. The next person ploughing through the code maybe won't have to create a dictionary like me!
And strictly steps_per_mm
should become steps_per_unit
and block->millimeters
should be block->units
if you want to maintain that units aren't necessarily mm. But if you go that route, there would need to be clarification in Configuration.h
that the conventional unit is mm so that innocent users reading units/sec^2 in the comments would know what was meant.
In fact, it might be better in the example configurations (which thus refer to particular machines) to comment that unit has been chosen to mm (in the #define steps_per_unit
) and retain the mm/sec^2 etc. comments in the other defines.
Well actually, once we get to the planner and stepper level, everything is expressed in mm. So we could actually change "units
" to "mm
" in many places and it would be more accurate.
If, as Blue-Marlin said earlier in the thread, the only connection of the code to physical displacements of the machine is through DEFAULT_STEPS_PER_UNIT, the planner and stepper are indifferent to the choice of unit - except for the dynamic range of the variables.
Those machines that print houses by extruding concrete might want bigger units...
the planner and stepper are indifferent to the choice of unit
At some level we have to choose a standard unit of linear measurement. In the case of Marlin, that standard unit is the millimeter and I can guarantee that is never going to change.
Those machines that print houses by extruding concrete might want bigger units...
That's some big printing! Marlin can express up to 1334 miles in millimeters before it runs out of bits.
It would indeed be trivial for your concrete printer guy to just hack DEFAULT_STEPS_PER_MM
and use Marlin to build your house.
Until yesterday we have been perfectly able to use any unit we want. But the inch-mode requires the 'unit' to be mm now.
It appears Marlin doesn't support G20/G21 unlike most other firmware.
Support inches, fahrenheit, and kelvin #3985. Merged yesterday. :-(
Could you point me to some documentation on DEFAULT_MAX_ACCELERATION? The wiki mentions DEFAULT_ACCELERATION and I'm unclear how these differ/interact. I couldn't figure out how to search the closed issues to see if these had already been discussed...