From 79eb28f55e9354787262464b785fdc0bad148f63 Mon Sep 17 00:00:00 2001 From: Thomas Dehaeze Date: Tue, 28 Jan 2020 17:15:19 +0100 Subject: [PATCH] Important update of the stewart-architecture file --- figs/frame_definition.png | Bin 0 -> 36689 bytes figs/joint_location.png | Bin 0 -> 41054 bytes figs/length_orientation_struts.png | Bin 0 -> 36632 bytes figs/stewart_platform_actuator.png | Bin 0 -> 2807 bytes src/initializeJointDynamics.m | 23 + stewart-architecture.html | 1162 +++++++++++------------ stewart-architecture.org | 1377 +++++++--------------------- 7 files changed, 887 insertions(+), 1675 deletions(-) create mode 100644 figs/frame_definition.png create mode 100644 figs/joint_location.png create mode 100644 figs/length_orientation_struts.png create mode 100644 figs/stewart_platform_actuator.png create mode 100644 src/initializeJointDynamics.m diff --git a/figs/frame_definition.png b/figs/frame_definition.png new file mode 100644 index 0000000000000000000000000000000000000000..7b080079384ce134dc83f4efd48b5cdb9a376921 GIT binary patch literal 36689 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

;sy5J`HrH1a`=9oOA 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%0D~Emi>XJI7 zXXh%jQ7nt3h{6?RQHdWH7q>T&FEYWVA?{T$F)%H23ScPf)zuEGN^jqykTxkTSoOq_0A(oh;HvPvEgK_c*Jk zP{+Ou70&xO`VRTr__jiNXt8__^e(ebB=2|e z{RijC$NQfX5%6)El*X|(oPMnQ+HM| z^sHb$*<)KD+*kdj8gOol?GJ4p3ky?0QUTC)@93zlx!Dg-_|*5;FGdeu1&O7+$Mp33 za~?Z;LsHa3gM)grl)(|}&L`s+FOG-ZOwhFaZ2T+$C0E^CUrg0|@LG)LDZ=pUm$|8_ ze&Ea@m}t~EGNFVE?qh+`g8`E`TPFo}P9+GsaXfohfHZ{}pPMTv75LhXxsw##iXD2m z<4`eC&46}8a*EB?KQa>Ou~Q%O?!8yk*}>}K`nuck^ZNwFY4GgPiyh$y&6w2qBqY#s z6rf(~{2Y7?@*Xp;i=oHXKLcME?j9Z*^(XQ{t9Skj0fETa*w@O+BQNG-nz%yj6P}p5 zUvt7d7|d%Uw}Z`@nHh>`*7yBztF~4=k&wc|owy1q2_w<$oSeV)Cv&YmJ-M^j26&1{q`kRU665iPcna`2Y-y_oNZZJ8XfN+ zPfp}tg1yOmH8MNOb(MG|)`|o#Wa8}*Uno8;j`YDzx z;H>6#(3EA66&;MPtDOGdWYJGBq6=%M@kY4ua+%c*a$7Xrrp{0*o%+n&!F4>(TiUCe zn{ZaKp=-zcMBvC80%;%?3c$AxYM(@(%SGz(xZncx29!&Ffriq-b#zNi7IJ``n-hhm z*OzBr<9f*PpJa6`jhFV&`Zn-OF%5;KeXWYZd*6;BK%OLIVTTi-(CKa~p6cH>5PT%$ znE-$xHGFs1mW}?~4VJC7M{ifE1GlZ2tu5P5-2pD3=Czb){{8xtL`OAZW zofFCbU1^@zZQqE>=hAMob%L!OdrE9oTy!^tjPrDAz}qAMhULQD-r99gx~Q-2-D_ry z`${)&;_zdEBz#6)(asGG7)U1+{;hM9N z%h!X5_E zh=9*AUha-!)+`G|YRDz*R9RWsWUU4*tN5KK zg+%ueGjm9}#f1HYjtjfPirjX?g|+b2p)%ye|7Il!BCMyX9ZYKxyp+Cbo1Y+y+TZJ- zUR+u-3a|JYc<;l2$c-S_F)>6=sMH>=dz6=zA?00S^GA4NV*|z3!J)OS?G`I5>q=ij zhjENfJAC}Rj5bCppcbN{tW4As{d^H{YlWAUxam{;qxnyG`|z1g^8zqG?uU+9wVLel zD?7W`MS0o|(#pNRZGyW^=#Y#})$#$tgE<|~;J~{D3R9E%2Woy+%m%JFxiI9C*xA{S z%`yTzQNG2*bOf_DblzO=-28=RK^2wz!NkuuVov1WyfNM!&xhI<;+PNW%o`g)pFW`j zaGP=YN=xr7W(d*w-X~6sI{g~Lk72*)jYV7IH{YRS<0#;KcPpoEZoE91y z8sI2yEx3;^@8`teSkKSh$Mdy1HVYf&t*oAdXeq-*u3vy-z1qJPaQ-(RAw`v1Q$r4N zp`fI^bN8-6*S9CyFqT6u@kQ}_c%i~D5sWBWhF}HC@y%nqn&F~fV26U!=lYT!1<{u< zlKJLhz-%P*3(5WaMP3)q+cldkb6zJpkhqvOMni8}#Q3-xq-SKDCUOC*&i^KxIR^yA z<>hgev*eB2f*v5<*q`YNz+>BuH{LU|vl?X|2qv^0a2!_qRc$h1VZH_RRo>If>#RfMdZH=6cY_3)%&21h>;nm7U_Cu;X-tIxt~wYpDUJ`#r37aCR0R z2^pM@FTfh>Kfrg;!~GSm1J!2rclL(WfGVu{P#+}st`t6pqy3vPtG z7E);|n%qj{J@^slfVYsp0=xyioF(o@<~VGG5ii$Sea^6Nu1^}Xb8{Cn6Rc@jSi%6U zXUfI3C@ToHsk!mS38wvdS zb?CC2cDN9-k+VJ@A+TNb zNs7u1LqTDn;ercfyH-A-yO>`&2gBs<{vVS|D(v~9@qDbX3i81L*N;blrw>3ABKRCu zZ2x$juWbA>G}M&y5G9R|r{ZX^Hd`I8GA=Mf2=g zj7>G*n81LbN2&8~TX6MG!-YE+-YPhZ{vOuGUJ#H*ovU5t`**M&K;%^?a~`NLTF0e& z{v)=non0}dG7yWvbzGe6tY*aMB56Wo#x-(K53sxL`g{}4mqY{BbE&0->9Y}uiM=ot z$<%pg4yS1}TiI;|j+?^ZNwfD_N=hvd1hC%z!!SaP;#>+2&$ReYoiBS?06D=Kd$HvBT zvQSSA4x$V$&brhTO1wia%og1eQ8WeO)v;Ex*Rh7lK=K6YO6T_ywe`g2>hA`L43myu%|_Ztf^b0p~8z+AyOsan+C3UbWauWw2-AeR!KX8yh z$olqs@Ryd9Obfw$BbY1{Av`oZEC#d#=q0Oc42v-^T>vV@3)b>FY-LI7ZeiWvz@8BSY>RkVyeZ01bg_^O}x;Y_$JS;9u=d13LfC@=T4BMZgp? zmj$w0B<+NdpxE5X${2u|;PvSu@;|duyyJl+6%!YC+wWq4xtOfa)be0t%w^u6P4J?0 zOiXtkk+~8zX}0{NI^`=mfS)-e3VZR#Xxn#bG^SQo@>eVgLaBO3Bn>;*R+zK3gsCX;`U5)exLf6ZG zCMHPOp3;2{Ow9Z7!#7;`JP>ju7%72DijL1(w=1??cOYK?;ZOIuInv}ePt>s`8}cv> z?N2MNu>`law)#MgCm5DlI5|0|{x9qP`Qrx)N@Uk>a6sMM6WXm0-f5@GNYQf4$Mu;+ zKi8534jyv4ZD$1|;GH2W<3oX+E4Ny5)6t;}z@yFtm-`75FWJ6iIWi+Nv&41J0RF2T zEOYPx4|}+qlc8A0J@>JIbpOm)%LT)88gM(l>%VSpxVFIv@@zBp#%-U6N zQB@>vCn9y}v_k~RQt5gfsRH(>xtaz?{vSiK>qk&4+)upW6nrg6D2a4WRF&(nDGSxB z$&0B0RDZ!@_<(a45)KHwXMJ>ZVHAn$ZQTY_&nWC4gLb=EPQ#cRbe~dgo=>p zhm5p0MI@yyn1s`2PH=YQF|Bh{M1+2BCl4I*Nd_jAYCz)zLSi)17r{afAcv~-*d9z3 z_q;lq5Imj#WIEaaAVpbM7q`9lwXC0iMTa9XKkAI{iSMS4j?P&t^>x#L_i?GP zRh}vYsT8kcGHS0w0^oDYW`FH$Y;=QxAfXbd12?j=Fib@dQ9=Ij;Z&s!H8Q1uHRS2m z*GRRou~aV+g8Oj=KB9WT|KYTd3rGOm#lQ#eMI=y6_;cycZrHy2n@E8TiUEiW4+1hx zpy(${P4NI|>z!=Rj*gE{CkKaxnZVIPAi=8swD(+I{JB|yohwx{LttEnM4~Y`Qu3q9 zH9c!WN0E(Y)*s7Jtsu0&qG4qXw?b4DgD8Nvl+wcc1^Iz;rrZL+&QC95RRS1zDbG8m9xA1?!S&4=F4c{^0u3zpV3U zF7(FR27bJimQ#O|{`;>9AVZv>o4rj%wJboS8F2Q<&;17vkk*V$0p{vGzJ`Z02n#2V z<-S8A@jAByfQ1WxgITu^Sd0h=pk7PNqTLD0QxFqFgH%Ci%OWprTwF}dz5M>_#CxAN zfTdwgO7r*0Xdyp5T}iN+1iuD0o>^2hc$`>UD*)c>&cW&cl2*XLz&P}{_zQ>#i8oD5 z=tUpcvhLo#k>!>jWnAaAIAiw!$U^qSFF8cq#N`V*(p6n_B7F;2?q^oVZIfPdOh72x|&Ya2Ex@CX<5T9tLRTrv8Y>0J4b0Wk!gM+Tf!o zUfB8qSMNVLsSarY6g==ej{l)HwYGj*AIai0Y`L38@q$dYb(rH=Y8ON)qSs+(zwfZBzC^z|uz7vRNg>PO$>UfwZmdYkp>i~O>j7y~JhR|Ak~Y5;vM?Eym-AUz$D(LmxtAQDVn zH|8GT<2Maw$o`MPg?#rnh{k*5wVd1%Ac@j3F`hU%$oU8&9DtFi@3@r}9~<>UaS3+pWW%>*4*Cq*0R95PE#5JD|`Bzbm5wCHy}DXx|Y{!dg-!@A*IN1T?uHOZB#ovF)gq+Bx?jDK5F|~ z5kQ?%pBwMvEkp;{nB~c5WWC1M&f)rSeI$>A1{}Wf{lxw?pX&;w23>2@6KZ_Aa&0WrTPDt{v1= z!YKH}6cq`;$rnZCSs)&o>p)Q?Bp@I_NF*rmkkcZ&E7F7WJi%CO#k%joQ(7TqEiG9C zgP&G8?Etrjhli&_nK9FpEvC!NkTpn9cp^$lAx7(o(eE3GL7T(-+_Lo88w&=k;^ z>W_52ocdhvN#d;u`QpJlQC}c&86>U$CbFa5#s9Bzx>eJc|9;;pl$8Ca4t^5sq?ODA z0y1|bu7sy)0|KIt`g#|$wtNwpIm|bILi&86oUq5VTTaAmBO@d135Y)pAGSP8=KM)u zEo;_o&=ZdgD9E%iFOPY1TW0=wh~oNs{Z+EpRo3Ds0zscp0tukSVA59M3K)h7)Gj}5 zuy*DY7e_#NFTaq2vbE7xPz8IO9Gvcp2mTHwu|B4ki*5S-l?bp?v2xF=^vZnA@*qGW z0l*S|L)bLdzxQ}(VPWBReYUCr8P$N`!97SZWE<-%JN04`5_&*0;GG_{?CcRxJAmn+ zbE%jkU0q)RQCDuN#J{ln`y=rz6A}?nCK$9vT>=Hu3T3Vg)LcIw1B?OTq4!@02&!NsjNyOWIeQ(bKtFpM%Q;H<*Ka;#O>bsHxYiBTLY^= zn|zCmN~(l{7010uD_`NTAf5^8k1;S!PD`kk{H0kvj#1Jn7d4vc+%iDJ4?8 zi=^``J%qR0Keq#&sO_;;jwI<^Jv%+8w(m#_2(-m~Ke7h-4p}v^D z!NJ(DN~ASEE3C60oV}T%ggK!VDCRh6kk}_(XF=Z;upQIxuktqmGyO7Ek&x);b8>Qm zByCzOgWG6jY02@-!4bSJl82my<6%Yt<0tvRzcie!JOupF4UPfPk3EgziFS!Sd7I0{ zDXf9(t@W=%^y}6V?Ypr}v1?Z)JuHU6(gHs9c^!}kwMt|(eDmfB6Vq34lgiir$2SOp zk<9jjLlhA#npB-fG@mCQ1|nvi1+A2mLj*WkJif{0d{bE#-={0}llmN5mFNgp-@dSFR=)?HCd(Vylj@x*W@7A!*Pr9!$V^O4 z!HMIRmX`MR_Tqn)FcJ`aiI1@`ZSU&(T9Ar?IJmf`rh8-KX|Z~UI!MsA$%iE_6^Y49U68NRsR3qd$QRi)Z zeK4-$S4!laYm?gAUJ0Kq5qTfwzMqZndU52QG&ZKHTj!d(vyv?0BhN*?6yF6K_+VNtapZcGL^E|YF|0{EXVIdoHbmXK{QBmQ3+>Pp5uL}m|xRdDiYtrh^8Ea%$QCZpV;bFq} zo_n_h1fJI_MEl;LTvMKgyqk>Q=ctw+Hfz6oN#^f+Ewmeb7GQ2O0vYN)@X&w9Z#uY@ z8SnFN^QcmUchrVat4><-NJ>c^&6+UYr@eodosTd3mTLRAyB{CTF!xS`Zf#jPJ3Aj9 z(GdqLvcxEOHgv1!SiJIJCLJ~BZaCj~<_#obF|4K3bYQxppumnf{^lz?-u>MIn{VC^kp{rEewR zrXUL=jw$<&#Mh61sXWbUkoWNs@e>tw`I8Hc20z;z9UWDcRPaA*1$>hp>zmE(H{xKx zjZv!7W@&G4Cw=&kjskbn-O=$otnu`;N}Fgvx?FP^&*v09oLXcB>A<@p8D>k`MGTBM zZ?ZIoW4w}Mx~%@|cb4>n_i~Zao}(z!kJjB9|NEDg+H)7x!NGw;ZSNyvOwVJ&JA_{` zpqH6{Zfc4qPVSq0mUPy@aa^f7GX@$eI1VR&m9}QRBD#j>vSwHxZR>wcY=R59x-tzb zowAfo>@un;P@Ix~|DM`U^vANvEOU$uo6X)q}nHW_0iU$dol&>d}dg=4RA&$9T~8;q|iU zq2u$s_YHR&{}i@y;bY-rVUUuO8+`bH1wTNH?Y)@`5yk&J(XqYFQmq}P%_7B<@Fbz{ z+rX-m7JVd5WY>pO=KFU|y{()|^Nl!2?-Ak#2yBQx@*Oi5y1MnnLGfwSDWpkfKfBPdIrYmmkKWiY-rpdH;dyK7{tt9mK#xoZ zlJ^eRm34j&eW*;AqBs?5kB@7_Y(Uf97HP$iNoi<*DJbunfmtED+$Q- zyyEh`zPu&zx8&*R?+@!2`-L4qs5<669nz;;rCoqaaO7UEsU}2)XI=R)ykmsGqkc}S za>(yd9SblsjKsm;WuC}n5H8zS)A7h=Xs{fd367Z`Y42E6BAi%*s-<2#G|kJ__P^%lmx5H`AyUKzlx+qPv$OENfTtiZrR?>dK;VZp_2rtO_4Ps^b4*Ok?>)=W74G%&8A^P``EMCNWDD9j7nA4~R&L@X2KCkB zKUMq5B#SzGZ{vu+SY6JP1yE7{{yxW)<-|hN(@$o^y&W?}8NqY+X_E>`9@ zwbs4YIMx65q-6y$U%5K-y?gi8{weV4JJrq}o}3th!Y=k&nb(!|EN_qwtQ?%VCkK-q zHDskqT&ODggpaUcCsyZQ-A>oiN*fxSs*}lR0Rs<}6yL#D&Q}wd{{DiBimF1eK)2Ar z)pe3KQikn)N8g}y)vR@*d{%>oeYN)a*zTCVls4zpSGCJmOH<1Qci?DAta0Fg`kZEkXJN&V*uHQA`v>PdOH8nz zA8L}~&e)1`ZLwzlb1SNF%z#$Ek@fFUFFz{-l+$EXtuHBQfvOX0bsoBiEpxOC2T_d6 zI9i~i?i0%<1nIt8BiSF!m37)QFE6i<&`@>(fu7#pdw?N<=n0sb(x8n9?6tnnLK&s1 z%7N{lNJU9m+}K!XdKfK}QD6nh=jf)>tQt#<85cQJ$k!}&tF^bQemVB6o0yo$%IKH#P@6C){vhp8t*xG~25rbr39SoydU`0qZ9o6CF4*do zPHE0f%$P(=KZ%_!>H4_K4;Kf}2GB4!H&-G}(V&=g=)-pj+M&%-ZOmjtqh~P*M|gee z?eBF_CHM=4(VJ3GPF@fXRkF8-JI@Y|o0PJ1b7wqJkzR)fYu4Kxme)qYPI=lSd5bs| zgK7Z9)6<%jU&bC>Q1mQuDr>x~X)olWO`1r+@(-Cai@xYvB$KOUjsx=nV8Ox7-G-cm z5*f*#oRSi=mj-aGuZ>e-z@S4D|CET_T z>@}{6tt2g{ZY*!rFB!Y#=;Vaxt3+&a@;EI&JNwJWg!%>sA4MP8GBL0M%+sbGUgy%% z(t>A)nGWSD1^M{|;T;MHbYbkerdalCbjgbS@V3*9^Ka3lH=9rzt_L&qFAhZOgw zlb_&x5&JAglk_~QI31SA8!nbQ_$@;&LkU0zVAw#(G*b;c?hd=mVeJMf`h%IL68yI~ zo%M*tMOWjG?)itvqqi~$O_`Jue3ifoXhmuU4^R8r+OM$Ig`$6TG!S;bbefb}+So+C ze*F3|;p0eY9fnA0Kx7veS^dpjXzY6V8qcylQ6(az1;vOWvKU%O=CwY=)XlRJ>=_TOHJGVc5V+XA5dW$^tHbhz@j%x#&SEdo;E~JRx8|ZkKHHRGsPZ~=CwEQ`RK+r*8m&pM5W>l&H zIM~tBdcdUAG^$Hn@8N3$ETfO|soGNXn^-Y{ud{3)6dMGtzQA8mmsHLFi_akEY2LB8 z_W>0L0}Y96{QY+?uAuw}QJIXKoE9I8O;C_oK={r_TNa2O03_t-#aUuD8BP3PAG4l6 z9F<2Grzh$o+#&2p2WtlI`rY~(dm;v|}`jPJg)5xj0&dXHPy<5H$HfdW@5_`jUV)q@2` z{$j)yxMppZn6M;y2AGEeKq6XwtK&J=#24tJ3~HktGmrYekV`B&rp8QsWS60o`j)XQ zFg@t~OY#R!_h?j}Ac#%*h-FH(yMI4?x%TmO)+22}s+yi(L0+Ui3TM*>KBd}gt0j$% zjjxoVLUJI4R+d5C5h8$=K_w!z4_=PsjP6g0ckiBFvHGs7Ac@irmG+7%y0<>aO@D!3MaItYlI54S(FPWn4)9=t-wB)Yi`jhoZ&O-^$xP2w3%3i z)pn%^88bb4StSZKy0Ed3s{C4Y4+S?w6{W68FMQIkm@+3OCf4%kDahWE=OH+9O^H4$ z-9i$!ar3S5Of{0V@s$IzXI4{N$6=~imONS=>4gwC68p!82-I@R)3zSZSf5n;^K+4h z#>A5<<*V_%_%JJ3qm=Df1|vV5nTK_9#~ig%-ws-t%jp-ZV}wi%$*h1xp|$hh)>gUT z_S#w?V1?(A8A{n{TZCQuy*ULa#`nxrI-cCqQ0Zt}8HkdIZ&ONF#4o_7P5NkiP;AHi zBTU(V+P}^@*ot%*+kXaE@7|ODR93fA1KH_n!e~C}1VH6M?huSZhkY`Y*I@m zkQCYQ{X+uThvY>KKAY$&KN?fhj1U?NlkY#`vJJ4}<8(xiq;k6$%S{AGIb23PlgUlh oo7SAS$1{!aYp^rHwO60{wCvydEF3F9h5}#GujC~P#PmM?f5h!X;{X5v literal 0 HcmV?d00001 diff --git a/figs/joint_location.png b/figs/joint_location.png new file mode 100644 index 0000000000000000000000000000000000000000..d065427b1ffd2fbf3eb4077136e8484e952bf1bf GIT binary patch literal 41054 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 l`FM=8>Dsl{6J|kD6co{{UjC|4IM= literal 0 HcmV?d00001 diff --git a/figs/length_orientation_struts.png b/figs/length_orientation_struts.png new file mode 100644 index 0000000000000000000000000000000000000000..51f5ebfcf9cee31b749011d4a1f70bb5b02a46fc GIT binary patch literal 36632 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 JPDHLkV1n4_KMeo? literal 0 HcmV?d00001 diff --git a/src/initializeJointDynamics.m b/src/initializeJointDynamics.m new file mode 100644 index 0000000..586a469 --- /dev/null +++ b/src/initializeJointDynamics.m @@ -0,0 +1,23 @@ +function [stewart] = initializeJointDynamics(stewart, args) +% initializeJointDynamics - Add Stiffness and Damping properties for the spherical joints +% +% Syntax: [stewart] = initializeJointDynamics(args) +% +% Inputs: +% - args - Structure with the following fields: +% - Kri [6x1] - Rotational Stiffness for each spherical joints [N/rad] +% - Cri [6x1] - Damping of each spherical joint [N/(rad/s)] +% +% Outputs: +% - stewart - updated Stewart structure with the added fields: +% - Kri [6x1] - Rotational Stiffness for each spherical joints [N/rad] +% - Cri [6x1] - Damping of each spherical joint [N/(rad/s)] + +arguments + stewart + args.Kri (6,1) double {mustBeNumeric, mustBePositive} = zeros(6,1) + args.Cri (6,1) double {mustBeNumeric, mustBePositive} = zeros(6,1) +end + +stewart.Kri = args.Kri; +stewart.Cri = args.Cri; diff --git a/stewart-architecture.html b/stewart-architecture.html index 1cb20d3..b033165 100644 --- a/stewart-architecture.html +++ b/stewart-architecture.html @@ -1,11 +1,10 @@ - - + Stewart Platform - Definition of the Architecture @@ -284,116 +283,104 @@ for the JavaScript code in this tag.

