Closed lrpirlet closed 8 years ago
I am using repetier host version 1.6.2 to test the UBL branch...
@lrpirlet I have only tested using PronterFace. The M option works flawlessly with PronterFace. Even the weird cases where you do something like G29 P1 R M and it generates map after map. They keep just scrolling up the screen showing you what has been discovered about the bed's topology.
I think the use of M as a parameter to G29 is not going to work smoothly with Repetier... and maybe other host software... see further
As stated, it works flawlessly with PronterFace. But Repetier Host is very important. We will have to figure out what is keeping it from working there and get it fixed.
@repetier Is there anything you need from me to get this working better? If so, just let me know. It is possible the problem is on the Marlin side of things. But if so, I'll need some guidance on what I should change to make it so Marlin is not getting Repetier Host angry with us. Please let me know!!!
We can't use "M" as the letter for a parameter. Verboten. Nor "G" or "N". "T" seems to be excepted.
We can't use "M" as the letter for a parameter.
@thinkyhead Can you give more detail? I've been using that since the start of UBL and it works fine with PronterFace. M is easy to remember for 'Map'. So if possible, I would like to keep using it for that purpose.
M
, G
, and T
are GCode reserved letters, along with N
and F
.
Repetier is well within rights to interpret these letters as having standard meanings.
The more we diverge from standard GCode, the more grief we get from CNC world.
The more we diverge from standard GCode, the more grief we get from CNC world.
Maybe. But I think if we put it up to a vote from the people already using UBL, they are going to say they want the 'M' option to stay there. And $#!%, take a look at the parameter (or option) list for UBL's G29. You can do that here: https://github.com/MarlinFirmware/Marlin/blob/devel-ubl/Marlin/G29_Unified_Bed_Leveling.cpp#L47
I really do need option letters that "Make Sense". @lrpirlet Can you try using a lower case 'm' and see if that blows up? I'm checking out an updated version of the code that is going to get uploaded in the next day or two. If a lower case 'm' doesn't cause any sickness, I'll just make that option take either version of the letter. And in a day or two, everything will be working for you.
UBL is hardly finalized, and "map" isn't the only word in the dictionary that could be applied. You'll find not a single commit from me where I chose to use N
, M
, G
, etc. as parameters because I've been assiduously avoiding their use. Specifically, because I researched GCode and examined several GCode parsers to get a sense of why it is the way it is.
In essence, each of these letters indicates a "mode change" in the character stream, and in fact standard GCode doesn't even require line-breaks. I realize that RepRap G-code represents a divergence from the standard, but I think in this case we ought to defer.
take a look at the parameter (or option) list
That's actually a really over-the-top list of options. I'm sure this will have to be seriously reformed before it will be acceptable. I don't have time to get into alternatives, but clearly it needs a re-design. Just as a for-example, "G29 A
" to activate? It really should be a whole different GCode. G29
is supposed to simply initiate a leveling procedure. We've already indulged enough with MBL's several S
parameter values. We shouldn't take that slip in our discipline as an invitation to further overload G29
.
Parses check for either M or G in commandline and match it. You can not mix. Also N is line number for every command so it also forbidden for all codes! T is an exception so you can use it as extruder for M104, also Tx is normally a command to switch tools.
I guess host/server may drop M or G or at least parse it wrong so you are provoking problems mixing M and G. Also, host will expect a number after M. Also it would now replace all missing values by 0, I think.
@Roxy-3D
Well, I issued "g29 m
" in the G-Code box... the result is M0G29
... Just for the fun I did input "hello there"... Repetier did output 20:53:49.341 : echo:Unknown command: "Hello There"
...
So, it looks like, maybe, the first letter of each word is changed to uppercase.
That said, I can still use the G29 M
by writing G29 V4 M
or G29 W M
... This seems to work, FOR ME and probably up to when I install a next version of Repetier... So, I will never trust myself and I will chose a different approach.
If you ask my advice, I would say that I feel this command to be much too complex for a G-Code... This looks like a UNIX command with lots and lots of modifier... I have a fairly good feeling for UNIX commands, but I will NEVER be fluent enough with this G29
G-Code to use it fully... Especially given the fact that I have no -h modifier
The only thing I ask to g29
is to transform a bed, 3 axes and one tip into a coherent system where, for chosen Z, the tip moves over the bed at a constant height relative to the bed... A set of 4 to 6 modifiers is about what I can and will remember... ( I do NOT use m48 to the full... I learned that m48 P12 V4
will give me the mean, a significant Sigma .. I know that I can move the tip first, I know that I can make the servo go up and down, I know that I can move the tip between probing... Without doc, I will NEVER trust my memory... and to be honest, when I have some time it is NOT to play with modifiers, but to print the part I want...)
Please understand that the above is MY opinion.... This is NO complaint against your choices... I will use what you produce or I will write it myself (If I can :-) )
Don't get me wrong, either. The geeks writing host software seem to be making some "brittle" choices in their parsers and don't seem to appreciate the power of regular expressions, for example.
As developers of the firmware, we should probably be providing code to the host developers to help them along —so-called "reference implementations"— to demonstrate how GCode and the serial output of various commands may be parsed to remain both backward and forward-compatible. Of course, this extra work takes time and effort, and I know we're all pretty constrained lately.
Well, I issued "g29 m" in the G-Code box... the result is M0G29... Just for the fun I did input "hello there"... Repetier did output 20:53:49.341 : echo:Unknown command: "Hello There"...
So, it looks like, maybe, the first letter of each word is changed to uppercase.
OK, in the new code the Map display is also enabled with an 'O' command. I'll let either one of them display the map.
If you ask my advice, I would say that I feel this command to be much too complex for a G-Code... This looks like a UNIX command with lots and lots of modifier... I
Yes, in a way this is true. But remember, I'm trying to provide all the features of the different existing Auto Bed Leveling systems, and do it for every machine type. Guess what? There are going to be a lot of options.
I'll make it so big chunks of the code can be turned off later once everything is working. The user should have the ability to just enable the parts they want. But for right now, there isn't much harm having everything turned on.
do it for every machine type
But it will only be installed on one machine at a time. So it's not necessary to provide every option on every machine. Likewise, I also presume that not every leveling method will be enabled at once, but just one. So again, we should keep it tight. Ideally just a bare G29
that will probe the bed according to previous configuration, and perhaps preserving the L
R
F
B
options we already have, to specify a smaller region (although I'm disinclined to keep that because we still have to extrapolate across the entire print region), do a dry run, and V
to do verbose logging.
For other options, including enable/disable, we should add a couple other GCodes.
I note that G32 is now tending towards being preferred for bed probing… Obviously we're bound to stick with G29 since default Start GCode in various slicers include it.
Also have a look at G33 which is basically Mesh Leveling. @repetier is adding support for various GCodes, so we will have to watch the RepRap Wiki and write a bot to watch their Github to keep abreast of these changes.
M320 : Activate Autolevel M321 : Deactivate Autolevel M322 : Reset Autolevel Matrix M323 : "Distortion correction" on/off
M371 : Move to next calibration point M372 : Record calibration value, move to next point M373 : End bed level calibration mode M374 : Save calibration grid M375 : Display / Load Matrix M565 : Set Z Probe offsets
M320 : Activate Autolevel M321 : Deactivate Autolevel M322 : Reset Autolevel Matrix M323 : "Distortion correction" on/off
At least for me... It is much more intuitive to know G29 is used for the Auto Bed Leveling. It is easy for me to remember a G29 A activates it. And it is easy for me to remember that G29 D deactivates it. I don't see any harm in 'over loading' G29 that way.
Customarily in G-Code "A" represents a value for the "A Axis."
Well, GCode is fine for what it is intended to do. But it is a very limited and constrained syntax. And... right now, every thing is in Cartesian coordinates, even if you are on a Scara or Delta. I'll address 'A-Axis' issues later if they come up.
Please load up the UBL System and use it. I think you will find it has a nice feel to it and it makes sense.
Please load up the UBL System and use it
Can't. I don't have a 3D printer at my disposal.
Actually, I've been making some allowances for raw moves on SCARA, so you can directly set the A and B angles. For my client's firmware it's G6 with A B C. A and B are angles in degrees. C is the Z stepper. It also allows uninterpolated moves with G0, something which is fine on SCARA but which we can't allow on Delta because it produces dips in the Z position.
which we can't allow on Delta because it produces dips in the Z position.
If it is desirable to allow it on Delta's, there are a couple of ways to do it and not have the dip. I'm really not trying to be argumentative. But here is the way I see it: When the term 'uninterpolated' is used, it is talking about the mapping of the coordinate system for the start and end points. It really isn't saying you can't do an intelligent trajectory to get from one to the other. The problem with Delta's is the simple case is an arc that dips. So... You still don't map (interpolate) the start and end point. But you can do a 'smart' path that is physically a straight line. One simple technique to do that is just break the line segment up into many smaller line segments (with very small dips).
PS. These are the discussions that I really find interesting. If they annoy you or make you think I'm just being difficult, please speak up. That isn't what is happening on my side. I really find these discussion to be fascinating and I learn a lot from them!
there are a couple of ways to do it and not have the dip
The only technique available is to split up lines into small moves. There isn't another option, because in any given straight cartesian movement, the tower carriages always move parabolically, not linearly. Even when the effector moves from the middle straight towards or away from a tower, the tower movement is parabolic.
One simple technique to do that is just break the line segment up into many smaller line segments
Yeppers!
I really find these discussion to be fascinating and I learn a lot from them!
Sorry if I'm being terse; I will try to be patient. I've just been getting a lot of "D'oh!" issues lately, and I'm trying to slog through a pile of changes that are a tangled web of interdependencies.
…break the line segment up…
Hmm, I'm going to continue to ruminate on this in a general way. Take note that for any given straight line in Cartesian space, an individual tower carriage might move up a bit, then down a bit, (as the effector moves past the tower). But it isn't always the case, so we could possibly do some heuristics ahead of time and plan the tower moves directly, instead of always working from the cartesian coordinates.
As mentioned, the tower carriages move non-linearly, gaining speed when the effector is closer to the tower, and reducing speed when the effector is farther away. So, we just might be able to build on the Bresenham technique to achieve the necessary parabolic movement. We just need to know the ratios of effector-to-tower for the start, middle, and end of any given linear movement (for all three towers).
Meanwhile, check it out. I added a hidden setting that you should try on a Delta at the next opportunity. If you enable DELTA_FAST_SQRT
it will use the Q_rsqrt
fast inverse square root algorithm (as used in Quake 3 Arena) instead of the float library's sqrt
function. It's supposed to be significantly faster than sqrt
— but since we need the reciprocal, there's one additional float division per tower.
The accuracy of Q_rsqrt
is supposed to be pretty good. For the moment, it completely supplants the sqrt
function in inverse_kinematics
, but we could periodically use sqrt
to make a correction, if it turns out to be too far off. Since we only need to be within a couple of stepper steps, it's probably accurate enough.
As mentioned, the tower carriages move non-linearly, gaining speed when the effector is closer to the tower, and reducing speed when the effector is farther away. So, we just might be able to build on the Bresenham technique to achieve the necessary parabolic movement. We just need to know the ratios of effector-to-tower for the start, middle, and end of any given linear movement (for all three towers).
I guess this is obvious but I didn't realize that was the cause of the dip until you pointed it out. With that realization, here is a question: Is the dip truly parabolic? Because, if it is, that type of curve can be approximated very accurately with just three data points. We already have the start and end point. I wonder if we could have a table (coming straight out from each tower) to get the third data point. Depending upon how close the effector is passing by the tower, we grab the third number out of a table and can exactly (and quickly) predict the expected dip????
Meanwhile, check it out. I added a hidden setting that you should try on a Delta at the next opportunity. If you enable DELTA_FAST_SQRT it will use the Q_rsqrt fast inverse square root algorithm (as used in Quake 3 Arena) instead of the float library's sqrt function. It's supposed to be significantly faster than sqrt — but since we need the reciprocal, there's one additional float division per tower
I'll definitely check out the faster square root algorithm. But I've got my head too full of stuff right now with a bug I'm trying to chase down. When I get to the point where I start trying to bring up the UBL code on Delta's I will be in a position to both look at and use the new square root code.
DELTA_FAST_SQRT
It's interesting.
Result of Arduino MEGA:
calculation time of sqrt(): 260108
calculation time of sqrtf(): 266968
calculation time of Q_rsqrt(): 314992
maximum error with sqrt(): 0.0542393
average error with sqrt(): -0.0204092
calculation time of Q_rsqrt2(): 535780
maximum error with sqrt(): 0.0001450
average error with sqrt(): -0.0000408
calculation time of Q_rsqrt3(): 741392
maximum error with sqrt(): 0.0000038
average error with sqrt(): -0.0000000
Result of Arduino Due:
calculation time of sqrt(): 158269
calculation time of sqrtf(): 55673
calculation time of Q_rsqrt(): 35595
maximum error with sqrt(): 0.0542397
average error with sqrt(): -0.0204093
calculation time of Q_rsqrt2(): 58142
maximum error with sqrt(): 0.0001452
average error with sqrt(): -0.0000408
calculation time of Q_rsqrt3(): 79701
maximum error with sqrt(): 0.0000047
average error with sqrt(): -0.0000000
In case of MEGA, It looks like that Q_rsqrt
is slower than default sqrt()
and sqrtf()
for some reason.
In case of Due, Q_rsqrt
is x2 ~ x4 faster than default sqrt()
, but Q_rsqrt2()
and Q_rsqrt3()
are slower than sqrtf()
.
IDE is 1.6.12 HourlyBuild 2016/09/08 10:33.
@esenapaj Do you know if the Due is doing 4 byte or 8 byte floating point math? If I remember right, the Due has a floating point co-processor built into the chip. If that is true, this all makes sense. The Q_rsqrt() would be a software algorithm that is having to loop and do a bunch of work to get its number calculated.
Also have a look at G33 which is basically Mesh Leveling. @repetier is adding support for various GCodes, so we will have to watch the RepRap Wiki and write a bot to watch their Github to keep abreast of these changes.
We already have something very similar with M421. We can warm that over and change it to be G33 so it is exactly compliant with that description. But really... I haven't been using M421. The Mesh Editor built into the UBL G29 code is much nicer to use.
@esenapaj That is interesting, alright. It sure would have been nice if Q_rsqrt
was faster. We really need a new trick to make Delta better. My guess it that Q_rsqrt
was faster for desktop platforms running Quake III Arena, but obviously it's not too hot on AVR (circa 1997) processors.
@Roxy-3D No. The Due has no FPU but much wider then 8bit registers and a integer division in hardware.
Floats are 32bit. Doubles are 32bit on the 8 bit processors and 64bit at the DUE. https://www.arduino.cc/en/Reference/Double
I've altered the above test program for more information and experiment.
Result of Arduino MEGA:
calculation time of sqrt(): 255580
calculation time of sqrtf(): 255568
maximum error with sqrt(): nodiff
average error with sqrt(): 0.0000000
Q_rsqrt() (1 time iteration):
calculation time of Q_rsqrt(): 337148
calculation time of 1.0f / Q_rsqrt(): 536100
maximum error with sqrt(): 0.0542393
average error with sqrt(): -0.0204092
Q_rsqrt() (2 time iteration):
calculation time of Q_rsqrt(): 541444
calculation time of 1.0f / Q_rsqrt(): 740512
maximum error with sqrt(): 0.0001450
average error with sqrt(): -0.0000408
Q_rsqrt() (3 time iteration):
calculation time of Q_rsqrt(): 745168
calculation time of 1.0f / Q_rsqrt(): 944372
maximum error with sqrt(): 0.0000038
average error with sqrt(): -0.0000000
Result of Arduino Due:
calculation time of sqrt(): 150328
calculation time of sqrtf(): 61020
maximum error with sqrt(): 0.0000010
average error with sqrt(): 0.0000000
Q_rsqrt() (1 time iteration):
calculation time of Q_rsqrt(): 40406
calculation time of 1.0f / Q_rsqrt(): 61214
maximum error with sqrt(): 0.0542400
average error with sqrt(): -0.0204093
Q_rsqrt() (2 time iteration):
calculation time of Q_rsqrt(): 64150
calculation time of 1.0f / Q_rsqrt(): 84956
maximum error with sqrt(): 0.0001452
average error with sqrt(): -0.0000408
Q_rsqrt() (3 time iteration):
calculation time of Q_rsqrt(): 87700
calculation time of 1.0f / Q_rsqrt(): 108507
maximum error with sqrt(): 0.0000046
average error with sqrt(): -0.0000000
In case of MEGA, It looks like that default sqrt()
or sqrtf()
is best.
In case of Due, It looks like that default sqrtf()
is best.
@esenapaj I'm looking at the possibility of using 1/2 as many sqrt
calls and interpolating between them, rather than doing sqrt
for every single segment. Do you think this will produce too much error? The general idea I'm thinking of for prepare_kinematic_move_to
is this…
float prev_delta[ABC];
if (segments >= 2) inverse_kinematics(logical); // 2 is enough
for (uint16_t s = segments + 1; --s;) { // (ex: 5+1=6, but --s so: 5,3,1)
if (s > 1) { // (5,3)
--s; // (4,2)
prev_delta[A_AXIS] = delta[A_AXIS];
prev_delta[B_AXIS] = delta[B_AXIS];
prev_delta[C_AXIS] = delta[C_AXIS];
LOOP_XYZE(i) logical[i] += segment_distance[i] + segment_distance[i];
inverse_kinematics(logical);
planner.buffer_line(
(prev_delta[A_AXIS] + delta[A_AXIS]) * 0.5,
(prev_delta[B_AXIS] + delta[B_AXIS]) * 0.5,
(prev_delta[C_AXIS] + delta[C_AXIS]) * 0.5,
logical[E_AXIS], _feedrate_mm_s, active_extruder
);
}
else { // (1)
LOOP_XYZE(i) logical[i] += segment_distance[i];
inverse_kinematics(logical);
}
planner.buffer_line(delta[A_AXIS], delta[B_AXIS], delta[C_AXIS], logical[E_AXIS], _feedrate_mm_s, active_extruder);
}
Also, there are 6 float subtract operations that can easily be eliminated for every Delta segment, by converting Delta moves to "raw" coordinates in advance of segmentation.
Currently we have this:
void inverse_kinematics(const float logical[XYZ]) {
const float cartesian[XYZ] = {
RAW_X_POSITION(logical[X_AXIS]),
RAW_Y_POSITION(logical[Y_AXIS]),
RAW_Z_POSITION(logical[Z_AXIS])
};
// Macro to obtain the Z position of an individual tower
#define DELTA_Z(T) cartesian[Z_AXIS] + _SQRT( \
delta_diagonal_rod_2_tower_##T - HYPOT2( \
delta_tower##T##_x - cartesian[X_AXIS], \
delta_tower##T##_y - cartesian[Y_AXIS] \
) \
)
delta[A_AXIS] = DELTA_Z(1);
delta[B_AXIS] = DELTA_Z(2);
delta[C_AXIS] = DELTA_Z(3);
}
By pre-subtracting the coordinate space offsets in prepare_kinematic_move_to
, this can be replaced by…
void inverse_kinematics(const float raw[XYZ]) {
// Macro to obtain the Z position of an individual tower
#define DELTA_Z(T) raw[Z_AXIS] + _SQRT( \
delta_diagonal_rod_2_tower_##T - HYPOT2( \
delta_tower##T##_x - raw[X_AXIS], \
delta_tower##T##_y - raw[Y_AXIS] \
) \
)
delta[A_AXIS] = DELTA_Z(1);
delta[B_AXIS] = DELTA_Z(2);
delta[C_AXIS] = DELTA_Z(3);
}
This will have the greatest effect on long straight lines, but probably not too much effect on lines under ~5mm. It will depend on delta speed.
Some other questions: Are small (and slow) moves too aggressively segmented by prepare_kinematic_move_to
? Does it make sense to split up lines into segments smaller than 0.2mm? Would vertical deviation at that scale make any noticeable difference in the print quality?
Do you think this will produce too much error?
I'm not familiar with it because it's a advanced content for me... Is this OK?
Result:
calculation time of prepare_kinematic_move_to() (not optimized): 26387400
calculation time of prepare_kinematic_move_to() (USE_RAW_KINEMATICS enabled): 23953812
maximum error with prepare_kinematic_move_to() (not optimized):
delta[A_AXIS] 0.0000153
delta[B_AXIS] 0.0000305
delta[C_AXIS] 0.0000458
average error with prepare_kinematic_move_to() (not optimized):
delta[A_AXIS] -0.0000002
delta[B_AXIS] -0.0000001
delta[C_AXIS] 0.0000001
calculation time of prepare_kinematic_move_to() (USE_DELTA_IK_INTERPOLATION enabled): 17734760
maximum error with prepare_kinematic_move_to() (not optimized):
delta[A_AXIS] 0.0000153
delta[B_AXIS] 0.0000305
delta[C_AXIS] 0.0000305
average error with prepare_kinematic_move_to() (not optimized):
delta[A_AXIS] -0.0000003
delta[B_AXIS] -0.0000002
delta[C_AXIS] 0.0000002
calculation time of prepare_kinematic_move_to() (USE_RAW_KINEMATICS USE_DELTA_IK_INTERPOLATION enabled): 16438640
maximum error with prepare_kinematic_move_to() (not optimized):
delta[A_AXIS] 0.0000153
delta[B_AXIS] 0.0000305
delta[C_AXIS] 0.0000305
average error with prepare_kinematic_move_to() (not optimized):
delta[A_AXIS] -0.0000003
delta[B_AXIS] -0.0000002
delta[C_AXIS] 0.0000002
Are small (and slow) moves too aggressively segmented by prepare_kinematic_move_to? Does it make sense to split up lines into segments smaller than 0.2mm? Would vertical deviation at that scale make any noticeable difference in the print quality?
Sorry, I haven't knowledge for answering about those at this time...
From 23,953,812µs down to 16,438,640µs saves 7,515,172µs, or 7.5 whole seconds. Or, about 32% faster. That's not too bad.
The one place I can see trouble is if you have something like: 12.5 … 12.7 … 12.4 where the middle move would be completely missed because we're at the top (or bottom) of the movement. This would end up interpolated as 12.5 … 12.45 … 12.4.
@thinkyhead @Roxy-3D @esenapaj This thread "slipped" away from the original subject... This is fine, as I did learn some , but I will let anyone of you close it, because I am not too sure that the subject has been exhausted...
Yeah... That does seem to happen! :) I think we have resolution on what caused the problem with the 'M' (Map) function, and I already have the system changed to accept either a lower case 'm' or an upper case 'O'. So... The option can be used on Repetier Host now.
" I already have the system changed to accept either a lower case 'm' or an upper case 'O'"
O is fine, but comment on lower case m: users are lazy and often write lower letters meaning someone will fix it and since older firmwares did not fix, host uppercases gcode letters normally if nor forced to send original command. As I understand GCode specification all letters were supposed uppercase anyway so relying on upper/lower case is a dangerous path.
I concur. No lower-case, please. That's just not good. I shouldn't need to explain why.
Alright.. I agree... Let's not cause any problems needlessly!
This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.
I am using repetier host version 1.6.2 to test the UBL branch...
@Roxy-3D, I think the use of M as a parameter to G29 is not going to work smoothly with Repetier... and maybe other host software... see further
@repetier I do issue the command Gnn M... Repetier changes this and send to the printer M0Gnn... It issues a wait code... Is that an intended behavior???
Here I issue G29 M in the repetier "Manual Control" box labeled G-Code: Repetier send M0G29 as you can see
Here, everythings seems blocked... G29 shows in the display... Repetier shows "1 command waiting" I press the button to proceed, the display clears... Sometimes Repetier comes back with Idle sometimes NOT... In this case Repetiercomes back "Idle" and allow me to issue another G-code...
I did try to replace G29 with any G command.. I get same behavior with G55 (that does NOT exist in Marlin
Note TEST12 is output by M0 in debug mode...
The "funny" thing is that when I insert V4 or W between the command and the M, the command behave as I expect it....