Query maximum and minimum feedrates
-
Is there a way to find the minimum and maximum feedrates for a given axis?
I took a look through the document model and for maximum feedrates it looks like I can use
move.axes[].speed
which is great. However for the minimum feedrate set byM203 I30
for example, I don't see a way to find the current value for this so I could fetch it into a variable.The minimum feedrate is shared by all axes I believe so wouldn't be in the per axis information but I don't find it anywhere else in the object model and don't see a Gcode to query it.
My use case is that I want to temporarily limit the feedrate of an axis and that might require me to temporarily also change the minimum feedrate to make it slow enough. When done I want to restore them to the previous values so I want to store the current ones first.
-
-
@ardenpm My best guess (and it is only a guess) is that the minimum feed rate would be zero. I can't think of any logical reason why one would want to impose any other limit. It's easy enough to test. Just do something like a G1 X200 Y0.1 Fn move and see if anything screwy happens.
-
@deckingman From my tests it does appear to default to 30mm/m per the documentation, however it can be changed by the user so to be generic I'd like to be able to query the current value to be able to restore it. For my specific case of course I know if I have changed it so can live without it but would be nice to have when writing things that someone might use on another machine.
When I tried to do a move slower than 30mm/m it definitely did not behave as expected until I issued an
M203 Innn
low enough. So for example if I just didG1 X10 F1
I'd expect it to take around 10 minutes, but it actually takes about 20 seconds, once I lower the minimum feedrate to 1 as well it takes the expected amount of time. I also don't really see the reason for the default minimum overall feedrate being 30mm/m, though I think Marlin has something similar from memory. -
@ardenpm Well that is strange indeed and one learns something new every day. From what you are saying, if you have a large move in (say) X accompanied by a small move in Y, then the overall feed rate would be increased in order for the Y axis not to go below its minimum feed rate speed.
Which begs the question, what would happen if that increased feed rate exceeded the maximum feed rate set for the X axis? Taking my (admittedly extreme) example of a 200mm move move in X accompanied by a 0.1mm in Y, then we have a ratio of 2,000:1. So if we used a reasonable feed rate of say 60mm/sec (3600 mm/minute) the feed rate for Y would be about 1.8mm/minute which is way below it's default minium of 30mm/min. So if the Y axis must run at 30mm/minute, then the X axis must run at (30*2000) = 60,000 mm/minute or 1 metre per second, which would be well above the likely maximum feed rate setting for that axis.
So one could foresee a situation where, if a minimum axis speed is imposed on one axis, then a combined two dimensional move would exceed the maximum speed limit for the other axis. What the hell happens then?
-
@deckingman Excellent question. Could the minimum feedrate be referring to the "tool" rather than the individual axes?
-
@ardenpm said in Query maximum and minimum feedrates:
@deckingman Excellent question. Could the minimum feedrate be referring to the "tool" rather than the individual axes?
Who knows? Given that M203 followed by an axis letter or extruder number sets the maximum feed rate for any particular axis or extruder, I would assume that the "I" parameter ("Minimum overall movement speed") applies to all axes - or rather the minimum movement speed for a combined move, (so in effect the tool path). But if there is a high ratio of move distances between individual axes, then one could conceivably exceed the maximum allowable speed for any one particular axis by imposing a minimum overall feed rate limit.
To put it another way, I can't see any way that one could avoid conflict by imposing both minimum overall and maximum individual axis feed rate limits when doing compound moves and where each axis move must start and end at the same time.
-
@deckingman Interesting thought! I was curious so I had a dig into the code and this is my interpretation of what it is doing. This also covers the question of what happens to the extrusion speed in a command like:
G1 X100 Y100 E1000 F123
So the key code to handle all of this is:
// Don't use the constrain function in the following, because if we have a very small XY movement and a lot of extrusion, we may have to make the // speed lower than the configured minimum movement speed. We must apply the minimum speed first and then limit it if necessary after that. requestedSpeed = min<float>(max<float>(reqSpeed, reprap.GetPlatform().MinMovementSpeed()), VectorBoxIntersection(normalisedDirectionVector, reprap.GetPlatform().MaxFeedrates()));
Which is part of the DDA::InitStandardMove function here: https://github.com/Duet3D/RepRapFirmware/blob/3.4-dev/src/Movement/DDA.cpp#L295
Another key part of the code (in terms of understanding how extrusion fits in) is this:
// 4. Normalise the direction vector and compute the amount of motion. // NIST standard section 2.1.2.5 rule A: if any of XYZ is moving then the feed rate specifies the linear XYZ movement // We treat additional linear axes the same as XYZ
My understanding is that first of all an n dimensional vector is calculated. Where the number of dimensions is the number of motion axis (not including extruders), typically this will be X, Y Z space, but it could extended if other axis are involved. This contains the amount of motion required for each of the axis of this space.
The motion required for the extruder(s) is then added by setting it to the requested extrusion distance. The magnitude of the original motion vector (without extruders) is then used to normalise all of the motion components including the extrusion elements. This in effect spreads out the total extrusion requested along the calculated movement vector.
Following this the feedrate is applied (see the code above), by first ensuring it is greater than the minimum set and then using the normalised vector calculated above, the feedrate is reduced such that the speed limits of each of the axis involved in the move (including the extruders) is respected. The code that does that is described here:
// Take a unit positive-hyperquadrant vector, and return the factor needed to obtain // length of the vector as projected to touch box[]. /*static*/ float DDA::VectorBoxIntersection(const float v[], const float box[]) noexcept
Then any kinematic specific feedrate limits are applied.
Finally the resultant feedrate is used to calculate the speeds (and accelerations) needed for each axis taking part in the move along with the total time etc.That's my take on what is a fairly complex process. I've missed out some of the steps in the above, but I think it can be seen that...
- The feedrate is not applied directly to the extruder (except for extruder only moves), but rather the requested extrusion length is made along the requested path.
- Individual axis speed limits are applied (including for extruders), such that they are never exceeded.
- The minimum feedrate is an overall (not per axis) minimum and speeds below this may be used in some circumstances to avoid exceeding maximum axis speeds.
- In all cases the individual driver movements are coordinated such that they start and end at the same time.
Hopefully that makes some sort of sense!
-
@gloomyandy Thanks for that and it kind of makes sense. Most of it confirms my understanding of how it all works. The only thing I don't understand is why is there a minium speed limit at all - especially as it might not get applied in some circumstances. But then I don't have an in depth knowledge of some of the more "exotic" kinematics classes and tend to think only in linear 3 dimensional space. Or maybe it's just some sort of "fail-safe" built into the code to prevent a move taking a near infinite amount of time to complete?
-
@deckingman Good question there is another comment in the code...
// 6. Set the speed to the smaller of the requested and maximum speed. // Also enforce a minimum speed of 0.5mm/sec. We need a minimum speed to avoid overflow in the movement calculations.
Which sort of answers your question, but raises the issue of what happens if the speed ends up being reduced below the minimum? Could be an out of date comment, but who knows....