Table of Contents

-Stewart platforms are generated in multiple steps. +In this document is explained how the Stewart Platform architecture is defined.

-We define 4 important frames: +Some efforts has been made such that the procedure for the definition of the Stewart Platform architecture is as logical and clear as possible. +

+ +

+When possible, the notations are compatible with the one used in taghirad13_paral. +

+ +

+The definition of the Stewart platform is done in three main parts: +

+
    +
  • First, the geometry if defined (Section 1)
  • +
  • Then, the inertia of the mechanical elements are defined (Section 2)
  • +
  • Finally, the Stiffness and Damping characteristics of the elements are defined (Section 3)
  • +
+ +

+In section 4, the procedure the initialize the Stewart platform is summarize and the associated Matlab code is shown. +

+ +

+Finally, all the Matlab function used to initialize the Stewart platform are described in section 5. +

+ +
+

1 Definition of the Stewart Platform Geometry

+
+

+ +

+

+Stewart platforms are generated in multiple steps: +

+
    +
  • Definition of the frames
  • +
  • Definition of the location of the joints
  • +
  • Computation of the length and orientation of the struts
  • +
  • Choice of the rest position of the mobile platform
  • +
+ +

+This steps are detailed below. +

+
+
+

1.1 Frames Definition

+
+

+We define 4 important frames (see Figure 1):

  • \(\{F\}\): Frame fixed to the Fixed base and located at the center of its bottom surface. This is used to fix the Stewart platform to some support.
  • \(\{M\}\): Frame fixed to the Moving platform and located at the center of its top surface. This is used to place things on top of the Stewart platform.
  • -
  • \(\{A\}\): Frame fixed to the fixed base. -It defined the center of rotation of the moving platform.
  • -
  • \(\{B\}\): Frame fixed to the moving platform. -The motion of the moving platforms and forces applied to it are defined with respect to this frame \(\{B\}\).
  • +
  • \(\{A\}\): Frame fixed to the fixed base.
  • +
  • \(\{B\}\): Frame fixed to the moving platform.

-Then, we define the location of the spherical joints: +Even though frames \(\{A\}\) and \(\{B\}\) don’t usually correspond to physical elements, they are of primary importance. +Firstly, they are used for the definition of the motion of the Mobile platform with respect to the fixed frame: +

+
    +
  • In position: \({}^A\bm{P}_{B}\) (read: Position of frame \(\{B\}\) expressed in frame \(\{A\}\))
  • +
  • In rotation: \({}^A\bm{R}_{B}\) (read: The rotation matrix that express the orientation of frame \(\{B\}\) expressed in frame \(\{A\}\))
  • +
+

+The frames \(\{A\}\) and \(\{B\}\) are used for all the kinematic analysis (Jacobian, Stiffness matrix, …). +

+ +

+Typical choice of \(\{A\}\) and \(\{B\}\) are: +

+
    +
  • Center of mass of the payload
  • +
  • Location where external forces are applied to the mobile platform (for instance when the mobile platform is in contact with a stiff environment)
  • +
  • Center of the cube for the cubic configuration
  • +
+ +

+The definition of the frames is done with the initializeFramesPositions function (link); +

+ + +
+

frame_definition.png +

+

Figure 1: Definition of the Frames for the Stewart Platform

+
+
+
+ +
+

1.2 Location of the Spherical Joints

+
+

+Then, we define the location of the spherical joints (see Figure 2):

  • \(\bm{a}_{i}\) are the position of the spherical joints fixed to the fixed base
  • @@ -427,49 +497,180 @@ Then, we define the location of the spherical joints:

-We define the rest position of the Stewart platform: +The location of the joints will define the Geometry of the Stewart platform. +Many characteristics of the platform depend on the location of the joints. +

+ +

+The location of the joints can be set to arbitrary positions (function generateGeneralConfiguration described here) or can be computed to obtain specific configurations such as:

    -
  • For simplicity, we suppose that the fixed base and the moving platform are parallel and aligned with the vertical axis at their rest position.
  • -
  • Thus, to define the rest position of the Stewart platform, we just have to defined its total height \(H\). -\(H\) corresponds to the distance from the bottom of the fixed base to the top of the moving platform.
  • +
  • A cubic configuration: function generateCubicConfiguration (link).
  • +
  • A symmetrical configuration

-From \(\bm{a}_{i}\) and \(\bm{b}_{i}\), we can determine the length and orientation of each strut: +The location of the spherical joints are then given by \({}^{F}\bm{a}_{i}\) and \({}^{M}\bm{b}_{i}\). +

+ + +
+

joint_location.png +

+

Figure 2: Position of the Spherical/Universal joints for the Stewart Platform

+
+
+
+ +
+

1.3 Length and orientation of the struts

+
+

+From the location of the joints (\({}^{F}\bm{a}_{i}\) and \({}^{M}\bm{b}_{i}\)), we compute the length \(l_i\) and orientation of each strut \(\hat{\bm{s}}_i\) (unit vector aligned with the strut). +The length and orientation of each strut is represented in figure 3. +

+ +

+This is done with the computeJointsPose function (link). +

+ + +
+

length_orientation_struts.png +

+

Figure 3: Length \(l_i\) and orientation \(\hat{\bm{s}}_i\) of the Stewart platform struts

+
+
+
+ +
+

1.4 Rest Position of the Stewart platform

+
+

+We may want to initialize the Stewart platform in some position and orientation that corresponds to its rest position. +

+ +

+To do so, we choose:

    -
  • \(l_{i}\) is the length of the strut
  • -
  • \({}^{A}\hat{\bm{s}}_{i}\) is the unit vector align with the strut
  • +
  • the position of \(O_B\) expressed in \(\{A\}\) using \({}^AP\)
  • +
  • the orientation of \(\{B\}\) expressed in \(\{A\}\) using a rotation matrix \({}^{A}R_{B}\)

-The position of the Spherical joints can be computed using various methods: +Then, the function initializeStewartPose (link) compute the corresponding initial and rest position of each of the strut. +

+
+
+
+ +
+

2 Definition of the Inertia and geometry of the Fixed base, Mobile platform and Struts

+
+

+ +

+

+Now that the geometry of the Stewart platform has been defined, we have to choose the inertia of:

    -
  • Cubic configuration
  • -
  • Circular configuration
  • -
  • Arbitrary position
  • -
  • These methods should be easily scriptable and corresponds to specific functions that returns \({}^{F}\bm{a}_{i}\) and \({}^{M}\bm{b}_{i}\). -The input of these functions are the parameters corresponding to the wanted geometry.
  • +
  • The Fixed base
  • +
  • The Mobile platform
  • +
  • The two parts of the struts

-For Simscape, we need: +The inertia of these elements will modify the dynamics of the systems. +It is thus important to set them properly. +

+
+
+

2.1 Inertia and Geometry of the Fixed and Mobile platforms

+
+

+In order to set the inertia of the fixed and mobile platforms, we can use the following function that assume that both platforms are cylindrical:

    -
  • The position and orientation of each spherical joint fixed to the fixed base: \({}^{F}\bm{a}_{i}\) and \({}^{F}\bm{R}_{a_{i}}\)
  • -
  • The position and orientation of each spherical joint fixed to the moving platform: \({}^{M}\bm{b}_{i}\) and \({}^{M}\bm{R}_{b_{i}}\)
  • -
  • The rest length of each strut: \(l_{i}\)
  • -
  • The stiffness and damping of each actuator: \(k_{i}\) and \(c_{i}\)
  • -
  • The position of the frame \(\{A\}\) with respect to the frame \(\{F\}\): \({}^{F}\bm{O}_{A}\)
  • -
  • The position of the frame \(\{B\}\) with respect to the frame \(\{M\}\): \({}^{M}\bm{O}_{B}\)
  • +
  • initializeCylindricalPlatforms (link): by choosing the height, radius and mass of the platforms, it computes the inertia matrix that will be used for simulation
  • +
+
+
+ +
+

2.2 Inertia and Geometry of the struts

+
+

+Similarly for the struts, we suppose here that they have a cylindrical shape. +They are initialize with the following function: +

+
    +
  • initializeCylindricalStruts (link): the two parts of each strut are supposed to by cylindrical. We can set the mass and geometry of both strut parts.
  • +
+
+
+
+ +
+

3 Definition of the stiffness and damping of the joints

+
+

+ +

+

+The global stiffness and damping of the Stewart platform depends on its geometry but also on the stiffness and damping of: +

