Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
672 lines (537 sloc) 28.7 KB
/* [wxMaxima batch file version 1] [ DO NOT EDIT BY HAND! ]*/
/* [ Created with wxMaxima version 18.10.0.unofficial ] */
/* [wxMaxima: title start ]
Rostock Calibration
[wxMaxima: title end ] */
/* [wxMaxima: comment start ]
Copyright © 2014-2018 Peter Hercek.
You can use, modify, and redistribute this under GNU GENERAL PUBLIC LICENSE Version 3.
[wxMaxima: comment end ] */
/* [wxMaxima: comment start ]
This document helps to find proper values for these firmware parameters:
* tower positions,
* tower tilt (each tower can be independently tilted in a different direction),
* bed tilt (which is the same as all toers tilted in one direction - i.e. it is a subset of the previous point),
* diagonal rod length (for each tower independently),
* (micro)step length,
* top endstop position offsets.
You cannot optimize tower positions, diagonal rod length and microstep length all at once. You
can optimize only two of these three at once. Otherwise the system would not be constrained
enough and it would diverge.
[wxMaxima: comment end ] */
/* [wxMaxima: section start ]
Applicability
[wxMaxima: section end ] */
/* [wxMaxima: comment start ]
Errors in these firmware parameters can be fixed perfectly provided the assumptions bellow are
valid:
* We assume that the diagonal rods in one parallelogram have the same length (although this length is
not known precisely). You can achieve this with a jig. You will always have same small differences in
the rod lengths. The wider your parallelogram is the less this matters. Make your parallelogram wide!
* We assume that a line connecting rod ends on a tower is parallel to the line connecting the
corresponding rod ends on the platform. This will not be true almost always but there is a hope that
small differences will not matter enough to screw up the search for best parameters. The more the
parralelogram is squezed the bigger this imprecision will tilt/rotate the platform and ivalidate our
approach. This screws up especitally YX dimensions. It is less bad for Z-height which is measured by
our Z-probe and used here. Also our delta printers do not print sideways enough to decrease
the diagonal rod distance too much. Therefore there is a hope.
* The Z-probe measure point should be just below the tip; i.e. its (x,y) offset should be (0,0). Small
(x,y) offset will not have a big impact on the resutls if towers are not too tilted. The probe can have
small non-zero height. It should be set precisely. If towers are not too tilted then the main consequence
of incorrectly set probe height is that all your computed tower endstop adjustements (oa,ob,oc)
will be uniformly offset by the probe height error. Also the tower positions will be computed with
a tiny errors. If your towers are too tilted then try to use as short probe as possible.
[wxMaxima: comment end ] */
/* [wxMaxima: section start ]
Notation
[wxMaxima: section end ] */
/* [wxMaxima: comment start ]
In this document:
* cartesian coordinates are refered as x,y,z;
* towers are refered as a,b,c;
* precise common rod length is r;
* diagonal rod lengths are refered for each tower as ra, rb, rc;
* imprecise values (because of incorrect firmware parameters) have prefix i;
* values measured in steps (instead of SI units) have suffix s;
* tower carriage position offsets are marked as oa, ob, oc for towers a, b, c respectively;
* tower carriage positions (coordinates on towers) are ta, tb, tc when measured from platform;
* tower carriage positions are tea, teb, tec when measured from end stops;
* tower tilts are dxa, dya, dxb, dyb, dxc, dyc for x and y coordinate for each tower a, b, c;
* (micro)step length is sl (for the corresponding towers it is sla, slb, slc);
* tower length (distance from endstop to heat bed along the tower) is zl;
* z-probe height is ph.
We want to make our coordinate system as fixed as possible. Lets mark (x,y) coordinates of towers
(a, b, c) as xa, ya, xb, yb, xc, yc. We place the coordinate system so that: xa = -xb, ya = yb, yc = -2*ya.
This will allow us to define tower positions with only 3 numbers. If the base plate is done precisely
then it will be the same as the firmware defaults computed from DELTA_RADIUS (see the firmware
source code).
[wxMaxima: comment end ] */
/* [wxMaxima: section start ]
Input parameter definition
[wxMaxima: section end ] */
/* [wxMaxima: comment start ]
Define your geometry as specified in the firmware here (18 optimization parameters, zl and ph).
ZL is not optimized - try to set it right. PH is not optimized as well - try harder to set it right.
[wxMaxima: comment end ] */
/* [wxMaxima: input start ] */
isla : 1/80.0 $
islb : isla $
islc : isla $
ira : 260$
irb : ira $
irc : ira $
ixa : -250/2*cos(%pi/6) $
iya : -250/2*sin(%pi/6) $
ixc : 0 $
ioas : 0 $
iobs : 0 $
iocs : 0 $
idxa : 0 $
idya : 0 $
idxb : 0 $
idyb : 0 $
idxc : 0 $
idyc : 0 $
izl : 620 $
iph : 10 $
/* [wxMaxima: input end ] */
/* [wxMaxima: comment start ]
These tower positions and their errors are fixed because of the limitations we place on our coordinate system.
We also fix the actual printer heigth zl to izl because there is a dependency between zl and endstop offset
adjutements (oa, ob, oc). We cannot optimize (zl, oa, ob, oc) all together.
[wxMaxima: comment end ] */
/* [wxMaxima: input start ] */
ixb : - ixa $
xb : -xa $
iyb : iya $
yb : ya $
iyc : -2*iya $
yc : -2*ya $
zl : izl $
ph : iph $
/* [wxMaxima: input end ] */
/* [wxMaxima: section start ]
Deriving cartesian->delta transformation
[wxMaxima: section end ] */
/* [wxMaxima: fold start ] */
/* [wxMaxima: comment start ]
DO NOT EXECUTE THIS SECTION WHEN CALIBRATING
[wxMaxima: comment end ] */
/* [wxMaxima: comment start ]
Equations for the firmware. These are not needed for the calibration parameter search. They are
here only for reference to find the best approach how to implement all the new calibration
parameters in firmware. The firmware query current position (M114) command must report
also the tower position ta, tb, tc. They will be needed by the calibration parameter search later.
[wxMaxima: comment end ] */
/* [wxMaxima: input start ] */
Acur : (x-(xa+dxa*ta))^2 + (y-(ya+dya*ta))^2 + ta^2*(1-dxa^2-dya^2) - ra^2 = 0 ;
Bcur : (x-(xb+dxb*tb))^2 + (y-(yb+dyb*tb))^2 + tb^2*(1-dxb^2-dyb^2) - rb^2 = 0 ;
Ccur : (x-(xc+dxc*tc))^2 + (y-(yc+dyc*tc))^2 + tc^2*(1-dxc^2-dyc^2) - rc^2 = 0 ;
TA: ta = zl - tea $
TB: tb = zl - teb $
TC: tc = zl - tec $
/* [wxMaxima: input end ] */
/* [wxMaxima: input start ] */
coeff(lhs(expand(Acur)), ta,2);
coeff(lhs(expand(Acur)), ta,1);
coeff(lhs(expand(Acur)), ta,0);
/* [wxMaxima: input end ] */
/* [wxMaxima: comment start ]
The solution for ta in Acur would look much nicer if xa and ya were zero, i.e. the coordinate
system would be temporarily moved so that its center is at the tower base:
[wxMaxima: comment end ] */
/* [wxMaxima: input start ] */
solve(subst(0, ya, subst(0, xa,Acur)), ta)[2];
/* [wxMaxima: input end ] */
/* [wxMaxima: comment start ]
And that is the same as:
[wxMaxima: comment end ] */
/* [wxMaxima: input start ] */
sqrt((dya*y+dxa*x)^2 + ra^2 - y^2 - x^2) + (dya*y+dxa*x);
/* [wxMaxima: input end ] */
/* [wxMaxima: comment start ]
... and that is our cartesian to delta transformation! Well, we need add also the tilt adjusted
tower position offset due to cartesian z-height but that is trivial. Yeah, and do not forget to
adjust tower positions based on the z-height.
[wxMaxima: comment end ] */
/* [wxMaxima: fold end ] */
/* [wxMaxima: section start ]
Finding cartesian position after homing
[wxMaxima: section end ] */
/* [wxMaxima: fold start ] */
/* [wxMaxima: comment start ]
DO NOT EXECUTE THIS SECTION WHEN CALIBRATING
[wxMaxima: comment end ] */
/* [wxMaxima: comment start ]
We are homed when all cariages are moved zl distance from heatbed (to endstops).
We find platform cartesian XY position at first:
[wxMaxima: comment end ] */
/* [wxMaxima: input start ] */
kill(zl)$
Ahome : subst(zl, ta, Acur);
Bhome : subst(zl, tb, Bcur);
Chome : subst(zl, tc, Ccur);
XYhome : solve([Chome-Ahome, Chome-Bhome], [x,y])[1] ;
/* [wxMaxima: input end ] */
/* [wxMaxima: input start ] */
ratdenom(rhs(XYhome[1])) - ratdenom(rhs(XYhome[2]));
dnom: ratdenom(rhs(XYhome[1])) / 2;
xnum: ratnumer(rhs(XYhome[1]));
ynum: ratnumer(rhs(XYhome[2]));
/* [wxMaxima: input end ] */
/* [wxMaxima: comment start ]
There are many repeated expressions there:
[wxMaxima: comment end ] */
/* [wxMaxima: input start ] */
dxal : dxa * zl $
dyal : dya * zl $
dxbl : dxb * zl $
dybl : dyb * zl $
dxcl : dxc * zl $
dycl : dyc * zl $
dxbal : dxbl - dxal $
dxcal : dxcl - dxal $
dxcbl : dxcl - dxbl $
dybal : dybl - dyal $
dycal : dycl - dyal $
dycbl : dycl - dybl $
dxbpal : dxbl + dxal $
/* [wxMaxima: input end ] */
/* [wxMaxima: input start ] */
dnom_1 : dxbal*dycl - dxcal*dybl + dxcbl*dyal +
-3*dxbal*ya - dybal*xc - (dycbl+dycal)*xa +
6*xa*ya $
dnom - dnom_1;
/* [wxMaxima: input end ] */
/* [wxMaxima: input start ] */
xnum_1 : (3*dycl*ya - dxcl*xc)*2*dybal + (-dxbpal*dycl + dxal*dybl + dxbl*dyal)*2*xa +
dxbpal*6*xa*ya + dybal*(xa^2-xc^2+rc^2-9*ya^2) - dycal*rb^2 + dycbl*ra^2 +
(rb^2-ra^2)*3*ya $
xnum-xnum_1;
/* [wxMaxima: input end ] */
/* [wxMaxima: input start ] */
ynum_1 : ((-dxbal*2*dycl - dxcal*dybl + dxcbl*dyal)*ya +dxbal*dxcl*xc +(dxbpal*dxcl - 2*dxal*dxbl)*xa) * 2 +
3*dxbal*ya^2 + (-dybal*2*xc +(4*dycl+dybl+dyal)*2*xa) *ya + dxbal*xc^2 -(dxcbl+dxcal)*2*xa*xc -dxbal*3*xa^2 - dxbal*rc^2 + dxcal*rb^2 -dxcbl*ra^2 +
(rb^2-ra^2)*xc + (2*(rc^2+xa^2-xc^2-3*ya^2)-rb^2-ra^2)*xa $
ynum_1 - ynum;
/* [wxMaxima: input end ] */
/* [wxMaxima: comment start ]
Then we compute platform cartesian Z position when homed based on the C tower geometry:
[wxMaxima: comment end ] */
/* [wxMaxima: input start ] */
zCarriageHeight : zl*sqrt(1 - dxc^2 - dyc^2) ;
xyPlatformDistToCarriage : sqrt((x - xc - dxc*zl)^2 + (y - yc -dyc*zl)^2) ;
zPlatformToCarriageHeight : sqrt(rc^2 - xyPlatformDistToCarriage^2) ;
z: zCarriageHeight - zPlatformToCarriageHeight;
/* [wxMaxima: input end ] */
/* [wxMaxima: fold end ] */
/* [wxMaxima: section start ]
Deriving the fitness function
[wxMaxima: section end ] */
/* [wxMaxima: comment start ]
Three equations (one for each tower) using precise callibration parameters for point (x,y) and tower
coordinates (ta,tb,tc). with carriage positions on towers (ta,tb,tc). These equations are valid when
the head is at the heatbed (z=0). They use also precise tower postions ta, tb, tc for now.
[wxMaxima: comment end ] */
/* [wxMaxima: input start ] */
A : (x-(xa+dxa*ta))^2 + (y-(ya+dya*ta))^2 + ta^2 *(1-dxa^2-dya^2) - ra^2 = 0 $
B : (x-(xb+dxb*tb))^2 + (y-(yb+dyb*tb))^2 + tb^2 *(1-dxb^2-dyb^2) - rb^2 = 0 $
C : (x-(xc+dxc*tc))^2 + (y-(yc+dyc*tc))^2 + tc^2 *(1-dxc^2-dyc^2) - rc^2 = 0 $
/* [wxMaxima: input end ] */
/* [wxMaxima: comment start ]
Lets precisely tie all the calibration paramters for one (ta,tb,tc) representing one point on heatbed.
We do it by getting rid of x and y (which we cannot precisely measure when Z-probing).
[wxMaxima: comment end ] */
/* [wxMaxima: input start ] */
XYEqs: solve([C-A, C-B], [x,y])[1] $
ZEq : subst( rhs(XYEqs[1]), lhs(XYEqs[1]), subst( rhs(XYEqs[2]), lhs(XYEqs[2]), C ) ) $
/* [wxMaxima: input end ] */
/* [wxMaxima: comment start ]
We have all the 18 optimization parameters except (oa, ob, oc) and (sla, slb, slc) in ZEq now.
ZEq is precise (it describes the real life) but the tower positions the firmware will report are
not precise (they use incorrect step length). We need to modify our ZEq so that it models also
the imprecise step length used by firmware and imprecise ph shfited tower positions (itas, itbs, itcs)
reported when probing. Firmware always counts number of steps teXs (X is a placeholder for one
of a, b, c) from the top endstops using equations iTP. This teXs is also bigger because of z-probe
height. The precise equations TP are analogous but they contain also an approximate ph
adjustement and endstop offset oXs to calibrate. Note that probe height compensation is
approximate and works well only for small tower tilts or small/zero probe height.
We derive what tX actually means first.
[wxMaxima: comment end ] */
/* [wxMaxima: input start ] */
iTP : itXs = izl/islX - teXs $
iSeq : solve(iTP, teXs)[1] ;
TP : tX = zl + oXs*slX - teXs*slX - ph $
Seq: subst(rhs(iSeq), lhs(iSeq), TP) ;
expand(subst(islX, slX, Seq));
/* [wxMaxima: input end ] */
/* [wxMaxima: comment start ]
We insert our substitue for (ta, tb, tc) into ZEq and get ZFn with all the optimization paramters
in it. We do the same for XYeqs. XYeqs will be used only for visualization of the results. ZFn will
be used for the calibration itself. ZFn is ready to receive our probe points (itas, itbs, itcs). Then we
extend ZFn application over all measurement points in function ToZFns.
[wxMaxima: comment end ] */
/* [wxMaxima: input start ] */
define(TxFn(oXs, slX, islX, itXs, dxX, dyX), expand(rhs(Seq))) ;
define( ZFn(itas, itbs, itcs),
subst(TxFn(oas, sla, isla, itas, dxa, dya), ta,
subst(TxFn(obs, slb, islb, itbs, dxb, dyb), tb,
subst(TxFn(ocs, slc, islc, itcs, dxc, dyc), tc,
lhs(ZEq))))) $
XYFns :
subst(TxFn(oas, sla, isla, itas, dxa, dya), ta,
subst(TxFn(obs, slb, islb, itbs, dxb, dyb), tb,
subst(TxFn(ocs, slc, islc, itcs, dxc, dyc), tc,
map(rhs, XYEqs)))) $
ToZFns(m) := map( lambda([args], apply(ZFn, args)), m ) $
/* [wxMaxima: input end ] */
/* [wxMaxima: section start ]
Input of measurement points
[wxMaxima: section end ] */
/* [wxMaxima: comment start ]
Now we will Z-probe in at least as many points as the number of parameters we are goint to optimize.
The best points are the center, near each tower base, and most far away from each tower base. Select the
non-center points as far away from the center as possible. These are the first 7 points. Add more points if
you are goingt to optimize more than 7 parameters. If you want nice grapns later then generate many
probing points in a regular grid and specify aslo the grid spacing gs [mm]. I take about 100 of measurement
points regularly spread over the whole heatbed. The measurement will be done by touching printhead with
the heatbed at these points and reading out the carriage positions on towers from heatbed as reported by
the firmware (itas,itbs,itcs). The data format is [[itas,itbs,itcs]]. Define the measured data m here:
[wxMaxima: comment end ] */
/* [wxMaxima: comment start ]
The sample measurement data below are from a "perfect printer". It is usefull to have such data if you
want to investigate how different geometric errors of your pritner influence bed leveling. If you are
interested in this then read more in sub-section 8.1.
[wxMaxima: comment end ] */
/* [wxMaxima: input start ] */
m :
[[21563,13648,11993],[21576,13668,13235],[21544,13618,14295],[21468,13494,15214],[21347,13296,16017]
,[21180,13019,16723],[20966,12659,17343],[20704,12207,17886],[20391,11651,18361],[20025,10976,18771]
,[19602,10154,19122],[19120,9142,19418],[18574,7861,19659],[21438,14697,11189],[21495,14782,12594]
,[21508,14802,13779],[21477,14755,14798],[21401,14642,15686],[21279,14460,16465],[21111,14208,17151]
,[20897,13880,17755],[20633,13471,18286],[20319,12974,18750],[19952,12376,19152],[19528,11660,19496]
,[19044,10802,19785],[18495,9762,20022],[17874,8464,20209],[21222,15548,10121],[21325,15691,11750]
,[21383,15771,13092],[21396,15789,14232],[21364,15745,15219],[21287,15639,16083],[21165,15470,16843]
,[20997,15235,17513],[20781,14931,18105],[20516,14554,18625],[20200,14097,19080],[19830,13552,19475]
,[19403,12906,19814],[18916,12143,20098],[18363,11236,20332],[17737,10145,20516],[17031,8795,20651]
,[21062,16429,10650],[21166,16564,12204],[21225,16639,13497],[21238,16656,14604],[21206,16615,15567]
,[21128,16515,16411],[21005,16356,17156],[20835,16134,17814],[20618,15849,18395],[20350,15495,18907]
,[20032,15068,19356],[19659,14561,19745],[19228,13965,20078],[18736,13267,20359],[18177,12448,20589]
,[17545,11482,20771],[16830,10323,20905],[20855,17207,11062],[20961,17336,12562],[21019,17407,13820]
,[21033,17424,14902],[21000,17384,15845],[20922,17289,16675],[20798,17137,17407],[20626,16926,18056]
,[20406,16655,18630],[20136,16320,19135],[19814,15916,19578],[19436,15439,19962],[19001,14880,20292]
,[18502,14229,20570],[17936,13473,20798],[17294,12591,20978],[16568,11552,21110],[20600,17896,11372]
,[20707,18019,12833],[20766,18088,14065],[20780,18104,15128],[20747,18066,16058],[20668,17975,16876]
,[20542,17829,17601],[20368,17627,18242],[20145,17367,18810],[19871,17046,19310],[19544,16661,19749]
,[19161,16207,20130],[18719,15677,20457],[18212,15063,20733],[17636,14353,20959],[16982,13532,21137]
,[16242,12576,21269],[20294,18506,11588],[20402,18625,13023],[20463,18692,14238],[20477,18707,15288]
,[20443,18670,16208],[20363,18582,17019],[20235,18441,17737],[20058,18246,18374],[19832,17996,18937]
,[19553,17687,19434],[19221,17317,19870],[18831,16881,20249],[18380,16374,20574],[17864,15789,20848]
,[17275,15115,21073],[16607,14340,21250],[15847,13446,21381],[19935,19046,11715],[20045,19161,13135]
,[20107,19226,14340],[20121,19240,15383],[20087,19205,16298],[20006,19119,17104],[19875,18983,17819]
,[19695,18794,18452],[19464,18551,19013],[19180,18252,19508],[18841,17894,19942],[18442,17473,20320]
,[17981,16985,20644],[17453,16422,20917],[16849,15777,21141],[16162,15038,21317],[15380,14191,21448]
,[19521,19521,11757],[19633,19633,13173],[19696,19696,14374],[19710,19710,15415],[19676,19676,16327]
,[19592,19592,17132],[19459,19459,17846],[19275,19275,18478],[19038,19038,19038],[18748,18748,19533]
,[18400,18400,19966],[17991,17991,20343],[17518,17518,20667],[16974,16974,20940],[16352,16352,21163]
,[15642,15642,21340],[14831,14831,21470],[19046,19935,11715],[19161,20045,13135],[19226,20107,14340]
,[19240,20121,15383],[19205,20087,16298],[19119,20006,17104],[18983,19875,17819],[18794,19695,18452]
,[18551,19464,19013],[18252,19180,19508],[17894,18841,19942],[17473,18442,20320],[16985,17981,20644]
,[16422,17453,20917],[15777,16849,21141],[15038,16162,21317],[14191,15380,21448],[18506,20294,11588]
,[18625,20402,13023],[18692,20463,14238],[18707,20477,15288],[18670,20443,16208],[18582,20363,17019]
,[18441,20235,17737],[18246,20058,18374],[17996,19832,18937],[17687,19553,19434],[17317,19221,19870]
,[16881,18831,20249],[16374,18380,20574],[15789,17864,20848],[15115,17275,21073],[14340,16607,21250]
,[13446,15847,21381],[17896,20600,11372],[18019,20707,12833],[18088,20766,14065],[18104,20780,15128]
,[18066,20747,16058],[17975,20668,16876],[17829,20542,17601],[17627,20368,18242],[17367,20145,18810]
,[17046,19871,19310],[16661,19544,19749],[16207,19161,20130],[15677,18719,20457],[15063,18212,20733]
,[14353,17636,20959],[13532,16982,21137],[12576,16242,21269],[17207,20855,11062],[17336,20961,12562]
,[17407,21019,13820],[17424,21033,14902],[17384,21000,15845],[17289,20922,16675],[17137,20798,17407]
,[16926,20626,18056],[16655,20406,18630],[16320,20136,19135],[15916,19814,19578],[15439,19436,19962]
,[14880,19001,20292],[14229,18502,20570],[13473,17936,20798],[12591,17294,20978],[11552,16568,21110]
,[16429,21062,10650],[16564,21166,12204],[16639,21225,13497],[16656,21238,14604],[16615,21206,15567]
,[16515,21128,16411],[16356,21005,17156],[16134,20835,17814],[15849,20618,18395],[15495,20350,18907]
,[15068,20032,19356],[14561,19659,19745],[13965,19228,20078],[13267,18736,20359],[12448,18177,20589]
,[11482,17545,20771],[10323,16830,20905],[15548,21222,10121],[15691,21325,11750],[15771,21383,13092]
,[15789,21396,14232],[15745,21364,15219],[15639,21287,16083],[15470,21165,16843],[15235,20997,17513]
,[14931,20781,18105],[14554,20516,18625],[14097,20200,19080],[13552,19830,19475],[12906,19403,19814]
,[12143,18916,20098],[11236,18363,20332],[10145,17737,20516],[8795,17031,20651],[14697,21438,11189]
,[14782,21495,12594],[14802,21508,13779],[14755,21477,14798],[14642,21401,15686],[14460,21279,16465]
,[14208,21111,17151],[13880,20897,17755],[13471,20633,18286],[12974,20319,18750],[12376,19952,19152]
,[11660,19528,19496],[10802,19044,19785],[9762,18495,20022],[8464,17874,20209],[13648,21563,11993]
,[13668,21576,13235],[13618,21544,14295],[13494,21468,15214],[13296,21347,16017],[13019,21180,16723]
,[12659,20966,17343],[12207,20704,17886],[11651,20391,18361],[10976,20025,18771],[10154,19602,19122]
,[9142,19120,19418],[7861,18574,19659]]$
/* [wxMaxima: input end ] */
/* [wxMaxima: section start ]
Computation of calibration parameters
[wxMaxima: section end ] */
/* [wxMaxima: comment start ]
And finally we just need to find [xa,ya,xc,oa,ob,oc] which will minimize sum of squares of ZEq over m.
Optionally we can also optimize for best diagonal rod length and (micro)step length.
Occasionally, there may be problems with convergence when optimizing both diagonal rod (xor
(micro)step length) and delta radius (tower positions) at once.
The tower positions contain the delta radius (corrected for tower radial/diagonal distance errors
if the towers are not precisely positioned). Both errors in the diagonal rod length and the delta radius
lead to nicely concave/convex heatbed z-position error near the centre (looks like a tip of ellipsoid or
paraboloid). These two can partialy compensate for each other especially when measurements are not
done far enough from centre. That means that their convergence (when optimized and the measurement
points are not far enough from the centre) together may be poor. They can drift from their precise values
together more easily. This drift will result in incorrect size (well and also incorrect shape because the error
is not linear) of the printed objects. Incorrect (micro)step length setting for the tower carriages results
in a similar kind of error too.
There will always be convergence problems if you try to optimize diagonal rod length, (micro)step
length and delta radius (tower positions) all at once. The reason is that these parameters are all linearly
dependent. That means the position errors measured by z-probe in steps are about the same when you
increase/decrease all of them by a constant factor.
[wxMaxima: comment end ] */
/* [wxMaxima: input start ] */
load(minpack) $
/* [wxMaxima: input end ] */
/* [wxMaxima: input start ] */
define( ZFns_rs(ra,rb,rc, sla,slb,slc), ZFns ) $
define( ZFns_s(sla,slb,slc), ZFns ) $
define( ZFns_r(ra,rb,rc), ZFns ) $
/* [wxMaxima: input end ] */
/* [wxMaxima: subsect start ]
Selection of what NOT to optimize
[wxMaxima: subsect end ] */
/* [wxMaxima: comment start ]
We define optimization parameters which we keep fixed in fArg and their fixed value in fVal.
Paramters which are going to be optimized are in vArg and the initial value from which for
the optimal values starts is in vVal.
Evaluate only one sub-sub-section below!
Current experience indicates that only sub-sub-sections 8.1.1. and 8.1.2 are numericably stable
(i.e. lead to reliable results).
[wxMaxima: comment end ] */
/* [wxMaxima: comment start ]
If you want to investigate how some printer geometric error influences the bed leveling then use the
perfect printer probing data in section 7 and fix the corresponding printer parameter to a wrong
value. Let's say you want to simulate how a tilted tower C influences the bed leveling. Evaluate some
sub-sub-section below which fixes tower tilts, e.g. 8.1.2 and set value of dyc to e.g. (idyc+0.01) instead
of idyc only. Run the optimization and check out the result analyzes to see the consequences.
[wxMaxima: comment end ] */
/* [wxMaxima: subsubsect start ]
Only endstop offsets
[wxMaxima: subsubsect end ] */
/* [wxMaxima: fold start ] */
/* [wxMaxima: input start ] */
fArg:[ra,rb,rc, sla,slb,slc, xa,ya,xc, dxa,dya, dxb,dyb, dxc, dyc] $
fVal: [ira,irb,irc, isla,islb,islc, ixa, iya, ixc, idxa,idya, idxb,idyb, idxc,idyc] $
vArg: [oas,obs,ocs] $
vVal: [0,0,0] $
err: 'err_0 $
/* [wxMaxima: input end ] */
/* [wxMaxima: fold end ] */
/* [wxMaxima: subsubsect start ]
Fixed tower tilt and fixed diagonal rod and microstep length
[wxMaxima: subsubsect end ] */
/* [wxMaxima: fold start ] */
/* [wxMaxima: input start ] */
fArg:[ra,rb,rc, sla,slb,slc, dxa,dya, dxb,dyb, dxc,dyc] $
fVal: [ira,irb,irc, isla,islb,islc, idxa,idya, idxb,idyb, idxc,idyc] $
vArg: [xa,ya,xc, oas,obs,ocs] $
vVal: [ixa,iya,ixc, 0,0,0] $
err: 'err_1 $
/* [wxMaxima: input end ] */
/* [wxMaxima: fold end ] */
/* [wxMaxima: subsubsect start ]
Fixed diagonal rod and microstep length
[wxMaxima: subsubsect end ] */
/* [wxMaxima: input start ] */
fArg:[ra,rb,rc, sla,slb,slc] $
fVal: [ira,irb,irc, isla,islb,islc] $
vArg: [xa,ya,xc, dxa,dya, dxb,dyb, dxc,dyc, oas,obs,ocs] $
vVal: [ixa,iya,ixc, 0,0, 0,0, 0,0, 0,0,0] $
err: 'err_2 $
/* [wxMaxima: input end ] */
/* [wxMaxima: subsubsect start ]
Fixed microstep length
[wxMaxima: subsubsect end ] */
/* [wxMaxima: fold start ] */
/* [wxMaxima: input start ] */
fArg:[sla,slb,slc] $
fVal: [isla,islb,islc] $
vArg: [ra,rb,rc, xa,ya,xc, dxa,dya, dxb,dyb, dxc,dyc, oas,obs,ocs] $
vVal: [ira,irb,irc, ixa,iya,ixc, 0,0, 0,0, 0,0, 0,0,0] $
err: 'err_3 $
/* [wxMaxima: input end ] */
/* [wxMaxima: fold end ] */
/* [wxMaxima: subsubsect start ]
Fixed diagonal rod length
[wxMaxima: subsubsect end ] */
/* [wxMaxima: fold start ] */
/* [wxMaxima: input start ] */
fArg:[ra,rb,rc] $
fVal: [ira,irb,irc] $
vArg: [sla,slb,slc, xa,ya,xc, dxa,dya, dxb,dyb, dxc,dyc, oas,obs,ocs] $
vVal: [isla,islb,islc, ixa,iya,ixc, 0,0, 0,0, 0,0, 0,0,0] $
err: 'err_4 $
/* [wxMaxima: input end ] */
/* [wxMaxima: fold end ] */
/* [wxMaxima: subsect start ]
Optimization
[wxMaxima: subsect end ] */
/* [wxMaxima: comment start ]
Run the optimization itself and store the result in RV. Compute the average postion error with
the optimized parameters (avgPosErr).
[wxMaxima: comment end ] */
/* [wxMaxima: input start ] */
define( funmake(ZFns, fArg), ToZFns(m) ) $
RV_raw: minpack_lsquares( apply(ZFns, fVal), vArg, vVal ) ;
avgPosErr : sqrt(RV_raw[2]/length(m)) / (2*irc) ;
RV : append(
makelist([fArg[i],fVal[i]], i, makelist(i,i,length(fArg))),
makelist([vArg[i],RV_raw[1][i]], i, makelist(i,i,length(vArg)))) ;
/* [wxMaxima: input end ] */
/* [wxMaxima: subsect start ]
Result analyzes
[wxMaxima: subsect end ] */
/* [wxMaxima: fold start ] */
/* [wxMaxima: comment start ]
Define analytics functions GetX, GetY, GetErr which compute XY position and the position error
for the given (itas, itbs, itcs). Fill the analytics into lists: chck_3d, chck_2d, chck_err. One element
for each measurement point.
[wxMaxima: comment end ] */
/* [wxMaxima: input start ] */
define( funmake(GetX_hlp, append(fArg, vArg)), XYFns[1]) $
define( GetX(itas, itbs, itcs), apply(GetX_hlp, append(fVal, RV_raw[1])) ) $
define( funmake(GetY_hlp, append(fArg, vArg)), XYFns[2]) $
define( GetY(itas, itbs, itcs), apply(GetY_hlp, append(fVal, RV_raw[1])) ) $
define( funmake(GetErr_hlp, append(fArg, vArg)), ZFn(itas, itbs, itcs)) $
define( GetErr(itas, itbs, itcs), apply(GetErr_hlp, append(fVal, RV_raw[1]))/(2*irc) ) $
chck_3d: sort(map( lambda([p], [[round(apply(GetX, p)), round(apply(GetY, p))], abs(round(1000*apply(GetErr, p)))]), m )) $
chck_2d: map( lambda([p], p[1]), chck_3d ) $
chck_err: sort(map( lambda([p], p[2]), chck_3d )) $
''err: chck_err $
/* [wxMaxima: input end ] */
/* [wxMaxima: comment start ]
Show the distribution of the measurement potins:
[wxMaxima: comment end ] */
/* [wxMaxima: input start ] */
plot2d([discrete, chck_2d], [style, points], grid2d) ;
/* [wxMaxima: input end ] */
/* [wxMaxima: comment start ]
Show the distribution of the position error after optimization:
[wxMaxima: comment end ] */
/* [wxMaxima: input start ] */
plot2d([discrete, chck_err], grid2d) ;
/* [wxMaxima: input end ] */
/* [wxMaxima: comment start ]
Show the position error map after optimization:
[wxMaxima: comment end ] */
/* [wxMaxima: input start ] */
selMin(d, v, l) := if [] = l then v else if l[1][1] >= d then selMin(d, v, rest(l)) else selMin(l[1][1], l[1][2], rest(l)) ;
f(x,y) := selMin(200, und , map( lambda([p], [(p[1][1]-x)^2 + (p[1][2]-y)^2, p[2]]), chck_3d )) ;
plot3d(f(x,y), [x,-80,80], [y,-80,80], [grid,32,32], color_bar, [ztics,false], [title, "position error [µm]"], [elevation,0], [azimuth,0]) ;
/* [wxMaxima: input end ] */
/* [wxMaxima: comment start ]
Compare error distributions between different optimization runs:
[wxMaxima: comment end ] */
/* [wxMaxima: input start ] */
plot2d([ [discrete, sort(err_1)], [discrete, sort(err_2)], [discrete, sort(err_3)], [discrete, sort(err_4)] ],
[legend, "tower tilt, rod and step length fixed", "rod and step length fixed", "step length fixed", "rod length fixed"],
[title, "expected position error distribution [µm]"]) ;
/* [wxMaxima: input end ] */
/* [wxMaxima: fold end ] */
/* Old versions of Maxima abort on loading files that end in a comment. */
"Created with wxMaxima 18.10.0.unofficial"$
You can’t perform that action at this time.