+
    +
  • the actuator because of the finite stiffness of the actuator / linear guide
  • +
  • the spherical joints
  • +
+
+ +
+

3.1 Stiffness and Damping of the Actuator

+
+

+Each Actuator is modeled by 3 elements in parallel (Figure 4): +

+
    +
  • A spring with a stiffness \(k_{i}\)
  • +
  • A dashpot with a damping \(c_{i}\)
  • +
  • An ideal force actuator
-
-

1 Procedure

-
+
+

stewart_platform_actuator.png +

+

Figure 4: Model of the Stewart platform actuator

+
+ +

+The initialization of the stiffness and damping properties of the actuators is done with the initializeStrutDynamics (link). +

+
+
+ +
+

3.2 Stiffness and Damping of the Spherical Joints

+
+

+Even though we often suppose that the spherical joint are perfect in the sense that we neglect its stiffness and damping, we can set some rotation stiffness and damping of each of the spherical/universal joints. +

+ +

+This is done with the initializeJointDynamics function (link). +

+
+
+
+ +
+

4 Summary of the Initialization Procedure and Matlab Example

+
+

+ +

The procedure to define the Stewart platform is the following:

@@ -483,61 +684,67 @@ We can do that using various methods depending on the wanted architecture:
  • generateCubicConfiguration permits to generate a cubic configuration
  • Compute the position and orientation of the joints with respect to the fixed base and the moving platform. -This is done with the computeJointsPose function.
  • -
  • Define the dynamical properties of the Stewart platform. -The output are the stiffness and damping of each strut \(k_{i}\) and \(c_{i}\). -This can be done we simply choosing directly the stiffness and damping of each strut. -The stiffness and damping of each actuator can also be determine from the wanted stiffness of the Stewart platform for instance.
  • -
  • Define the mass and inertia of each element of the Stewart platform.
  • +This is done with the computeJointsPose function. +If wanted, compute the rest position of each strut to have the wanted pose of the mobile platform with the function initializeStewartPose. +
  • Define the mass and inertia of each element of the Stewart platform with the initializeCylindricalPlatforms and initializeCylindricalStruts
  • +
  • Define the dynamical properties of the Stewart platform by setting the stiffness and damping of the actuators and joints.
  • By following this procedure, we obtain a Matlab structure stewart that contains all the information for the Simscape model and for further analysis.

    -
    - -
    -

    2 Matlab Code

    -
    -
    -
    -

    2.1 Simscape Model

    -
    -
    -
    open('stewart_platform.slx')
    -
    -
    -
    -
    - -
    -

    2.2 Test the functions

    -
    +
    +

    4.1 Example of the initialization of a Stewart Platform

    +
    +

    +Let’s first define the Stewart Platform Geometry. +

    stewart = initializeFramesPositions('H', 90e-3, 'MO_B', 45e-3);
    -% stewart = generateCubicConfiguration(stewart, 'Hc', 60e-3, 'FOc', 45e-3, 'FHa', 5e-3, 'MHb', 5e-3);
     stewart = generateGeneralConfiguration(stewart);
     stewart = computeJointsPose(stewart);
    -stewart = initializeStrutDynamics(stewart, 'Ki', 1e6*ones(6,1), 'Ci', 1e2*ones(6,1));
    -stewart = initializeCylindricalPlatforms(stewart);
    -stewart = initializeCylindricalStruts(stewart);
    -stewart = computeJacobian(stewart);
     stewart = initializeStewartPose(stewart, 'AP', [0;0;0.01], 'ARB', eye(3));
    -
    -[Li, dLi] = inverseKinematics(stewart, 'AP', [0;0;0.00001], 'ARB', eye(3));
    -[P, R] = forwardKinematicsApprox(stewart, 'dL', dLi);
     
    + +

    +Then, define the inertia and geometry of the fixed base, mobile platform and struts. +

    +
    +
    stewart = initializeCylindricalPlatforms(stewart);
    +stewart = initializeCylindricalStruts(stewart);
    +
    +
    + +

    +Finally, initialize the strut stiffness and damping properties. +

    +
    +
    stewart = initializeStrutDynamics(stewart, 'Ki', 1e6*ones(6,1), 'Ci', 1e2*ones(6,1));
    +stewart = initializeJointDynamics(stewart, 'Ksi', zeros(6,1), 'Csi', zeros(6,1));
    +
    +
    + +

    +The obtained stewart Matlab structure contains all the information for analysis of the Stewart platform and for simulations using Simscape. +

    -
    -

    3 initializeFramesPositions: Initialize the positions of frames {A}, {B}, {F} and {M}

    -
    +
    +

    5 Functions

    +

    - + +

    +
    +
    +

    5.1 initializeFramesPositions: Initialize the positions of frames {A}, {B}, {F} and {M}

    +
    +

    +

    @@ -545,9 +752,9 @@ This Matlab function is accessible her

    -
    -

    3.1 Function description

    -
    +
    +

    Function description

    +
    -
    -

    3.2 Documentation

    -
    +
    +

    Documentation

    +
    -
    +

    stewart-frames-position.png

    -

    Figure 1: Definition of the position of the frames

    +

    Figure 5: Definition of the position of the frames

    -
    -

    3.3 Optional Parameters

    -
    +
    +

    Optional Parameters

    +
    -
    -

    3.4 Initialize the Stewart structure

    -
    +
    +

    Initialize the Stewart structure

    +
    -
    -

    3.5 Compute the position of each frame

    -
    +
    +

    Compute the position of each frame

    +
    stewart.H = args.H; % Total Height of the Stewart Platform [m]
     
    @@ -622,15 +829,11 @@ stewart.FO_A = stewart.MO_B + stewart.FO_M; 
     
    -
    -

    4 Initialize the position of the Joints

    -
    -
    -
    -

    4.1 generateCubicConfiguration: Generate a Cubic Configuration

    -
    +
    +

    5.2 generateCubicConfiguration: Generate a Cubic Configuration

    +

    - +

    @@ -638,9 +841,9 @@ This Matlab function is accessible he

    -
    -

    4.1.1 Function description

    -
    +
    +

    Function description

    +
    -
    -

    4.1.2 Documentation

    -
    +
    +

    Documentation

    +
    -
    +

    cubic-configuration-definition.png

    -

    Figure 2: Cubic Configuration

    +

    Figure 6: Cubic Configuration

    -
    -

    4.1.3 Optional Parameters

    -
    +
    +

    Optional Parameters

    +
    -
    -

    4.1.4 Position of the Cube

    -
    +
    +

    Position of the Cube

    +

    We define the useful points of the cube with respect to the Cube’s center. \({}^{C}C\) are the 6 vertices of the cubes expressed in a frame {C} which is @@ -720,9 +923,9 @@ CCm = [Cc(:,2), Cc(:

    -
    -

    4.1.5 Compute the pose

    -
    +
    +

    Compute the pose

    +

    We can compute the vector of each leg \({}^{C}\hat{\bm{s}}_{i}\) (unit vector from \({}^{C}C_{f}\) to \({}^{C}C_{m}\)).

    @@ -743,11 +946,11 @@ stewart.Mb = CCf + [0; 0; args.FOc -

    4.2 generateGeneralConfiguration: Generate a Very General Configuration

    -
    +
    +

    5.3 generateGeneralConfiguration: Generate a Very General Configuration

    +

    - +

    @@ -755,9 +958,9 @@ This Matlab function is accessible

    -
    -

    4.2.1 Function description

    -
    +
    +

    Function description

    +
    -
    -

    4.2.2 Documentation

    -
    +
    +

    Documentation

    +

    Joints are positions on a circle centered with the Z axis of {F} and {M} and at a chosen distance from {F} and {M}. The radius of the circles can be chosen as well as the angles where the joints are located. @@ -792,9 +995,9 @@ The radius of the circles can be chosen as well as the angles where the joints a

    -
    -

    4.2.3 Optional Parameters

    -
    +
    +

    Optional Parameters

    +
    arguments
         stewart
    @@ -810,9 +1013,9 @@ The radius of the circles can be chosen as well as the angles where the joints a
     
    -
    -

    4.2.4 Compute the pose

    -
    +
    +

    Compute the pose

    +
    stewart.Fa = zeros(3,6);
     stewart.Mb = zeros(3,6);
    @@ -829,13 +1032,12 @@ stewart.Mb = zeros(3,6);
     
    -
    -
    -

    5 computeJointsPose: Compute the Pose of the Joints

    -
    +
    +

    5.4 computeJointsPose: Compute the Pose of the Joints

    +

    - +

    @@ -843,9 +1045,9 @@ This Matlab function is accessible here.

    -
    -

    5.1 Function description

    -
    +
    +

    Function description

    +
    -
    -

    5.2 Documentation

    -
    +
    +

    Documentation

    +
    -
    +

    stewart-struts.png

    -

    Figure 3: Position and orientation of the struts

    +

    Figure 7: Position and orientation of the struts

    -
    -

    5.3 Compute the position of the Joints

    -
    +
    +

    Compute the position of the Joints

    +
    stewart.Aa = stewart.Fa - repmat(stewart.FO_A, [1, 6]);
     stewart.Bb = stewart.Mb - repmat(stewart.MO_B, [1, 6]);
    @@ -902,9 +1104,9 @@ stewart.Ba = stewart.Aa - repmat( stewart.MO_B
     
    -
    -

    5.4 Compute the strut length and orientation

    -
    +
    +

    Compute the strut length and orientation

    +
    stewart.As = (stewart.Ab - stewart.Aa)./vecnorm(stewart.Ab - stewart.Aa); % As_i is the i'th vector of As
     
    @@ -919,9 +1121,9 @@ stewart.l = vecnorm(stewart.Ab - stewart.Aa)
     
    -
    -

    5.5 Compute the orientation of the Joints

    -
    +
    +

    Compute the orientation of the Joints

    +
    stewart.FRa = zeros(3,3,6);
     stewart.MRb = zeros(3,3,6);
    @@ -939,143 +1141,76 @@ stewart.MRb = zeros(3,3,6);
     
    -
    -

    6 initializeStrutDynamics: Add Stiffness and Damping properties of each strut

    -
    +
    +

    5.5 initializeStewartPose: Determine the initial stroke in each leg to have the wanted pose

    +

    - +

    -This Matlab function is accessible here. +This Matlab function is accessible here.

    -
    -

    6.1 Function description

    -
    +
    +

    Function description

    +
    -
    function [stewart] = initializeStrutDynamics(stewart, args)
    -% initializeStrutDynamics - Add Stiffness and Damping properties of each strut
    +
    function [stewart] = initializeStewartPose(stewart, args)
    +% initializeStewartPose - Determine the initial stroke in each leg to have the wanted pose
    +%                         It uses the inverse kinematic
     %
    -% Syntax: [stewart] = initializeStrutDynamics(args)
    +% Syntax: [stewart] = initializeStewartPose(stewart, args)
     %
     % Inputs:
    -%    - args - Structure with the following fields:
    -%        - Ki [6x1] - Stiffness of each strut [N/m]
    -%        - Ci [6x1] - Damping of each strut [N/(m/s)]
    +%    - stewart - A structure with the following fields
    +%        - Aa   [3x6] - The positions ai expressed in {A}
    +%        - Bb   [3x6] - The positions bi expressed in {B}
    +%    - args - Can have the following fields:
    +%        - AP   [3x1] - The wanted position of {B} with respect to {A}
    +%        - ARB  [3x3] - The rotation matrix that gives the wanted orientation of {B} with respect to {A}
     %
     % Outputs:
     %    - stewart - updated Stewart structure with the added fields:
    -%        - Ki [6x1] - Stiffness of each strut [N/m]
    -%        - Ci [6x1] - Damping of each strut [N/(m/s)]
    +%      - dLi[6x1] - The 6 needed displacement of the struts from the initial position in [m] to have the wanted pose of {B} w.r.t. {A}
     
    -
    -

    6.2 Optional Parameters

    -
    +
    +

    Optional Parameters

    +
    arguments
         stewart
    -    args.Ki (6,1) double {mustBeNumeric, mustBePositive} = 1e6*ones(6,1)
    -    args.Ci (6,1) double {mustBeNumeric, mustBePositive} = 1e1*ones(6,1)
    +    args.AP  (3,1) double {mustBeNumeric} = zeros(3,1)
    +    args.ARB (3,3) double {mustBeNumeric} = eye(3)
     end
     
    -
    -

    6.3 Add Stiffness and Damping properties of each strut

    -
    +
    +

    Use the Inverse Kinematic function

    +
    -
    stewart.Ki = args.Ki;
    -stewart.Ci = args.Ci;
    +
    [Li, dLi] = inverseKinematics(stewart, 'AP', args.AP, 'ARB', args.ARB);
    +
    +stewart.dLi = dLi;
     
    -
    -

    7 computeJacobian: Compute the Jacobian Matrix

    -
    +
    +

    5.6 initializeCylindricalPlatforms: Initialize the geometry of the Fixed and Mobile Platforms

    +

    - -

    - -

    -This Matlab function is accessible here. -

    -
    - -
    -

    7.1 Function description

    -
    -
    -
    function [stewart] = computeJacobian(stewart)
    -% computeJacobian -
    -%
    -% Syntax: [stewart] = computeJacobian(stewart)
    -%
    -% Inputs:
    -%    - stewart - With at least the following fields:
    -%        - As [3x6] - The 6 unit vectors for each strut expressed in {A}
    -%        - Ab [3x6] - The 6 position of the joints bi expressed in {A}
    -%
    -% Outputs:
    -%    - stewart - With the 3 added field:
    -%        - J [6x6] - The Jacobian Matrix
    -%        - K [6x6] - The Stiffness Matrix
    -%        - C [6x6] - The Compliance Matrix
    -
    -
    -
    -
    - -
    -

    7.2 Compute Jacobian Matrix

    -
    -
    -
    stewart.J = [stewart.As' , cross(stewart.Ab, stewart.As)'];
    -
    -
    -
    -
    - -
    -

    7.3 Compute Stiffness Matrix

    -
    -
    -
    stewart.K = stewart.J'*diag(stewart.Ki)*stewart.J;
    -
    -
    -
    -
    - -
    -

    7.4 Compute Compliance Matrix

    -
    -
    -
    stewart.C = inv(stewart.K);
    -
    -
    -
    -
    -
    - -
    -

    8 Initialize the Geometry of the Mechanical Elements

    -
    -
    -
    -

    8.1 initializeCylindricalPlatforms: Initialize the geometry of the Fixed and Mobile Platforms

    -
    -

    - +

    @@ -1083,9 +1218,9 @@ This Matlab function is accessible -

    8.1.1 Function description

    -
    +
    +

    Function description

    +
    function [stewart] = initializeCylindricalPlatforms(stewart, args)
     % initializeCylindricalPlatforms - Initialize the geometry of the Fixed and Mobile Platforms
    @@ -1117,9 +1252,9 @@ This Matlab function is accessible 
    -

    8.1.2 Optional Parameters

    -
    +
    +

    Optional Parameters

    +
    arguments
         stewart
    @@ -1135,9 +1270,9 @@ This Matlab function is accessible 
    -

    8.1.3 Create the platforms struct

    -
    +
    +

    Create the platforms struct

    +
    platforms = struct();
     
    @@ -1159,9 +1294,9 @@ platforms.Mpi = diag([1/12 
     
    -
    -

    8.1.4 Save the platforms struct

    -
    +
    +

    Save the platforms struct

    +
    stewart.platforms = platforms;
     
    @@ -1170,11 +1305,11 @@ platforms.Mpi = diag([1/12
    -
    -

    8.2 initializeCylindricalStruts: Define the mass and moment of inertia of cylindrical struts

    -
    +
    +

    5.7 initializeCylindricalStruts: Define the inertia of cylindrical struts

    +

    - +

    @@ -1182,9 +1317,9 @@ This Matlab function is accessible h

    -
    -

    8.2.1 Function description

    -
    +
    +

    Function description

    +
    -
    -

    8.2.2 Optional Parameters

    -
    +
    +

    Optional Parameters

    +
    -
    -

    8.2.3 Create the struts structure

    -
    +
    +

    Create the struts structure

    +
    struts = struct();
     
    @@ -1268,267 +1403,123 @@ struts.Msi = zeros(3, 3, 6);
     
    -
    -
    -

    9 initializeStewartPose: Determine the initial stroke in each leg to have the wanted pose

    -
    +
    +

    5.8 initializeStrutDynamics: Add Stiffness and Damping properties of each strut

    +

    - +

    -This Matlab function is accessible here. +This Matlab function is accessible here.

    -
    -

    9.1 Function description

    -
    +
    +

    Function description

    +
    -
    function [stewart] = initializeStewartPose(stewart, args)
    -% initializeStewartPose - Determine the initial stroke in each leg to have the wanted pose
    -%                         It uses the inverse kinematic
    +
    function [stewart] = initializeStrutDynamics(stewart, args)
    +% initializeStrutDynamics - Add Stiffness and Damping properties of each strut
     %
    -% Syntax: [stewart] = initializeStewartPose(stewart, args)
    +% Syntax: [stewart] = initializeStrutDynamics(args)
     %
     % Inputs:
    -%    - stewart - A structure with the following fields
    -%        - Aa   [3x6] - The positions ai expressed in {A}
    -%        - Bb   [3x6] - The positions bi expressed in {B}
    -%    - args - Can have the following fields:
    -%        - AP   [3x1] - The wanted position of {B} with respect to {A}
    -%        - ARB  [3x3] - The rotation matrix that gives the wanted orientation of {B} with respect to {A}
    +%    - args - Structure with the following fields:
    +%        - Ki [6x1] - Stiffness of each strut [N/m]
    +%        - Ci [6x1] - Damping of each strut [N/(m/s)]
     %
     % Outputs:
     %    - stewart - updated Stewart structure with the added fields:
    -%      - dLi[6x1] - The 6 needed displacement of the struts from the initial position in [m] to have the wanted pose of {B} w.r.t. {A}
    +%        - Ki [6x1] - Stiffness of each strut [N/m]
    +%        - Ci [6x1] - Damping of each strut [N/(m/s)]
     
    -
    -

    9.2 Optional Parameters

    -
    +
    +

    Optional Parameters

    +
    arguments
         stewart
    -    args.AP  (3,1) double {mustBeNumeric} = zeros(3,1)
    -    args.ARB (3,3) double {mustBeNumeric} = eye(3)
    +    args.Ki (6,1) double {mustBeNumeric, mustBePositive} = 1e6*ones(6,1)
    +    args.Ci (6,1) double {mustBeNumeric, mustBePositive} = 1e1*ones(6,1)
     end
     
    -
    -

    9.3 Use the Inverse Kinematic function

    -
    +
    +

    Add Stiffness and Damping properties of each strut

    +
    -
    [Li, dLi] = inverseKinematics(stewart, 'AP', args.AP, 'ARB', args.ARB);
    -
    -stewart.dLi = dLi;
    +
    stewart.Ki = args.Ki;
    +stewart.Ci = args.Ci;
     
    -
    -

    10 Utility Functions

    -
    -
    -
    -

    10.1 inverseKinematics: Compute Inverse Kinematics

    -
    +
    +

    5.9 initializeJointDynamics: Add Stiffness and Damping properties for spherical joints

    +

    - +

    -This Matlab function is accessible here. +This Matlab function is accessible here.

    -
    -

    10.1.1 Function description

    -
    +
    +

    Function description

    +
    -
    function [Li, dLi] = inverseKinematics(stewart, args)
    -% inverseKinematics - Compute the needed length of each strut to have the wanted position and orientation of {B} with respect to {A}
    +
    function [stewart] = initializeJointDynamics(stewart, args)
    +% initializeJointDynamics - Add Stiffness and Damping properties for the spherical joints
     %
    -% Syntax: [stewart] = inverseKinematics(stewart)
    +% Syntax: [stewart] = initializeJointDynamics(args)
     %
     % Inputs:
    -%    - stewart - A structure with the following fields
    -%        - Aa   [3x6] - The positions ai expressed in {A}
    -%        - Bb   [3x6] - The positions bi expressed in {B}
    -%    - args - Can have the following fields:
    -%        - AP   [3x1] - The wanted position of {B} with respect to {A}
    -%        - ARB  [3x3] - The rotation matrix that gives the wanted orientation of {B} with respect to {A}
    +%    - args - Structure with the following fields:
    +%        - Kri [6x1] - Rotational Stiffness for each spherical joints [N/rad]
    +%        - Cri [6x1] - Damping of each spherical joint [N/(rad/s)]
     %
     % Outputs:
    -%    - Li   [6x1] - The 6 needed length of the struts in [m] to have the wanted pose of {B} w.r.t. {A}
    -%    - dLi  [6x1] - The 6 needed displacement of the struts from the initial position in [m] to have the wanted pose of {B} w.r.t. {A}
    +%    - stewart - updated Stewart structure with the added fields:
    +%        - Kri [6x1] - Rotational Stiffness for each spherical joints [N/rad]
    +%        - Cri [6x1] - Damping of each spherical joint [N/(rad/s)]
     
    -
    -

    10.1.2 Optional Parameters

    -
    +
    +

    Optional Parameters

    +
    arguments
         stewart
    -    args.AP  (3,1) double {mustBeNumeric} = zeros(3,1)
    -    args.ARB (3,3) double {mustBeNumeric} = eye(3)
    +    args.Kri (6,1) double {mustBeNumeric, mustBePositive} = zeros(6,1)
    +    args.Cri (6,1) double {mustBeNumeric, mustBePositive} = zeros(6,1)
     end
     
    -
    -

    10.1.3 Theory

    -
    -

    -For inverse kinematic analysis, it is assumed that the position \({}^A\bm{P}\) and orientation of the moving platform \({}^A\bm{R}_B\) are given and the problem is to obtain the joint variables, namely, \(\bm{L} = [l_1, l_2, \dots, l_6]^T\). -

    - -

    -From the geometry of the manipulator, the loop closure for each limb, \(i = 1, 2, \dots, 6\) can be written as -

    -\begin{align*} - l_i {}^A\hat{\bm{s}}_i &= {}^A\bm{A} + {}^A\bm{b}_i - {}^A\bm{a}_i \\ - &= {}^A\bm{A} + {}^A\bm{R}_b {}^B\bm{b}_i - {}^A\bm{a}_i -\end{align*} - -

    -To obtain the length of each actuator and eliminate \(\hat{\bm{s}}_i\), it is sufficient to dot multiply each side by itself: -

    -\begin{equation} - l_i^2 \left[ {}^A\hat{\bm{s}}_i^T {}^A\hat{\bm{s}}_i \right] = \left[ {}^A\bm{P} + {}^A\bm{R}_B {}^B\bm{b}_i - {}^A\bm{a}_i \right]^T \left[ {}^A\bm{P} + {}^A\bm{R}_B {}^B\bm{b}_i - {}^A\bm{a}_i \right] -\end{equation} - -

    -Hence, for \(i = 1, 2, \dots, 6\), each limb length can be uniquely determined by: -

    -\begin{equation} - l_i = \sqrt{{}^A\bm{P}^T {}^A\bm{P} + {}^B\bm{b}_i^T {}^B\bm{b}_i + {}^A\bm{a}_i^T {}^A\bm{a}_i - 2 {}^A\bm{P}^T {}^A\bm{a}_i + 2 {}^A\bm{P}^T \left[{}^A\bm{R}_B {}^B\bm{b}_i\right] - 2 \left[{}^A\bm{R}_B {}^B\bm{b}_i\right]^T {}^A\bm{a}_i} -\end{equation} - -

    -If the position and orientation of the moving platform lie in the feasible workspace of the manipulator, one unique solution to the limb length is determined by the above equation. -Otherwise, when the limbs’ lengths derived yield complex numbers, then the position or orientation of the moving platform is not reachable. -

    -
    -
    - -
    -

    10.1.4 Compute

    -
    +
    +

    Add Stiffness and Damping properties of each strut

    +
    -
    Li = sqrt(args.AP'*args.AP + diag(stewart.Bb'*stewart.Bb) + diag(stewart.Aa'*stewart.Aa) - (2*args.AP'*stewart.Aa)' + (2*args.AP'*(args.ARB*stewart.Bb))' - diag(2*(args.ARB*stewart.Bb)'*stewart.Aa));
    -
    -
    - -
    -
    dLi = Li-stewart.l;
    -
    -
    -
    -
    -
    - -
    -

    10.2 forwardKinematicsApprox: Compute the Forward Kinematics

    -
    -

    - -

    - -

    -This Matlab function is accessible here. -

    -
    - -
    -

    10.2.1 Function description

    -
    -
    -
    function [P, R] = forwardKinematicsApprox(stewart, args)
    -% forwardKinematicsApprox - Computed the approximate pose of {B} with respect to {A} from the length of each strut and using
    -%                           the Jacobian Matrix
    -%
    -% Syntax: [P, R] = forwardKinematicsApprox(stewart, args)
    -%
    -% Inputs:
    -%    - stewart - A structure with the following fields
    -%        - J  [6x6] - The Jacobian Matrix
    -%    - args - Can have the following fields:
    -%        - dL [6x1] - Displacement of each strut [m]
    -%
    -% Outputs:
    -%    - P  [3x1] - The estimated position of {B} with respect to {A}
    -%    - R  [3x3] - The estimated rotation matrix that gives the orientation of {B} with respect to {A}
    -
    -
    -
    -
    - -
    -

    10.2.2 Optional Parameters

    -
    -
    -
    arguments
    -    stewart
    -    args.dL (6,1) double {mustBeNumeric} = zeros(6,1)
    -end
    -
    -
    -
    -
    - -
    -

    10.2.3 Computation

    -
    -

    -From a small displacement of each strut \(d\bm{\mathcal{L}}\), we can compute the -position and orientation of {B} with respect to {A} using the following formula: -\[ d \bm{\mathcal{X}} = \bm{J}^{-1} d\bm{\mathcal{L}} \] -

    -
    -
    X = stewart.J\args.dL;
    -
    -
    - -

    -The position vector corresponds to the first 3 elements. -

    -
    -
    P = X(1:3);
    -
    -
    - -

    -The next 3 elements are the orientation of {B} with respect to {A} expressed -using the screw axis. -

    -
    -
    theta = norm(X(4:6));
    -s = X(4:6)/theta;
    -
    -
    - -

    -We then compute the corresponding rotation matrix. -

    -
    -
    R = [s(1)^2*(1-cos(theta)) + cos(theta) ,        s(1)*s(2)*(1-cos(theta)) - s(3)*sin(theta), s(1)*s(3)*(1-cos(theta)) + s(2)*sin(theta);
    -     s(2)*s(1)*(1-cos(theta)) + s(3)*sin(theta), s(2)^2*(1-cos(theta)) + cos(theta),         s(2)*s(3)*(1-cos(theta)) - s(1)*sin(theta);
    -     s(3)*s(1)*(1-cos(theta)) - s(2)*sin(theta), s(3)*s(2)*(1-cos(theta)) + s(1)*sin(theta), s(3)^2*(1-cos(theta)) + cos(theta)];
    +
    stewart.Kri = args.Kri;
    +stewart.Cri = args.Cri;
     
    @@ -1536,87 +1527,16 @@ We then compute the corresponding rotation matrix.
    -
    -

    11 Other Elements

    -
    -
    -
    -

    11.1 Z-Axis Geophone

    -

    - + +

    Bibliography

    +

    - -

    -This Matlab function is accessible here. -

    - -
    -
    function [geophone] = initializeZAxisGeophone(args)
    -    arguments
    -        args.mass (1,1) double {mustBeNumeric, mustBePositive} = 1e-3 % [kg]
    -        args.freq (1,1) double {mustBeNumeric, mustBePositive} = 1    % [Hz]
    -    end
    -
    -    %%
    -    geophone.m = args.mass;
    -
    -    %% The Stiffness is set to have the damping resonance frequency
    -    geophone.k = geophone.m * (2*pi*args.freq)^2;
    -
    -    %% We set the damping value to have critical damping
    -    geophone.c = 2*sqrt(geophone.m * geophone.k);
    -
    -    %% Save
    -    save('./mat/geophone_z_axis.mat', 'geophone');
    -end
    -
    -
    -
    -
    - -
    -

    11.2 Z-Axis Accelerometer

    -
    -

    - -

    - -

    -This Matlab function is accessible here. -

    - -
    -
    function [accelerometer] = initializeZAxisAccelerometer(args)
    -    arguments
    -        args.mass (1,1) double {mustBeNumeric, mustBePositive} = 1e-3 % [kg]
    -        args.freq (1,1) double {mustBeNumeric, mustBePositive} = 5e3  % [Hz]
    -    end
    -
    -    %%
    -    accelerometer.m = args.mass;
    -
    -    %% The Stiffness is set to have the damping resonance frequency
    -    accelerometer.k = accelerometer.m * (2*pi*args.freq)^2;
    -
    -    %% We set the damping value to have critical damping
    -    accelerometer.c = 2*sqrt(accelerometer.m * accelerometer.k);
    -
    -    %% Gain correction of the accelerometer to have a unity gain until the resonance
    -    accelerometer.gain = -accelerometer.k/accelerometer.m;
    -
    -    %% Save
    -    save('./mat/accelerometer_z_axis.mat', 'accelerometer');
    -end
    -
    -
    -
    -
    -

    Author: Dehaeze Thomas

    -

    Created: 2020-01-27 lun. 17:41

    +

    Created: 2020-01-28 mar. 17:13

    diff --git a/stewart-architecture.org b/stewart-architecture.org index 2b2bcb0..bfdef68 100644 --- a/stewart-architecture.org +++ b/stewart-architecture.org @@ -21,48 +21,146 @@ :END: * Introduction :ignore: -Stewart platforms are generated in multiple steps. +In this document is explained how the Stewart Platform architecture is defined. -We define 4 important *frames*: +Some efforts has been made such that the procedure for the definition of the Stewart Platform architecture is as logical and clear as possible. + +When possible, the notations are compatible with the one used in cite:taghirad13_paral. + +The definition of the Stewart platform is done in three main parts: +- First, the geometry if defined (Section [[sec:definition_geometry]]) +- Then, the inertia of the mechanical elements are defined (Section [[sec:definition_inertia]]) +- Finally, the Stiffness and Damping characteristics of the elements are defined (Section [[sec:definition_dynamics]]) + +In section [[sec:summary_initialization]], the procedure the initialize the Stewart platform is summarize and the associated Matlab code is shown. + +Finally, all the Matlab function used to initialize the Stewart platform are described in section [[sec:functions]]. + +* Definition of the Stewart Platform Geometry +<> +** Introduction :ignore: +Stewart platforms are generated in multiple steps: +- Definition of the frames +- Definition of the location of the joints +- Computation of the length and orientation of the struts +- Choice of the rest position of the mobile platform + +This steps are detailed below. + +** Frames Definition +We define 4 important *frames* (see Figure [[fig:frame_definition]]): - $\{F\}$: Frame fixed to the *Fixed* base and located at the center of its bottom surface. This is used to fix the Stewart platform to some support. - $\{M\}$: Frame fixed to the *Moving* platform and located at the center of its top surface. This is used to place things on top of the Stewart platform. - $\{A\}$: Frame fixed to the fixed base. - It defined the center of rotation of the moving platform. - $\{B\}$: Frame fixed to the moving platform. - The motion of the moving platforms and forces applied to it are defined with respect to this frame $\{B\}$. -Then, we define the *location of the spherical joints*: +Even though frames $\{A\}$ and $\{B\}$ don't usually correspond to physical elements, they are of primary importance. +Firstly, they are used for the definition of the motion of the Mobile platform with respect to the fixed frame: +- In position: ${}^A\bm{P}_{B}$ (read: Position of frame $\{B\}$ expressed in frame $\{A\}$) +- In rotation: ${}^A\bm{R}_{B}$ (read: The rotation matrix that express the orientation of frame $\{B\}$ expressed in frame $\{A\}$) +The frames $\{A\}$ and $\{B\}$ are used for all the kinematic analysis (Jacobian, Stiffness matrix, ...). + +Typical choice of $\{A\}$ and $\{B\}$ are: +- Center of mass of the payload +- Location where external forces are applied to the mobile platform (for instance when the mobile platform is in contact with a stiff environment) +- Center of the cube for the cubic configuration + +The definition of the frames is done with the =initializeFramesPositions= function ([[sec:initializeFramesPositions][link]]); + +#+name: fig:frame_definition +#+caption: Definition of the Frames for the Stewart Platform +#+attr_html: :width 500px +[[file:figs/frame_definition.png]] + +** Location of the Spherical Joints +Then, we define the *location of the spherical joints* (see Figure [[fig:joint_location]]): - $\bm{a}_{i}$ are the position of the spherical joints fixed to the fixed base - $\bm{b}_{i}$ are the position of the spherical joints fixed to the moving platform -We define the *rest position* of the Stewart platform: -- For simplicity, we suppose that the fixed base and the moving platform are parallel and aligned with the vertical axis at their rest position. -- Thus, to define the rest position of the Stewart platform, we just have to defined its total height $H$. - $H$ corresponds to the distance from the bottom of the fixed base to the top of the moving platform. +The location of the joints will define the Geometry of the Stewart platform. +Many characteristics of the platform depend on the location of the joints. -From $\bm{a}_{i}$ and $\bm{b}_{i}$, we can determine the *length and orientation of each strut*: -- $l_{i}$ is the length of the strut -- ${}^{A}\hat{\bm{s}}_{i}$ is the unit vector align with the strut +The location of the joints can be set to arbitrary positions (function =generateGeneralConfiguration= described [[sec:generateGeneralConfiguration][here]]) or can be computed to obtain specific configurations such as: +- A cubic configuration: function =generateCubicConfiguration= ([[sec:generateCubicConfiguration][link]]). +- A symmetrical configuration -The position of the Spherical joints can be computed using various methods: -- Cubic configuration -- Circular configuration -- Arbitrary position -- These methods should be easily scriptable and corresponds to specific functions that returns ${}^{F}\bm{a}_{i}$ and ${}^{M}\bm{b}_{i}$. - The input of these functions are the parameters corresponding to the wanted geometry. +The location of the spherical joints are then given by ${}^{F}\bm{a}_{i}$ and ${}^{M}\bm{b}_{i}$. -For Simscape, we need: -- The position and orientation of each spherical joint fixed to the fixed base: ${}^{F}\bm{a}_{i}$ and ${}^{F}\bm{R}_{a_{i}}$ -- The position and orientation of each spherical joint fixed to the moving platform: ${}^{M}\bm{b}_{i}$ and ${}^{M}\bm{R}_{b_{i}}$ -- The rest length of each strut: $l_{i}$ -- The stiffness and damping of each actuator: $k_{i}$ and $c_{i}$ -- The position of the frame $\{A\}$ with respect to the frame $\{F\}$: ${}^{F}\bm{O}_{A}$ -- The position of the frame $\{B\}$ with respect to the frame $\{M\}$: ${}^{M}\bm{O}_{B}$ +#+name: fig:joint_location +#+caption: Position of the Spherical/Universal joints for the Stewart Platform +#+attr_html: :width 500px +[[file:figs/joint_location.png]] +** Length and orientation of the struts +From the location of the joints (${}^{F}\bm{a}_{i}$ and ${}^{M}\bm{b}_{i}$), we compute the length $l_i$ and orientation of each strut $\hat{\bm{s}}_i$ (unit vector aligned with the strut). +The length and orientation of each strut is represented in figure [[fig:length_orientation_struts]]. -* Procedure +This is done with the =computeJointsPose= function ([[sec:computeJointsPose][link]]). + +#+name: fig:length_orientation_struts +#+caption: Length $l_i$ and orientation $\hat{\bm{s}}_i$ of the Stewart platform struts +#+attr_html: :width 500px +[[file:figs/length_orientation_struts.png]] + +** Rest Position of the Stewart platform +We may want to initialize the Stewart platform in some position and orientation that corresponds to its rest position. + +To do so, we choose: +- the position of $O_B$ expressed in $\{A\}$ using ${}^AP$ +- the orientation of $\{B\}$ expressed in $\{A\}$ using a rotation matrix ${}^{A}R_{B}$ + +Then, the function =initializeStewartPose= ([[sec:initializeStewartPose][link]]) compute the corresponding initial and rest position of each of the strut. + +* Definition of the Inertia and geometry of the Fixed base, Mobile platform and Struts +<> +** Introduction :ignore: +Now that the geometry of the Stewart platform has been defined, we have to choose the inertia of: +- The Fixed base +- The Mobile platform +- The two parts of the struts + +The inertia of these elements will modify the dynamics of the systems. +It is thus important to set them properly. + +** Inertia and Geometry of the Fixed and Mobile platforms +In order to set the inertia of the fixed and mobile platforms, we can use the following function that assume that both platforms are cylindrical: +- =initializeCylindricalPlatforms= ([[sec:initializeCylindricalPlatforms][link]]): by choosing the height, radius and mass of the platforms, it computes the inertia matrix that will be used for simulation + +** Inertia and Geometry of the struts +Similarly for the struts, we suppose here that they have a cylindrical shape. +They are initialize with the following function: +- =initializeCylindricalStruts= ([[sec:initializeCylindricalStruts][link]]): the two parts of each strut are supposed to by cylindrical. We can set the mass and geometry of both strut parts. + +* Definition of the stiffness and damping of the joints +<> + +** Introduction :ignore: +The global stiffness and damping of the Stewart platform depends on its geometry but also on the stiffness and damping of: +- the actuator because of the finite stiffness of the actuator / linear guide +- the spherical joints + +** Stiffness and Damping of the Actuator +Each Actuator is modeled by 3 elements in parallel (Figure [[fig:stewart_platform_actuator]]): +- A spring with a stiffness $k_{i}$ +- A dashpot with a damping $c_{i}$ +- An ideal force actuator + +#+name: fig:stewart_platform_actuator +#+caption: Model of the Stewart platform actuator +[[file:figs/stewart_platform_actuator.png]] + +The initialization of the stiffness and damping properties of the actuators is done with the =initializeStrutDynamics= ([[sec:initializeStrutDynamics][link]]). + +** Stiffness and Damping of the Spherical Joints +Even though we often suppose that the spherical joint are perfect in the sense that we neglect its stiffness and damping, we can set some rotation stiffness and damping of each of the spherical/universal joints. + +This is done with the =initializeJointDynamics= function ([[sec:initializeJointDynamics][link]]). + +* Summary of the Initialization Procedure and Matlab Example +<> +** Introduction :ignore: The procedure to define the Stewart platform is the following: 1. Define the initial position of frames {A}, {B}, {F} and {M}. We do that using the =initializeFramesPositions= function. @@ -72,16 +170,13 @@ The procedure to define the Stewart platform is the following: - =generateCubicConfiguration= permits to generate a cubic configuration 3. Compute the position and orientation of the joints with respect to the fixed base and the moving platform. This is done with the =computeJointsPose= function. -4. Define the dynamical properties of the Stewart platform. - The output are the stiffness and damping of each strut $k_{i}$ and $c_{i}$. - This can be done we simply choosing directly the stiffness and damping of each strut. - The stiffness and damping of each actuator can also be determine from the wanted stiffness of the Stewart platform for instance. -5. Define the mass and inertia of each element of the Stewart platform. + If wanted, compute the rest position of each strut to have the wanted pose of the mobile platform with the function =initializeStewartPose=. +4. Define the mass and inertia of each element of the Stewart platform with the =initializeCylindricalPlatforms= and =initializeCylindricalStruts= +5. Define the dynamical properties of the Stewart platform by setting the stiffness and damping of the actuators and joints. By following this procedure, we obtain a Matlab structure =stewart= that contains all the information for the Simscape model and for further analysis. -* Matlab Code -** Matlab Init :noexport:ignore: +** Matlab Init :noexport:ignore: #+begin_src matlab :tangle no :exports none :results silent :noweb yes :var current_dir=(file-name-directory buffer-file-name) <> #+end_src @@ -94,28 +189,32 @@ By following this procedure, we obtain a Matlab structure =stewart= that contain simulinkproject('./'); #+end_src -** Simscape Model -#+begin_src matlab - open('stewart_platform.slx') -#+end_src - -** Test the functions +** Example of the initialization of a Stewart Platform +Let's first define the Stewart Platform Geometry. #+begin_src matlab stewart = initializeFramesPositions('H', 90e-3, 'MO_B', 45e-3); - % stewart = generateCubicConfiguration(stewart, 'Hc', 60e-3, 'FOc', 45e-3, 'FHa', 5e-3, 'MHb', 5e-3); stewart = generateGeneralConfiguration(stewart); stewart = computeJointsPose(stewart); - stewart = initializeStrutDynamics(stewart, 'Ki', 1e6*ones(6,1), 'Ci', 1e2*ones(6,1)); - stewart = initializeCylindricalPlatforms(stewart); - stewart = initializeCylindricalStruts(stewart); - stewart = computeJacobian(stewart); stewart = initializeStewartPose(stewart, 'AP', [0;0;0.01], 'ARB', eye(3)); - - [Li, dLi] = inverseKinematics(stewart, 'AP', [0;0;0.00001], 'ARB', eye(3)); - [P, R] = forwardKinematicsApprox(stewart, 'dL', dLi); #+end_src -* =initializeFramesPositions=: Initialize the positions of frames {A}, {B}, {F} and {M} +Then, define the inertia and geometry of the fixed base, mobile platform and struts. +#+begin_src matlab + stewart = initializeCylindricalPlatforms(stewart); + stewart = initializeCylindricalStruts(stewart); +#+end_src + +Finally, initialize the strut stiffness and damping properties. +#+begin_src matlab + stewart = initializeStrutDynamics(stewart, 'Ki', 1e6*ones(6,1), 'Ci', 1e2*ones(6,1)); + stewart = initializeJointDynamics(stewart, 'Ksi', zeros(6,1), 'Csi', zeros(6,1)); +#+end_src + +The obtained =stewart= Matlab structure contains all the information for analysis of the Stewart platform and for simulations using Simscape. + +* Functions +<> +** =initializeFramesPositions=: Initialize the positions of frames {A}, {B}, {F} and {M} :PROPERTIES: :header-args:matlab+: :tangle src/initializeFramesPositions.m :header-args:matlab+: :comments none :mkdirp yes :eval no @@ -124,7 +223,10 @@ By following this procedure, we obtain a Matlab structure =stewart= that contain This Matlab function is accessible [[file:src/initializeFramesPositions.m][here]]. -** Function description +*** Function description +:PROPERTIES: +:UNNUMBERED: t +:END: #+begin_src matlab function [stewart] = initializeFramesPositions(args) % initializeFramesPositions - Initialize the positions of frames {A}, {B}, {F} and {M} @@ -144,13 +246,19 @@ This Matlab function is accessible [[file:src/initializeFramesPositions.m][here] % - FO_A [3x1] - Position of {A} with respect to {F} [m] #+end_src -** Documentation +*** Documentation +:PROPERTIES: +:UNNUMBERED: t +:END: #+name: fig:stewart-frames-position #+caption: Definition of the position of the frames [[file:figs/stewart-frames-position.png]] -** Optional Parameters +*** Optional Parameters +:PROPERTIES: +:UNNUMBERED: t +:END: #+begin_src matlab arguments args.H (1,1) double {mustBeNumeric, mustBePositive} = 90e-3 @@ -158,12 +266,18 @@ This Matlab function is accessible [[file:src/initializeFramesPositions.m][here] end #+end_src -** Initialize the Stewart structure +*** Initialize the Stewart structure +:PROPERTIES: +:UNNUMBERED: t +:END: #+begin_src matlab stewart = struct(); #+end_src -** Compute the position of each frame +*** Compute the position of each frame +:PROPERTIES: +:UNNUMBERED: t +:END: #+begin_src matlab stewart.H = args.H; % Total Height of the Stewart Platform [m] @@ -174,7 +288,6 @@ This Matlab function is accessible [[file:src/initializeFramesPositions.m][here] stewart.FO_A = stewart.MO_B + stewart.FO_M; % Position of {A} with respect to {F} [m] #+end_src -* Initialize the position of the Joints ** =generateCubicConfiguration=: Generate a Cubic Configuration :PROPERTIES: :header-args:matlab+: :tangle src/generateCubicConfiguration.m @@ -185,6 +298,9 @@ This Matlab function is accessible [[file:src/initializeFramesPositions.m][here] This Matlab function is accessible [[file:src/generateCubicConfiguration.m][here]]. *** Function description +:PROPERTIES: +:UNNUMBERED: t +:END: #+begin_src matlab function [stewart] = generateCubicConfiguration(stewart, args) % generateCubicConfiguration - Generate a Cubic Configuration @@ -207,11 +323,17 @@ This Matlab function is accessible [[file:src/generateCubicConfiguration.m][here #+end_src *** Documentation +:PROPERTIES: +:UNNUMBERED: t +:END: #+name: fig:cubic-configuration-definition #+caption: Cubic Configuration [[file:figs/cubic-configuration-definition.png]] *** Optional Parameters +:PROPERTIES: +:UNNUMBERED: t +:END: #+begin_src matlab arguments stewart @@ -223,6 +345,9 @@ This Matlab function is accessible [[file:src/generateCubicConfiguration.m][here #+end_src *** Position of the Cube +:PROPERTIES: +:UNNUMBERED: t +:END: We define the useful points of the cube with respect to the Cube's center. ${}^{C}C$ are the 6 vertices of the cubes expressed in a frame {C} which is located at the center of the cube and aligned with {F} and {M}. @@ -243,6 +368,9 @@ located at the center of the cube and aligned with {F} and {M}. #+end_src *** Compute the pose +:PROPERTIES: +:UNNUMBERED: t +:END: We can compute the vector of each leg ${}^{C}\hat{\bm{s}}_{i}$ (unit vector from ${}^{C}C_{f}$ to ${}^{C}C_{m}$). #+begin_src matlab CSi = (CCm - CCf)./vecnorm(CCm - CCf); @@ -264,6 +392,9 @@ We now which to compute the position of the joints $a_{i}$ and $b_{i}$. This Matlab function is accessible [[file:src/generateGeneralConfiguration.m][here]]. *** Function description +:PROPERTIES: +:UNNUMBERED: t +:END: #+begin_src matlab function [stewart] = generateGeneralConfiguration(stewart, args) % generateGeneralConfiguration - Generate a Very General Configuration @@ -286,10 +417,16 @@ This Matlab function is accessible [[file:src/generateGeneralConfiguration.m][he #+end_src *** Documentation +:PROPERTIES: +:UNNUMBERED: t +:END: Joints are positions on a circle centered with the Z axis of {F} and {M} and at a chosen distance from {F} and {M}. The radius of the circles can be chosen as well as the angles where the joints are located. *** Optional Parameters +:PROPERTIES: +:UNNUMBERED: t +:END: #+begin_src matlab arguments stewart @@ -303,6 +440,9 @@ The radius of the circles can be chosen as well as the angles where the joints a #+end_src *** Compute the pose +:PROPERTIES: +:UNNUMBERED: t +:END: #+begin_src matlab stewart.Fa = zeros(3,6); stewart.Mb = zeros(3,6); @@ -315,7 +455,7 @@ The radius of the circles can be chosen as well as the angles where the joints a end #+end_src -* =computeJointsPose=: Compute the Pose of the Joints +** =computeJointsPose=: Compute the Pose of the Joints :PROPERTIES: :header-args:matlab+: :tangle src/computeJointsPose.m :header-args:matlab+: :comments none :mkdirp yes :eval no @@ -324,7 +464,10 @@ The radius of the circles can be chosen as well as the angles where the joints a This Matlab function is accessible [[file:src/computeJointsPose.m][here]]. -** Function description +*** Function description +:PROPERTIES: +:UNNUMBERED: t +:END: #+begin_src matlab function [stewart] = computeJointsPose(stewart) % computeJointsPose - @@ -352,13 +495,19 @@ This Matlab function is accessible [[file:src/computeJointsPose.m][here]]. % - MRb [3x3x6] - The i'th 3x3 array is the rotation matrix to orientate the top of the i'th strut from {M} #+end_src -** Documentation +*** Documentation +:PROPERTIES: +:UNNUMBERED: t +:END: #+name: fig:stewart-struts #+caption: Position and orientation of the struts [[file:figs/stewart-struts.png]] -** Compute the position of the Joints +*** Compute the position of the Joints +:PROPERTIES: +:UNNUMBERED: t +:END: #+begin_src matlab stewart.Aa = stewart.Fa - repmat(stewart.FO_A, [1, 6]); stewart.Bb = stewart.Mb - repmat(stewart.MO_B, [1, 6]); @@ -367,7 +516,10 @@ This Matlab function is accessible [[file:src/computeJointsPose.m][here]]. stewart.Ba = stewart.Aa - repmat( stewart.MO_B+stewart.FO_M-stewart.FO_A, [1, 6]); #+end_src -** Compute the strut length and orientation +*** Compute the strut length and orientation +:PROPERTIES: +:UNNUMBERED: t +:END: #+begin_src matlab stewart.As = (stewart.Ab - stewart.Aa)./vecnorm(stewart.Ab - stewart.Aa); % As_i is the i'th vector of As @@ -378,7 +530,10 @@ This Matlab function is accessible [[file:src/computeJointsPose.m][here]]. stewart.Bs = (stewart.Bb - stewart.Ba)./vecnorm(stewart.Bb - stewart.Ba); #+end_src -** Compute the orientation of the Joints +*** Compute the orientation of the Joints +:PROPERTIES: +:UNNUMBERED: t +:END: #+begin_src matlab stewart.FRa = zeros(3,3,6); stewart.MRb = zeros(3,3,6); @@ -392,92 +547,61 @@ This Matlab function is accessible [[file:src/computeJointsPose.m][here]]. end #+end_src -* =initializeStrutDynamics=: Add Stiffness and Damping properties of each strut +** =initializeStewartPose=: Determine the initial stroke in each leg to have the wanted pose :PROPERTIES: -:header-args:matlab+: :tangle src/initializeStrutDynamics.m +:header-args:matlab+: :tangle src/initializeStewartPose.m :header-args:matlab+: :comments none :mkdirp yes :eval no :END: -<> +<> -This Matlab function is accessible [[file:src/initializeStrutDynamics.m][here]]. +This Matlab function is accessible [[file:src/initializeStewartPose.m][here]]. -** Function description +*** Function description +:PROPERTIES: +:UNNUMBERED: t +:END: #+begin_src matlab - function [stewart] = initializeStrutDynamics(stewart, args) - % initializeStrutDynamics - Add Stiffness and Damping properties of each strut + function [stewart] = initializeStewartPose(stewart, args) + % initializeStewartPose - Determine the initial stroke in each leg to have the wanted pose + % It uses the inverse kinematic % - % Syntax: [stewart] = initializeStrutDynamics(args) + % Syntax: [stewart] = initializeStewartPose(stewart, args) % % Inputs: - % - args - Structure with the following fields: - % - Ki [6x1] - Stiffness of each strut [N/m] - % - Ci [6x1] - Damping of each strut [N/(m/s)] + % - stewart - A structure with the following fields + % - Aa [3x6] - The positions ai expressed in {A} + % - Bb [3x6] - The positions bi expressed in {B} + % - args - Can have the following fields: + % - AP [3x1] - The wanted position of {B} with respect to {A} + % - ARB [3x3] - The rotation matrix that gives the wanted orientation of {B} with respect to {A} % % Outputs: % - stewart - updated Stewart structure with the added fields: - % - Ki [6x1] - Stiffness of each strut [N/m] - % - Ci [6x1] - Damping of each strut [N/(m/s)] + % - dLi[6x1] - The 6 needed displacement of the struts from the initial position in [m] to have the wanted pose of {B} w.r.t. {A} #+end_src -** Optional Parameters +*** Optional Parameters +:PROPERTIES: +:UNNUMBERED: t +:END: #+begin_src matlab arguments stewart - args.Ki (6,1) double {mustBeNumeric, mustBePositive} = 1e6*ones(6,1) - args.Ci (6,1) double {mustBeNumeric, mustBePositive} = 1e1*ones(6,1) + args.AP (3,1) double {mustBeNumeric} = zeros(3,1) + args.ARB (3,3) double {mustBeNumeric} = eye(3) end #+end_src -** Add Stiffness and Damping properties of each strut -#+begin_src matlab - stewart.Ki = args.Ki; - stewart.Ci = args.Ci; -#+end_src - -* =computeJacobian=: Compute the Jacobian Matrix +*** Use the Inverse Kinematic function :PROPERTIES: -:header-args:matlab+: :tangle src/computeJacobian.m -:header-args:matlab+: :comments none :mkdirp yes :eval no +:UNNUMBERED: t :END: -<> - -This Matlab function is accessible [[file:src/computeJacobian.m][here]]. - -** Function description #+begin_src matlab - function [stewart] = computeJacobian(stewart) - % computeJacobian - - % - % Syntax: [stewart] = computeJacobian(stewart) - % - % Inputs: - % - stewart - With at least the following fields: - % - As [3x6] - The 6 unit vectors for each strut expressed in {A} - % - Ab [3x6] - The 6 position of the joints bi expressed in {A} - % - % Outputs: - % - stewart - With the 3 added field: - % - J [6x6] - The Jacobian Matrix - % - K [6x6] - The Stiffness Matrix - % - C [6x6] - The Compliance Matrix + [Li, dLi] = inverseKinematics(stewart, 'AP', args.AP, 'ARB', args.ARB); + + stewart.dLi = dLi; #+end_src -** Compute Jacobian Matrix -#+begin_src matlab - stewart.J = [stewart.As' , cross(stewart.Ab, stewart.As)']; -#+end_src - -** Compute Stiffness Matrix -#+begin_src matlab - stewart.K = stewart.J'*diag(stewart.Ki)*stewart.J; -#+end_src - -** Compute Compliance Matrix -#+begin_src matlab - stewart.C = inv(stewart.K); -#+end_src - -* Initialize the Geometry of the Mechanical Elements ** =initializeCylindricalPlatforms=: Initialize the geometry of the Fixed and Mobile Platforms :PROPERTIES: :header-args:matlab+: :tangle src/initializeCylindricalPlatforms.m @@ -488,6 +612,9 @@ This Matlab function is accessible [[file:src/computeJacobian.m][here]]. This Matlab function is accessible [[file:src/initializeCylindricalPlatforms.m][here]]. *** Function description +:PROPERTIES: +:UNNUMBERED: t +:END: #+begin_src matlab function [stewart] = initializeCylindricalPlatforms(stewart, args) % initializeCylindricalPlatforms - Initialize the geometry of the Fixed and Mobile Platforms @@ -517,6 +644,9 @@ This Matlab function is accessible [[file:src/initializeCylindricalPlatforms.m][ #+end_src *** Optional Parameters +:PROPERTIES: +:UNNUMBERED: t +:END: #+begin_src matlab arguments stewart @@ -530,6 +660,9 @@ This Matlab function is accessible [[file:src/initializeCylindricalPlatforms.m][ #+end_src *** Create the =platforms= struct +:PROPERTIES: +:UNNUMBERED: t +:END: #+begin_src matlab platforms = struct(); @@ -549,11 +682,14 @@ This Matlab function is accessible [[file:src/initializeCylindricalPlatforms.m][ #+end_src *** Save the =platforms= struct +:PROPERTIES: +:UNNUMBERED: t +:END: #+begin_src matlab stewart.platforms = platforms; #+end_src -** =initializeCylindricalStruts=: Define the mass and moment of inertia of cylindrical struts +** =initializeCylindricalStruts=: Define the inertia of cylindrical struts :PROPERTIES: :header-args:matlab+: :tangle src/initializeCylindricalStruts.m :header-args:matlab+: :comments none :mkdirp yes :eval no @@ -563,6 +699,9 @@ This Matlab function is accessible [[file:src/initializeCylindricalPlatforms.m][ This Matlab function is accessible [[file:src/initializeCylindricalStruts.m][here]]. *** Function description +:PROPERTIES: +:UNNUMBERED: t +:END: #+begin_src matlab function [stewart] = initializeCylindricalStruts(stewart, args) % initializeCylindricalStruts - Define the mass and moment of inertia of cylindrical struts @@ -592,6 +731,9 @@ This Matlab function is accessible [[file:src/initializeCylindricalStruts.m][her #+end_src *** Optional Parameters +:PROPERTIES: +:UNNUMBERED: t +:END: #+begin_src matlab arguments stewart @@ -605,6 +747,9 @@ This Matlab function is accessible [[file:src/initializeCylindricalStruts.m][her #+end_src *** Create the =struts= structure +:PROPERTIES: +:UNNUMBERED: t +:END: #+begin_src matlab struts = struct(); @@ -632,984 +777,108 @@ This Matlab function is accessible [[file:src/initializeCylindricalStruts.m][her stewart.struts = struts; #+end_src -* =initializeStewartPose=: Determine the initial stroke in each leg to have the wanted pose +** =initializeStrutDynamics=: Add Stiffness and Damping properties of each strut :PROPERTIES: -:header-args:matlab+: :tangle src/initializeStewartPose.m +:header-args:matlab+: :tangle src/initializeStrutDynamics.m :header-args:matlab+: :comments none :mkdirp yes :eval no :END: -<> +<> -This Matlab function is accessible [[file:src/initializeStewartPose.m][here]]. +This Matlab function is accessible [[file:src/initializeStrutDynamics.m][here]]. -** Function description +*** Function description +:PROPERTIES: +:UNNUMBERED: t +:END: #+begin_src matlab - function [stewart] = initializeStewartPose(stewart, args) - % initializeStewartPose - Determine the initial stroke in each leg to have the wanted pose - % It uses the inverse kinematic + function [stewart] = initializeStrutDynamics(stewart, args) + % initializeStrutDynamics - Add Stiffness and Damping properties of each strut % - % Syntax: [stewart] = initializeStewartPose(stewart, args) + % Syntax: [stewart] = initializeStrutDynamics(args) % % Inputs: - % - stewart - A structure with the following fields - % - Aa [3x6] - The positions ai expressed in {A} - % - Bb [3x6] - The positions bi expressed in {B} - % - args - Can have the following fields: - % - AP [3x1] - The wanted position of {B} with respect to {A} - % - ARB [3x3] - The rotation matrix that gives the wanted orientation of {B} with respect to {A} + % - args - Structure with the following fields: + % - Ki [6x1] - Stiffness of each strut [N/m] + % - Ci [6x1] - Damping of each strut [N/(m/s)] % % Outputs: % - stewart - updated Stewart structure with the added fields: - % - dLi[6x1] - The 6 needed displacement of the struts from the initial position in [m] to have the wanted pose of {B} w.r.t. {A} + % - Ki [6x1] - Stiffness of each strut [N/m] + % - Ci [6x1] - Damping of each strut [N/(m/s)] #+end_src -** Optional Parameters +*** Optional Parameters +:PROPERTIES: +:UNNUMBERED: t +:END: #+begin_src matlab arguments stewart - args.AP (3,1) double {mustBeNumeric} = zeros(3,1) - args.ARB (3,3) double {mustBeNumeric} = eye(3) + args.Ki (6,1) double {mustBeNumeric, mustBePositive} = 1e6*ones(6,1) + args.Ci (6,1) double {mustBeNumeric, mustBePositive} = 1e1*ones(6,1) end #+end_src -** Use the Inverse Kinematic function +*** Add Stiffness and Damping properties of each strut +:PROPERTIES: +:UNNUMBERED: t +:END: #+begin_src matlab - [Li, dLi] = inverseKinematics(stewart, 'AP', args.AP, 'ARB', args.ARB); - - stewart.dLi = dLi; + stewart.Ki = args.Ki; + stewart.Ci = args.Ci; #+end_src -* Utility Functions -** =inverseKinematics=: Compute Inverse Kinematics +** =initializeJointDynamics=: Add Stiffness and Damping properties for spherical joints :PROPERTIES: -:header-args:matlab+: :tangle src/inverseKinematics.m +:header-args:matlab+: :tangle src/initializeJointDynamics.m :header-args:matlab+: :comments none :mkdirp yes :eval no :END: -<> +<> -This Matlab function is accessible [[file:src/inverseKinematics.m][here]]. +This Matlab function is accessible [[file:src/initializeJointDynamics.m][here]]. *** Function description +:PROPERTIES: +:UNNUMBERED: t +:END: #+begin_src matlab - function [Li, dLi] = inverseKinematics(stewart, args) - % inverseKinematics - Compute the needed length of each strut to have the wanted position and orientation of {B} with respect to {A} + function [stewart] = initializeJointDynamics(stewart, args) + % initializeJointDynamics - Add Stiffness and Damping properties for the spherical joints % - % Syntax: [stewart] = inverseKinematics(stewart) + % Syntax: [stewart] = initializeJointDynamics(args) % % Inputs: - % - stewart - A structure with the following fields - % - Aa [3x6] - The positions ai expressed in {A} - % - Bb [3x6] - The positions bi expressed in {B} - % - args - Can have the following fields: - % - AP [3x1] - The wanted position of {B} with respect to {A} - % - ARB [3x3] - The rotation matrix that gives the wanted orientation of {B} with respect to {A} + % - args - Structure with the following fields: + % - Kri [6x1] - Rotational Stiffness for each spherical joints [N/rad] + % - Cri [6x1] - Damping of each spherical joint [N/(rad/s)] % % Outputs: - % - Li [6x1] - The 6 needed length of the struts in [m] to have the wanted pose of {B} w.r.t. {A} - % - dLi [6x1] - The 6 needed displacement of the struts from the initial position in [m] to have the wanted pose of {B} w.r.t. {A} + % - stewart - updated Stewart structure with the added fields: + % - Kri [6x1] - Rotational Stiffness for each spherical joints [N/rad] + % - Cri [6x1] - Damping of each spherical joint [N/(rad/s)] #+end_src *** Optional Parameters +:PROPERTIES: +:UNNUMBERED: t +:END: #+begin_src matlab arguments stewart - args.AP (3,1) double {mustBeNumeric} = zeros(3,1) - args.ARB (3,3) double {mustBeNumeric} = eye(3) + args.Kri (6,1) double {mustBeNumeric, mustBePositive} = zeros(6,1) + args.Cri (6,1) double {mustBeNumeric, mustBePositive} = zeros(6,1) end #+end_src -*** Theory -For inverse kinematic analysis, it is assumed that the position ${}^A\bm{P}$ and orientation of the moving platform ${}^A\bm{R}_B$ are given and the problem is to obtain the joint variables, namely, $\bm{L} = [l_1, l_2, \dots, l_6]^T$. - -From the geometry of the manipulator, the loop closure for each limb, $i = 1, 2, \dots, 6$ can be written as -\begin{align*} - l_i {}^A\hat{\bm{s}}_i &= {}^A\bm{A} + {}^A\bm{b}_i - {}^A\bm{a}_i \\ - &= {}^A\bm{A} + {}^A\bm{R}_b {}^B\bm{b}_i - {}^A\bm{a}_i -\end{align*} - -To obtain the length of each actuator and eliminate $\hat{\bm{s}}_i$, it is sufficient to dot multiply each side by itself: -\begin{equation} - l_i^2 \left[ {}^A\hat{\bm{s}}_i^T {}^A\hat{\bm{s}}_i \right] = \left[ {}^A\bm{P} + {}^A\bm{R}_B {}^B\bm{b}_i - {}^A\bm{a}_i \right]^T \left[ {}^A\bm{P} + {}^A\bm{R}_B {}^B\bm{b}_i - {}^A\bm{a}_i \right] -\end{equation} - -Hence, for $i = 1, 2, \dots, 6$, each limb length can be uniquely determined by: -\begin{equation} - l_i = \sqrt{{}^A\bm{P}^T {}^A\bm{P} + {}^B\bm{b}_i^T {}^B\bm{b}_i + {}^A\bm{a}_i^T {}^A\bm{a}_i - 2 {}^A\bm{P}^T {}^A\bm{a}_i + 2 {}^A\bm{P}^T \left[{}^A\bm{R}_B {}^B\bm{b}_i\right] - 2 \left[{}^A\bm{R}_B {}^B\bm{b}_i\right]^T {}^A\bm{a}_i} -\end{equation} - -If the position and orientation of the moving platform lie in the feasible workspace of the manipulator, one unique solution to the limb length is determined by the above equation. -Otherwise, when the limbs' lengths derived yield complex numbers, then the position or orientation of the moving platform is not reachable. - -*** Compute -#+begin_src matlab - Li = sqrt(args.AP'*args.AP + diag(stewart.Bb'*stewart.Bb) + diag(stewart.Aa'*stewart.Aa) - (2*args.AP'*stewart.Aa)' + (2*args.AP'*(args.ARB*stewart.Bb))' - diag(2*(args.ARB*stewart.Bb)'*stewart.Aa)); -#+end_src - -#+begin_src matlab - dLi = Li-stewart.l; -#+end_src - -** =forwardKinematicsApprox=: Compute the Forward Kinematics +*** Add Stiffness and Damping properties of each strut :PROPERTIES: -:header-args:matlab+: :tangle src/forwardKinematicsApprox.m -:header-args:matlab+: :comments none :mkdirp yes :eval no +:UNNUMBERED: t :END: -<> - -This Matlab function is accessible [[file:src/forwardKinematicsApprox.m][here]]. - -*** Function description -#+begin_src matlab - function [P, R] = forwardKinematicsApprox(stewart, args) - % forwardKinematicsApprox - Computed the approximate pose of {B} with respect to {A} from the length of each strut and using - % the Jacobian Matrix - % - % Syntax: [P, R] = forwardKinematicsApprox(stewart, args) - % - % Inputs: - % - stewart - A structure with the following fields - % - J [6x6] - The Jacobian Matrix - % - args - Can have the following fields: - % - dL [6x1] - Displacement of each strut [m] - % - % Outputs: - % - P [3x1] - The estimated position of {B} with respect to {A} - % - R [3x3] - The estimated rotation matrix that gives the orientation of {B} with respect to {A} -#+end_src - -*** Optional Parameters -#+begin_src matlab - arguments - stewart - args.dL (6,1) double {mustBeNumeric} = zeros(6,1) - end -#+end_src - -*** Computation -From a small displacement of each strut $d\bm{\mathcal{L}}$, we can compute the -position and orientation of {B} with respect to {A} using the following formula: -\[ d \bm{\mathcal{X}} = \bm{J}^{-1} d\bm{\mathcal{L}} \] -#+begin_src matlab - X = stewart.J\args.dL; -#+end_src - -The position vector corresponds to the first 3 elements. -#+begin_src matlab - P = X(1:3); -#+end_src - -The next 3 elements are the orientation of {B} with respect to {A} expressed -using the screw axis. -#+begin_src matlab - theta = norm(X(4:6)); - s = X(4:6)/theta; -#+end_src - -We then compute the corresponding rotation matrix. -#+begin_src matlab - R = [s(1)^2*(1-cos(theta)) + cos(theta) , s(1)*s(2)*(1-cos(theta)) - s(3)*sin(theta), s(1)*s(3)*(1-cos(theta)) + s(2)*sin(theta); - s(2)*s(1)*(1-cos(theta)) + s(3)*sin(theta), s(2)^2*(1-cos(theta)) + cos(theta), s(2)*s(3)*(1-cos(theta)) - s(1)*sin(theta); - s(3)*s(1)*(1-cos(theta)) - s(2)*sin(theta), s(3)*s(2)*(1-cos(theta)) + s(1)*sin(theta), s(3)^2*(1-cos(theta)) + cos(theta)]; -#+end_src - -* Other Elements -** Z-Axis Geophone -:PROPERTIES: -:header-args:matlab+: :tangle ./src/initializeZAxisGeophone.m -:header-args:matlab+: :comments none :mkdirp yes :eval no -:END: -<> - -This Matlab function is accessible [[file:../src/initializeZAxisGeophone.m][here]]. - -#+begin_src matlab - function [geophone] = initializeZAxisGeophone(args) - arguments - args.mass (1,1) double {mustBeNumeric, mustBePositive} = 1e-3 % [kg] - args.freq (1,1) double {mustBeNumeric, mustBePositive} = 1 % [Hz] - end - - %% - geophone.m = args.mass; - - %% The Stiffness is set to have the damping resonance frequency - geophone.k = geophone.m * (2*pi*args.freq)^2; - - %% We set the damping value to have critical damping - geophone.c = 2*sqrt(geophone.m * geophone.k); - - %% Save - save('./mat/geophone_z_axis.mat', 'geophone'); - end -#+end_src - -** Z-Axis Accelerometer -:PROPERTIES: -:header-args:matlab+: :tangle ./src/initializeZAxisAccelerometer.m -:header-args:matlab+: :comments none :mkdirp yes :eval no -:END: -<> - -This Matlab function is accessible [[file:../src/initializeZAxisAccelerometer.m][here]]. - -#+begin_src matlab - function [accelerometer] = initializeZAxisAccelerometer(args) - arguments - args.mass (1,1) double {mustBeNumeric, mustBePositive} = 1e-3 % [kg] - args.freq (1,1) double {mustBeNumeric, mustBePositive} = 5e3 % [Hz] - end - - %% - accelerometer.m = args.mass; - - %% The Stiffness is set to have the damping resonance frequency - accelerometer.k = accelerometer.m * (2*pi*args.freq)^2; - - %% We set the damping value to have critical damping - accelerometer.c = 2*sqrt(accelerometer.m * accelerometer.k); - - %% Gain correction of the accelerometer to have a unity gain until the resonance - accelerometer.gain = -accelerometer.k/accelerometer.m; - - %% Save - save('./mat/accelerometer_z_axis.mat', 'accelerometer'); - end -#+end_src - -* OLD :noexport: -** Define the Height of the Platform :noexport: -#+begin_src matlab - %% 1. Height of the platform. Location of {F} and {M} - H = 90e-3; % [m] - FO_M = [0; 0; H]; -#+end_src - -** Define the location of {A} and {B} :noexport: -#+begin_src matlab - %% 2. Location of {A} and {B} - FO_A = [0; 0; 100e-3] + FO_M;% [m,m,m] - MO_B = [0; 0; 100e-3];% [m,m,m] -#+end_src - -** Define the position of $a_{i}$ and $b_{i}$ :noexport: -#+begin_src matlab - %% 3. Position of ai and bi - Fa = zeros(3, 6); % Fa_i is the i'th vector of Fa - Mb = zeros(3, 6); % Mb_i is the i'th vector of Mb -#+end_src - -#+begin_src matlab - Aa = Fa - repmat(FO_A, [1, 6]); - Bb = Mb - repmat(MO_B, [1, 6]); - - Ab = Bb - repmat(-MO_B-FO_M+FO_A, [1, 6]); - Ba = Aa - repmat( MO_B+FO_M-FO_A, [1, 6]); - - As = (Ab - Aa)./vecnorm(Ab - Aa); % As_i is the i'th vector of As - l = vecnorm(Ab - Aa); - - Bs = (Bb - Ba)./vecnorm(Bb - Ba); - - FRa = zeros(3,3,6); - MRb = zeros(3,3,6); - - for i = 1:6 - FRa(:,:,i) = [cross([0;1;0],As(:,i)) , cross(As(:,i), cross([0;1;0], As(:,i))) , As(:,i)]; - FRa(:,:,i) = FRa(:,:,i)./vecnorm(FRa(:,:,i)); - - MRb(:,:,i) = [cross([0;1;0],Bs(:,i)) , cross(Bs(:,i), cross([0;1;0], Bs(:,i))) , Bs(:,i)]; - MRb(:,:,i) = MRb(:,:,i)./vecnorm(MRb(:,:,i)); - end -#+end_src - -** Define the dynamical properties of each strut :noexport: -#+begin_src matlab - %% 4. Stiffness and Damping of each strut - Ki = 1e6*ones(6,1); - Ci = 1e2*ones(6,1); -#+end_src - -** Old Introduction :noexport: -First, geometrical parameters are defined: -- ${}^A\bm{a}_i$ - Position of the joints fixed to the fixed base w.r.t $\{A\}$ -- ${}^A\bm{b}_i$ - Position of the joints fixed to the mobile platform w.r.t $\{A\}$ -- ${}^B\bm{b}_i$ - Position of the joints fixed to the mobile platform w.r.t $\{B\}$ -- $H$ - Total height of the mobile platform - -These parameter are enough to determine all the kinematic properties of the platform like the Jacobian, stroke, stiffness, ... -These geometrical parameters can be generated using different functions: =initializeCubicConfiguration= for cubic configuration or =initializeGeneralConfiguration= for more general configuration. - -A function =computeGeometricalProperties= is then used to compute: -- $\bm{J}_f$ - Jacobian matrix for the force location -- $\bm{J}_d$ - Jacobian matrix for displacement estimation -- $\bm{R}_m$ - Rotation matrices to position the leg vectors - -Then, geometrical parameters are computed for all the mechanical elements with the function =initializeMechanicalElements=: -- Shape of the platforms - - External Radius - - Internal Radius - - Density - - Thickness -- Shape of the Legs - - Radius - - Size of ball joint - - Density - -Other Parameters are defined for the Simscape simulation: -- Sample mass, volume and position (=initializeSample= function) -- Location of the inertial sensor -- Location of the point for the differential measurements -- Location of the Jacobian point for velocity/displacement computation - -** Cubic Configuration :noexport: -To define the cubic configuration, we need to define 4 parameters: -- The size of the cube -- The location of the cube -- The position of the plane joint the points $a_{i}$ -- The position of the plane joint the points $b_{i}$ - -To do so, we specify the following parameters: -- $H_{C}$ the height of the useful part of the cube -- ${}^{F}O_{C}$ the position of the center of the cube with respect to $\{F\}$ -- ${}^{F}H_{A}$: the height of the plane joining the points $a_{i}$ with respect to the frame $\{F\}$ -- ${}^{M}H_{B}$: the height of the plane joining the points $b_{i}$ with respect to the frame $\{M\}$ - -We define the parameters -#+begin_src matlab - Hc = 60e-3; % [m] - FOc = 50e-3; % [m] - FHa = 15e-3; % [m] - MHb = 15e-3; % [m] -#+end_src - -We define the useful points of the cube with respect to the Cube's center. -${}^{C}C$ are the 6 vertices of the cubes expressed in a frame {C} which is located at the center of the cube and aligned with {F} and {M}. -#+begin_src matlab - sx = [ 2; -1; -1]; - sy = [ 0; 1; -1]; - sz = [ 1; 1; 1]; - - R = [sx, sy, sz]./vecnorm([sx, sy, sz]); - - L = Hc*sqrt(3); - - Cc = R'*[[0;0;L],[L;0;L],[L;0;0],[L;L;0],[0;L;0],[0;L;L]] - [0;0;1.5*Hc]; - - CCf = [Cc(:,1), Cc(:,3), Cc(:,3), Cc(:,5), Cc(:,5), Cc(:,1)]; % CCf(:,i) corresponds to the bottom cube's vertice corresponding to the i'th leg - CCm = [Cc(:,2), Cc(:,2), Cc(:,4), Cc(:,4), Cc(:,6), Cc(:,6)]; % CCm(:,i) corresponds to the top cube's vertice corresponding to the i'th leg -#+end_src - -We can compute the vector of each leg ${}^{C}\hat{\bm{s}}_{i}$ (unit vector from ${}^{C}C_{f}$ to ${}^{C}C_{m}$). -#+begin_src matlab - CSi = (CCm - CCf)./vecnorm(CCm - CCf); -#+end_src - -We now which to compute the position of the joints $a_{i}$ and $b_{i}$. -#+begin_src matlab - Fa = zeros(3, 6); % Fa_i is the i'th vector of Fa - Mb = zeros(3, 6); % Mb_i is the i'th vector of Mb -#+end_src - -#+begin_src matlab - Fa = CCf + [0; 0; FOc] + ((FHa-(FOc-Hc/2))./CSi(3,:)).*CSi; - Mb = CCf + [0; 0; FOc-H] + ((H-MHb-(FOc-Hc/2))./CSi(3,:)).*CSi; % TODO -#+end_src - -** initializeGeneralConfiguration :noexport: -:PROPERTIES: -:HEADER-ARGS:matlab+: :exports code -:HEADER-ARGS:matlab+: :comments no -:HEADER-ARGS:matlab+: :eval no -:HEADER-ARGS:matlab+: :tangle src/initializeGeneralConfiguration.m -:END: - -*** Function description -The =initializeGeneralConfiguration= function takes one structure that contains configurations for the hexapod and returns one structure representing the Hexapod. - -#+begin_src matlab - function [stewart] = initializeGeneralConfiguration(opts_param) -#+end_src - -*** Optional Parameters -Default values for opts. -#+begin_src matlab - opts = struct(... - 'H_tot', 90, ... % Height of the platform [mm] - 'H_joint', 15, ... % Height of the joints [mm] - 'H_plate', 10, ... % Thickness of the fixed and mobile platforms [mm] - 'R_bot', 100, ... % Radius where the legs articulations are positionned [mm] - 'R_top', 80, ... % Radius where the legs articulations are positionned [mm] - 'a_bot', 10, ... % Angle Offset [deg] - 'a_top', 40, ... % Angle Offset [deg] - 'da_top', 0 ... % Angle Offset from 0 position [deg] - ); -#+end_src - -Populate opts with input parameters -#+begin_src matlab - if exist('opts_param','var') - for opt = fieldnames(opts_param)' - opts.(opt{1}) = opts_param.(opt{1}); - end - end -#+end_src - -*** Geometry Description -#+name: fig:stewart_bottom_plate -#+caption: Schematic of the bottom plates with all the parameters -[[file:./figs/stewart_bottom_plate.png]] - -*** Compute Aa and Ab -We compute $[a_1, a_2, a_3, a_4, a_5, a_6]^T$ and $[b_1, b_2, b_3, b_4, b_5, b_6]^T$. - -#+begin_src matlab - Aa = zeros(6, 3); % [mm] - Ab = zeros(6, 3); % [mm] - Bb = zeros(6, 3); % [mm] -#+end_src - -#+begin_src matlab - for i = 1:3 - Aa(2*i-1,:) = [opts.R_bot*cos( pi/180*(120*(i-1) - opts.a_bot) ), ... - opts.R_bot*sin( pi/180*(120*(i-1) - opts.a_bot) ), ... - opts.H_plate+opts.H_joint]; - Aa(2*i,:) = [opts.R_bot*cos( pi/180*(120*(i-1) + opts.a_bot) ), ... - opts.R_bot*sin( pi/180*(120*(i-1) + opts.a_bot) ), ... - opts.H_plate+opts.H_joint]; - - Ab(2*i-1,:) = [opts.R_top*cos( pi/180*(120*(i-1) + opts.da_top - opts.a_top) ), ... - opts.R_top*sin( pi/180*(120*(i-1) + opts.da_top - opts.a_top) ), ... - opts.H_tot - opts.H_plate - opts.H_joint]; - Ab(2*i,:) = [opts.R_top*cos( pi/180*(120*(i-1) + opts.da_top + opts.a_top) ), ... - opts.R_top*sin( pi/180*(120*(i-1) + opts.da_top + opts.a_top) ), ... - opts.H_tot - opts.H_plate - opts.H_joint]; - end - - Bb = Ab - opts.H_tot*[0,0,1]; -#+end_src - -*** Returns Stewart Structure -#+begin_src matlab :results none - stewart = struct(); - stewart.Aa = Aa; - stewart.Ab = Ab; - stewart.Bb = Bb; - stewart.H_tot = opts.H_tot; -end -#+end_src - -** initializeCubicConfiguration :noexport: -:PROPERTIES: -:HEADER-ARGS:matlab+: :exports code -:HEADER-ARGS:matlab+: :comments no -:HEADER-ARGS:matlab+: :eval no -:HEADER-ARGS:matlab+: :tangle src/initializeCubicConfiguration.m -:END: -<> - -*** Function description -#+begin_src matlab - function [stewart] = initializeCubicConfiguration(opts_param) -#+end_src - -*** Optional Parameters -Default values for opts. -#+begin_src matlab - opts = struct(... - 'H_tot', 90, ... % Total height of the Hexapod [mm] - 'L', 110, ... % Size of the Cube [mm] - 'H', 40, ... % Height between base joints and platform joints [mm] - 'H0', 75 ... % Height between the corner of the cube and the plane containing the base joints [mm] - ); -#+end_src - -Populate opts with input parameters -#+begin_src matlab - if exist('opts_param','var') - for opt = fieldnames(opts_param)' - opts.(opt{1}) = opts_param.(opt{1}); - end - end -#+end_src - -*** Cube Creation -#+begin_src matlab :results none - points = [0, 0, 0; ... - 0, 0, 1; ... - 0, 1, 0; ... - 0, 1, 1; ... - 1, 0, 0; ... - 1, 0, 1; ... - 1, 1, 0; ... - 1, 1, 1]; - points = opts.L*points; -#+end_src - -We create the rotation matrix to rotate the cube -#+begin_src matlab :results none - sx = cross([1, 1, 1], [1 0 0]); - sx = sx/norm(sx); - - sy = -cross(sx, [1, 1, 1]); - sy = sy/norm(sy); - - sz = [1, 1, 1]; - sz = sz/norm(sz); - - R = [sx', sy', sz']'; -#+end_src - -We use to rotation matrix to rotate the cube -#+begin_src matlab :results none - cube = zeros(size(points)); - for i = 1:size(points, 1) - cube(i, :) = R * points(i, :)'; - end -#+end_src - -*** Vectors of each leg -#+begin_src matlab :results none - leg_indices = [3, 4; ... - 2, 4; ... - 2, 6; ... - 5, 6; ... - 5, 7; ... - 3, 7]; -#+end_src - -Vectors are: -#+begin_src matlab :results none - legs = zeros(6, 3); - legs_start = zeros(6, 3); - - for i = 1:6 - legs(i, :) = cube(leg_indices(i, 2), :) - cube(leg_indices(i, 1), :); - legs_start(i, :) = cube(leg_indices(i, 1), :); - end -#+end_src - -*** Verification of Height of the Stewart Platform -If the Stewart platform is not contained in the cube, throw an error. - -#+begin_src matlab :results none - Hmax = cube(4, 3) - cube(2, 3); - if opts.H0 < cube(2, 3) - error(sprintf('H0 is not high enought. Minimum H0 = %.1f', cube(2, 3))); - else if opts.H0 + opts.H > cube(4, 3) - error(sprintf('H0+H is too high. Maximum H0+H = %.1f', cube(4, 3))); - error('H0+H is too high'); - end -#+end_src - -*** Determinate the location of the joints -We now determine the location of the joints on the fixed platform w.r.t the fixed frame $\{A\}$. -$\{A\}$ is fixed to the bottom of the base. -#+begin_src matlab :results none - Aa = zeros(6, 3); - for i = 1:6 - t = (opts.H0-legs_start(i, 3))/(legs(i, 3)); - Aa(i, :) = legs_start(i, :) + t*legs(i, :); - end -#+end_src - -And the location of the joints on the mobile platform with respect to $\{A\}$. -#+begin_src matlab :results none - Ab = zeros(6, 3); - for i = 1:6 - t = (opts.H0+opts.H-legs_start(i, 3))/(legs(i, 3)); - Ab(i, :) = legs_start(i, :) + t*legs(i, :); - end -#+end_src - -And the location of the joints on the mobile platform with respect to $\{B\}$. -#+begin_src matlab :results none - Bb = zeros(6, 3); - Bb = Ab - (opts.H0 + opts.H_tot/2 + opts.H/2)*[0, 0, 1]; -#+end_src - -#+begin_src matlab :results none - h = opts.H0 + opts.H/2 - opts.H_tot/2; - Aa = Aa - h*[0, 0, 1]; - Ab = Ab - h*[0, 0, 1]; -#+end_src - -*** Returns Stewart Structure -#+begin_src matlab :results none - stewart = struct(); - stewart.Aa = Aa; - stewart.Ab = Ab; - stewart.Bb = Bb; - stewart.H_tot = opts.H_tot; -end -#+end_src - -** computeGeometricalProperties :noexport: -:PROPERTIES: -:HEADER-ARGS:matlab+: :exports code -:HEADER-ARGS:matlab+: :comments no -:HEADER-ARGS:matlab+: :eval no -:HEADER-ARGS:matlab+: :tangle src/computeGeometricalProperties.m -:END: - -*** Function description -#+begin_src matlab - function [stewart] = computeGeometricalProperties(stewart, opts_param) -#+end_src - -*** Optional Parameters -Default values for opts. -#+begin_src matlab - opts = struct(... - 'Jd_pos', [0, 0, 30], ... % Position of the Jacobian for displacement estimation from the top of the mobile platform [mm] - 'Jf_pos', [0, 0, 30] ... % Position of the Jacobian for force location from the top of the mobile platform [mm] - ); -#+end_src - -Populate opts with input parameters #+begin_src matlab - if exist('opts_param','var') - for opt = fieldnames(opts_param)' - opts.(opt{1}) = opts_param.(opt{1}); - end - end + stewart.Kri = args.Kri; + stewart.Cri = args.Cri; #+end_src -*** Rotation matrices -We initialize $l_i$ and $\hat{s}_i$ -#+begin_src matlab - leg_length = zeros(6, 1); % [mm] - leg_vectors = zeros(6, 3); -#+end_src - -We compute $b_i - a_i$, and then: -\begin{align*} - l_i &= \left|b_i - a_i\right| \\ - \hat{s}_i &= \frac{b_i - a_i}{l_i} -\end{align*} - -#+begin_src matlab - legs = stewart.Ab - stewart.Aa; - - for i = 1:6 - leg_length(i) = norm(legs(i,:)); - leg_vectors(i,:) = legs(i,:) / leg_length(i); - end -#+end_src - -We compute rotation matrices to have the orientation of the legs. -The rotation matrix transforms the $z$ axis to the axis of the leg. The other axis are not important here. -#+begin_src matlab - stewart.Rm = struct('R', eye(3)); - - for i = 1:6 - sx = cross(leg_vectors(i,:), [1 0 0]); - sx = sx/norm(sx); - - sy = -cross(sx, leg_vectors(i,:)); - sy = sy/norm(sy); - - sz = leg_vectors(i,:); - sz = sz/norm(sz); - - stewart.Rm(i).R = [sx', sy', sz']; - end -#+end_src - -*** Jacobian matrices -Compute Jacobian Matrix -#+begin_src matlab - Jd = zeros(6); - - for i = 1:6 - Jd(i, 1:3) = leg_vectors(i, :); - Jd(i, 4:6) = cross(0.001*(stewart.Bb(i, :) - opts.Jd_pos), leg_vectors(i, :)); - end - - stewart.Jd = Jd; - stewart.Jd_inv = inv(Jd); -#+end_src - -#+begin_src matlab - Jf = zeros(6); - - for i = 1:6 - Jf(i, 1:3) = leg_vectors(i, :); - Jf(i, 4:6) = cross(0.001*(stewart.Bb(i, :) - opts.Jf_pos), leg_vectors(i, :)); - end - - stewart.Jf = Jf; - stewart.Jf_inv = inv(Jf); -#+end_src - -#+begin_src matlab - end -#+end_src - -** initializeMechanicalElements :noexport: -:PROPERTIES: -:HEADER-ARGS:matlab+: :exports code -:HEADER-ARGS:matlab+: :comments no -:HEADER-ARGS:matlab+: :eval no -:HEADER-ARGS:matlab+: :tangle src/initializeMechanicalElements.m -:END: - -*** Function description -#+begin_src matlab - function [stewart] = initializeMechanicalElements(stewart, opts_param) -#+end_src - -*** Optional Parameters -Default values for opts. -#+begin_src matlab - opts = struct(... - 'thickness', 10, ... % Thickness of the base and platform [mm] - 'density', 1000, ... % Density of the material used for the hexapod [kg/m3] - 'k_ax', 1e8, ... % Stiffness of each actuator [N/m] - 'c_ax', 1000, ... % Damping of each actuator [N/(m/s)] - 'stroke', 50e-6 ... % Maximum stroke of each actuator [m] - ); -#+end_src - -Populate opts with input parameters -#+begin_src matlab - if exist('opts_param','var') - for opt = fieldnames(opts_param)' - opts.(opt{1}) = opts_param.(opt{1}); - end - end -#+end_src - -*** Bottom Plate -#+name: fig:stewart_bottom_plate -#+caption: Schematic of the bottom plates with all the parameters -[[file:./figs/stewart_bottom_plate.png]] - -The bottom plate structure is initialized. -#+begin_src matlab - BP = struct(); -#+end_src - -We defined its internal radius (if there is a hole in the bottom plate) and its outer radius. -#+begin_src matlab - BP.Rint = 0; % Internal Radius [mm] - BP.Rext = 150; % External Radius [mm] -#+end_src - -We define its thickness. -#+begin_src matlab - BP.H = opts.thickness; % Thickness of the Bottom Plate [mm] -#+end_src - -We defined the density of the material of the bottom plate. -#+begin_src matlab - BP.density = opts.density; % Density of the material [kg/m3] -#+end_src - -And its color. -#+begin_src matlab - BP.color = [0.7 0.7 0.7]; % Color [RGB] -#+end_src - -Then the profile of the bottom plate is computed and will be used by Simscape -#+begin_src matlab - BP.shape = [BP.Rint BP.H; BP.Rint 0; BP.Rext 0; BP.Rext BP.H]; % [mm] -#+end_src - -The structure is added to the stewart structure -#+begin_src matlab - stewart.BP = BP; -#+end_src - -*** Top Plate -The top plate structure is initialized. -#+begin_src matlab - TP = struct(); -#+end_src - -We defined the internal and external radius of the top plate. -#+begin_src matlab - TP.Rint = 0; % [mm] - TP.Rext = 100; % [mm] -#+end_src - -The thickness of the top plate. -#+begin_src matlab - TP.H = 10; % [mm] -#+end_src - -The density of its material. -#+begin_src matlab - TP.density = opts.density; % Density of the material [kg/m3] -#+end_src - -Its color. -#+begin_src matlab - TP.color = [0.7 0.7 0.7]; % Color [RGB] -#+end_src - -Then the shape of the top plate is computed -#+begin_src matlab - TP.shape = [TP.Rint TP.H; TP.Rint 0; TP.Rext 0; TP.Rext TP.H]; -#+end_src - -The structure is added to the stewart structure -#+begin_src matlab - stewart.TP = TP; -#+end_src - -*** Legs -#+name: fig:stewart_legs -#+caption: Schematic for the legs of the Stewart platform -[[file:./figs/stewart_legs.png]] - -The leg structure is initialized. -#+begin_src matlab - Leg = struct(); -#+end_src - -The maximum Stroke of each leg is defined. -#+begin_src matlab - Leg.stroke = opts.stroke; % [m] -#+end_src - -The stiffness and damping of each leg are defined -#+begin_src matlab - Leg.k_ax = opts.k_ax; % Stiffness of each leg [N/m] - Leg.c_ax = opts.c_ax; % Damping of each leg [N/(m/s)] -#+end_src - -The radius of the legs are defined -#+begin_src matlab - Leg.Rtop = 10; % Radius of the cylinder of the top part of the leg[mm] - Leg.Rbot = 12; % Radius of the cylinder of the bottom part of the leg [mm] -#+end_src - -The density of its material. -#+begin_src matlab - Leg.density = opts.density; % Density of the material used for the legs [kg/m3] -#+end_src - -Its color. -#+begin_src matlab - Leg.color = [0.5 0.5 0.5]; % Color of the top part of the leg [RGB] -#+end_src - -The radius of spheres representing the ball joints are defined. -#+begin_src matlab - Leg.R = 1.3*Leg.Rbot; % Size of the sphere at the extremity of the leg [mm] -#+end_src - -We estimate the length of the legs. -#+begin_src matlab - legs = stewart.Ab - stewart.Aa; - Leg.lenght = norm(legs(1,:))/1.5; -#+end_src - -Then the shape of the bottom leg is estimated -#+begin_src matlab - Leg.shape.bot = ... - [0 0; ... - Leg.Rbot 0; ... - Leg.Rbot Leg.lenght; ... - Leg.Rtop Leg.lenght; ... - Leg.Rtop 0.2*Leg.lenght; ... - 0 0.2*Leg.lenght]; -#+end_src - -The structure is added to the stewart structure -#+begin_src matlab - stewart.Leg = Leg; -#+end_src - -*** Ball Joints -#+name: fig:stewart_ball_joints -#+caption: Schematic of the support for the ball joints -[[file:./figs/stewart_ball_joints.png]] - -=SP= is the structure representing the support for the ball joints at the extremity of each leg. - -The =SP= structure is initialized. -#+begin_src matlab - SP = struct(); -#+end_src - -We can define its rotational stiffness and damping. For now, we use perfect joints. -#+begin_src matlab - SP.k = 0; % [N*m/deg] - SP.c = 0; % [N*m/deg] -#+end_src - -Its height is defined -#+begin_src matlab - SP.H = stewart.Aa(1, 3) - BP.H; % [mm] -#+end_src - -Its radius is based on the radius on the sphere at the end of the legs. -#+begin_src matlab - SP.R = Leg.R; % [mm] -#+end_src - -#+begin_src matlab - SP.section = [0 SP.H-SP.R; - 0 0; - SP.R 0; - SP.R SP.H]; -#+end_src - -The density of its material is defined. -#+begin_src matlab - SP.density = opts.density; % [kg/m^3] -#+end_src - -Its color is defined. -#+begin_src matlab - SP.color = [0.7 0.7 0.7]; % [RGB] -#+end_src - -The structure is added to the Hexapod structure -#+begin_src matlab - stewart.SP = SP; -#+end_src - -** initializeSample :noexport: -:PROPERTIES: -:HEADER-ARGS:matlab+: :exports code -:HEADER-ARGS:matlab+: :comments no -:HEADER-ARGS:matlab+: :eval no -:HEADER-ARGS:matlab+: :tangle src/initializeSample.m -:END: - -*** Function description -#+begin_src matlab - function [] = initializeSample(opts_param) -#+end_src - -*** Optional Parameters -Default values for opts. -#+begin_src matlab - sample = struct( ... - 'radius', 100, ... % radius of the cylinder [mm] - 'height', 100, ... % height of the cylinder [mm] - 'mass', 10, ... % mass of the cylinder [kg] - 'measheight', 50, ... % measurement point z-offset [mm] - 'offset', [0, 0, 0], ... % offset position of the sample [mm] - 'color', [0.9 0.1 0.1] ... - ); -#+end_src - -Populate opts with input parameters -#+begin_src matlab - if exist('opts_param','var') - for opt = fieldnames(opts_param)' - sample.(opt{1}) = opts_param.(opt{1}); - end - end -#+end_src - -*** Save the Sample structure -#+begin_src matlab - save('./mat/sample.mat', 'sample'); -#+end_src - -#+begin_src matlab - end -#+end_src +* Bibliography :ignore: +bibliographystyle:unsrt +bibliography:ref.bib