From 877199e4fe5e6303113fa8a293a9026d3e20bacd Mon Sep 17 00:00:00 2001 From: williamckha Date: Sun, 4 Aug 2024 21:20:39 -0700 Subject: [PATCH 01/18] Docs update --- README.md | 11 +- docs/images/tbots_logo_dark.png | Bin 0 -> 30114 bytes docs/images/tbots_logo_light.png | Bin 0 -> 41798 bytes docs/images/thunderscope.png | Bin 0 -> 295628 bytes docs/software-architecture-and-design.md | 259 ++++++++++++++--------- 5 files changed, 171 insertions(+), 99 deletions(-) create mode 100644 docs/images/tbots_logo_dark.png create mode 100644 docs/images/tbots_logo_light.png create mode 100644 docs/images/thunderscope.png diff --git a/README.md b/README.md index 023354ceef..61f9b802f0 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,15 @@ -# Software + + + Thunderbots Logo + + +--- [![Tbots CI](https://github.com/UBC-Thunderbots/Software/actions/workflows/main.yml/badge.svg)](https://github.com/UBC-Thunderbots/Software/actions?query=workflow%3A%22Tbots+CI%22+branch%3Amaster) -Our main software and firmware repository. To get started, please see [Getting Started](docs/getting-started.md). Please thoroughly read this guide, along with our [style guide](docs/code-style-guide.md), before making *any* contributions. +**Welcome to our main software and firmware repository!** + +To get started with building and setting up our software, please see [Getting Started](docs/getting-started.md). Please thoroughly read this guide, along with our [style guide](docs/code-style-guide.md), before making *any* contributions. For an explanation of our software layout and architecture, check out [software architecture and design](docs/software-architecture-and-design.md). diff --git a/docs/images/tbots_logo_dark.png b/docs/images/tbots_logo_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..f03f1c692be8b882df95996e0801089911695605 GIT binary patch literal 30114 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

jZfD1ru5igzh!<^0%`cg3@_xcHWiM&)32d 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 X=(qgJ8X~z02}w!r^{a9jv(WzmjTirj literal 0 HcmV?d00001 diff --git a/docs/images/tbots_logo_light.png b/docs/images/tbots_logo_light.png new file mode 100644 index 0000000000000000000000000000000000000000..e053733afbca5a98e04f29cb48d8ed8f643afaf8 GIT binary patch literal 41798 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�Cd$v*pPEhK*X_9uB0 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 AOaK4? literal 0 HcmV?d00001 diff --git a/docs/images/thunderscope.png b/docs/images/thunderscope.png new file mode 100644 index 0000000000000000000000000000000000000000..633c33e1a1886d5d0439f8192f2289bc9429a101 GIT binary patch literal 295628 zcmce8Wk8f&*Di`+ARsE8f^@gEK}btWcc*kCDgpu$Djf<^(%lWxAl)F{-F?Z@|m_hJhcv$F~=GX|G^yWbdSFYlviQWo>E5Xs2&$XlP|;Vr{>PTq6iyqD6e^ znXRF&y{WYonWCwsA(D!r0U0|hnS_G{85;{52N}yFUd~6n>?~wYq{%dms-u%25GPzuJ^BaY{$nsaetBHx^8fb6!)v~LHbM%lIUf#)h?TT%& zM^BcxH|d6U^WnQasW5RPw)t}kUIN|+ciMJU>CHRW?79SN*rT33jURC%TN^QK9_%OXTtxSG^C63Pzfbnp<9A z{rw81|1h>*-R_stiv8b*6*BV@>F@k~46Ez~lL?s`=cu1tXolb4FU1fv92HR?g3^@Y zn-Qx|ICD9^xS+h9SHf%E4MW&=qCqRj?=#MzI1B<710a61sme*Wj)zgu(|u^*1xVb;~vNkwz` zpPik_k0B!?yZrXP-qO`&G+Jo-i0EU%W<}+Pz#FVvgGm?n`KDtMIC&NS`Tg9}7#=&S z>gsBwy_JCgu#j*D)vGr3UPK~)PT$ryW?kd)(<9z>CB0yydu%M`_ir6Nef_e_i&IIT zM6dVXSXo(1HJBxqotwInX2}P zFV4+nLE5N3wR-yWY3_(c=F7Y{O#!&Gjuq+3Sp-R9!3$qhv>q@sW4?ay?EUZg`KChC zzOBQ<#f^$hDsu9xUS5~?K3>0Z^QP|aTJQc$)lZd`{0umf=>*bL_XJ$`zKR6kL`qRP zZj86CjTGdKSRn1Kk41}CMzzA_Fv_nY$oEWD znLd7}#rxwU=_Z8SRu5TOL*b_SGE|s*dwYk=9aiy!clY;`9oI)YVtGCl7IMJjhz64g z@HfXuQIR5M zIQq7()(?wfYiDOB#=80e8QJT}D!1A7_0CF{U8FRX9Fo(+P2=5#&TH4N_hqSbzsDr) zYV^N%#bmscwPezj-fpprl9Tg`)kOKL!wDyL&ogJ)Bl$jK}oFnBQY5J z?{?;z#$|ig(ba(rv4I~-E~{B3{1m*JOt{FXw{^B>n&RcYihU%~-JGn7Zw?l^c(lJd zWZWGuV81#Tlq?yMZ#F=ORDF5jcCnx1g@ujXl&9a^by9TqA2TW=_`KNiYxW%fgW%a# zgZRP^dl$J(gYirA|yR@B{l*Ae(HSRR!5zm#>ybS+-t0 zmZo09)E>?_+Y(BF)cEtK?b5Gr^14e2>o@_){d>h=F0~e1_pq@=9^?iCp7Nu=*33=B~baL==B1d{I`N5)q*i6)ZI2_5AWSQ>sjy>r)d~ z_q1cD-NkO>(}Q*UaP1bRFssg zmZKaHacA(0qQb)=Kyk|4&{a@SxQT&5#m_(9r<|e87%M{!KcHS0dib!B{iJW*@l$-f zjJ^HdO$SJ|b}r(7u9@xH8O=$*TUhodB7gt>eQVm6l2@4B`!znKzZ*T9# z@lBVU2fV*styh$|cP>h}JhfEat0(;bNun(xVG$8x^73~fAQ<)}irmM+0ds!( zaShBK2B~02)!}4&qDVkXXJ@kQd|Ujwa>f@<^TA&bd>{opg2{%9%+1Y(goN1i3I>T% z5c4_iWs(x$;w~P8!_K#xf(s$imHAM1)3W`HZP{>z6LV{8>$u0^1cOHD9WO7hlY{m4 z57_kltG-tY%?55|418#q{wJCW2*g3^L&`O1y}MC5i@|_{=61NzWWj}qD=E@3ZF{31 z{&^0??*-@&WlL~OR4pef%cRaxuU-3m>)BSq2NCb5|dMN5e-q1)u81L%mLVN9G_GCK%P}eOt;`^py&BXPmPxs zBwrU7m$iwCp@QyA)dCtCny+BoN5{vyc`sk)>eSJm?(ObU2nxoN2)O>XEqg8_WArl+ zAIZSjm>uTknCb!vu>JlFK&-H;*z5R@okkQ8i6h#T z=x(F5bax-VOH@@=UF44m{w9|sx>)_IjWoV&C}N3);xbmJDcSJZe?05%{FV_BR0Hoi-XpxXg?GNgwF}6NL;HP>!$q;$NXY( zeH*+RrXS58*hNttZU!1Mnmm`ajwdp1GGaEz{4>)3{)?*|mC|83@=I8)IHn<;;6FI( z-%lg5?c&*nkRB$NKksJR?M?dk_@BSHO+2zutEfKT{_C)|yj(+ydB ziRWm#xCh~87$vm^43}GOXWaLE(ybs@S>>@bS#|xvg9q`&U7EZKS!(;YGFQflw5|J& zoM&cZw6}IqA@k3ltTG?D{E1-yiDSwO1taMqIbvy(g@i^4NaJ047K0kSpNjL`n!H-Y z1#G^V?=9IhuQm=?Iz2tD=A0^6Ui4p_sHxNWI$4CAK9b0N3uT5V-;wPx#ooJI z;bq#FziD_US;MDN1Z8x!7F>o@<6RF{IxmCp8*1V`-Wy6rgpYD>jeIhh=$ZaCVqV9G3=FXy9k(&oglbEjrsjw9 z`q>W0^6ZS`Jr1<(OE(%1i~gEczt|dp7w6CPTiRuG`_2woqC2j=Q%<=kLSEusL&kAu zd-G=PGn!_qn9Rx*u8Ykoc}t)0K-=XCtFbE_>jz|~Ll?DqZ)3K0(8(UAU|^^}Dckd+ zRomLVT$-v8IuzO>qYr0pp0~YXGvP3VHI<2vDYW;SlJxzB>13r#M+|$a;@G!mH|Ki~ z?Yf0z1Hu`jb`mZ_BAxxVwrmKvtKW~0$J#Dy|2+pxfpE81h(wMJNJefxcAZgXFuh*3 zO`32AM`iOnV&)B9gD*ZHMsxIACz7zD`O_iY&E4Hbw_JmVSMF#QpbXg)Ke16n&kVOe z$U2TkUR{j+HI?we^4Q>^CH?NP40X9Oy{-IV1c7CAsRI_$l?Oe0E_>>O9qw-%8PNpB zP6bcUeVrH$+v|hVM~_?yoXUJ(hdd%Gc0b5G`8Yvey}dRzAHN;n93bcxvi4cv+Pj}U znWxW$2Tk5LSk1R|8Cs~H;mi1{c@!eFiDNa+>9dQDLpIRHAQHbT6Og}BQ7`ggbWB!q7 zu;=Fm#%TQ_wPVXxYxk4Z=3$HC0znlhXYgIStAxeGLO(|~`jUFqj&hnK9XX!dF18$N ztI>8tr-_nq+&H`3&M{8VJNT28qqsyk`7 zSvBrD_SkA=Y%$Z!dLjj#-T0!Bd+Kbck83e_tH>!~lK=1w&#G!3r`x1wX$jBsXqh_R zb0r~Dtt<@da7uP_(&Gji`us~ZUhAr3)YYM^-Mu3Bc{-$9XaP%(&sy)7GpZNQcwZ;| zZj`0=Jvo_G|D>cNn&;kYC>(Ygg%T3gip;K|qJ~99)vc)(Y;A9UTSe!-OHAApO3_-$ zt;@eUm@SZD{&)N-yBp^~c0vu{O*{GdN?{p_Z`H4RVc{aqUqtN*PPi%}yc)tqNbjju z(K4R$Klw)a>2npmtkM%@?Rm4m5;7HL)&D+5NTU#DH zRQ!-8aTbIb7U%lf!@Qcg&tY?o0B-EFLpf!KWE7d8XT3A$MdnqaS>YY1yEzP8| zdd*$y{D*+bu}JFlW%<3^*Jm0Ir-U->ZWHnQ$t98Kj`pXo4d=yS5cBSAly37MH_m2i z7Q8Q79qcV$FN!~(jp1z8VS&;^UzTiiE;_|xB>(vHgUlY2MgzL@Nt&FVEI`VI=1#;@ z-A5n$`;(H3v$To`O2(vPxUvKum=-K_zTzda7%dI8nsBojigViT8ne!`zPthu`;qO@ z^K`-YlMc9BLvCf;oI@;D_1CH|R_F!Kej`V7TK`m#6?!HriVAUqnvL!Qm2~u0nIAO?{NrPnah^RZE%#+ZtLk)88Q&xgt?Pefp3wGA)$56&oYCxC zK25K$fCY@L8})UQ>U2ue@3zK_v%HzpY#%vTH9%quE5=ev;^CaBNMO4YlsWm?Ti=s* z;9w$yJG|_D%~;+X+SNCS%eLK**n-#QYTuVVwA2o4*S${WGGuF3QhxJoo!{6x`43kG z4Gcb0arGPi**V*2f@x|fj7{52o z<0r~LjQcZ2+I`Kfi5u#qcWFA>=a#BD8wbn6BS*8^i2Sa)pKLeVuMLMT#$O7l6&x7|$BKRo;rb;9#h6(wFxiIST;VxmIE-RmI{Llw>@GA4gZzF~Xh-ZC}iP`(2ibRqyb zPG-KW9xs?WL0@fc>oC|&k=B?hqK6V(f4Uw8X>M_Tw7xI_`fZ17l-i zKO@Rbz4KV7TAkWv=E%~Mb<;^Zj#7;^ZJ`V)YRsT4-;uFk^@L0FTWU$I!d*Qcsr*!@ zOM-*l9wmzEE=R`l-|%sv^iJmF4hmUPTXaBFCr*>D0VR_z5sWe15o!Sip696V ze0=jvwrAuWqNS)H!*>rmLE!}r+DE!8gAV3HY$rWp+uPf^=j9H=>yD#ZZj1%So!`Oj z+y!0Og85HqzR;my;o?d@fBrn3Wy{&ls9SHLqh>O|XK+XTl#`a$|8%3u7ksKW$yjz0 z@05zqY3=ujaeT_xudlUn81?2FFlRS6g9pr#MFPS*Vz_Z%qo8@FSl4)-9gZz`#IgHE z37yyWB&DYcXrH5^Z|(0Jwr)xaSW;&>;dx9F=+)4cE0A#wS>E7DeEjJg!B z_DA#F3|k4lS(OA}_ch-E$9Bl6`a<|#)?jmmbhz^Ovs#bd-ABYtbB08E^MMgE3Z#YQ1m>ClTpr6^BFr=>2$1!d**xhsAe&qZyGPA^JB^3 zvbNpZI-8$%xY*cvj-3RfCDz^V_gDQsd@$--Q@u^V;b)#>Df#7x5|8^M|Hj5fg@e%e z_&Ug{GA2&E5?Ad=NfYeUcK4j2WXn=7$#q!8sg7Zd>#m8c&z){K-a0=#HtcyyLc;k$ zCaxma_>hTCCB1${iE{Og(RX8(y{?KS*9P?4)#r|==p-E(Ih7qb0l4}$31?NhC1c0y zB~wS6D%vDNo+~Hoj(k+R+M8&;1#|H%F;#8uo&S~+h`$khv&TdhY;Lo*mpr_?!8*+^ zdJW|~abWDewh*N9Plh>${2D%)GbE`C3!OX8Ux@YG8*h#6JpP!o-ME;{v*u&)(CPtA z;*V6z&6Ulx-ZZqHBDLvzciKXUB_)YJIhx#~uRa$lX1WM0x4f=%aFA4*X7D|+#Op=6 zhg~1W-8*VNdND=)`|50AHWix2Zp*mi-pHrv^2v1I8!%?_+Dt>*4&k>1C#(X0hAsMH z5GUs5hA3yLN34_>t`0tYNVNCvbAXqs@G6(((nKmV;b2a)RY`$f(=A@7vUn!VY~!AK z5yKxs6cog-2{>ihKO9)^$L}4#g0v?rA#rOUL*+UdL?{%Y%V1CL3E@)=VsWT}5$&#X z;*WYbOh-{zhv@o!KZ9=L+g?X!*^aNSrZ;MwjKPj{*Xok5s)uUH5&V zq4?NSnN9Z#;pY{*=FPq($Tg#wo<8q7g=QIwvFRDIbxem)69Cb|JEF|MRbmLc8C_G~6Q&ucZT=bLG-g7C$dY9!<{g!U@alX|}+1OL^ zpCkOeZ0?8eHL}Z;xUrt^%?95laOaz)lKP#&Ttm*z{x)*S1cQ<)-(!qxXJ;pOY~8-> z!nN3PN>tg1Y8fA&!@B29G^crJh)u|)RD8!I_>;iwMNQy-e#6MTcYSNVvhH^XvF$qtPgp?z{p^yqoAA3a^*e)PW#R2 zrR{wq0|WUo32a0lB;>Y$1f>O`ai56C_F6$iRPm6OBy^sl1l&?mgYo-P+1E32`~w0E zFV2qR55gJMv54+U+1lQMka-s$yQ$~%eWZhpk)ZbZnQy+L`8GXIp)dHevdk`OrwO<6 zvd*{i;^)hS?gUvmxd)u){RWVopi>gD?C^IPTt*P5M5Y#L7nruPjX--=5%=751$oj> zUmj0L5{(@5y~zK$R2O7tI=szMn|edgk7H<<6GS#yi&3vaD$Fy{`TBNJHj&ndwc2%Y#dP3W1@s zJ=Cld0rBPs)-OIs)cs5lY7F!A(-w4lZ6qMt0}vHY+9sIw7yQ*nXLj+P2imvG&mAY-XC11K z7i#Xm%(`85O0rR5{Yc#Rlk-BlSHA7MM7IkR053~*t_Zm8>y7k=9S(e49}^ddmT-0D z6~iE9QaEpFYT~~*O5)$&W3SxXX-E2=YMk#mp=};bqP;oJQ(!t#&Y48&^4XWf`E^Go z0|Z4Wd#T&-qleVg?4IL~JdZB;WJzz{yqT$95k6=+%Hp-5A?r3^rc?%K=bev_+=~~r z(4&fEvEoOfr4_@!+^D!sC>XmT;AT6wr8}6Z)wCcT<7}`;L*nUtpSkLc4NeVK_70m~ zh33B+EIilWL#xyUhqVwVJX01Q3rkKHMH7RLd+G6NOuXL4yRlcpX!PZ=3T-VdX-jvr zc_C-xK^$6ar6$Q)lK&grWUF0xPR2JI3m9$;bWxMx)x5rO_J+c=XBDgXl50K;M?Nv%naAZv-57%QXxmh1H85C4L|SjTU#_7vP#s=~Lt&L5mb=6k+sl<&1Ji>(=^ zL5_+})Yw_Fw`e1Om-(YhJTxyA?ZyAj4LjGRqufyXK9~J{(3bP$^mEzITba-PzE|P7 zH~*_qmH8?A0q;^1C2j>q8ImBu#P>wWzdZ#j{RP2;KOOde&#%JpEJ-wI+)FSIXY@*% zB5epP=Sfj1_+Z1b+FvhQt~D+`kz(@v0z0Iw!`%Z5KHawQ(zaLk$JU{>JY&nlto7xu zufu;0f6uQ=CrfxMW+(^2SLDYeP!hrG^_Yu4g~q>|oH4p}z9v z>MOprc+2F$JLu5%rl&Yf#HIPKbK6!kxE#MjMTsz@$MyrvCjIF@OF{qnRs>~4pMR?b z-GC8)Q}uuSk~~7-f3@=d*C77yZr}g6udqe9`Fi&_i)pHkzt^1AqScXcDW1IfHd!J-RJq1Z^ zZLHi^V-Nl;kz-+%X^dDpT5u7DSGp5@oUz@k8NVuLr^8X5*V&fAhsDE;>aHI%U6|q` z`fZs6yXul@85sfUUUh)%qohUE4Swd;{0N{kp)A81at#7+aEESNI*p7vC`(1xkXg?cj;{5Rg-)A?YtN*iFBb-gL&Szh4k1SW9{nEvO z(#zTPg-2xv^~Edqi%~_c_3rf7A0%#X$fH;ngfe^e`1wf2^)Qd`zC2t?rsNurICbs+ zozW!zkc589Yj}QV`_QeQ`nws5vaQQXPdOXrq4nd}IrtInK}~8MlN30f8sRPF6ZqJg zlRW+y`}09wg>(MFgS2<5-W|P*b^S2T-s4O3=fQ=A+o<^Xe1GM>$S=rm&+3L}M%VJ3 zANX?C8IH_j!4s+egOR>l>&ZaN{LiD3Q~ATRmgL3F!=L^V@oH?2F~ zBUpNNIQS~?Tuf5y(v?1dnO#nSJ8QE4AI2qN=!Pt;fp_K)H$&hTe6Y97L=hv-ZF*u_KNaai$T*zsSYaSxERsi zLS>doBMNa-Wlt@yz%`+(%Aa~3*Er@WVjNQZ>XypuYr<>~>vq{w`{TT9?l+8B4`LKf6;!It@R(JUs#=k+(aMu12Yn1f-XzJA-$=Dv9 zT9Y&La?X;mpo%%`QpKP>7`7Omj9@*dQvOf*0~vRpKMDPWLikaa4X=gX9?3@Xv`x`} zPrr4+K9h^ua>dtHJ9x#N?T`#bL`F&!IVj_Lo~Jce1?J-Ptl>j}#qpH&T`ofW!6Z}^ z5e%aoiMn=+?{jk>X+PC4Hag*ikUHj1Y`e)T*_+YJRNuWu8Ego^JqCr=GK`&AkKS;*gMNS>asf zAoF)yCqwG3Ek!+vR(OX8nGGA?HB!zh6W%<%UgDJ1YUjjdxJ6$xZBq^=ygQjzye88& z-$Wa819L}rj}iS<#e_S*TX5<{NvgH6tbA+7omPBG(&q&19PyDXLX(%TaEtY*4-d1t z+Yh;n=iVumPEgmpCsb=>Jvxb&I?|=SuCU{GbC-fgv(N6|<)W4WaqlI{>;}$h`_hFR z&IL9`N5Lq!U%Qnp8wT387dM*?)z*k4&Q~!Ll*rH1R47C6Ye=`(5<;T8(_&VCT}0o& z$rf4|IehM_8#TmXp(%9Vi}c>*F^~5f@=M*9-CtI1bCJMi?g4@-b#EKD)m;>xAiOtxH0|3qs}P^w*i4w7{{J*dOHPJe|~OW-l^vsL$U0mh{0S_L^)f3{wQ2??&h;A@@xUQ*cE9+ z8}0E8E{*Sw!@@0h-+d#OR}=P=ZRHqlmJW^yQF~m1(-SF;`sS=^Yo9AmDEasOs@iBx z)!S=|KG#qB^=7LrxJWyiE=tlfM6&OrO>Jzr#2Pa$)C6Gebk2lfViu+0c4=}CCW=at zAyFlTYKrqvuP<&|S!o9e4kcGtC^bU^jN19T&9Q_=v^!)kPlEvdZp_Bsjn>3~w zDwKY?5`rBb=cwI+qDfai^}NnGOi#T`Q%Rm{cuFcX+0|!sq%YwY`9esR%(YUR>-(&CzT%y{$M?_v4Lsy3u*@3qC}5zj#};qEu=aP9+2K<*yspaN;0P=c zHuBV0IEO!iOR$iJOs&?QHD|g%Iz{R<^Zk`A_h^Xoqt0leaQ?+h?w4~CthV)ZYfVfH zgL?TpYo(W^%yeQ$yC+*Xh>$IACpm~t>|%G$elS#}M3iK0+Cpu2ko(G-s#=gri*$0P zuz8r6Nh+nr^9Jwb5mH}*<$)fqfAfxu%gVyNk44xOGRN$r8#KrM$1T^*Wg>TY1rGab zNDb61ZhN^=LeRERPhGja^fE4Q%3`*pGd;Bm<6qn#N*|h+h!zqsYod&WirgP~bF0uL zDhOgF95|LviV9PGZlA_{A?Ow4=#PHb)ZD(rBP*I6*P>(XUbTO4k0R7TJFyvkTO$#Fm>ta_f~9o*oEf0`u1^FO$t9xKTtXS3Ry@cmBe=@w+Ds>np3SCpD3Z37>~FMrr`e?AEV$N*014O|@N| zU8@BD!VzI66@mw@{%GiXiLUm`wGGN^$xqD?`zaOn;L~?E2sK7{J+P${lOiHSG6v)hh8Gdb8P!C(Kbfy%&p{23cDdM@AH5U}o`g;HNl@Bdn=6?6^YcO#; zIpuU-4pQkeJ7N(m1?}EepjzY8`{s4}12NaczWLr^oD$v5nb_j+K8SnMy0xT+DkRF7 zg10fEvGA%RNn4#>(WhvomRcrG8XDUdty2N-l8!B8Ta5ZH7~=7UBh&6^W27wHo727< z9dA`=yvwV5?YgTSN1w#&1YEfX)kK~B|F7J$b&w}>^*5JikEG(13|`_5lWXbs@n0Mt z3U2>YCMXz27$Y`4Z#ZWY{e>Bah`i?4t1b@_-xFKoA+zLB<;^y|?G%m_27cjSW!AkK zCX5I|M@rQrL;YxDoL~GIZL7WLNIaW=;uPp}J*x$%lsZ_p$DLHP$@mg?VU0)c0^Vn!m1^ z-_c4Jbo3373g|3gGEtpV4RA3zGb7oUdM$>^(P+RH60gv>xO;fzw_^k0<;2fV$b`Em ze&GglIIOQ0tnLQS@189Z;!kEUy{#C0*fJHf#!nc)^*xsBPS#!QT8Me%g<+V3OixcfiucyXnu_rcVHvVRMsgf!I4xoYn9BCF zDzW2?eMl2YD#(EHy)ZJHV+X`W!b8-1=37)xc1f}v+I_J#{QY7(>Jmg4*O{+>Rid~ZCm`}!aRJ$hC^j(^Uef1<& z^x!RW#xc>n1`(-JQYdS3J#$2}{bK`AmFRU@UN^1OHn%^IInlk(r$KZyMk9|1Q=vO| z@81^&;@7ut-y%DWfb!YW)<#ZA>64h4-~FA;mj7+t<1chdrMq2x_&m0Vj)t>~i!PAS z^ns>C!^A{ILGd~y1|Y$4h_O|6Iyc*!praPHo_r&?x9sgNpT*q0(* zs*xR_Hs&y-DQ09u<#w=EmbO@>#$od7H4s3Rvo&1gy2pMf(f|BNEC~$E?VTN7-3nM! zwct`HGE>rWna74@?w{=4{0%4jtIQ^vPo6yC-|ttrjnDQDsFh(MA+<-_v-m=u{6IS; z6$>V*`no9eWu(A3;&|Bq9(BG>-5c9XQAAzZt7zrDl%R0oA1ltp;^`uy@@l_Fz;!;V z2*pUr9!uWpLXa^Ptgt1SoQdfpu9mYm5WsS+rvzbPs1ew@t=-+!TwLJ?>tlVuB116V zPB&}1jT1aXfo+G9({91lmnus-={$>W)Dc-nXkF>uX;krhQ2-ZKrYd31`qLGBfx$`Q zw#KTQ`SQwR;5kOI=w5|cSevRz@VeMdfc50$H}p)M&CR|*<%+9&dwq8e8oSn${6rYd zC<3X#m{H15mWtsD0sjZVRc^J1J6f~xGYlAcQUFm`h&M>{GQC~{Uj$_Nx-yG%EPm6)oo@()3A z&em3NRk39t3%J62%YDAI3Mp`k8u!7lL(FwT>&W^T`I-(tPg~C*mC9uJw+@9i@m5iz8>RhRCT(7q(xkpGS z3G5I5j~`JbL<0viRD!{V*er%wfGDZ4Q8eMQ7&rc^nK+P`FPyph=xW6TM(t+JWf%0k z@mTe)U0hs@gBfENryyvF&&9=gGCbg8&zYGSnX)QaZ_L!JD6W*a2XmTkGcRbEePQzt zeK~^9%Ih!dJ6DU(K~(37#xb zxVyVUOga%ibmEPhTU^x7d&zVH0cmm)2J-9N`O@m@>d3G=jN2YH&tbJ1e}o`3mfB3C5YoDW?exM}$?K*Kn9T##Ul(Kw@u3M! z5drw@MlA4M0#37cbx^Nz^rkCNZ&dEe!0@YY6v5rgX=q42efnnc1i1dsd@+)NEqw-Y zh{Iwy1Uz&HEYc1{0k%2Q&?t;K?%6< zQGy=4K&V7CbIf}ZQ4p+Fpp4MM!VCX;^+bge!nUtnyN2+3Xv-6_v9k+|B_$@}LHq=c zIq?4yv^|e~C?&%+mLzF#_g4n=8~v~l8jdJ-xzK7b$$2*X)! z+`7e^v25BLh~EGNejacslyuX%mQd+S>y{DZ~(zVpxP~E2;*zdL$RL`C+zhp`jf^aImSEK&%Dm)?b_Sy7W*h zvFaSs_UZ(tZT;4CgSbR_B`P{XWdc7u`b^4#=v0@*(*9}fhi23V;=)uY^@TR*?B7qoCeSV-m>2av3R%lWOKHFB6-QTZBB^xg_QSLBOWR5%g zGl7pSm{g#ji4BFMPFnVFp(XMS+ zg}S=B{M(K95H<^hU+vswov|WwF)+h)u88*eR2{24^p%(q$DkQ6M~1{{5GvIl6mOdvbRcilHbqzFVb z1dW69j6XF~zzYsGwy>M`s91p5+}&abvk*!j^oOt-n(^y*-CI*IW(ZEe;%0$tp`4>7 z4W#v)ssjSZz>L_Vl_x717Ndp!q+VxO03v{JkB~V5)e}KF?~@gBNudl14o-#S2@mvp zb+sMB%P|nAOh)o4Jx=x>fPM!C9dJcky$>4mDCebzbQy$d(Ef~6I9aEA0Hqq_CP|tV zjz>pF2NX2rVT;d zlg~{|XaIH?0PDtiTMt$+7osk9q&8`3Zt_@FtaGglW=YD)Va0G+>J4V9#+z!KpPk`x znB0L-3`_M<=7+e|Q zE?(!W+Ns1rXCO>MQ zI8Q%avw{mDRDswvkCKrEd5Ss^1C)P=Ob3zmE$C^GDEr7ZL0Z$;D9mfWWK(b7prxe+ z3a*rKWVzR{2*%=mWFvSycMp8213a?+^5U>Y{`8FJO|f>3=QR|R?O)F@HG2y%5vnbS zAaTG{g|Zc*X);(Kwq`iss^?|@p*Y)uLAtPmATPPJG!mF3toBPU!otEJojw5Z1%!Xs zt34qhcR(ju$aiTF%obpeBGpqk`dQt~t9K)A_zmhYa4p zTI)7M$9&U1;0m2FwaTdhB_S1|t%~Lh0NGi&<9Zv!$aX+YflYdKfVSY&(eMF~^xp&r zVBM8^4Ni{f)bLaH}Z8h zo8OONfNtA}*Q5ZFO@geDB-!kk-J=*`t_uq*#~dA2B2I)M=4b(LC! zr$fO2R?^TH9vdqqBZJ|v(hp;R-Vclr{pOFMp`p_w#&ACz=7WKd;t`P+{IT@>U@VHm z^e%{+YM1Tf2lfhapTTV+WLC-<`>`J-B_$z#-6bS+^QNO`)&F_>?EKsXY6%|Oxf|A1 z`-8Moms~MHU?H!7!;H{XAT&=O;dY;_Rwy<#HvWP`ILuldU_>&f*6(3l;i8FPEtPw{ zk{yw(vu_4*@bO*hmnw+rQsp0tT=fTn#~JE;MBB|IuD(_#CW_%(}RPlnfG}bR4e(n4&I7HGp4;1$wIX z`9x5)L1-%Qy7UCe3aAz+eDzKi&>f7;;ii3#2EY zoINs?hFH_s+?-%P2GMCa-%!#;^FkbaKj7%dS@7aWUv?ef^8(}@kWrE#0t5p10;6{a z9>aBzoZoQ`5A1>i&SEiHdHnet)MjIL9X&~6E(asVroG>9sux>)1F~8WA-C%RIzV)U zbA7B))b2xA%574?*a&UUD4-$cxgYP`8=O3ITjz6J`wH#{fqoZi4c&r~uA}&J$c9&r z&UU*6C{6+0FO3$_3!QBtgO8T682w9^%v z)%qZti!dmjKc=In*N0jbfKCtyT({cjb66k@moRL*?k&lIlvQnxgy~~-Tzd)OxfVWN{`CzRbiAL#!+W82<`)n+ zZXms=oooH1xgOPN1V5x-X9kri=pEV22N@8$T1eR4bTe@mZ>b~gU}8@o)`Jm z2W!BuUcCZ8{plbjFE8)&R0S|Kh^GK4DyrT&&w`wgsZ0;34V1aQzka=-l8Sr`)f5Ot z6AKIb_uUl-L_M6P`g(hhhH5TE!2Xwqa!3)-x;dD1F{@gZRk;StA+2| z&P-2x2M5dg7}jRwgOW{>s3(VwjSW!Az+^)SbVLy54T&tS0B^rG zTURxqF;_lTR>lDgVSAp7tOK!uf2W0_@?g{)Q3(V1AFPNy;yy)@gD{R2+Aal3)F?K?TaX*)0b@f8hZQDh=;HI|`=H!Yd)|TbFBf2G ztb`earr*Gsvriw!$5(-~C%l3{e`_5F8(V2K6*P7*yopd!1rqUux$G|Ff%dc-D(qX$ zamR+{nx3s@EOpLN2qWSkg@*V zP50CF65~$Z({1@ZjoAshcqQMbzhPgW~TBgPlO%+`MAS!Z?cS0p`o$yr&{|n!flEX0 zW~=d@EYf^aD%{0(2YWX{o+^00*Jn0{*hB#GAQcZ!S^eE#`%j>lgtEXGb|#2ew=H|& znKK4;2dl@4J))J^b$U_W4$-)!qvJdD%0N52yo}gUAj6UxE(7^dYi*0p;iUO0vJ2`GhQ+mAuVnC{(5&6KHHNw#lHQeAP71`cA({&53aNK-am4`9z3{{=K~zqFDCN}D z+Mq0DiIM_Nc`kIpB=iy5V_x29kh$xz-~qC!H7hFLxb8ybt8Eh@IytpQFW+=cnfY2_2?Bjcxm>$t!y_5(IXo&@Ep4$Qet9h zM@O#C816;r3pwmB+Vi%;J{3^F0VIXJ7=%qsOp3M#eVh9&xY%JLpqC~ES`}bHE-jfr zDK4iw(gK=l$b@2Gfr!(TuV(85Ld~w%amY!BO*UAelLH$?2zs6@Q$wo)pfLjKmzF+) zu|ueh5oHZDabo#hb}}h_A;lnoH=>njro>RT81H5R^)CV;85$ZQ_N5@SD)s*U{UIc? zNIaet+0_e(-T zH*}5bgf5S}?U>AC;Vq&RMuK*Me}R$7v*TblM05Gpty@ekl{H@?BU@m*hbSR0K?uh) zp<*P^1o8X|AP_|JAyHA{aDQ;)hz19gJ?)&~CkC*jfvEPtgkvFBD7j?bLbUOB+!Pj3 zf_^MgpU9gkW*F`g%yhgj{{X7 zN(E>$6Z6{t1{ji(nHdQEtStx#Wd|yU(R6flGhl`KZJ%io6$^M5Y|L;3F-yY|(fCI+ zlQXi*Z+UrnLB$GeTikW6H>nYe{O7S*T2%yq1hcD8%-|+@0Ovy|+dqTM61Fnw_PS{3 zHwcb6}VKEA$Cv=AX=>i-m3dQBgAKOCt*-=$(zur?JxNHm(mwEh?9PH*0v zjxvr<4{?f!?lfw!D$!?)0@*nBM!I>C+AH2T*ji!D(Jg4B+m#iPETZFv*mYwquNk3j zg?K?hO}&^oqydfDWcG08FNmHafHGFSM!y215nNo{ij8|38XE4(Px_~Aa;+wKp#YlY z4LB?T+yOueBLJ6q0nze>1_yN02RY5p_dXy)QU|QB9fr373joj>(@xTFsITuTn=mWd zL9A#Qw1x%XM?>iI8^edK8#FKP-LM>uefMtkQcsYLEpc>Lz4-Rf8g3}B9$Sn_PbLrb zr?9Rv?PD5w?#}__`(h5q&ZA|5L!zRhimqo-&BbwhYU^)-nQA9^^QM0zX>i%^VzUgu zh=`?^n)7vQhXcbZ4t|KYDS*xPZMi9h6{|lRomZcOF#qZcN4DmLpr(- zfO8OY$z?H&R10T!fvzpg&;u%}_u%iPGREUB5NaSpBMKlyBN#5$MfcchvNB5Dsw}xn z@68S=2`rSvz+OFl-=6v2V&x&iP+|fe=5l`1>yi(Q3^%JA4S!SMaJ&IxnMaQv0@{}0sg?Nukn7B& z3k}6G_?}vRk-dwbNcBlv`{+YImRl6@r?MS4EXac^?``G2U!*aSqMV(zZ5oe%7r%$- z07LneqLlW8X*DXCgw zMeKFlt_@ueH%(vna9B2Fv0IQrw2&v=ccl^G8!-P-yY@vrqFW0-=qwlT?XeI3;bKPl zzzrzcgb8kyj6eG$by-QRuYU@Sb#V!a8EC}YIX&t{V$dxA47f}p? z9@)1%2cefA$}>c2KnSv6TMR4$f?NNGvA2M#vhBKsHzJ^dfQkr`f)b)2-JpVipdcY2 z(kR{CU?5#0C8czCH`3kR4bt84ukG{V_q^XZWBg~2Auw>W@4BuPbImo^WANCpn%@IN zj)#X=$T?)jZN7l(bl4pg!m5W4av%0!N(|qKDMsBwsH4XpD{`SV~p@ zLK*|K&w?HCM-a`-?xiz_mMwJ5E7%|3R{6HO#2nN3sexW#<0_Vk6%EDJkEWu3j*L9` z9E-p<#bxh>U*21Mvte=x0p|K)CDkaZ`!Agmq|Yvg@RS-4h|#vS-(4JFvpn6#=G3Vl zB^k5P>7KqXG`4xyXr#Y&^rr~PZx&Sw0V;lv1Ydq^*NCstJYCoKa%Tkos#YFx`_TsB-n;g{oX+7W|0hEvgx{H5r{@cqLgEAwZK`ZzM^@n^pwZx-^^ zF#8;>6TPM2IkRc^^qajwW&$sv3r`igG-g-~?PsKec-UP^y)Ih0(n#Gi8mF>8+~4YL zE|@m|s4^XIPRika*$jW<iONoPpFw3`@&L>CnS9gRUEHT-YQ}#_6=#OTsmth&x0k}fY0M_d`V~Ua#&twn}($L zKO!}7j*5{oxM>0r7%!sxLrT_-y23|tr}g)3QK+#Ej91nMj4qtixBrxUe2Go(nk&0g z>)e`hl^O$TWpjPh9rj}vw$Th|91pOym&+xvn%@*`jr1lk9zDq|Q^(W9F_Ka*$T{_#SFCMFRMuFuYkdIE zTs;Rb({9IgSz$xjyAAD<=kICTm0B|S`pp8(DCRcj3FDz1;#T&IvBtmx-j}}q-2<8C zr_V^vHp)^84~)h;EEZl8kCvAX?Rk%Bti?NInC!FaeCgCyKf*D}F{|Z%J?ALW?1L4y z$>ANAU)5ai8-0w0ZMc6SCxLy%)~BlCx!ER@c;;#IJco^ScgA!E#Vv_2>odD_C#Tb2 zt?%xVChl@_^b=U7*$0>RxBZkpThf^!6I3(2t;c8cH9+{cW!+DijQ0s2-bM1XFsSgY z4OyBGpDCU}@g-1MT4>}DN5OKTU0A}$f`p8a*Go^UtWEf=@XK*a0Bf;jcv3#+>)|DJ z1G8i*4Q@H{*TJ4mv`DXnd=-r(k}C)o`xbgv1(0gi`+ACq4TvqJQxfnmy*%BUdmtyt zGF@}0&v6$kf6D%;!ZT*;uId@Bds$8=2?(#S11^-Rw1M?rPx(zI?LnOmn|etFbr3>Q z-Q2z~u^;)Gc)Z}YaHuytgd)@5(r}q~xn~K40x(wWRH{!c&hA<6iNdC66y^H@-e@m* zFAMLT#-q?h<~hT}WlI#~$@5p=q@She@W%B4(hET4hZUi}ylPvhV4aIGV5@nkzK4Z7HJx zbQVpMnHo8Gs!TS8`QAlaXvblnb56IkXmZ{Vnx81vjqNb0lp8ZUzEm*YS!vI*Y89?o zJ-y5jg%C}9#>&;dXnw)Z-`Y8f|Ii8Xx=nY9>sYpHYR{iIC!$ObzuRa;KcD^xC+=R5 zC!1qJ_w%IIkDb*eJo&m~>_g@iSH#rVD(nx4g#toPzr}^dPkGk(9q(b=y~!)G9)imuTXe@jG&H|R?KCq^ zXUttQdsvnp*;af{!avj;?`-1HCew9>q3H*=B*YbXCM6v%uXU`2iz&%jyyPrD(u&3q zry{@m@mM+|I4A<$&t~(|K`6DJ{Yqlf!HkSShG$-5(s!Sgmhj}~^!F3aJ<5z}%tvjK zM>f`-YeR#}Z;lw>23KG|{`Fx8Hc!=$B{KEKq>tK`O^n&nJ}7?I3q0M#Q7?P`u0Gv~ z>MAv0P{>_rEI2D_wrJ1$EI_otr>@IdM)Zi_rL{FH#UqxFV=-&LR3BZhFk*e|a#Rpk zvl=ZBrFU7czxk%H&4ZHmVg}uoHZrBN{F}2T)s$kFu)N8sS+Sj^^!)XL#4I-%hjt4+ zYEYNlhPRjz-U5^htaJ2oM5uNAm9XOnH%C(tv2`nVO9lA3cA{QQdXA6Rp%vDhP21s2 zX9i!G&Dk#Y4VV3S$!v}QmJe-{81=@4EitG$)bGh|ad?yvz9ij8|I(GUW__DouR8KI z83Gr-H>_bn&HixtUH_8Cs1`mI@AjRS-}9=MXT3YMDK=Fe%Ky~HnBcugtTww%iJGMDjpR5$RhHhY9Wo>M`w%C7+<<%Fc_NFtb&^C zIL`5q{o!fq8)eqUlK|m@SK(35OzWwV3K%j^Wm#4z4}mkmIPfhrO#W<|E!GPHak(y zzs)2$|7xfP-?%Bb^!U{l8+eb`^5{4dGyX5JB9AYD1#c2f%U$Mh9@AK*;z;F1pvU-c zcQ>!NDH$FT6 zF6)ugn_rWyDkZaymQu_K!6|5&__JB3Ia(ZrI<$zNY0)T!8~!SuHvw#RcAj{29mil| zf9$na)BzVGx6`}vLkUHf&fjgkN?s}MyJdA#<{a*$Wfy3op4(b4S(y`>PNUrtbPB8P zi?+8s&UK66FT;E_dnEL_jeTz`M|^5}PY?UnyI=;b;f0?3-=TzIImhj2&_ZQS!DC8t{y3GBynE&KKv zbxEiD~ft9oI zDQo#swZGKdYNLx)Cq29z$2PT_YChV(k(-^pNhtV5^nTd;I5yKR^@ELwBCWNYKvk~1 zi<Eq@%xtC6oo`KLjk;?3mm7Mpnr&j6X57wGW)e-P>P2ATs8f^q@Nv877TUM022V zT0z+7sosvu_fXlsH4{5&JaFLHiTc@UL3nRc`k;EmcQEIWlI?**`H&gP{j}t$pUoY# z)<@{FG|J(9EZKC6m-C_wb`CJvH5l?>=?R!PvWX|4CZ0OPFy%Em*o9vGwAfE<$zHy>_{Hpet?%oQIO-iSWuXhh7!^@iwGaEH`P7hUVYtCPGKrd!+zx(-UI6bZ>?^s-;2 zduP?(f0IU*UXZUYza(-63{xpzX-&HL_w^`uNsnvucuS`d+0q&`ba~f_@m(618~e`6 z#MKP%Bc9nT?(egqlb_U}V4lAR~W<^b-5*70h;Wt?iKl&~tDD4+mv)W5moF5pd zkYbRdlcGI^lWI{bDXXw^tDV(9(DYk;T6E(}31bJwlee;BC+hE`ao+u?59 zy=UomlzrdwXo8jK&U{gc$|v$G7-F_68}$!0t6Z)M(z~|=2qWaT8u>5jc1AK^n< zC_1%ARMYf8%HOeS^7WihS7#a|8=@JK%nMGVC;Cdey54OMv+!`cvNZxX&|EEIbp+)c z4=ZeD;>j{Hjg})Y7nl~%yKd~3Tp>W8UL<=SemMMU$Crvpe3Wc`*)hd&Jn@BrS;c+0 zag9c%`vtm(#}S^@%1xaHXVU|_@4cdSsN@uFTs_z;P~YdPf7P(;NIDbzai}MHe42+h zuhpG3F37b@(!Tn-qTDd0#8PH1dj1Qq?({TRbnjY$|Mdb)RCI71y-`+ExM?L=F$TUV zG!5bu@c|&*b5}JioV*)hj

aH8#k}5pYc2@mZA@ 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 mCV>&c8<=z;EGt17qvJ6ohUcJGW>MRJ^bB@4 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%0D(khDThT8xvWY7- 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 E0o4quGXMYp literal 0 HcmV?d00001 diff --git a/docs/software-architecture-and-design.md b/docs/software-architecture-and-design.md index f59204b60b..b530911b37 100644 --- a/docs/software-architecture-and-design.md +++ b/docs/software-architecture-and-design.md @@ -11,7 +11,6 @@ * [Ball](#ball) * [Field](#field) * [GameState](#gamestate) - * [Intents](#intents) * [Dynamic Parameters](#dynamic-parameters) * [Protobuf](#protobuf) * [Important Protobuf Messages](#important-protobuf-messages) @@ -61,7 +60,6 @@ * [3D Visualizer](#3d-visualizer) * [Layers](#layers) * [Simulator](#simulator) - * [Standalone Simulator](#standalone-simulator) * [Simulated Tests](#simulated-tests) * [Simulated Tests Architecture](#simulated-tests-architecture) * [Validation Functions](#validation-functions) @@ -101,18 +99,10 @@ The Field class represents the state of the physical field being played on, whic ### GameState These represent the current state of the game as dictated by the Gamecontroller. These provide functions like `isPlaying()`, `isHalted()` which tell the rest of the system what game state we are in, and make decisions accordingly. We need to obey the rules! -## Intents -An `Intent` represents a simple thing the [AI](#ai) wants (or intends for) a robot to do, but is at a level that requires knowledge of the state of the game and the field (e.g. Referee state, location of the other robots). It does not represent or include _how_ these things are achieved. Some examples are: -* Moving to a position without colliding with anything on its way and while following all rules -* Pivoting around a point -* Kicking the ball at a certain direction or at a target - -There are two types of `Intent`s: `DirectPrimitiveIntent`s and `NavigatingIntent`s. `DirectPrimitiveIntent`s directly represent the [Primitives](#primitives) that the AI is trying to send to the robots. `NavigatingIntent`s are intents that require moving while avoiding obstacles, so they contain extra parameters to help with [Navigation](#navigation). - ## Dynamic Parameters `Dynamic Parameters` are the system we use to change values in our code at runtime. The reason we want to change values at runtime is primarily because we may want to tweak our strategy or aspects of our gameplay very quickly. During games we are only allowed to touch our computers and make changes during halftime or a timeout, so every second counts! Using `Dynamic Parameters` saves us from having to stop the [AI](#ai), change a constant, recompile the code, and restart the [AI](#ai). -Additionally, we can use `Dynamic Parameters` to communicate between [Thunderscope](#thunderscope) and the rest of our system. [Thunderscope](#thunderscope) can change the values of `DynamicParameters` when buttons or menu items are clicked, and these new values will be picked up by the rest of the code. For example, we can define a `Dynamic Parameter` called `run_ai` that is a boolean value. Then when the `Start [AI](#ai)` button is clicked in [Thunderscope](#thunderscope), it sets the value of `run_ai` to `true`. In the "main loop" for the [AI](#ai), it will check if the value of `run_ai` is true before running its logic. +Additionally, we can use `Dynamic Parameters` to communicate between [Thunderscope](#thunderscope) and the rest of our system. [Thunderscope](#thunderscope) can change the values of `DynamicParameters` when buttons or menu items are clicked, and these new values will be picked up by the rest of the code. For example, we can define a `Dynamic Parameter` called `run_ai` that is a boolean value. Then when the Start AI button is clicked in [Thunderscope](#thunderscope), it sets the value of `run_ai` to `true`. In the "main loop" for the [AI](#ai), it will check if the value of `run_ai` is true before running its logic. Here's a slightly more relevant example of how we used `Dynamic Parameters` during a game in RoboCup 2019. We had a parameter called `enemy_team_can_pass`, which indicates whether or not we think the enemy team can pass. This parameter was used in several places in our defensive logic, and specifically affected how we would shadow enemy robots when we were defending them. If we assumed the enemy team could pass, we would shadow between the robots and the ball to block any passes, otherwise we would shadow between the enemy robot and our net to block shots. During the start of a game, we had `enemy_team_can_pass` set to `false` but the enemy did start to attempt some passes during the game. However, we didn't want to use one of our timeouts to change the value. Luckily later during the half, the enemy team took a time out. Because `Dynamic Parameters` can be changed quick without stopping [AI](#ai), we were quickly able to change `enemy_team_can_pass` to `true` while the enemy team took their timeout. This made our defence much better against that team and didn't take so much time that we had to burn our own timeout. Altogether this is an example of how we use `Dynamic Parameters` to control our [AI](#ai) and other parts of the code. @@ -122,7 +112,7 @@ It is worth noting that constants are still useful, and should still be used whe # Protobuf [Protobufs or protocol buffers](https://protobuf.dev/) are used to pass messages between components in our system. After building using Bazel, the `.proto` files are generated into `.pb.h` and `.pb.cc` files, which are found in `bazel-out/k8-fastbuild/bin/proto`. -To include these files in our code, we simply include `proto/.pb.h` +To include these files in our code, we simply include `proto/.pb.h`. ## Important Protobuf Messages These are [protobuf](https://developers.google.com/protocol-buffers/docs/cpptutorial) messages that we define and that are important for understanding how the [AI](#ai) works. @@ -142,23 +132,11 @@ The `TbotsProto::RobotStatus` protobuf message contains information about the st * The capacitor charge on the robot * The temperature of the dribbler motor -Information about the robot status is communicated and stored as `RobotStatus` protobuf messages. [Thunderscope](#thunderscope) displays warnings from incoming `RobotStatus`es so we can take appropriate action. For example, during a game we may get a "Low battery warning" for a certain robot, and then we know to substitute it and replace the battery before it dies on the field. +Information about the robot status is communicated and stored as `RobotStatus` protobuf messages. [Thunderscope](#thunderscope) displays warnings from incoming `RobotStatus`es so we can take appropriate action. For example, during a game we may get a "low battery warning" for a certain robot, so we know to substitute it and replace the battery before it dies on the field. # Design Patterns Below are the main design patterns we use in our code, and what they are used for. -## Abstract Classes and Inheritance -Abstract classes let us define interfaces for various components of our code. Then we can implement different objects that obey the interface, and use them interchangeably, with the guarantee that as long as they follow the same interface we can use them in the same way. - -Read https://www.geeksforgeeks.org/inheritance-in-c/ for more information. - -Examples of this can be found in many places, including: -* [Plays](#plays) -* [Tactics](#tactics) -* [Intents](#intents) -* Different implementations of the [Backend](#backend) - - ## Singleton Pattern The Singleton pattern is useful for having a single, global instance of an object that can be accessed from anywhere. Though it's generally considered an anti-pattern (aka _bad_), it is useful in specific scenarios. @@ -211,19 +189,17 @@ Read https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern for an intr We use the pub-sub pattern to facilitate [inter-process communication](#inter-process-communication) in our system. Through a class called [`ProtoUnixIO`](../src/software/thunderscope/proto_unix_io.py), components can subscribe to receive certain [Protobuf](#protobuf) message types sent out by other processes or system components. ## C++ Templating -While debatably not a design pattern depending on who you ask, templating in C++ is a powerful tool that is very useful to understand. [https://www.geeksforgeeks.org/templates-cpp/] gives a great explanantion and example. - -We use templating in a few places around the codebase, with the most notable examples being our [Factory Design Patterns](#factory-pattern), and our `Gradient Descent` optimizer. - +While debatably not a design pattern depending on who you ask, templating in C++ is a powerful tool that is very useful to understand. We use templating throughout around our codebase. `learncpp.com` has a good explanation on [function templates](https://www.learncpp.com/cpp-tutorial/function-templates/) and [class templates](https://www.learncpp.com/cpp-tutorial/class-templates/). # Coroutines + ## What Are Coroutines? Coroutines are a general control structure where the flow control is cooperatively passed between two different routines without returning, by allowing execution to be suspended and resumed. This is very similar to the `yield` statement and generators in `Python`. Rather than using the `return` keyword to return data, coroutines use the `yield` keyword. The main difference is that when `return` is encountered, the data is returned and the function terminates. If the function is called again, it starts back from the beginning. On the other hand, when `yield` is encountered some data is returned, but the state of the function / coroutine is saved and the function does not terminate. This means that when the function is called again, execution resumes immediately after the `yield` statement that previously returned the data, with all the previous context (variables, etc) as if the function never stopped running. This is the "suspend and resume" functionality of coroutines. See the following C++ pseudocode for an example. This coroutine function computes and returns the fibonacci sequence. -``` +```cpp int fib(Coroutine::push_type& yield) { int f1 = 1; int f2 = 0; @@ -266,6 +242,10 @@ We use the [boost Coroutine2 library](https://www.boost.org/doc/libs/1_71_0/libs ## How Do We Use Coroutines? + +> [!IMPORTANT] +> We are currently in the process of moving away from using coroutines and transitioning to using [finite-state machines](#finite-state-machines) for all our STP logic. + We use Coroutines to write our [strategy logic](#strategy). The "pause and resume" functionality of Coroutines makes it much easier to write [Plays](#plays). Specifically, we use Coroutines as a way to break down our strategy into "stages". Once a "stage" completes we generally don't want to re-evaluate it, and would rather commit to a decision and move on. Coroutines makes it much easier to write "stages" of strategy without requiring complex state machine logic to check what stage we are in, and it's easier for developers to see what the intended order of operations is (eg. "Line up to take the shot" -> "shoot"). @@ -273,15 +253,15 @@ Specifically, we use Coroutines as a way to break down our strategy into "stages In the past, we had issues with our gameplay logic "committing" to decisions if we were near certain edge cases. This caused robots to behave oddly, and sometimes get significantly slowed down in "analysis paralysis". Coroutines solve this problem by allowing us to write "stages" that execute top-to-bottom in a function, and once we make a decision we commit to it and move on to the next stage. Here's a more specific example. In this example we are going to pretend to write a [Tactic](#tactic) that will pass the ball. -``` +```cpp def executeStrategy(IntentCoroutine::push_type& yield, Pass pass) { do { yield(/* align the robot to make the pass */) - }while(current_time < pass.start_time); + } while(current_time < pass.start_time); do { yield(/* kick the ball at the pass location */) - }while(/* robot has not kicked the ball */) + } while(/* robot has not kicked the ball */) } ``` We will pretend that this function is getting called 30 times per second to get the most up-to-date gameplay decision. @@ -308,64 +288,147 @@ A finite state machine (FSM) is a system with a finite number of states with def [source](https://www.block-net.de/Programmierung/cpp/fsm/fsm.html) ## Boost-ext SML Library -We use the [Boost-Ext SML](https://github.com/boost-ext/sml), short for State Machine Library, to manage our finite state machines. This library defines state machines through a transition table, where a row indicates the transition from one state to another subject to _guards_, _actions_ and _events_. The syntax of a row of the transition table looks like this: +We use the [Boost-Ext SML](https://github.com/boost-ext/sml), short for State Machine Library, to manage our finite state machines. This library defines state machines through a transition table, where a row indicates the transition from one state to another state using _guards_, _actions_ and _events_. The syntax of a row of the transition table looks like this: ``` src_state + event [guard] / action = dest_state ``` -where the src\_state transitions to the dest\_state, while performing the _action_, only if the _event_ is processed and the _guard_ is true. Events are structs of new information that FSMs receive, so _guards_ and _actions_ take events as arguments. _Guards_ must return a boolean and _actions_ must return void. An asterix (\*) at the start of a row indicates that the state is an initial state. The rows of the transition table are processed in order and the first row to match is executed. +where the `src_state` transitions to the `dest_state`, while performing the `action`, only if the `event` is processed and the `guard` is true. _Events_ are structs of new information that FSMs receive, and _guards_ and _actions_ are functions that take events as arguments. _Guards_ must return a boolean and _actions_ must return void. An asterix (\*) at the start of a row indicates that the state is an initial state. The rows of the transition table are processed in order from top to bottom and the first row to match is executed. -The library also supports hierarchical FSMs. Sub-FSMs are treated as states where an unconditional transition occurs when the sub-FSM is in the terminal state, X. -``` -/* omitted rows of transition table */ -SubFSM = next_state, // Transitions to next_state only when the SubFSM is in the terminal state, X -/* omitted rows of transition table */ -``` -In order to update a subFSM with an event, we need to do the following: +The library also supports hierarchical FSMs. Sub-FSMs are treated as states where an unconditional transition occurs when the sub-FSM is in the terminal state, `X`. +```cpp +const auto SubFSM_S = boost::sml::state; + +// ...in the transition table... +SubFSM_S = next_state // Transitions to next_state only when the SubFSM is in the terminal state, X ``` +In order to update a sub-FSM with an event, we need to do the following: +```cpp const auto update_sub_fsm_action = - [](auto event, back::process processEvent) { - TypeOfSubFSMEvent sub_fsm_event = // initialize the subFSM event + [](auto event, boost::sml::back::process processEvent) { + TypeOfSubFSMEvent sub_fsm_event = // initialize the sub-FSM event processEvent(sub_fsm_event); }; + +// ...in the transition table... +SubFSM_S + event / update_sub_fsm_action +// When the parent FSM is updated with an event and it is +// in the SubFSM_S state, the update_sub_fsm_action will be +// invoked in the parent FSM. In turn, the update_sub_fsm_action +// will update the SubFSM with an event by calling processEvent ``` The convenience of this syntax comes at the cost of hard to read error messages due to the functor and templating system. ## How Do We Use SML? -We use SML to manage our [Tactics](#tactic). Each state represents a stage in the tactic where the robot should be doing a particular action or looking for certain conditions to be true. An example of this is the MoveFSM. While the robot is not at the destination and oriented correctly, the FSM is in the move state. Once the robot reaches its destination, it enters the terminal state, _X_, to indicate that it's done. SML also allows us to easily reuse FSMs in other tactics. For example, if a shadowing tactic needs to move to a particular destination with a certain orientation, then it can use the MoveFSM as a sub-FSM state. +We use SML to implement our [Plays](#plays) and [Tactics](#tactic). Each state represents a stage in the play/tactic where the team/robot should be doing a particular thing or looking for certain conditions to be true. An example of this is the `MoveFSM`. While the robot is not at the destination and oriented correctly, the FSM is in the move state. Once the robot reaches its destination, it enters the terminal state, `X`, to indicate that it's done. SML also allows us to easily reuse FSMs in other tactics. For example, if a shadowing tactic needs to move to a particular destination with a certain orientation, then it can use the MoveFSM as a sub-FSM state. + +If you're having trouble understanding the SML syntax, take a look at [`docs/fsm-diagrams.md`](./fsm-diagrams.md). It contains automatically generated diagrams of the FSMs in our codebase, which can help with visualizing the FSM control flow. ## SML Best Practices -Boost-ext SML is a library that supports complex functionality with similarly complex syntax and semantics. If complex syntax is misused, the complicated error messages can make development difficult. Thus, we need to carefully choose a standardized subset of the library's syntax to implement our functionality while maintaining high readability. -* Only use one _event_ per FSM: In gameplay, we react to changes in the [World](#world), so since there's only one source of new information, we should only need one _event_ -* Only one _guard_ or _action_ per transition: For readability of the transition table, we should only have one _guard_ or _action_ per transition. This can always be achieved by defining a _guard_ or _action_ outside of the transition table that checks multiple conditions or performs multiple actions if that's required. -* Define _guards_ and _actions_ outside of the transition table: The names of _guards_ and _actions_ should be succinct so that transition tables rows fit on one line and readers can easily understand the FSM from the transition table. In other words, no lambdas/anonymous functions in transition tables. -* States should be defined as classes in the FSM struct so that users of the FSM can check what state the FSM is in: -``` - // inside the struct - class KickState; - // inside the operator()() - const auto kick_s = state; - // allows for this syntax - fsm.is(boost::sml::state) -``` -* Avoid entry and exit conditions: Everything that can be implemented with entry and exit conditions can easily be implemented as actions, so this rule reduces source of confusion for the reader +Boost-ext SML is a library that supports complex functionality with similarly complex syntax and semantics. If complex syntax is misused, the complicated error messages can make development difficult. Thus, we have carefully chosen a standardized subset of the library's syntax to implement our functionality while maintaining high readability. + +* Define _guards_ and _actions_ outside of the transition table: The names of _guards_ and _actions_ should be succinct so that transition tables rows fit on one line and readers can easily understand the FSM from the transition table. In other words, no inserting lambdas/anonymous functions directly in transition tables. + + To aid with this, we have **macros** in [`software/util/sml_fsm/sml_fsm.h`](../src/software/util/sml_fsm/sml_fsm.h) that generate named lambda wrappers around guard and action methods you define in your FSM struct. There are also macros for generating state and events that will be compatible with the SML library. + + ```cpp + struct KickFSM + { + // Define states inside the FSM struct + class KickState; + + // Define an event for this FSM + class Update; + + // Define your guards and actions as member functions + bool isBallInDribbler(Update event); + void kickBall(Update event); + + auto operator()() + { + using namespace boost::sml; + + DEFINE_SML_STATE(KickState) + // Equivalent to: + // const auto KickState_S = boost::sml::state; + + DEFINE_SML_EVENT(Update) + // Equivalent to: + // const auto Update_E = boost::sml::event; + + DEFINE_SML_GUARD(isBallInDribbler) + // Equivalent to: + // const auto isBallInDribbler_G = [this](auto event) { return isBallInDribbler(event); }; + + DEFINE_SML_ACTION(kickBall) + // Equivalent to: + // const auto kickBall_A = [this](auto event) { kickBall(event); }; + + // You can use the macro-generated states, events, guards, and actions + // in the transition table + return make_transition_table( + *KickState_S + Update_E[isBallInDribbler_G] / kickBall_A, + ); + } + }; + + // We can instantiate this FSM and update it with an event + FSM fsm(KickFSM()); + fsm.process_event(KickFSM::Update()); + ``` + We also have macros for working with sub-FSMs: + ```cpp + struct KickFSM + { + class Update; + + // Define an action that will update the sub-FSM + void moveToKickOrigin(Update event, + boost::sml::back::process processEvent) + { + // Make sure to call processEvent to update the sub-FSM! + processEvent(MoveFSM::Update()); + } + + auto operator()() + { + using namespace boost::sml; + + // Declare the sub-FSM as a state + DEFINE_SML_STATE(MoveFSM) + + DEFINE_SML_EVENT(Update) + + // Similar to DEFINE_SML_ACTION -- generates moveToKickOrigin_A + DEFINE_SML_SUB_FSM_UPDATE_ACTION(moveToKickOrigin) + + return make_transition_table( + *MoveFSM_S + Update_E / moveToKickOrigin_A + ); + } + }; + + // When instantiating an FSM with sub-FSMs, you need to + // pass in instances of all the sub-FSMs structs along with the + // parent FSM struct into the FSM constructor + FSM fsm(KickFSM(), MoveFSM()); + ``` +* Avoid entry and exit conditions: Everything that can be implemented with entry and exit conditions can easily be implemented as actions, so this rule reduces source of confusion for the reader. * Avoid self transitions, i.e. `src_state + event [guard] / action = src_state`: self transitions call entry and exit conditions, which complicates the FSM. If we want a state to stay in the same state while performing an action, then we should use an internal transition, i.e. `src_state + event [guard] / action`. -* Avoid orthogonal regions: Multiple FSMs running in parallel is hard to reason about and isn't necessary for implementing single robot behaviour. Thus, only prefix one state with an asterix (\*) +* Avoid orthogonal regions: Multiple FSMs running in parallel is hard to reason about and isn't necessary for implementing single robot behaviour. Thus, only prefix one state with an asterix (\*) so that there is only one initial state. * Use callbacks in _events_ to return information from the FSM: Since the SML library cannot directly return information, we need to return information through callbacks. For example, if we want to return a double from an FSM, we can pass in `std::function callback` as part of the event and then make the _action_ call that function with the value we want returned. * When a variable needs to be shared between multiple states or can be initialized upon construction of the FSM, then define a private member and constructor in the FSM struct, and pass that in when constructing the FSM. Here's a code snippet: -``` -(drive_forward_fsm.h) -DriveForwardFSM -{ - public: - DriveForwardFSM(double max_speed): max_speed(max_speed){} - private: - double max_speed; -} -(drive_forward_tactic.h) - FSM fsm; -(drive_forward_tactic.cpp: constructor) - fsm(DriveForwardFSM(10.0)) -``` + ```cpp + struct DriveForwardFSM + { + public: + DriveForwardFSM(double max_speed): max_speed(max_speed){} + // ... + private: + double max_speed; + } + + FSM fsm(DriveForwardFSM(10.0)); + ``` # Conventions Various conventions we use and follow that you need to know. @@ -404,7 +467,7 @@ At a high-level, our system is split into several independent processes that [co - The [**Simulator**](#simulator) provides a physics simulation of the [World](#world), enabling testing of our gameplay when we don't have access to a real field. This process is optional and used only for development and testing purposes; in a real match, our system will receive data from [SSL-Vision](#ssl-vision). -- [**Thunderloop**](/docs/robot-software-architecture.md#thunderloop) is responsible for coordinating communication between our [AI](#ai) computer and the motor and power boards in our robots. It is part our robot software architecture, which is documented [here](/docs/robot-software-architecture.md). +- [**Thunderloop**](/docs/robot-software-architecture.md#thunderloop) is the software that runs onboard our robots. It is responsible for coordinating communication between our [AI](#ai) computer and the motor and power boards in our robots. It is part our robot software architecture, which is documented [here](/docs/robot-software-architecture.md). # Fullsystem @@ -444,32 +507,35 @@ The `AI` is the part of the [Fullsystem](#fullsystem) where all of our gameplay The two main components of the `AI` are strategy and navigation. ## Strategy -We use a framework called `STP (Skills, Tactics, Plays)` to implement our stratgy. The `STP` framework was originally proposed by Carnegie Mellon University back in 2004. The original paper can be found [here](https://kilthub.cmu.edu/articles/STP_Skills_Tactics_and_Plays_for_Multi-Robot_Control_in_Adversarial_Environments/6561002/1). +We use a framework called `STP (Skills, Tactics, Plays)` to implement our gameplay strategy. The `STP` framework was originally proposed by Carnegie Mellon University back in 2004. The original paper can be found [here](https://kilthub.cmu.edu/articles/STP_Skills_Tactics_and_Plays_for_Multi-Robot_Control_in_Adversarial_Environments/6561002/1). `STP` is a way of breaking down roles and responsibilities into a simple hierarchy, making it easier to build up more complex strategies from simpler pieces. This is the core of where our strategy is implemented. -When the [AI](#ai) is given new information and asked to make a decision, our `STP` strategy is what is executed first. It takes in a [World](#world) and returns [Intents](#intents). - ### STP Diagram The STP diagram shows how this works. Functions to assign tactics to robots and build motion constraints are passed into a `Play`'s `get` function, which the `Play` uses to generate tactics with assigned robots and with updated motion constraints. ![STP Diagram](images/STP.svg) -### Tactics -The `T` in `STP` stands for `Tactics`. A `Tactic` represents a "single-robots' role" on a team. Examples include: -1. Being a goalie -2. Being a passer or pass receiver -3. Being a defender that shadows enemy robots -4. Being a defender that tries to steal the ball from enemies +### Skills +The `S` in `STP` stands for `Skills`. A `Skill` represents a lower-level behaviour that a robot can execute. Examples include: -They can also represent lower level behaviours, such as 1. Moving to a position (without colliding with anything) 2. Shooting the ball at a target 3. Intercepting a moving ball -The high level behaviours can use the lower level behaviours in a hierarchical way. +Skills use [Primitives](#primitives) to implement their behaviour, so that our strategy is decoupled from the [Navigator](#navigation). + +### Tactics +The `T` in `STP` stands for `Tactics`. A `Tactic` represents a single robot's role on a team. Examples include: +1. Being a goalie +2. Being an attacker +3. Being a pass receiver +4. Being a defender that shadows enemy robots +5. Being a defender that tries to steal the ball from enemies -Tactics use [Intents](#intents) to implement their behaviour, so that it can decouple strategy from the [Navigator](#navigation). +Tactics can use Skills in a hierarchical way. + +Tactics use [Primitives](#primitives) to implement their behaviour, so that it can decouple strategy from the [Navigator](#navigation). ### Plays The `P` in `STP` stands for `Plays`. A `Play` represents a "team-wide goal" for the robots. They can be thought of much like Plays in real-life soccer. Examples include: @@ -507,10 +573,12 @@ The `Path Planner` is an interface for the responsibility of path planning a sin # Thunderscope -[`Thunderscope Main`](/src/software/thunderscope/thunderscope_main.py) serves as the main entry point for our entire system. It starts up the [Thunderscope GUI](#thunderscope-gui) and other processes, such as a [Fullsystem](#fullsystem) for each [AI](#ai) team. +[`thunderscope_main.py`](/src/software/thunderscope/thunderscope_main.py) serves as the main entry point for our entire system. It starts up the [Thunderscope GUI](#thunderscope-gui) and other processes, such as a [Fullsystem](#fullsystem) for each [AI](#ai) team. ## Thunderscope GUI +![Thunderscope GUI](images/thunderscope.png) + [Thunderscope](#thunderscope) is our main visualizer of our [AI](#ai). It provides a GUI that shows us the state of the [World](#world), and it is also able to display extra information that the [AI](#ai) would like to show. For example, it can show the planned paths of each friendly robot on the field, or highlight which enemy robots it thinks are a threat. Furthermore, it displays any warnings or status messages from the robots, such as if a robot is low on battery. Thunderscope also lets us control the [AI](#ai) by setting [Dynamic Parameters](#dynamic-parameters). The GUI lets us choose what strategy the [AI](#ai) should use, what colour we are playing as (yellow or blue), and tune more granular behaviour such as how close an enemy must be to the ball before we consider them a threat. @@ -537,18 +605,15 @@ We organize our graphics into "layers" so that we can toggle the visibility of d A `GLLayer` is in fact a `GLGraphicsItem` that is added to the scenegraph. When we add or remove `GLGraphicsItem`s to a `GLLayer`, we're actually setting the `GLLayer` as the parent of the `GLGraphicsItem`; this is because the scenegraph has a tree-like structure. In theory, `GLLayer`s could also be nested within one another. # Simulator -The `Simulator` is what we use for physics simulation to do testing when we don't have access to real field. In terms of the architecture, the `Simulator` "simulates" the following components' functionalities: +Our simulator is what we use for physics simulation to do testing when we don't have access to real field. The simulator is a standalone application that simulates the following components' functionalities: * [SSL-Vision](#ssl-vision) by publishing new vision data * the robots by accepting new [Primitives](#primitives) -Using the current state of the simulated world, the `Simulator` simulates the new [Primitives](#primitives) over some time step and publishes new ssl vision data based on the updated simulated world. The `Simulator` is designed to be "perfect", which means that -* the vision data it publishes exactly reflects the state of the simulated world -* the simulation perfectly reflects our best understanding of the physics (e.g. friction) with no randomness. +Using the current state of the simulated world, the simulator simulates the new [Primitives](#primitives) over some time step and publishes new SSL vision data based on the updated simulated world. Since the simulator interfaces with the our software over the network, it is essentially indistinguishible from robots receiving [Primitives](#primitives) and an [SSL-Vision](#ssl-vision) client publishing data over the network. -The `Simulator` uses `Box2D`, which provides 2D physics simulation for free. While this simplifies the simulator greatly, it means that we manually implement the physics for "3D effects", such as dribbling and chipping. +The simulation can also be configured with "realism" parameters that control the amount of noise added to vision detections, simulate missed vision detections and packet loss, and add artificial vision/processing delay, all with some degree of randomness. -## Standalone Simulator -The `Standalone Simulator` is a wrapper around the `Simulator` so that we can run it as a standlone application that publishes and receives data over the network. The `Standalone Simulator` is designed to interface with the [WifiBackend](#backend) over the network, and so it is essentially indistinguishible from robots receiving [Primitives](#primitives) and an [SSL-Vision](#ssl-vision) client publishing data over the network. The `Standalone Simulator` also has a [GUI](#gui) that provides user-friendly features, such as moving the ball around. +The code for our simulator is adapted from the [ER Force Simulator](https://github.com/robotics-erlangen/framework?tab=readme-ov-file#simulator-cli) built by another team in our league. The simulator uses the real-time [Bullet physics engine](https://github.com/bulletphysics/bullet3), which simulates collision detection and soft/rigid-body dynamics in 3D. ## Simulated Tests @@ -609,9 +674,9 @@ The data sent between Fullsystem and Thunderscope is serialized using [protobufs Logging protobufs is done at the VISUALIZE level (e.g. LOG(VISUALIZE) << some_random_proto;). Protobufs need to be converted to strings in order to log them with g3log. We've overloaded the stream (<<) operator to automatically pack protobufs into a google::protobuf::Any and serialize them to a string, so you don't need to do the conversion yourself.
-In Thunderscope, the [`ProtoUnixIO`](../src/software/thunderscope/proto_unix_io.py) is responsible for communicating protobufs over unix sockets. `ProtoUnixIO` utilizes a variation of the [publisher-subscriber ("pub-sub")](#publisher-subscriber-pattern) messaging pattern. Through `ProtoUnixIO`, clients can register as a subscriber by providing a type of protobuf to receive and a [`ThreadSafeBuffer`](../src/software/thunderscope/thread_safe_buffer.py) to place incoming those protobuf messages. The `ProtoUnixIO` can then be configured with a unix receiver to receive protobufs over a unix socket and place those messages onto the `ThreadSafeBuffer`s of that proto's subscribers. Classes can also publish protobufs via `ProtoUnixIO` by configuring it with a unix sender. +In Thunderscope, the [`ProtoUnixIO`](../src/software/thunderscope/proto_unix_io.py) is responsible for communicating protobufs over unix sockets. `ProtoUnixIO` utilizes a variation of the [publisher-subscriber ("pub-sub")](#publisher-subscriber-pattern) messaging pattern. Through `ProtoUnixIO`, clients can register as a subscriber by providing a type of protobuf to receive and a [`ThreadSafeBuffer`](../src/software/thunderscope/thread_safe_buffer.py) to place incoming protobuf messages. The `ProtoUnixIO` can then be configured with a unix receiver to receive protobufs over a unix socket and place those messages onto the `ThreadSafeBuffer`s of that proto's subscribers. Classes can also publish protobufs via `ProtoUnixIO` by configuring it with a unix sender. # Estop -The `Estop` allows us to quickly and manually command physical robots to stop what they are doing. It is a physical push button that is connected to the computer via a USB cable. When Thunderscope is launched, a `ThreadedEstopReader` is initialized (within `RobotCommunication`) that is responsible for communicating and reading values from the `Estop` via UART. While running, it will poll the status of the `Estop` to determine whether it is in the `STOP` or `PLAY` state: +The `Estop` allows us to quickly and manually command physical robots to stop what they are doing. It is a physical push button that is connected to the computer via a USB cable (we also have a `--keyboard-estop` flag you can use when running Thunderscope that lets you use the spacebar as the `Estop`). When Thunderscope is launched, a `ThreadedEstopReader` is initialized (within `RobotCommunication`) that is responsible for communicating and reading values from the `Estop` via UART. While running, it will poll the status of the `Estop` to determine whether it is in the `STOP` or `PLAY` state: - If the `Estop` is in the `STOP` state, it overrides the [Primitives](#primitives) sent to the robots with `Stop` primitives. On the robot, `Thunderloop` is responsible for handling the primitive message and ensuring that the power & motor boards receive the correct inputs for the robot to stop. - If the `Estop` is in the `PLAY` state, primitives are communicated as normal. From 7923f40768da811bcbec0f3935205fc5f28992d5 Mon Sep 17 00:00:00 2001 From: williamckha Date: Tue, 6 Aug 2024 17:37:56 -0700 Subject: [PATCH 02/18] Update getting-started-wsl.md --- docs/getting-started-wsl.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/getting-started-wsl.md b/docs/getting-started-wsl.md index 999f86e7b8..50b7ce1cdd 100644 --- a/docs/getting-started-wsl.md +++ b/docs/getting-started-wsl.md @@ -13,9 +13,10 @@ Windows has a Windows Subsystem for Linux component that can be used to develop and run code for Linux on Windows. WSL1 was a Windows component that implemented Linux kernel interfaces, and didn't work great with Thunderbots software. WSL2 runs a full-fledged Linux kernel in a VM, and works great with Thunderbots software with the exception that we need to use software rendering instead of GPU-accelerated rendering for our AI. WSLg is WSL2 but with built-in support for running GUI applications (e.g. Thunderscope). -**Support for WSL is experimental. Because we use software rendering, the experience will also be degraded on computers with weak or old CPUs.** - -**Note that this will not work with legacy robots. Due to the lack of USB support in WSL2, we are unable to use the USB dongle used to communicate with them.** +> [!WARNING] +> **Support for WSL is experimental. Because we use software rendering, the experience will also be degraded on computers with weak or old CPUs.** +> +> **Note that this will not work with legacy robots. Due to the lack of USB support in WSL2, we are unable to use the USB dongle used to communicate with them.** ## WSLg Setup (Windows 11 - Recommended) 1. Installing WSLg is more straight forward than WSL2. For up to date documentation, please follow the [official documentation for setting up WSLg](https://github.com/microsoft/wslg#installing-wslg). From a33d33f7a413572ee4cbdc69c1b83b328431cc46 Mon Sep 17 00:00:00 2001 From: williamckha Date: Tue, 6 Aug 2024 18:21:22 -0700 Subject: [PATCH 03/18] Update getting-started-wsl.md --- docs/getting-started-wsl.md | 42 ++++++++++++++++++++++++++++--------- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/docs/getting-started-wsl.md b/docs/getting-started-wsl.md index 50b7ce1cdd..99cc8b0997 100644 --- a/docs/getting-started-wsl.md +++ b/docs/getting-started-wsl.md @@ -2,29 +2,28 @@ ## Table of Contents -* [Table Of Contents](#table-of-contents) +* [Table of Contents](#table-of-contents) * [Introduction](#introduction) -* [WSLg Setup (Windows 11 - Recommended)](#wslg-setup-(windows-11---recommended)) -* [WSL2 Setup (windows 10)](#wsl2-setup-(windows-10)) +* [WSLg Setup (Windows 11/10 - Recommended)](#wslg-setup-windows-1110---recommended) +* [WSL2 Setup (Windows 10)](#wsl2-setup-windows-10) * [X Server Setup](#x-server-setup) - +* [Networking Issues](#networking-issues) +* [USB Issues](#usb-issues) ## Introduction Windows has a Windows Subsystem for Linux component that can be used to develop and run code for Linux on Windows. WSL1 was a Windows component that implemented Linux kernel interfaces, and didn't work great with Thunderbots software. WSL2 runs a full-fledged Linux kernel in a VM, and works great with Thunderbots software with the exception that we need to use software rendering instead of GPU-accelerated rendering for our AI. WSLg is WSL2 but with built-in support for running GUI applications (e.g. Thunderscope). > [!WARNING] -> **Support for WSL is experimental. Because we use software rendering, the experience will also be degraded on computers with weak or old CPUs.** -> -> **Note that this will not work with legacy robots. Due to the lack of USB support in WSL2, we are unable to use the USB dongle used to communicate with them.** +> **Support for WSL is experimental. Performance will be degraded, features may not work properly, and the developer experience will be worse overall.** -## WSLg Setup (Windows 11 - Recommended) -1. Installing WSLg is more straight forward than WSL2. For up to date documentation, please follow the [official documentation for setting up WSLg](https://github.com/microsoft/wslg#installing-wslg). +## WSLg Setup (Windows 11/10 - Recommended) +1. Installing WSLg is more straight forward than WSL2 and is the recommended way to run Linux GUI applications in Windows. For up to date documentation, please follow the [official documentation for setting up WSLg](https://github.com/microsoft/wslg#installing-wslg). 2. Once you have completed all of the above, complete the [Software Setup](./getting-started.md). ## WSL2 Setup (Windows 10) -If you are not using Windows 11 and would prefer not to upgrade, you can follow the following steps. Note that this setup is more complex than the [WSLg](#wslg-setup-(windows-11---recommended)) setup as it does not support GUI applications out of the box. +If you are not using Windows 11 or the latest version of Windows 10 and would prefer not to upgrade, you can follow the following steps. Note that this setup is more complex than the [WSLg](#wslg-setup-(windows-11---recommended)) setup as it does not support GUI applications out of the box. 1. You'll need to be on build 19041 or later to use WSL2. If you have updated to Windows 10 version 2004 or newer, you will be able to use WSL2. 2. When you have ensured that your Windows version supports WSL2, do the following to enable it. - Enable WSL by opening an Administrator PowerShell window and running command @@ -63,3 +62,26 @@ If you are not using Windows 11 and would prefer not to upgrade, you can follow 7. Verify that your system is configured correctly by running `glxgears -info` on the Linux command line. You should see a window pop up with spinning gears and the line `GL_RENDERER = llvmpipe (LLVM 9.0, 256 bits)` at the top of the output. Once you have completed all of the above, complete the [Software Setup](./getting-started.md). + +## Networking Issues + +Networking compatibility with WSL is limited but it can be improved by enabling [mirrored mode](https://learn.microsoft.com/en-us/windows/wsl/networking#mirrored-mode-networking). There are still many unresolved issues with mirrored mode enabled (no vision, no robot status, etc.) but robot diagnostics should work and you should be able to control robots on the network. + +Create a `.wslconfig` file in your `%UserProfile%` directory (typically your home directory, `cd ~`) and copy the following into the config file: + +``` +[wsl2] +networkingMode = mirrored +``` + +This will enable [mirrored mode networking for WSL](https://learn.microsoft.com/en-us/windows/wsl/networking#mirrored-mode-networking). This mode “mirrors” the networking interfaces you have on Windows into Linux, which improves networking capabilities and compatibility. + +When selecting a network interface to use, choose `eth0` or similar. There probably won’t be a `wlan0` interface since WSL only sees the virtual network interface `eth0`. + +## USB Issues + +WSL does not natively support connecting USB devices, which is necessary for some tasks like flashing firmware onto our robots or using a physical e-stop. You will need to install a piece of open-source software called `usbipd-win` to support USB connectivity. + +Please follow the [official documentation on installing `usbipd-win`](https://github.com/dorssel/usbipd-win?tab=readme-ov-file#how-to-install). + +Note that connected devices are not automatically shared with `usbipd`, so you will have to manually share the device with `usbipd` and attach/detach the device to a `usbipd` client whenever you plug/unplug it (or between reboots). See the [official documentation for details on usage](https://github.com/dorssel/usbipd-win?tab=readme-ov-file#how-to-install). From 513d2d60cbd585c1f07c4cdf81905533642187c6 Mon Sep 17 00:00:00 2001 From: williamckha Date: Wed, 28 Aug 2024 12:48:08 -0700 Subject: [PATCH 04/18] Update PR template --- .github/PULL_REQUEST_TEMPLATE.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index fb74510f17..89f73899ac 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,8 +1,8 @@ +This file outlines a list of common things that should be addressed when opening a PR. It's built from previous issues we've seen in a lot of pull requests. If you notice something that's being noted in a lot of PRs, it should probably be added here to help save people time in the future. -## Please fill out the following before requesting review on this PR +Please fill out the following before requesting review on this PR! +--> ### Description @@ -19,13 +19,14 @@ This file outlines a list of common things that should be addressed when opening ### Resolved Issues ### Length Justification and Key Files to Review - + ### Review Checklist From d8c7559eb0cd0a858b71f567192282b64d3d27dd Mon Sep 17 00:00:00 2001 From: williamckha Date: Sun, 1 Sep 2024 12:58:40 -0700 Subject: [PATCH 05/18] Getting Started changes --- docs/getting-started.md | 74 +++++++++++++++++++++++------------------ 1 file changed, 42 insertions(+), 32 deletions(-) diff --git a/docs/getting-started.md b/docs/getting-started.md index 0f52c75903..71e9335b2d 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -54,10 +54,10 @@ Table of Contents ## Introduction These instructions assume that you have the following accounts setup: -- [Github](https://github.com/login) +- [GitHub](https://github.com/login) - [Discord](https://discord.com). Please contact a Thunderbots lead to receive the invite link. -These instructions assume you have a basic understanding of Linux and the command-line. There are many great tutorials online, such as [LinuxCommand](http://linuxcommand.org/). The most important things you'll need to know are how to move around the filesystem, and how to run programs or scripts. +These instructions assume you have a basic understanding of Linux and the command-line. There are many great tutorials online, such as [LinuxCommand](http://linuxcommand.org/). The most important things you'll need to know are how to move around the filesystem and how to run programs or scripts. ## Installation and Setup @@ -75,18 +75,25 @@ You can use Ubuntu 20.04 LTS and Ubuntu 22.04 LTS inside Windows through Windows 4. Click the `Fork` button in the top-right to fork the repository ([click here to learn about Forks](https://help.github.com/en/articles/fork-a-repo)) 1. Click on your user when prompted 2. You should be automatically redirected to your new fork -5. Clone your fork of the repository. As GitHub is forcing users to stop using usernames and passwords, we will be using the SSH link. Returning members who are migrating to using SSH after cloning from a previous method can use the following instructions to set up a new local repository using SSH. - 1. To connect to GitHub using SSH, if not setup prior, you will need to add an SSH key to your GitHub account. Instructions can be found [here](https://docs.github.com/en/authentication/connecting-to-github-with-ssh/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent). For each computer you contribute to GitHub with, you will need an additional SSH Key pair linked to your account. - 2. After you have successfully set up a SSH key for your device and added it to GitHub, you can clone the repository using the following command (you can put it wherever you like): - 1. Eg. `git clone git@github.com:/Software.git` - 2. You can find this link under the green `Clone or Download` button on the main page of the Software repository, under the SSH tab. (This should now be available after adding your SSH key to GitHub successfully.) +5. Clone your fork of the repository. We recommend cloning using HTTPS since it is the easiest to set up. You should be able to clone your fork using the following command (you can put it wherever you like): + ``` + git clone https://github.com//Software.git + ``` + You can find your fork's remote URL under the green `Code` button on the main page of your fork on GitHub, under the HTTPS tab. + + If you would like to clone using SSH: + + 1. If not setup prior, you will need to add an SSH key to your GitHub account. Instructions can be found [here](https://docs.github.com/en/authentication/connecting-to-github-with-ssh/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent). For each computer you contribute to GitHub with, you will need an additional SSH Key pair linked to your account. + 2. After you have successfully set up a SSH key for your device and added it to GitHub, you can clone the repository using the following command: + 1. e.g. `git clone git@github.com:/Software.git` + 2. You can find this link under the green `Clone or Download` button on the main page of your fork on GitHub, under the SSH tab. (This should now be available after adding your SSH key to GitHub successfully.) 6. Set up your git remotes ([what is a remote and how does it work?](https://git-scm.com/book/en/v2/Git-Basics-Working-with-Remotes)) 1. You should have a remote named `origin` that points to your fork of the repository. Git will have set this up automatically when you cloned your fork in the previous step. 2. You will need to add a second remote, named `upstream`, that points to our main Software repository, which is where you created your fork from. (**Note:** This is _not_ your fork) 1. Open a terminal and navigate to the folder you cloned (your fork): `cd path/to/the/repository/Software` - 2. Navigate to our main Software repository in your browser and copy the url from the "Clone or Download" button. Copy the HTTPS url if you originally cloned with HTTPS, and use the SSH url if you previously cloned with SSH + 2. Navigate to our main Software repository in your browser and copy the url from the green `Code` button. Copy the HTTPS url if you originally cloned with HTTPS, or use the SSH url if you previously cloned with SSH 3. From your terminal, add the new remote by running `git remote add upstream ` (without the angle brackets) - 1. Eg. `git remote add upstream https://github.com/UBC-Thunderbots/Software.git` + 1. e.g. `git remote add upstream https://github.com/UBC-Thunderbots/Software.git` 4. That's it. If you want to double check your remotes are set up correctly, run `git remote -v` from your terminal (at the base of the repository folder again). You should see two entries: `origin` with the url for your fork of the repository, and `upstream` with the url for the main repository *See our [workflow](#workflow) for how to use git to make branches, submit Pull Requests, and track issues* @@ -95,10 +102,10 @@ You can use Ubuntu 20.04 LTS and Ubuntu 22.04 LTS inside Windows through Windows We have several setup scripts to help you easily install the necessary dependencies in order to build and run our code. You will want to run the following scripts, which can all be found in `Software/environment_setup` -* Inside a terminal, navigate to the environment_setup folder. Eg. `cd path/to/the/repository/Software/environment_setup` +* Inside a terminal, navigate to the environment_setup folder. e.g. `cd path/to/the/repository/Software/environment_setup` * Run `./setup_software.sh` * You will be prompted for your admin password - * This script will install everything necessary in order to build and run our main `AI` software + * This script will install everything necessary in order to build and run our software ### Installing an IDE @@ -119,18 +126,17 @@ CLion is free for students, and you can use your UBC alumni email address to cre ##### Installing CLion * Inside a terminal, navigate to the environment_setup folder. Eg. `cd path/to/the/repository/Software/environment_setup` -* Run `./install_clion.sh` (* **DO NOT** download CLion yourself unless you know what you're doing. The `install_clion.sh` script will grab the correct version of CLion and the Bazel plugin to ensure everything is compatible *). +* Run `./install_clion.sh` (* **We highly recommend using the script and not downloading CLion yourself unless you know what you're doing.** The `install_clion.sh` script will grab the correct version of CLion and the Bazel plugin to ensure everything is compatible *). * When you run CLion for the first time you will be prompted to enter your JetBrains account or License credentials. Use your student account. -### Installing an IDE: VSCode +### Installing an IDE: VS Code -VSCode is the more lightweight IDE, with support for code navigation, code completion, and integrated building and testing. However, debugging isn't integrated into this IDE. +VS Code is a more lightweight "IDE", with support for code navigation, code completion, and integrated building and testing. However, debugging isn't integrated by default into VS Code. 1. Inside a terminal, navigate to the environment_setup folder. Eg. `cd path/to/the/repository/Software/environment_setup` -2. Run `./install_vscode.sh` (* **DO NOT** download VSCode yourself unless you know what you're doing. The `install_vscode.sh` script will grab the most stable version of VSCode *) -3. Open `vscode`. You can type `vscode` in the terminal, or click the icon on your Desktop. -&. Click `Open Folder` and navigate to where you cloned software. So if I cloned the repo to `/home/my_username/Downloads/Software`, I would select `/home/my_username/Downloads/Software`. -4. VSCode will prompt you to install recommended extensions, click `Install`, this installs necessary plugins to work on the codebase. (Bazel, C++, Python, etc..) +2. Run `./install_vscode.sh` (* **We highly recommend using the script and not downloading VSCode yourself unless you know what you're doing.** The `install_vscode.sh` script will grab the most stable version of VSCode *) +3. Open `vscode`. You can type `vscode` in the terminal, or click the icon on your Desktop. Go to File -> Open Folder and navigate to where you cloned the software repo. So if I cloned the repo to `/home/my_username/Downloads/Software`, I would select `/home/my_username/Downloads/Software`. +4. VSCode will prompt you to install recommended extensions. Click `Install` — this installs necessary plugins to work on the codebase. (Bazel, C++, Python, etc.) 5. Navigate to File -> Preferences -> Settings -> Workspace -> Extensions -> Bazel and select the `Bazel: Enable Code Lens` option. ### Editing with Vim or NeoVim @@ -158,7 +164,7 @@ These tools require a `compile_commands.json` file, which can be generated by fo ### Building from the command-line using the fuzzy finder -We have a ./tbots.py test runner script in the src folder that will fuzzy find for targets. For example, +We have a `tbots.py` test runner script in the src folder that will fuzzy find for targets and call Bazel. For example, 1. Build a specific target for running (for example): `./tbots.py build angletest` 2. Run a specific target by running (for example): `./tbots.py run goalietactictest -t` @@ -168,7 +174,7 @@ where the `-t` flag indicates whether Thunderscope should be launched. Run `./tb ### Building with CLion -First we need to setup CLion +First, we need to setup CLion: 1. Open CLion 2. Select `Import Bazel Project` 3. Set `Workspace` to wherever you cloned the repository + `/src`. So if I cloned the repo to `/home/my_username/Downloads/Software`, my workspace would be `/home/my_username/Downloads/Software/src`. @@ -178,7 +184,7 @@ First we need to setup CLion 7. Click `Finish` and you're good to go! Give CLion some time to find everything in your repo. Now that you're setup, if you can run it on the command line, you can run it in CLion. There are two main ways of doing so. -1. Open any `BUILD` file and right clight in a `cc_library()` call. This will give you the option to `Run` or `Debug` that specific target. Try it by opening `Software/src/software/geom/BUILD` and right-clicking on the `cc_library` for `angle_test`! +1. Open any `BUILD` file and right click on a `cc_library()` call. This will give you the option to `Run` or `Debug` that specific target. Try it by opening `Software/src/software/geom/BUILD` and right-clicking on the `cc_library` for `angle_test`! 2. Add a custom build configuration (more powerful, so make sure you understand this!) 1. Select `Add Configuration` from the drop-down in the top-right of CLion 2. Click on `+`, choose `Bazel Command`. @@ -195,8 +201,8 @@ Now that you're setup, if you can run it on the command line, you can run it in ### Running our AI, Simulator, SimulatedTests or Robot Diagnostics -1. Run our AI on Thunderscope: - - Thunderscope is the software that coordinates our AI, Simulator, Visualizer and RobotDiagnostics +1. Run our AI on [Thunderscope](./software-architecture-and-design.md#thunderscope-gui): + - [Thunderscope](./software-architecture-and-design.md#thunderscope-gui) is the software that coordinates and visualizes our AI, Simulator, and RobotDiagnostics. - After launching Thunderscope, we can see what the AI is currently "seeing" and interact with it through dynamic parameters. - If we want to run with simulated AI vs AI: - `./tbots.py run thunderscope_main --enable_autoref` will start Thunderscope with a Simulator, a blue FullSystem, yellow FullSystem and a headless Autoref. @@ -298,7 +304,7 @@ To debug from the command line, first you need to build your target with the deb ## Profiling -Profiling is an optimization tool used to identify the time and space used by code, with a detailed breakdown to help identify areas of potential performance improvements. Unfortunately profiling for Bazel targets is not supported in CLion at this time. Hence the only way is via command line. Use the following command: +Profiling is an optimization tool used to identify the time and space used by code, with a detailed breakdown to help identify areas of potential performance improvements. Unfortunately profiling for Bazel targets is not supported in CLion at this time. Hence, the only way to profile our software is via the command line. ### Callgrind @@ -349,7 +355,9 @@ We use ansible to automatically update software running on the Jetson Nano. [Mor To update binaries on a working robot, you can run: -`bazel run //software/jetson_nano/ansible:run_ansible --cpu=jetson_nano -- --playbook deploy_nano.yml --hosts --ssh_pass ` +``` +bazel run //software/jetson_nano/ansible:run_ansible --cpu=jetson_nano -- --playbook deploy_nano.yml --hosts --ssh_pass +``` ## Setting up Virtual Robocup 2021 @@ -372,7 +380,7 @@ After editing the dockerfile, build the image and push it to dockerhub with the ## Issue and Project Tracking -We try keep our issue and project tracking fairly simple, to reduce the overhead associated with tracking all the information and to make it easier to follow. If you are unfamiliar with GitHub issues, [this article](https://guides.github.com/features/issues/) gives a good overview. +We try keep our issue and project tracking fairly simple to reduce the overhead associated with tracking all the information and to make it easier to follow. If you are unfamiliar with GitHub issues, [this article](https://guides.github.com/features/issues/) gives a good overview. ### Issues @@ -403,10 +411,12 @@ For each Issue of project you are working on, you should have a separate branch. 1. Navigate to the base folder of your Software repository: `cd path/to/the/repository/Software` 2. Make git aware of any new changes to `upstream` by running `git fetch upstream` 3. Create a new branch from `upstream/master` by running `git checkout upstream/master` then `git checkout -b your-branch-name` - 1. Our branch naming convention is: `your_name/branch_name` (all lowercase, words separated by underscores). The branch name should be short and descriptive of the work being done on the branch. -**Example:** if you were working on a new navigation system using RRT and your name was "Bob" your branch name might look like: `bob/new_rrt_navigator` -4. You can now commit changes to this branch, and push them to your fork with `git push origin your_branch_name` or `git push -u` + Our branch naming convention is: `your_name/branch_name` (all lowercase, words separated by underscores). The branch name should be short and descriptive of the work being done on the branch. + + **Example:** if you were working on a new navigation system using RRT and your name was "Bob" your branch name might look like: `bob/new_rrt_navigator` + +4. You can now commit changes to this branch and push them to your fork with `git push origin your_branch_name` or `git push -u`
Aside: Why should you only create branches from "upstream/master"? @@ -421,7 +431,7 @@ tl;dr Always create new branches from upstream/master. Do not create branches fr ### Making Commits -We don't impose any rules for how you should be committing code, just keep the following general rules in mind: +We don't impose any rules for how you should be committing code, just keep the following general guidelines in mind: 1. Commits should represent logical steps in your workflow. Avoid making commits too large, and try keep related changes together 2. Commit messages should give a good idea of the changes made. You don't have to go in-depth with technical details, but no one will know what you've done if your commit message is "fixed broken stuff" @@ -435,13 +445,13 @@ To do this, you have 2 options: rebase or merge. [What's the difference?](https: Merging is generally recommended, because it is easier to handle conflicts and get stuff working. To merge, simply run `git pull upstream master`. -Rebasing requires more knowledge of git and can cause crazy merge conflicts, so it isn't recommended. You can simply `git pull --rebase upstream master` to rebase your branch onto the latest `upstream/master`. +Rebasing requires more knowledge of git and can cause crazy merge conflicts, so it isn't recommended. You can simply `git pull --rebase upstream master` to rebase your branch onto the latest `upstream/master`. The main benefit of rebasing is that you get a clean, linear commit history; however, we squash all the commits in each PR into a single commit before merging into master, so the extra effort involved in rebasing is pointless. If you do rebase or merge and get conflicts, you'll need to resolve them manually. [See here for a quick tutorials on what conflicts are and how to resolve them](https://www.atlassian.com/git/tutorials/using-branches/merge-conflicts). Feel free to do this in your IDE or with whatever tool you are most comfortable with. Updating your branch often helps keep conflicts to a minimum, and when they do appear they are usually smaller. Ask for help if you're really stuck! ### Formatting Your Code -We use [clang-format](https://electronjs.org/docs/development/clang-format) to automatically format our code. Using an automatic tool helps keep things consistent across the codebase without developers having to change their personal style as they write. See the [code style guide](code-style-guide.md) for more information on exactly what it does. +We use a variety of code formatters and linters to automatically format our code. Using automatic tools helps keep things consistent across the codebase without developers having to change their personal style as they write. See the [code style guide](code-style-guide.md) for more information on exactly what these tools enforce. To format the code, from the `Software` directory run `./formatting_scripts/fix_formatting.sh`. From ecc921d1db34f9f83cff83498c938548089504ae Mon Sep 17 00:00:00 2001 From: williamckha Date: Sun, 8 Sep 2024 12:07:29 -0700 Subject: [PATCH 06/18] Update wsl instructions --- docs/getting-started-wsl.md | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/docs/getting-started-wsl.md b/docs/getting-started-wsl.md index 99cc8b0997..c9433d5025 100644 --- a/docs/getting-started-wsl.md +++ b/docs/getting-started-wsl.md @@ -27,14 +27,13 @@ If you are not using Windows 11 or the latest version of Windows 10 and would pr 1. You'll need to be on build 19041 or later to use WSL2. If you have updated to Windows 10 version 2004 or newer, you will be able to use WSL2. 2. When you have ensured that your Windows version supports WSL2, do the following to enable it. - Enable WSL by opening an Administrator PowerShell window and running command - ``` - dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart - ``` + ``` + dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart + ``` - Enable the 'Virtual Machine Platform' component by Administrator PowerShell window and running command - ``` - dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart - - ``` + ``` + dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart + ``` - Reboot your machine. 3. Now, let's install Ubuntu. - Download the WSL2 kernel from [here](https://docs.microsoft.com/en-us/windows/wsl/wsl2-kernel). @@ -74,9 +73,9 @@ Create a `.wslconfig` file in your `%UserProfile%` directory (typically your hom networkingMode = mirrored ``` -This will enable [mirrored mode networking for WSL](https://learn.microsoft.com/en-us/windows/wsl/networking#mirrored-mode-networking). This mode “mirrors” the networking interfaces you have on Windows into Linux, which improves networking capabilities and compatibility. +This will enable [mirrored mode networking for WSL](https://learn.microsoft.com/en-us/windows/wsl/networking#mirrored-mode-networking). This mode “mirrors” the networking interfaces you have on Windows onto Linux, which improves networking capabilities and compatibility. -When selecting a network interface to use, choose `eth0` or similar. There probably won’t be a `wlan0` interface since WSL only sees the virtual network interface `eth0`. +When selecting a network interface to use, choose `eth...`/`en...` or similar. There probably won’t be a `wlan` interface since WSL only sees the virtual network interface `eth...`. ## USB Issues From e65839abc80abfc66e4e1c3fb11832e09473a3f8 Mon Sep 17 00:00:00 2001 From: williamckha Date: Sun, 8 Sep 2024 12:43:47 -0700 Subject: [PATCH 07/18] Update docs --- docs/software-architecture-and-design.md | 37 ++++++++++++++---------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/docs/software-architecture-and-design.md b/docs/software-architecture-and-design.md index b530911b37..81c8d474f3 100644 --- a/docs/software-architecture-and-design.md +++ b/docs/software-architecture-and-design.md @@ -137,6 +137,17 @@ Information about the robot status is communicated and stored as `RobotStatus` p # Design Patterns Below are the main design patterns we use in our code, and what they are used for. +## Abstract Classes and Inheritance +While not a "design pattern" per se, inheritance and related OOP paradigms are prevalent throughout of our code base. Abstract classes let us define interfaces for various components of our code. Then we can implement different objects that obey the interface, and use them interchangeably, with the guarantee that as long as they follow the same interface we can use them in the same way. + +To learn more about inheritance in C++, read the following `learncpp.com` articles: +- [Introduction to inheritance](https://www.learncpp.com/cpp-tutorial/introduction-to-inheritance/) +- [Virtual functions](https://www.learncpp.com/cpp-tutorial/pointers-and-references-to-the-base-class-of-derived-objects/) + +Examples of this can be found in many places, including: +* [Plays](#plays) +* [Tactics](#tactics) + ## Singleton Pattern The Singleton pattern is useful for having a single, global instance of an object that can be accessed from anywhere. Though it's generally considered an anti-pattern (aka _bad_), it is useful in specific scenarios. @@ -156,8 +167,6 @@ Read http://derydoca.com/2019/03/c-tutorial-auto-registering-factory/ for more i The auto-registering factory is particularly useful for our `PlayFactory`, which is responsible for creating [Plays](#plays). Every time we run our [AI](#ai) we want to know what [Plays](#plays) are available to choose from. The Factory pattern makes this really easy, and saves us having to remember to update some list of "available Plays" each time we add or remove one. -The Factory pattern is also used to create different [Backends](#backend) - ## Visitor Pattern The Visitor pattern is useful when we need to perform different operations on a group of "similar" objects, like objects that inherit from the same parent class (e.g. [Tactic](#tactics)). We might only know all these objects are a [Tactic](#tactic), but we don't know specifically which type each one is (eg. `AttackerTactic` vs `ReceiverTactic`). The Visitor Pattern helps us "recover" that type information so we can perform different operations on the different types of objects. It is generally preferred to a big `if-block` with a case for each type, because the compiler can help warn you when you've forgotten to handle a certain type, and therefore helps prevent mistakes. @@ -173,8 +182,9 @@ Our implementation of this pattern consists of two classes, `Observer` and `Subj ### Threaded Observer In our system, we need to be able to do multiple things (receive camera data, run the [AI](#ai), send commands to the robots) at the same time. In order to facilitate this, we extend the `Observer` to the `ThreadedObserver` class. The `ThreadedObserver` starts a thread with an infinite loop that waits for new data from `Subject` and performs some operation with it. - -**WARNING:** If a class extends multiple `ThreadedObserver`s (for example, [AI](#ai) could extend `ThreadedObserver` and `ThreadedObserver`), then there will be two threads running, one for each observer. We **do not check** for data race conditions between observers, so it's entirely possible that one `ThreadedObserver` thread could read/write from data at the same time as the other `ThreadedObserver` is reading/writing the same data. Please make sure any data read/written to/from multiple `ThreadedObserver`s is thread-safe. + +> [!WARNING] +> If a class extends multiple `ThreadedObserver`s (for example, [AI](#ai) could extend `ThreadedObserver` and `ThreadedObserver`), then there will be two threads running, one for each observer. We **do not check** for data race conditions between observers, so it's entirely possible that one `ThreadedObserver` thread could read/write from data at the same time as the other `ThreadedObserver` is reading/writing the same data. Please make sure any data read/written to/from multiple `ThreadedObserver`s is thread-safe. One example of this is [SensorFusion](#sensor-fusion), which extends `Subject` and the [AI](#ai), which extends `ThreadedObserver`. [SensorFusion](#sensor-fusion) runs in one thread and sends data to the [AI](#ai), which receives and processes it another thread. @@ -538,18 +548,15 @@ Tactics can use Skills in a hierarchical way. Tactics use [Primitives](#primitives) to implement their behaviour, so that it can decouple strategy from the [Navigator](#navigation). ### Plays -The `P` in `STP` stands for `Plays`. A `Play` represents a "team-wide goal" for the robots. They can be thought of much like Plays in real-life soccer. Examples include: -1. A Play for taking friendly free kicks -2. A Play for defending enemy kickoffs -3. A general defense play -4. A passing-based offense play -5. A dribbling-based offense play - -Plays are made up of `Tactics`. Plays can have "stages" and change what `Tactics` are being used as the state of the game changes, which allows us to implement more complex behaviour. Read the section on [Coroutines](#coroutines) to learn more about how we write strategy with "stages". +The `P` in `STP` stands for `Plays`. A `Play` represents a "team-wide goal" for the robots. They can be thought of much like plays in real-life soccer. Examples include: -Furthermore, every play specifies an `Applicable` and `Invariant` condition. These are used to determine what plays should be run at what time, and when a Play should terminate. +- A play for taking friendly free kicks +- A play for defending enemy kickoffs +- A general defense play +- A passing-based offense play +- A dribbling-based offense play -`Applicable` indicates when a `Play` can be started. For example, we would not want to start a `Defense Play` if our team is in possession of the ball. The `Invariant` condition is a condition that must always be met for the `Play` to continue running. If this condition ever becomes false, the current `Play` will stop running and a new one will be chosen. For example, once we start running a friendly `Corner Kick` play, we want the `Play` to continue running as long as the enemy team does not have possession of the ball. +Plays are made up of `Tactics`. Plays can have "stages" and change what `Tactics` are being used as the state of the game changes, which allows us to implement more complex behaviour. Read the section on [FSMs](#finite-state-machines) to learn more about how we write strategy with "stages". ## Navigation @@ -602,7 +609,7 @@ Thunderscope has a field visualizer that uses [PyQtGraph's 3D graphics system](h ### Layers We organize our graphics into "layers" so that we can toggle the visibility of different parts of our visualization. Each layer is responsible for visualizing a specific portion of our AI (e.g. vision data, path planning, passing, etc.). A layer can also handle layer-specific functionality; for instance, `GLWorldLayer` lets the user place or kick the ball using the mouse. The base class for a layer is [`GLLayer`](../src/software/thunderscope/gl/layers/gl_layer.py). -A `GLLayer` is in fact a `GLGraphicsItem` that is added to the scenegraph. When we add or remove `GLGraphicsItem`s to a `GLLayer`, we're actually setting the `GLLayer` as the parent of the `GLGraphicsItem`; this is because the scenegraph has a tree-like structure. In theory, `GLLayer`s could also be nested within one another. +A `GLLayer` is in fact a `GLGraphicsItem` that is added to the scenegraph. When we add or remove `GLGraphicsItem`s to a `GLLayer`, we're actually setting the `GLLayer` as the parent of the `GLGraphicsItem`; this is because the scenegraph has a hierarchical tree-like structure. # Simulator Our simulator is what we use for physics simulation to do testing when we don't have access to real field. The simulator is a standalone application that simulates the following components' functionalities: From 56eaa49a62e3999b77ec9c3193ededb3d79a5c08 Mon Sep 17 00:00:00 2001 From: williamckha Date: Wed, 18 Sep 2024 22:08:37 -0700 Subject: [PATCH 08/18] Address comments --- docs/getting-started.md | 24 +++++++++++------------- docs/software-architecture-and-design.md | 22 ++++++++++++++-------- 2 files changed, 25 insertions(+), 21 deletions(-) diff --git a/docs/getting-started.md b/docs/getting-started.md index cb520a45aa..62f4d4bb69 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -16,13 +16,13 @@ Table of Contents * [Installing an IDE: CLion](#installing-an-ide-clion) * [Getting your Student License](#getting-your-student-license) * [Installing CLion](#installing-clion) - * [Installing an IDE: VSCode](#installing-an-ide-vscode) + * [Installing an IDE: VS Code](#installing-an-ide-vs-code) * [Editing with Vim or NeoVim](#editing-with-vim-or-neovim) * [Building and Running the Code](#building-and-running-the-code) * [Building from the command-line](#building-from-the-command-line) * [Building from the command-line using the fuzzy finder](#building-from-the-command-line-using-the-fuzzy-finder) * [Building with CLion](#building-with-clion) - * [Building with VSCode](#building-with-vscode) + * [Building with VS Code](#building-with-vs-code) * [Running our AI, Simulator, SimulatedTests or Robot Diagnostics](#running-our-ai-simulator-simulatedtests-or-robot-diagnostics) * [Debugging](#debugging) * [Debugging with CLion](#debugging-with-clion) @@ -75,18 +75,16 @@ You can use Ubuntu 20.04 LTS and Ubuntu 22.04 LTS inside Windows through Windows 4. Click the `Fork` button in the top-right to fork the repository ([click here to learn about Forks](https://help.github.com/en/articles/fork-a-repo)) 1. Click on your user when prompted 2. You should be automatically redirected to your new fork -5. Clone your fork of the repository. We recommend cloning using HTTPS since it is the easiest to set up. You should be able to clone your fork using the following command (you can put it wherever you like): - ``` - git clone https://github.com//Software.git - ``` - You can find your fork's remote URL under the green `Code` button on the main page of your fork on GitHub, under the HTTPS tab. +5. Clone your fork of the repository. As GitHub is forcing users to stop using usernames and passwords for authorization, we will be using the SSH link. - If you would like to clone using SSH: + To clone using SSH: 1. If not setup prior, you will need to add an SSH key to your GitHub account. Instructions can be found [here](https://docs.github.com/en/authentication/connecting-to-github-with-ssh/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent). For each computer you contribute to GitHub with, you will need an additional SSH Key pair linked to your account. 2. After you have successfully set up a SSH key for your device and added it to GitHub, you can clone the repository using the following command: 1. e.g. `git clone git@github.com:/Software.git` 2. You can find this link under the green `Clone or Download` button on the main page of your fork on GitHub, under the SSH tab. (This should now be available after adding your SSH key to GitHub successfully.) + + Alternatively, you can clone using HTTPS. You'll need to either use a credential helper (Git Credential Manager, GitHub CLI, etc.) or a personal access token ([details here](https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls)). 6. Set up your git remotes ([what is a remote and how does it work?](https://git-scm.com/book/en/v2/Git-Basics-Working-with-Remotes)) 1. You should have a remote named `origin` that points to your fork of the repository. Git will have set this up automatically when you cloned your fork in the previous step. 2. You will need to add a second remote, named `upstream`, that points to our main Software repository, which is where you created your fork from. (**Note:** This is _not_ your fork) @@ -109,7 +107,7 @@ We have several setup scripts to help you easily install the necessary dependenc ### Installing an IDE -For those who prefer working on C/C++ with an IDE, we provide two options: CLion for an integrated experience and VSCode for a more lightweight setup. Both support our build system `bazel`. +For those who prefer working on C/C++ with an IDE, we provide two options: CLion for an integrated experience and VS Code for a more lightweight setup. Both support our build system `bazel`. #### Installing an IDE: CLion @@ -134,9 +132,9 @@ CLion is free for students, and you can use your UBC alumni email address to cre VS Code is a more lightweight "IDE", with support for code navigation, code completion, and integrated building and testing. However, debugging isn't integrated by default into VS Code. 1. Inside a terminal, navigate to the environment_setup folder. Eg. `cd path/to/the/repository/Software/environment_setup` -2. Run `./install_vscode.sh` (* **We highly recommend using the script and not downloading VSCode yourself unless you know what you're doing.** The `install_vscode.sh` script will grab the most stable version of VSCode *) +2. Run `./install_vscode.sh` (* **We highly recommend using the script and not downloading VS Code yourself unless you know what you're doing.** The `install_vscode.sh` script will grab the most stable version of VS Code *) 3. Open `vscode`. You can type `vscode` in the terminal, or click the icon on your Desktop. Go to File -> Open Folder and navigate to where you cloned the software repo. So if I cloned the repo to `/home/my_username/Downloads/Software`, I would select `/home/my_username/Downloads/Software`. -4. VSCode will prompt you to install recommended extensions. Click `Install` — this installs necessary plugins to work on the codebase. (Bazel, C++, Python, etc.) +4. VS Code will prompt you to install recommended extensions. Click `Install` — this installs necessary plugins to work on the codebase. (Bazel, C++, Python, etc.) 5. Navigate to File -> Preferences -> Settings -> Workspace -> Extensions -> Bazel and select the `Bazel: Enable Code Lens` option. ### Editing with Vim or NeoVim @@ -192,9 +190,9 @@ Now that you're setup, if you can run it on the command line, you can run it in 4. For `Bazel Command` you can put any Bazel command, like `build`, `run`, `test`, etc. 5. Click `Ok`, then there should be a green arrow in the top right corner by the drop-down menu. Click it and the test will run! -### Building with VSCode +### Building with VS Code -1. Open VSCode +1. Open VS Code 2. Navigate to `Software/src/software/geom/BUILD` 3. On top of every `cc_test`, `cc_library` and `cc_binary` there should be a `Test ...`, `Build ...` or `Run ...` for the respective target. 4. Click `Test //software/geom:angle_test` to run the `angle_test` diff --git a/docs/software-architecture-and-design.md b/docs/software-architecture-and-design.md index 81c8d474f3..0b93dbe1f8 100644 --- a/docs/software-architecture-and-design.md +++ b/docs/software-architecture-and-design.md @@ -210,10 +210,12 @@ Rather than using the `return` keyword to return data, coroutines use the `yield See the following C++ pseudocode for an example. This coroutine function computes and returns the fibonacci sequence. ```cpp -int fib(Coroutine::push_type& yield) { +int fib(Coroutine::push_type& yield) +{ int f1 = 1; int f2 = 0; - while(true) { + while (true) + { int fn = f1 + f2; // Compute the next value in the sequence f2 = f1; // Save the previous 2 values f1 = fn; @@ -221,7 +223,8 @@ int fib(Coroutine::push_type& yield) { } } -int main() { +int main() +{ // Coroutine setup stuff // Lets pretend that we have created the Coroutine and called it `yield` std::cout << fib(yield) << std::endl; // Prints 1 @@ -264,14 +267,17 @@ In the past, we had issues with our gameplay logic "committing" to decisions if Here's a more specific example. In this example we are going to pretend to write a [Tactic](#tactic) that will pass the ball. ```cpp -def executeStrategy(IntentCoroutine::push_type& yield, Pass pass) { - do { +def executeStrategy(IntentCoroutine::push_type& yield, Pass pass) +{ + do + { yield(/* align the robot to make the pass */) - } while(current_time < pass.start_time); + } while (current_time < pass.start_time); - do { + do + { yield(/* kick the ball at the pass location */) - } while(/* robot has not kicked the ball */) + } while (/* robot has not kicked the ball */) } ``` We will pretend that this function is getting called 30 times per second to get the most up-to-date gameplay decision. From 3df8f40005333cc9f04ae4540a3df7bd7a8049c5 Mon Sep 17 00:00:00 2001 From: williamckha Date: Tue, 24 Sep 2024 20:48:04 -0700 Subject: [PATCH 09/18] Remove scripts for installing CLion and VS Code --- docs/getting-started.md | 21 ++++---- environment_setup/install_clion.sh | 78 ----------------------------- environment_setup/install_vscode.sh | 47 ----------------- 3 files changed, 10 insertions(+), 136 deletions(-) delete mode 100755 environment_setup/install_clion.sh delete mode 100755 environment_setup/install_vscode.sh diff --git a/docs/getting-started.md b/docs/getting-started.md index 62f4d4bb69..fc6bf3be94 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -123,19 +123,18 @@ CLion is free for students, and you can use your UBC alumni email address to cre ##### Installing CLion -* Inside a terminal, navigate to the environment_setup folder. Eg. `cd path/to/the/repository/Software/environment_setup` -* Run `./install_clion.sh` (* **We highly recommend using the script and not downloading CLion yourself unless you know what you're doing.** The `install_clion.sh` script will grab the correct version of CLion and the Bazel plugin to ensure everything is compatible *). -* When you run CLion for the first time you will be prompted to enter your JetBrains account or License credentials. Use your student account. +1. Follow [the latest instructions from JetBrains](https://www.jetbrains.com/help/clion/installation-guide.html#toolbox) on installing CLion. We recommend installing CLion through the JetBrains Toolbox App which makes it easy to upgrade/downgrade your version of CLion if necessary. +2. When you run CLion for the first time, you will be prompted to enter your JetBrains account or License credentials. Use your student account. +3. Install the [Bazel plugin for CLion](https://plugins.jetbrains.com/plugin/9554-bazel-for-clion). ### Installing an IDE: VS Code VS Code is a more lightweight "IDE", with support for code navigation, code completion, and integrated building and testing. However, debugging isn't integrated by default into VS Code. -1. Inside a terminal, navigate to the environment_setup folder. Eg. `cd path/to/the/repository/Software/environment_setup` -2. Run `./install_vscode.sh` (* **We highly recommend using the script and not downloading VS Code yourself unless you know what you're doing.** The `install_vscode.sh` script will grab the most stable version of VS Code *) -3. Open `vscode`. You can type `vscode` in the terminal, or click the icon on your Desktop. Go to File -> Open Folder and navigate to where you cloned the software repo. So if I cloned the repo to `/home/my_username/Downloads/Software`, I would select `/home/my_username/Downloads/Software`. -4. VS Code will prompt you to install recommended extensions. Click `Install` — this installs necessary plugins to work on the codebase. (Bazel, C++, Python, etc.) -5. Navigate to File -> Preferences -> Settings -> Workspace -> Extensions -> Bazel and select the `Bazel: Enable Code Lens` option. +1. Follow the [latest instructions from the VS Code documentation](https://code.visualstudio.com/docs/setup/linux) on installing VS Code. +2. Open VS Code. Go to File -> Open Folder and navigate to where you cloned the software repo. So if I cloned the repo to `/home/my_username/Downloads/Software`, I would select `/home/my_username/Downloads/Software`. +3. VS Code will prompt you to install recommended extensions. Click `Install` — this installs necessary plugins to work on the codebase. (Bazel, C++, Python, etc.) +4. Navigate to File -> Preferences -> Settings -> Workspace -> Extensions -> Bazel and select the `Bazel: Enable Code Lens` option. ### Editing with Vim or NeoVim @@ -300,7 +299,7 @@ Debugging in CLion is as simple as running the above instructions for building C To debug from the command line, first you need to build your target with the debugging flag - `bazel build -c dbg //some/target:here`. When the target builds, you should see a path `bazel-bin/`. Copy that path, and run `gdb `. Please see [here](https://www.cs.cmu.edu/~gilpin/tutorial/) for a tutorial on how to use `gdb` if you're not familiar with it. Alternatively, you could do `bazel run -c dbg --run_under="gdb" //some/target:here`, which will run the target in `gdb`. While this is taken directly from the Bazel docs, gdb may sometimes hang when using `--run_under`, so building the target first with debugging flags and running afterwards is preferred. -## Profiling +## Profiling Profiling is an optimization tool used to identify the time and space used by code, with a detailed breakdown to help identify areas of potential performance improvements. Unfortunately profiling for Bazel targets is not supported in CLion at this time. Hence, the only way to profile our software is via the command line. @@ -343,11 +342,11 @@ Tracy also samples call stacks. If the profiled binary is run with root permissi ./tbots.py run thunderscope_main --tracy --sudo -## Building for Jetson Nano +## Building for Jetson Nano To build for the Jetson Nano, build the target with the `--cpu=jetson_nano` flag and the toolchain will automatically build using the ARM toolchain for Jetson Nano. For example, `bazel build --cpu=jetson_nano //software/geom/...`. -## Deploying to Jetson Nano +## Deploying to Jetson Nano We use ansible to automatically update software running on the Jetson Nano. [More info here.](useful-robot-commands.md#flashing-the-nano) diff --git a/environment_setup/install_clion.sh b/environment_setup/install_clion.sh deleted file mode 100755 index 2191094039..0000000000 --- a/environment_setup/install_clion.sh +++ /dev/null @@ -1,78 +0,0 @@ -#!/bin/bash - -echo "================================================================" -echo "Installing CLion" -echo "================================================================" - -clion_version_year="2021" -clion_version_major="2" -clion_version_minor="4" -clion_version="${clion_version_year}.${clion_version_major}.${clion_version_minor}" -clion_executable_path="/usr/local/bin/clion" - - -# Check the correct clion version is installed -if [ -e "/opt/clion-${clion_version}/bin/clion.sh" ] && [ -e ${clion_executable_path}-${clion_version} ] -then - echo "================================================================" - echo "CLion is already installed" - echo "================================================================" -else - # Download clion - wget -O /tmp/CLion-${clion_version}.tar.gz "https://download.jetbrains.com/cpp/CLion-${clion_version}.tar.gz" - - # Unzip and symlink to usr location - sudo tar xfz /tmp/CLion-${clion_version}.tar.gz -C /opt - - # Install clion desktop entry - wget -O ~/.local/share/applications/jetbrains-clion.desktop "https://raw.githubusercontent.com/pld-linux/clion/master/clion.desktop" - echo "Icon=/opt/clion-${clion_version}/bin/clion.png" >> ~/.local/share/applications/jetbrains-clion.desktop -fi - -echo "================================================================" -echo "Symlinking CLion" -echo "================================================================" -# Symlink clion binary to a location in the PATH -# We do this outside the above `if` because this gives us the ability to -# change clion versions without re-downloading -sudo ln -s -f /opt/clion-${clion_version}/bin/clion.sh ${clion_executable_path}-${clion_version} -sudo ln -s -f ${clion_executable_path}-${clion_version} $clion_executable_path - -echo "================================================================" -echo "Installing Bazel Plugin" -echo "================================================================" - -clion_plugin_dir="${HOME}/.CLion${clion_version_year}.${clion_version_major}/config/plugins" -bazel_plugin_version_year="2022" -bazel_plugin_version_major="03" -bazel_plugin_version_minor="22" -bazel_plugin_version="v${bazel_plugin_version_year}.${bazel_plugin_version_major}.${bazel_plugin_version_minor}" - -if [ -d "${clion_plugin_dir}/clwb" ] -then - echo "================================================================" - echo "Bazel Plugin Already Installed" - echo "To force reinstallation please remove ${clion_plugin_dir}/clwb". - echo "================================================================" -else - # Download bazel plugin - wget -O /tmp/bazelbuild-${bazel_plugin_version}.tar.gz "https://github.com/bazelbuild/intellij/archive/${bazel_plugin_version}.tar.gz" - - # Unpack and build the plugin from the source - mkdir -p /tmp/bazelbuild-${bazel_plugin_version} - tar xfz /tmp/bazelbuild-${bazel_plugin_version}.tar.gz -C /tmp/bazelbuild-${bazel_plugin_version} - cd /tmp/bazelbuild-${bazel_plugin_version}/intellij* || exit - bazel build //clwb:clwb_bazel_zip --define=ij_product=clion-${clion_version_year}.${clion_version_major} - - # Copy the compiled plugin to the CLion directory - mkdir -p "$clion_plugin_dir" - unzip bazel-bin/clwb/clwb_bazel.zip -d "$clion_plugin_dir" - - # Cleanup - rm -rf /tmp/bazelbuild -fi - - -echo "================================================================" -echo "Done" -echo "================================================================" diff --git a/environment_setup/install_vscode.sh b/environment_setup/install_vscode.sh deleted file mode 100755 index 436d4cd6a7..0000000000 --- a/environment_setup/install_vscode.sh +++ /dev/null @@ -1,47 +0,0 @@ -#!/bin/bash - -echo "================================================================" -echo "Installing VSCode" -echo "================================================================" - -if [ "$EUID" -ne 0 ] - then echo "Please run as root" - exit -fi - -if [ -d "/opt/VSCode-linux-x64" ] -then - echo "Old VSCode installation detected, please delete /opt/VSCode-linux-x64 and re-run" - exit 1 -fi - -# permalink obtained from here: https://github.com/microsoft/vscode/issues/1084 -download_permalink_linux64=http://go.microsoft.com/fwlink/?LinkID=620884 -vscode_executable_path="/usr/local/bin/vscode" - -echo "Downloading Stable VSCode" -wget -O /tmp/vscode-stable.tar.gz $download_permalink_linux64 - -echo "Unzipping to /opt folder" -tar -xvf /tmp/vscode-stable.tar.gz -C /opt - -echo "Creating Desktop Entry" - -VSCODE_DESKTOP_ENTRY=''' -[Desktop Entry] -Name=Visual Studio Code -Comment=Programming Text Editor -Exec=/opt/VSCode-linux-x64/code -Icon=/opt/VSCode-linux-x64/resources/app/resources/linux/code.png -Terminal=false -Type=Application -Categories=Programming; -''' -echo "$VSCODE_DESKTOP_ENTRY" > ~/.local/share/applications/vscode.desktop - -echo "Symlink VSCode" -sudo ln -s -f /opt/VSCode-linux-x64/code ${vscode_executable_path} - -echo "================================================================" -echo "Done" -echo "================================================================" From 5022a95c351f2454ad2338c103bb5057423d7731 Mon Sep 17 00:00:00 2001 From: williamckha Date: Sun, 27 Oct 2024 22:59:14 -0700 Subject: [PATCH 10/18] Add markdown table of contents generator to lint_and_format.sh --- docs/code-style-guide.md | 33 +++-- docs/getting-started-wsl.md | 18 ++- docs/getting-started.md | 104 +++++++------- docs/robot-software-architecture.md | 22 +-- docs/software-architecture-and-design.md | 149 ++++++++++---------- docs/useful-robot-commands.md | 50 +++---- environment_setup/ubuntu20_requirements.txt | 1 + environment_setup/ubuntu22_requirements.txt | 1 + environment_setup/ubuntu24_requirements.txt | 1 + scripts/lint_and_format.sh | 9 ++ 10 files changed, 211 insertions(+), 177 deletions(-) diff --git a/docs/code-style-guide.md b/docs/code-style-guide.md index 4385fef6f7..c26f594e7b 100644 --- a/docs/code-style-guide.md +++ b/docs/code-style-guide.md @@ -1,19 +1,24 @@ # Code Style Guide -## Table of Contents -* [Names and Variables](#names-and-variables) -* [Comments](#comments) -* [Headers](#headers) -* [Includes](#includes) -* [Namespaces](#namespaces) -* [Exceptions](#exceptions) -* [Tests](#tests) -* [Getter And Setter Functions](#getter-and-setter-functions) -* [Static Creators](#static-creators) -* [Spelling](#spelling) -* [Miscellaneous](#miscellaneous) -* [Protobuf](#protobuf) - +### Table of Contents + + + +- [Table of Contents](#table-of-contents) +- [Names and Variables](#names-and-variables) +- [Comments](#comments) +- [Headers](#headers) +- [Includes](#includes) +- [Namespaces](#namespaces) +- [Exceptions](#exceptions) +- [Tests](#tests) +- [Getter And Setter Functions](#getter-and-setter-functions) +- [Static Creators](#static-creators) +- [Spelling](#spelling) +- [Miscellaneous](#miscellaneous) +- [Protobuf](#protobuf) + + Our C++ coding style is based off of [Google's C++ Style Guide](https://google.github.io/styleguide/cppguide.html). We use [clang-format](https://clang.llvm.org/docs/ClangFormat.html) to enforce most of the nit-picky parts of the style, such as brackets and alignment, so this document highlights the important rules to follow that clang-format cannot enforce. diff --git a/docs/getting-started-wsl.md b/docs/getting-started-wsl.md index e939c03826..bacf96489d 100644 --- a/docs/getting-started-wsl.md +++ b/docs/getting-started-wsl.md @@ -2,13 +2,17 @@ ## Table of Contents -* [Table of Contents](#table-of-contents) -* [Introduction](#introduction) -* [WSLg Setup (Windows 11/10 - Recommended)](#wslg-setup-windows-1110---recommended) -* [WSL2 Setup (Windows 10)](#wsl2-setup-windows-10) - * [X Server Setup](#x-server-setup) -* [Networking Issues](#networking-issues) -* [USB Issues](#usb-issues) + + +- [Table of Contents](#table-of-contents) +- [Introduction](#introduction) +- [WSLg Setup (Windows 11/10 - Recommended)](#wslg-setup-windows-1110---recommended) +- [WSL2 Setup (Windows 10)](#wsl2-setup-windows-10) + - [X Server Setup](#x-server-setup) +- [Networking Issues](#networking-issues) +- [USB Issues](#usb-issues) + + ## Introduction diff --git a/docs/getting-started.md b/docs/getting-started.md index 2b9bc85a78..ab9d6041f0 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -1,56 +1,54 @@ -Table of Contents -================= - -* [Software Setup](#software-setup) - * [Introduction](#introduction) - * [Installation and Setup](#installation-and-setup) - * [Operating systems](#operating-systems) - * [Getting the Code](#getting-the-code) - * [Installing Software Dependencies](#installing-software-dependencies) - * [Installing an IDE](#installing-an-ide) - * [Installing an IDE: CLion](#installing-an-ide-clion) - * [Getting your Student License](#getting-your-student-license) - * [Installing CLion](#installing-clion) - * [Installing an IDE: VS Code](#installing-an-ide-vs-code) - * [Editing with Vim or NeoVim](#editing-with-vim-or-neovim) - * [Building and Running the Code](#building-and-running-the-code) - * [Building from the command-line](#building-from-the-command-line) - * [Building from the command-line using the fuzzy finder](#building-from-the-command-line-using-the-fuzzy-finder) - * [Building with CLion](#building-with-clion) - * [Building with VS Code](#building-with-vs-code) - * [Running our AI, Simulator, SimulatedTests or Robot Diagnostics](#running-our-ai-simulator-simulatedtests-or-robot-diagnostics) - * [Debugging](#debugging) - * [Debugging with CLion](#debugging-with-clion) - * [Debugging from the Command line](#debugging-from-the-command-line) - * [Profiling](#profiling) - * [Callgrind](#callgrind) - * [Tracy](#tracy) - * [Building for the robot](#building-for-the-robot) - * [Deploying Robot Software to the robot](#deploying-robot-software-to-the-robot) - * [Setting up Virtual Robocup 2021](#setting-up-virtual-robocup-2021) - * [Setting up the SSL Simulation Environment](#setting-up-the-ssl-simulation-environment) - * [Pushing a Dockerfile to dockerhub](#pushing-a-dockerfile-to-dockerhub) -* [Workflow](#workflow) - * [Issue and Project Tracking](#issue-and-project-tracking) - * [Issues](#issues) - * [Git Workflow](#git-workflow) - * [Forking and Branching](#forking-and-branching) - * [Creating a new Branch](#creating-a-new-branch) - * [Making Commits](#making-commits) - * [Updating Your Branch and Resolving Conflicts](#updating-your-branch-and-resolving-conflicts) - * [Formatting Your Code](#formatting-your-code) - * [Pull Requests](#pull-requests) - * [Reviewing Pull Requests](#reviewing-pull-requests) - * [Example Workflow](#example-workflow) - * [Testing](#testing) - - +# Getting Started + +# Table of Contents + + + +- [Table of Contents](#table-of-contents) +- [Software Setup](#software-setup) + - [Introduction](#introduction) + - [Installation and Setup](#installation-and-setup) + - [Operating systems](#operating-systems) + - [Getting the Code](#getting-the-code) + - [Installing Software Dependencies](#installing-software-dependencies) + - [Installing an IDE](#installing-an-ide) + - [Installing an IDE: CLion](#installing-an-ide-clion) + - [Getting your Student License](#getting-your-student-license) + - [Installing CLion](#installing-clion) + - [Installing an IDE: VS Code](#installing-an-ide-vs-code) + - [Editing with Vim or NeoVim](#editing-with-vim-or-neovim) + - [Building and Running the Code](#building-and-running-the-code) + - [Building from the command-line](#building-from-the-command-line) + - [Building from the command-line using the fuzzy finder](#building-from-the-command-line-using-the-fuzzy-finder) + - [Building with CLion](#building-with-clion) + - [Building with VS Code](#building-with-vs-code) + - [Running our AI, Simulator, SimulatedTests or Robot Diagnostics](#running-our-ai-simulator-simulatedtests-or-robot-diagnostics) + - [Debugging](#debugging) + - [Debugging with CLion](#debugging-with-clion) + - [Debugging from the Command line](#debugging-from-the-command-line) + - [Profiling](#profiling) + - [Callgrind](#callgrind) + - [Tracy](#tracy) + - [Building for the robot](#building-for-the-robot) + - [Deploying Robot Software to the robot](#deploying-robot-software-to-the-robot) + - [Setting up Virtual Robocup 2021](#setting-up-virtual-robocup-2021) + - [Setting up the SSL Simulation Environment](#setting-up-the-ssl-simulation-environment) + - [Pushing a Dockerfile to dockerhub](#pushing-a-dockerfile-to-dockerhub) +- [Workflow](#workflow) + - [Issue and Project Tracking](#issue-and-project-tracking) + - [Issues](#issues) + - [Git Workflow](#git-workflow) + - [Forking and Branching](#forking-and-branching) + - [Creating a new Branch](#creating-a-new-branch) + - [Making Commits](#making-commits) + - [Updating Your Branch and Resolving Conflicts](#updating-your-branch-and-resolving-conflicts) + - [Formatting Your Code](#formatting-your-code) + - [Pull Requests](#pull-requests) + - [Reviewing Pull Requests](#reviewing-pull-requests) + - [Example Workflow](#example-workflow) + - [Testing](#testing) + + # Software Setup diff --git a/docs/robot-software-architecture.md b/docs/robot-software-architecture.md index 9f6059524b..cc69d1560c 100644 --- a/docs/robot-software-architecture.md +++ b/docs/robot-software-architecture.md @@ -1,14 +1,20 @@ # Robot Software Architecture # Table of Contents -* [Tools](#tools) - * [Ansible](#ansible) - * [Systemd](#systemd) - * [Redis](#redis) -* [Redis](#redis) -* [Thunderloop](#thunderloop) -* [Announcements](#announcements) -* [Display](#display) + + + +- [Table of Contents](#table-of-contents) +- [Robot Software Diagram](#robot-software-diagram) +- [Tools](#tools) + - [Ansible](#ansible) + - [Systemd](#systemd) + - [Redis](#redis) +- [Thunderloop](#thunderloop) + + + +# Robot Software Diagram ![Robot Software Diagram](images/robot_software_diagram.svg) diff --git a/docs/software-architecture-and-design.md b/docs/software-architecture-and-design.md index 0b93dbe1f8..3ac2df0da6 100644 --- a/docs/software-architecture-and-design.md +++ b/docs/software-architecture-and-design.md @@ -1,72 +1,79 @@ # Architecture and Design Rationales # Table of Contents -* [Tools](#tools) - * [SSL-Vision](#ssl-vision) - * [SSL-Gamecontroller](#ssl-gamecontroller) -* [Important Classes](#important-classes) - * [World](#world) - * [Team](#team) - * [Robot](#robot) - * [Ball](#ball) - * [Field](#field) - * [GameState](#gamestate) - * [Dynamic Parameters](#dynamic-parameters) -* [Protobuf](#protobuf) - * [Important Protobuf Messages](#important-protobuf-messages) - * [Primitives](#primitives) - * [Robot Status](#robot-status) -* [Design Patterns](#design-patterns) - * [Abstract Classes and Inheritance](#abstract-classes-and-inheritance) - * [Singleton Pattern](#singleton-pattern) - * [Factory Pattern](#factory-pattern) - * [Visitor Pattern](#visitor-pattern) - * [Observer Pattern](#observer-pattern) - * [Threaded Observer](#threaded-observer) - * [Publisher-Subscriber Pattern](#publisher-subscriber-pattern) - * [C++ Templating](#c-templating) -* [Coroutines](#coroutines) - * [What Are Coroutines?](#what-are-coroutines) - * [What Coroutines Do We Use?](#what-coroutines-do-we-use) - * [How Do We Use Coroutines?](#how-do-we-use-coroutines) - * [Coroutine Best Practices](#coroutine-best-practices) -* [Finite State Machines](#finite-state-machines) - * [What Are Finite State Machines?](#what-are-finite-state-machines) - * [Boost-ext SML Library](#boost-ext-sml-library) - * [How Do We Use SML?](#how-do-we-use-sml) - * [SML Best Practices](#sml-best-practices) -* [Conventions](#conventions) - * [Coordinates](#coordinates) - * [Angles](#angles) - * [Convention Diagram](#convention-diagram) -* [Architecture Overview](#architecture-overview) - * [Fullsystem](#fullsystem) - * [Backend](#backend) - * [Backend Diagram](#backend-diagram) - * [Sensor Fusion](#sensor-fusion) - * [Filters](#filters) - * [AI](#ai) - * [Strategy](#strategy) - * [STP Diagram](#stp-diagram) - * [Tactics](#tactics) - * [Plays](#plays) - * [Navigation](#navigation) - * [Path Manager](#path-manager) - * [Path Objective](#path-objective) - * [Path Planner](#path-planner) - * [AI Diagram](#ai-diagram) - * [Thunderscope](#thunderscope) - * [Thunderscope GUI](#thunderscope-gui) - * [3D Visualizer](#3d-visualizer) - * [Layers](#layers) - * [Simulator](#simulator) - * [Simulated Tests](#simulated-tests) - * [Simulated Tests Architecture](#simulated-tests-architecture) - * [Validation Functions](#validation-functions) - * [Component Connections and Determinism](#component-connections-and-determinism) - * [Simulated Tests Diagram](#simulated-tests-diagram) - * [Inter-process Communication](#inter-process-communication) - * [Estop](#estop) + + + +- [Table of Contents](#table-of-contents) +- [Tools](#tools) + - [SSL-Vision](#ssl-vision) + - [SSL-Gamecontroller](#ssl-gamecontroller) +- [Important Classes](#important-classes) + - [World](#world) + - [Team](#team) + - [Robot](#robot) + - [Ball](#ball) + - [Field](#field) + - [GameState](#gamestate) + - [Dynamic Parameters](#dynamic-parameters) +- [Protobuf](#protobuf) + - [Important Protobuf Messages](#important-protobuf-messages) + - [Primitives](#primitives) + - [Robot Status](#robot-status) +- [Design Patterns](#design-patterns) + - [Abstract Classes and Inheritance](#abstract-classes-and-inheritance) + - [Singleton Pattern](#singleton-pattern) + - [Factory Pattern](#factory-pattern) + - [Visitor Pattern](#visitor-pattern) + - [Observer Pattern](#observer-pattern) + - [Threaded Observer](#threaded-observer) + - [Publisher-Subscriber Pattern](#publisher-subscriber-pattern) + - [C++ Templating](#c-templating) +- [Coroutines](#coroutines) + - [What Are Coroutines?](#what-are-coroutines) + - [What Coroutines Do We Use?](#what-coroutines-do-we-use) + - [How Do We Use Coroutines?](#how-do-we-use-coroutines) + - [Coroutine Best Practices](#coroutine-best-practices) +- [Finite State Machines](#finite-state-machines) + - [What Are Finite State Machines?](#what-are-finite-state-machines) + - [Boost-ext SML Library](#boost-ext-sml-library) + - [How Do We Use SML?](#how-do-we-use-sml) + - [SML Best Practices](#sml-best-practices) +- [Conventions](#conventions) + - [Coordinates](#coordinates) + - [Angles](#angles) + - [Convention Diagram](#convention-diagram) +- [Architecture Overview](#architecture-overview) +- [Fullsystem](#fullsystem) + - [Backend](#backend) + - [Backend Diagram](#backend-diagram) + - [Sensor Fusion](#sensor-fusion) + - [Filters](#filters) +- [AI](#ai) + - [Strategy](#strategy) + - [STP Diagram](#stp-diagram) + - [Skills](#skills) + - [Tactics](#tactics) + - [Plays](#plays) + - [Navigation](#navigation) + - [Path Manager](#path-manager) + - [Path Objective](#path-objective) + - [Path Planner](#path-planner) + - [AI Diagram](#ai-diagram) +- [Thunderscope](#thunderscope) + - [Thunderscope GUI](#thunderscope-gui) + - [3D Visualizer](#3d-visualizer) + - [Layers](#layers) +- [Simulator](#simulator) + - [Simulated Tests](#simulated-tests) + - [Simulated Tests Architecture](#simulated-tests-architecture) + - [Validation Functions](#validation-functions) + - [Component Connections and Determinism](#component-connections-and-determinism) + - [Simulated Tests Diagram](#simulated-tests-diagram) +- [Inter-process Communication](#inter-process-communication) +- [E-Stop](#e-stop) + + # Tools A few commonly-used terms and tools to be familiar with: @@ -581,7 +588,7 @@ A path objective is a simple datastructure used to communicate between the navig ### Path Planner The `Path Planner` is an interface for the responsibility of path planning a single robot around a single set of obstacles from a given start to a given destination. The interface allows us to easily swap out path planners. -## [AI](#ai) Diagram +## AI Diagram ![AI Diagram](images/ai_diagram.svg) # Thunderscope @@ -689,7 +696,7 @@ Logging protobufs is done at the VISUALIZE level (e.g. LOG(VI In Thunderscope, the [`ProtoUnixIO`](../src/software/thunderscope/proto_unix_io.py) is responsible for communicating protobufs over unix sockets. `ProtoUnixIO` utilizes a variation of the [publisher-subscriber ("pub-sub")](#publisher-subscriber-pattern) messaging pattern. Through `ProtoUnixIO`, clients can register as a subscriber by providing a type of protobuf to receive and a [`ThreadSafeBuffer`](../src/software/thunderscope/thread_safe_buffer.py) to place incoming protobuf messages. The `ProtoUnixIO` can then be configured with a unix receiver to receive protobufs over a unix socket and place those messages onto the `ThreadSafeBuffer`s of that proto's subscribers. Classes can also publish protobufs via `ProtoUnixIO` by configuring it with a unix sender. -# Estop -The `Estop` allows us to quickly and manually command physical robots to stop what they are doing. It is a physical push button that is connected to the computer via a USB cable (we also have a `--keyboard-estop` flag you can use when running Thunderscope that lets you use the spacebar as the `Estop`). When Thunderscope is launched, a `ThreadedEstopReader` is initialized (within `RobotCommunication`) that is responsible for communicating and reading values from the `Estop` via UART. While running, it will poll the status of the `Estop` to determine whether it is in the `STOP` or `PLAY` state: -- If the `Estop` is in the `STOP` state, it overrides the [Primitives](#primitives) sent to the robots with `Stop` primitives. On the robot, `Thunderloop` is responsible for handling the primitive message and ensuring that the power & motor boards receive the correct inputs for the robot to stop. -- If the `Estop` is in the `PLAY` state, primitives are communicated as normal. +# E-Stop +The E-Stop allows us to quickly and manually command physical robots to stop what they are doing. It is a physical push button that is connected to the computer via a USB cable. We also have a `--keyboard_estop` flag you can use when running Thunderscope that lets you use the spacebar as the E-Stop. When Thunderscope is launched, a `ThreadedEstopReader` is initialized (within `RobotCommunication`) that is responsible for communicating and reading values from the E-Stop via UART. While running, it will poll the status of the E-Stop to determine whether it is in the `STOP` or `PLAY` state: +- If the E-Stop is in the `STOP` state, it overrides the [Primitives](#primitives) sent to the robots with `Stop` primitives. On the robot, Thunderloop is responsible for handling the primitive message and ensuring that the power & motor boards receive the correct inputs for the robot to stop. +- If the E-Stop is in the `PLAY` state, primitives are communicated as normal. diff --git a/docs/useful-robot-commands.md b/docs/useful-robot-commands.md index 431f7c3c45..297153cc19 100644 --- a/docs/useful-robot-commands.md +++ b/docs/useful-robot-commands.md @@ -1,27 +1,29 @@ -Table of Contents -================= - -* [Table of Contents](#table-of-contents) -* [Common Debugging Steps](#common-debugging-steps) -* [Off Robot Commands](#off-robot-commands) - * [Wifi Disclaimer](#wifi-disclaimer) - * [Miscellaneous Ansible Tasks & Options](#miscellaneous-ansible-tasks--options) - * [Flashing the robot's compute module](#flashing-the-robots-compute-module) - * [Flashing the powerboard](#flashing-the-powerboard) - * [Setting up the embedded host](#setting-up-the-embedded-host) - * [Jetson Nano](#jetson-nano) - * [Raspberry Pi](#raspberry-pi) - * [Robot Diagnostics](#robot-diagnostics) - * [For Just Diagnostics](#for-just-diagnostics) - * [For AI + Diagnostics](#for-ai--diagnostics) - * [Robot Auto Test](#robot-auto-test) -* [On Robot Commands](#on-robot-commands) - * [Systemd Services](#systemd-services) - * [Debugging Uart](#debugging-uart) - * [Redis](#redis) - - - +# Useful Robot Commands + +# Table of Contents + + + +- [Table of Contents](#table-of-contents) +- [Common Debugging Steps](#common-debugging-steps) +- [Off Robot Commands](#off-robot-commands) + - [Wifi Disclaimer](#wifi-disclaimer) + - [Miscellaneous Ansible Tasks & Options](#miscellaneous-ansible-tasks--options) + - [Flashing the robot's compute module](#flashing-the-robots-compute-module) + - [Flashing the powerboard](#flashing-the-powerboard) + - [Setting up the embedded host](#setting-up-the-embedded-host) + - [Jetson Nano](#jetson-nano) + - [Raspberry Pi](#raspberry-pi) + - [Robot Diagnostics](#robot-diagnostics) + - [For Just Diagnostics](#for-just-diagnostics) + - [For AI + Diagnostics](#for-ai--diagnostics) + - [Robot Auto Test](#robot-auto-test) +- [On Robot Commands](#on-robot-commands) + - [Systemd Services](#systemd-services) + - [Debugging Uart](#debugging-uart) + - [Redis](#redis) + + # Common Debugging Steps ```mermaid diff --git a/environment_setup/ubuntu20_requirements.txt b/environment_setup/ubuntu20_requirements.txt index e521b08ed0..675bd298c7 100644 --- a/environment_setup/ubuntu20_requirements.txt +++ b/environment_setup/ubuntu20_requirements.txt @@ -8,3 +8,4 @@ psutil==5.9.0 PyOpenGL==3.1.6 qt-material==2.12 ruff==0.5.5 +md-toc==9.0.0 diff --git a/environment_setup/ubuntu22_requirements.txt b/environment_setup/ubuntu22_requirements.txt index 3a9e4d6385..0607bdff3e 100644 --- a/environment_setup/ubuntu22_requirements.txt +++ b/environment_setup/ubuntu22_requirements.txt @@ -9,3 +9,4 @@ PyOpenGL==3.1.6 numpy==1.26.4 qt-material==2.12 ruff==0.5.5 +md-toc==9.0.0 diff --git a/environment_setup/ubuntu24_requirements.txt b/environment_setup/ubuntu24_requirements.txt index 983fcdda89..5383aa6992 100644 --- a/environment_setup/ubuntu24_requirements.txt +++ b/environment_setup/ubuntu24_requirements.txt @@ -6,3 +6,4 @@ psutil==5.9.0 PyOpenGL==3.1.6 qt-material==2.12 ruff==0.5.5 +md-toc==9.0.0 diff --git a/scripts/lint_and_format.sh b/scripts/lint_and_format.sh index 0f6fc83187..6d262e15e3 100755 --- a/scripts/lint_and_format.sh +++ b/scripts/lint_and_format.sh @@ -99,6 +99,14 @@ function run_code_spell(){ fi } +function run_md_toc() { + printf "Adding table of contents to Markdown files...\n\n" + for file in $CURR_DIR/../docs/*.md + do + /opt/tbotspython/bin/python3 -m md_toc --in-place --no-list-coherence --skip-lines 1 github $file + done +} + function run_git_diff_check(){ printf "Checking for merge conflict markers...\n\n" cd $CURR_DIR && git -c "core.whitespace=-trailing-space" --no-pager diff --check @@ -124,6 +132,7 @@ run_code_spell run_clang_format run_bazel_formatting run_ruff +run_md_toc run_eof_new_line run_git_diff_check From 82c9a05a7ed6c7d2a88ad90b677c268a320f86ff Mon Sep 17 00:00:00 2001 From: williamckha Date: Mon, 4 Nov 2024 14:25:52 -0800 Subject: [PATCH 11/18] Rename command-line to command line when it is a noun --- docs/getting-started.md | 14 +++++++------- src/software/field_tests/field_test_fixture.py | 2 +- src/software/logger/logger.h | 2 +- src/software/network_log_listener_main.cpp | 1 - .../simulated_tests/simulated_test_fixture.py | 2 +- 5 files changed, 10 insertions(+), 11 deletions(-) diff --git a/docs/getting-started.md b/docs/getting-started.md index ab9d6041f0..098f1f3b24 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -18,14 +18,14 @@ - [Installing an IDE: VS Code](#installing-an-ide-vs-code) - [Editing with Vim or NeoVim](#editing-with-vim-or-neovim) - [Building and Running the Code](#building-and-running-the-code) - - [Building from the command-line](#building-from-the-command-line) - - [Building from the command-line using the fuzzy finder](#building-from-the-command-line-using-the-fuzzy-finder) + - [Building from the command line](#building-from-the-command-line) + - [Building from the command line using the fuzzy finder](#building-from-the-command-line-using-the-fuzzy-finder) - [Building with CLion](#building-with-clion) - [Building with VS Code](#building-with-vs-code) - [Running our AI, Simulator, SimulatedTests or Robot Diagnostics](#running-our-ai-simulator-simulatedtests-or-robot-diagnostics) - [Debugging](#debugging) - [Debugging with CLion](#debugging-with-clion) - - [Debugging from the Command line](#debugging-from-the-command-line) + - [Debugging from the Command Line](#debugging-from-the-command-line) - [Profiling](#profiling) - [Callgrind](#callgrind) - [Tracy](#tracy) @@ -58,7 +58,7 @@ These instructions assume that you have the following accounts setup: - [GitHub](https://github.com/login) - [Discord](https://discord.com). Please contact a Thunderbots lead to receive the invite link. -These instructions assume you have a basic understanding of Linux and the command-line. There are many great tutorials online, such as [LinuxCommand](http://linuxcommand.org/). The most important things you'll need to know are how to move around the filesystem and how to run programs or scripts. +These instructions assume you have a basic understanding of Linux and the command line. There are many great tutorials online, such as [LinuxCommand](http://linuxcommand.org/). The most important things you'll need to know are how to move around the filesystem and how to run programs or scripts. ## Installation and Setup @@ -153,7 +153,7 @@ These tools require a `compile_commands.json` file, which can be generated by fo ## Building and Running the Code -### Building from the command-line +### Building from the command line 1. Navigate to the root of this repository (wherever you have it cloned on your computer) 2. Navigate to `src`. @@ -166,7 +166,7 @@ These tools require a `compile_commands.json` file, which can be generated by fo *See the Bazel [command-line docs](https://bazel.build/reference/command-line-reference) for more info.* *Note: the targets are defined in the BUILD files in our repo* -### Building from the command-line using the fuzzy finder +### Building from the command line using the fuzzy finder We have a `tbots.py` test runner script in the src folder that will fuzzy find for targets and call Bazel. For example, @@ -302,7 +302,7 @@ Debugging from the command line is certainly possible, but debugging in a full I Debugging in CLion is as simple as running the above instructions for building CLion, but clicking the little green bug in the top right corner instead of the little green arrow! -### Debugging from the Command line +### Debugging from the Command Line To debug from the command line, first you need to build your target with the debugging flag - `bazel build -c dbg //some/target:here`. When the target builds, you should see a path `bazel-bin/`. Copy that path, and run `gdb `. Please see [here](https://www.cs.cmu.edu/~gilpin/tutorial/) for a tutorial on how to use `gdb` if you're not familiar with it. Alternatively, you could do `bazel run -c dbg --run_under="gdb" //some/target:here`, which will run the target in `gdb`. While this is taken directly from the Bazel docs, gdb may sometimes hang when using `--run_under`, so building the target first with debugging flags and running afterwards is preferred. diff --git a/src/software/field_tests/field_test_fixture.py b/src/software/field_tests/field_test_fixture.py index f6e2e78d33..02b115156b 100644 --- a/src/software/field_tests/field_test_fixture.py +++ b/src/software/field_tests/field_test_fixture.py @@ -199,7 +199,7 @@ def excepthook(args): def load_command_line_arguments(): - """Load from command line arguments using argpase + """Load in command-line arguments using argparse NOTE: Pytest has its own built in argument parser (conftest.py, pytest_addoption) but it doesn't seem to play nicely with bazel. We just use argparse instead. diff --git a/src/software/logger/logger.h b/src/software/logger/logger.h index 461ff8f732..ea6f5a4b6f 100644 --- a/src/software/logger/logger.h +++ b/src/software/logger/logger.h @@ -85,7 +85,7 @@ class LoggerSingleton // tests:bazel-out/k8-fastbuild/bin/software/simulated_tests/TEST_NAME.runfiles/__main__/ // where TEST_NAME is the name of the simulated test - // Log locations can also be defined by setting the --logging_dir command line + // Log locations can also be defined by setting the --logging_dir command-line // arg. Note: log locations are defaulted to the bazel-out folder due to Bazel's // hermetic build principles diff --git a/src/software/network_log_listener_main.cpp b/src/software/network_log_listener_main.cpp index b762e63ef1..62ddfef28c 100644 --- a/src/software/network_log_listener_main.cpp +++ b/src/software/network_log_listener_main.cpp @@ -38,7 +38,6 @@ void logFromNetworking(TbotsProto::RobotLog log) int main(int argc, char **argv) { - // load command line arguments struct CommandLineArgs { bool help = false; diff --git a/src/software/simulated_tests/simulated_test_fixture.py b/src/software/simulated_tests/simulated_test_fixture.py index 034ed48873..bb96047d8f 100644 --- a/src/software/simulated_tests/simulated_test_fixture.py +++ b/src/software/simulated_tests/simulated_test_fixture.py @@ -385,7 +385,7 @@ def run_test( def load_command_line_arguments(): - """Load from command line arguments using argpase + """Load in command-line arguments using argparse NOTE: Pytest has its own built in argument parser (conftest.py, pytest_addoption) but it doesn't seem to play nicely with bazel. We just use argparse instead. From 248d004fa513d46b09e09274c05b31a98dfc9b01 Mon Sep 17 00:00:00 2001 From: williamckha Date: Mon, 4 Nov 2024 15:20:26 -0800 Subject: [PATCH 12/18] Various nits --- docs/getting-started.md | 20 ++++++++++---------- docs/software-architecture-and-design.md | 14 +++++++------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/docs/getting-started.md b/docs/getting-started.md index 098f1f3b24..c26005b666 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -89,16 +89,16 @@ You can use Ubuntu 20.04 LTS, Ubuntu 22.04 LTS or Ubuntu 24.04 LTS inside Window 1. If not setup prior, you will need to add an SSH key to your GitHub account. Instructions can be found [here](https://docs.github.com/en/authentication/connecting-to-github-with-ssh/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent). For each computer you contribute to GitHub with, you will need an additional SSH Key pair linked to your account. 2. After you have successfully set up a SSH key for your device and added it to GitHub, you can clone the repository using the following command: 1. e.g. `git clone git@github.com:/Software.git` - 2. You can find this link under the green `Clone or Download` button on the main page of your fork on GitHub, under the SSH tab. (This should now be available after adding your SSH key to GitHub successfully.) + 2. You can find this link under the green `Code` button on the main page of your fork on GitHub, under the SSH tab. (This should now be available after adding your SSH key to GitHub successfully.) Alternatively, you can clone using HTTPS. You'll need to either use a credential helper (Git Credential Manager, GitHub CLI, etc.) or a personal access token ([details here](https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls)). 6. Set up your git remotes ([what is a remote and how does it work?](https://git-scm.com/book/en/v2/Git-Basics-Working-with-Remotes)) 1. You should have a remote named `origin` that points to your fork of the repository. Git will have set this up automatically when you cloned your fork in the previous step. 2. You will need to add a second remote, named `upstream`, that points to our main Software repository, which is where you created your fork from. (**Note:** This is _not_ your fork) 1. Open a terminal and navigate to the folder you cloned (your fork): `cd path/to/the/repository/Software` - 2. Navigate to our main Software repository in your browser and copy the url from the green `Code` button. Copy the HTTPS url if you originally cloned with HTTPS, or use the SSH url if you previously cloned with SSH + 2. Navigate to our main Software repository in your browser and copy the url from the green `Code` button. Copy the SSH url if you originally cloned with SSH, or use the HTTPS url if you previously cloned with HTTPS 3. From your terminal, add the new remote by running `git remote add upstream ` (without the angle brackets) - 1. e.g. `git remote add upstream https://github.com/UBC-Thunderbots/Software.git` + 1. e.g. `git remote add upstream git@github.com:UBC-Thunderbots/Software.git` 4. That's it. If you want to double check your remotes are set up correctly, run `git remote -v` from your terminal (at the base of the repository folder again). You should see two entries: `origin` with the url for your fork of the repository, and `upstream` with the url for the main repository *See our [workflow](#workflow) for how to use git to make branches, submit Pull Requests, and track issues* @@ -408,7 +408,7 @@ In general, we follow the Forking Workflow ### Creating a new Branch -For each Issue of project you are working on, you should have a separate branch. This helps keep work organized and separate. +For each issue that you work on, you should have a separate branch. This helps keep work organized and separate. **Branches should always be created from the latest code on the `master` branch of our main Software repository**. If you followed the steps in [Installation and Setup](#installation-and-setup), this will be `upstream/master`. Once this branch is created, you can push it to your fork and update it with commits until it is ready to merge. @@ -423,7 +423,7 @@ For each Issue of project you are working on, you should have a separate branch. 4. You can now commit changes to this branch and push them to your fork with `git push origin your_branch_name` or `git push -u`
-Aside: Why should you only create branches from "upstream/master"? +Aside: Why should you only create branches from upstream/master? Because we squash our commits when we merge Pull Requests, a new commit with a new hash will be created, containing the multiple commits from the PR branch. Because the hashes are different, git will not recognize that the squashed commit and the series of commits that are inside the squashed commit contain the same changes, which can result in conflicts. @@ -449,9 +449,9 @@ To do this, you have 2 options: rebase or merge. [What's the difference?](https: Merging is generally recommended, because it is easier to handle conflicts and get stuff working. To merge, simply run `git pull upstream master`. -Rebasing requires more knowledge of git and can cause crazy merge conflicts, so it isn't recommended. You can simply `git pull --rebase upstream master` to rebase your branch onto the latest `upstream/master`. The main benefit of rebasing is that you get a clean, linear commit history; however, we squash all the commits in each PR into a single commit before merging into master, so the extra effort involved in rebasing is pointless. +Rebasing requires more knowledge of git and can cause crazy merge conflicts, so it isn't recommended. You can simply `git pull --rebase upstream master` to rebase your branch onto the latest `upstream/master`. The main benefit of rebasing is that you get a clean, linear commit history; however, we squash all the commits in each PR into a single commit before merging into master, so the extra effort involved in rebasing is somewhat pointless. -If you do rebase or merge and get conflicts, you'll need to resolve them manually. [See here for a quick tutorials on what conflicts are and how to resolve them](https://www.atlassian.com/git/tutorials/using-branches/merge-conflicts). Feel free to do this in your IDE or with whatever tool you are most comfortable with. Updating your branch often helps keep conflicts to a minimum, and when they do appear they are usually smaller. Ask for help if you're really stuck! +If you do rebase or merge and get conflicts, you'll need to resolve them manually. [See here for a quick tutorial on what conflicts are and how to resolve them](https://www.atlassian.com/git/tutorials/using-branches/merge-conflicts). Feel free to do this in your IDE or with whatever tool you are most comfortable with. Updating your branch often helps keep conflicts to a minimum, and when they do appear they are usually smaller. Ask for help if you're really stuck! ### Formatting Your Code @@ -488,14 +488,14 @@ The Pull Request process usually looks like the following: 5. Mark the Pull Request as "Approved" when you think it looks good 2. **If you are the recipient of the review (the PR creator):** 1. **Make sure to reply to the PR comments as you address / fix issues**. This helps the reviewers know you have made a change without having to go check the code diffs to see if you made a change. - 1. Eg. Reply with "done" or "fixed" to comments as you address them + 1. e.g. Reply with "done" or "fixed" to comments as you address them 2. Leave comments unresolved, let the reviewer resolve them. 2. Don't be afraid to ask for clarification regarding changes or suggest alternatives if you don't agree with what was suggested. The reviewers and reviewee should work together to come up with the best solution. 3. **Do not resolve conversations as you address them** (but make sure to leave a comment as mentioned above). That is the responsibility of the reviewers. 4. Once you have addressed all the comments, re-request review from reviewers. -11. Make sure our automated tests with Github Actions are passing. There will be an indicator near the bottom of the Pull Request. If something fails, you can click on the links provided to get more information and debug the problems. More than likely, you'll just need to re-run clang-format on the code. +11. Make sure our automated tests with Github Actions are passing. There will be an indicator near the bottom of the Pull Request. If something fails, you can click on the links provided to get more information and debug the problems. 12. Once your Pull Request has been approved and the automated tests pass, you can merge the code. There will be a big 'merge" button at the bottom of the Pull Request with several options to choose from - 1. We only allow "Squash and merge". This is because it keep the commit history on `upstream/master` shorter and cleaner, without losing any context from the commit messages (since they are combined in the squashed commit. A squashed commit also makes it easier to revert and entire change/feature, rather than having to "know" the range of commits to revert. + 1. We only allow "Squash and merge". This is because it keeps the commit history on `upstream/master` shorter and cleaner, without losing any context from the commit messages (since they are combined in the squashed commit. A squashed commit also makes it easier to revert and entire change/feature, rather than having to "know" the range of commits to revert. 13. That's it, your changes have been merged! You will be given the option to delete your remote branch. but are not required to do so. We recommend it since it will keep your fork cleaner, but you can do whatever you like. *Remember, code reviews can be tough. As a reviewer, it can be very tricky to give useful constructive criticism without coming off as condescending or degrading (emotions are hard to express through text!). As the recipient of a code review, it might feel like you are being criticized too harshly and that your hard work is being attacked. Remember that these are your teammates, who are not trying to arbitrarily devalue your contributions but are trying to help make the code as good as possible, for the good of the team.* diff --git a/docs/software-architecture-and-design.md b/docs/software-architecture-and-design.md index 3ac2df0da6..b227f3be84 100644 --- a/docs/software-architecture-and-design.md +++ b/docs/software-architecture-and-design.md @@ -107,13 +107,13 @@ The Field class represents the state of the physical field being played on, whic These represent the current state of the game as dictated by the Gamecontroller. These provide functions like `isPlaying()`, `isHalted()` which tell the rest of the system what game state we are in, and make decisions accordingly. We need to obey the rules! ## Dynamic Parameters -`Dynamic Parameters` are the system we use to change values in our code at runtime. The reason we want to change values at runtime is primarily because we may want to tweak our strategy or aspects of our gameplay very quickly. During games we are only allowed to touch our computers and make changes during halftime or a timeout, so every second counts! Using `Dynamic Parameters` saves us from having to stop the [AI](#ai), change a constant, recompile the code, and restart the [AI](#ai). +**Dynamic Parameters** are the system we use to change values in our code at runtime. The reason we want to change values at runtime is primarily because we may want to tweak our strategy or aspects of our gameplay very quickly. During games we are only allowed to touch our computers and make changes during halftime or a timeout, so every second counts! Using Dynamic Parameters saves us from having to stop the [AI](#ai), change a constant, recompile the code, and restart the [AI](#ai). -Additionally, we can use `Dynamic Parameters` to communicate between [Thunderscope](#thunderscope) and the rest of our system. [Thunderscope](#thunderscope) can change the values of `DynamicParameters` when buttons or menu items are clicked, and these new values will be picked up by the rest of the code. For example, we can define a `Dynamic Parameter` called `run_ai` that is a boolean value. Then when the Start AI button is clicked in [Thunderscope](#thunderscope), it sets the value of `run_ai` to `true`. In the "main loop" for the [AI](#ai), it will check if the value of `run_ai` is true before running its logic. +[Thunderscope](#thunderscope) has a widget that displays all our Dynamic Parameters and lets the user change their values. Whenever a Dynamic Parameter value is changed in the widget, [Fullsystem](#fullsystem) and [AI](#ai) will be updated with the new value. For example, we can define a Dynamic Parameter called `run_ai` that is a boolean value. The `run_ai` param will show up in the Parameters widget in [Thunderscope](#thunderscope) with a checkbox that sets the value of `run_ai`. In the "main loop" for the [AI](#ai), it will check if the value of `run_ai` is true before running its logic. -Here's a slightly more relevant example of how we used `Dynamic Parameters` during a game in RoboCup 2019. We had a parameter called `enemy_team_can_pass`, which indicates whether or not we think the enemy team can pass. This parameter was used in several places in our defensive logic, and specifically affected how we would shadow enemy robots when we were defending them. If we assumed the enemy team could pass, we would shadow between the robots and the ball to block any passes, otherwise we would shadow between the enemy robot and our net to block shots. During the start of a game, we had `enemy_team_can_pass` set to `false` but the enemy did start to attempt some passes during the game. However, we didn't want to use one of our timeouts to change the value. Luckily later during the half, the enemy team took a time out. Because `Dynamic Parameters` can be changed quick without stopping [AI](#ai), we were quickly able to change `enemy_team_can_pass` to `true` while the enemy team took their timeout. This made our defence much better against that team and didn't take so much time that we had to burn our own timeout. Altogether this is an example of how we use `Dynamic Parameters` to control our [AI](#ai) and other parts of the code. +Here's a slightly more relevant example of how we used Dynamic Parameters during a game in RoboCup 2019. We had a parameter called `enemy_team_can_pass`, which indicates whether or not we think the enemy team can pass. This parameter was used in several places in our defensive logic, and specifically affected how we would shadow enemy robots when we were defending them. If we assumed the enemy team could pass, we would shadow between the robots and the ball to block any passes, otherwise we would shadow between the enemy robot and our net to block shots. During the start of a game, we had `enemy_team_can_pass` set to `false` but the enemy did start to attempt some passes during the game. However, we didn't want to use one of our timeouts to change the value. Luckily later during the half, the enemy team took a time out. Because Dynamic Parameters can be changed quick without stopping [AI](#ai), we were quickly able to change `enemy_team_can_pass` to `true` while the enemy team took their timeout. This made our defence much better against that team and didn't take so much time that we had to burn our own timeout. Altogether this is an example of how we use Dynamic Parameters to control our [AI](#ai) and other parts of the code. -It is worth noting that constants are still useful, and should still be used whenever possible. If a value realistically doesn't need to be changed, it should be a constant (with a nice descriptive name) rather than a `Dynamic Parameter`. Having too many `Dynamic Parameters` is overwhelming because there are too many values to understand and change, and this can make it hard to tune values to get the desired behaviour while under pressure during a game. +It is worth noting that constants are still useful, and should still be used whenever possible. If a value realistically doesn't need to be changed, it should be a constant (with a nice descriptive name) rather than a Dynamic Parameter. Having too many Dynamic Parameters is overwhelming because there are too many values to understand and change, and this can make it hard to tune values to get the desired behaviour while under pressure during a game. # Protobuf @@ -258,7 +258,7 @@ This example / pseudocode does hide away some details about how coroutines are s ## What Coroutines Do We Use? We use the [boost Coroutine2 library](https://www.boost.org/doc/libs/1_71_0/libs/coroutine2/doc/html/index.html). Specifically, we use Asymmetric Coroutines. -[This stackoverfow answer](https://stackoverflow.com/a/42042904) gives a decent explanation of the difference between Symmetric and Asymmetric Coroutines, but understanding the difference is not critical for our purposes. We use Asymmetric Coroutines because boost does not provide Symmetric Coroutines, and the hierarchical structure of Asymmetric Coroutines is more useful to us. +[This Stack Overflow answer](https://stackoverflow.com/a/42042904) gives a decent explanation of the difference between Symmetric and Asymmetric Coroutines, but understanding the difference is not critical for our purposes. We use Asymmetric Coroutines because boost does not provide Symmetric Coroutines, and the hierarchical structure of Asymmetric Coroutines is more useful to us. ## How Do We Use Coroutines? @@ -311,7 +311,7 @@ A finite state machine (FSM) is a system with a finite number of states with def [source](https://www.block-net.de/Programmierung/cpp/fsm/fsm.html) ## Boost-ext SML Library -We use the [Boost-Ext SML](https://github.com/boost-ext/sml), short for State Machine Library, to manage our finite state machines. This library defines state machines through a transition table, where a row indicates the transition from one state to another state using _guards_, _actions_ and _events_. The syntax of a row of the transition table looks like this: +We use [Boost-ext SML](https://github.com/boost-ext/sml), short for State Machine Library, to manage our finite state machines. This library defines state machines through a transition table, where a row indicates the transition from one state to another state using _guards_, _actions_ and _events_. The syntax of a row of the transition table looks like this: ``` src_state + event [guard] / action = dest_state ``` @@ -342,7 +342,7 @@ SubFSM_S + event / update_sub_fsm_action The convenience of this syntax comes at the cost of hard to read error messages due to the functor and templating system. ## How Do We Use SML? -We use SML to implement our [Plays](#plays) and [Tactics](#tactic). Each state represents a stage in the play/tactic where the team/robot should be doing a particular thing or looking for certain conditions to be true. An example of this is the `MoveFSM`. While the robot is not at the destination and oriented correctly, the FSM is in the move state. Once the robot reaches its destination, it enters the terminal state, `X`, to indicate that it's done. SML also allows us to easily reuse FSMs in other tactics. For example, if a shadowing tactic needs to move to a particular destination with a certain orientation, then it can use the MoveFSM as a sub-FSM state. +We use SML to implement our [Plays](#plays) and [Tactics](#tactics). Each state represents a stage in the play/tactic where the team/robot should be doing a particular thing or looking for certain conditions to be true. An example of this is the `MoveFSM`. While the robot is not at the destination and oriented correctly, the FSM is in the move state. Once the robot reaches its destination, it enters the terminal state, `X`, to indicate that it's done. SML also allows us to easily reuse FSMs in other tactics. For example, if a shadowing tactic needs to move to a particular destination with a certain orientation, then it can use the MoveFSM as a sub-FSM state. If you're having trouble understanding the SML syntax, take a look at [`docs/fsm-diagrams.md`](./fsm-diagrams.md). It contains automatically generated diagrams of the FSMs in our codebase, which can help with visualizing the FSM control flow. From c1529c330bfdec259458118c10aaf4bd7224c2ab Mon Sep 17 00:00:00 2001 From: williamckha Date: Fri, 15 Nov 2024 13:59:07 -0800 Subject: [PATCH 13/18] Remove references to World from Thunderloop --- src/software/embedded/BUILD | 5 +++-- src/software/embedded/primitive_executor.h | 4 +++- src/software/embedded/thunderloop.cpp | 11 +++-------- src/software/embedded/thunderloop.h | 12 +++++------- 4 files changed, 14 insertions(+), 18 deletions(-) diff --git a/src/software/embedded/BUILD b/src/software/embedded/BUILD index d43be47e00..9da22336b0 100644 --- a/src/software/embedded/BUILD +++ b/src/software/embedded/BUILD @@ -42,7 +42,9 @@ cc_library( "//software/ai/navigator/trajectory:trajectory_path", "//software/math:math_functions", "//software/physics:velocity_conversion_util", - "//software/world", + "//software/time:duration", + "//software/world:robot_state", + "//software/world:team_colour", ], ) @@ -60,7 +62,6 @@ cc_library( "//software/logger:network_logger", "//software/tracy:tracy_constants", "//software/util/scoped_timespec_timer", - "//software/world:team", "@tracy", ], ) diff --git a/src/software/embedded/primitive_executor.h b/src/software/embedded/primitive_executor.h index c95b4638f2..891ff31bd0 100644 --- a/src/software/embedded/primitive_executor.h +++ b/src/software/embedded/primitive_executor.h @@ -5,7 +5,9 @@ #include "software/ai/navigator/trajectory/bang_bang_trajectory_1d_angular.h" #include "software/ai/navigator/trajectory/trajectory_path.h" #include "software/geom/vector.h" -#include "software/world/world.h" +#include "software/time/duration.h" +#include "software/world/robot_state.h" +#include "software/world/team_types.h" class PrimitiveExecutor { diff --git a/src/software/embedded/thunderloop.cpp b/src/software/embedded/thunderloop.cpp index 6e7ec7cf76..6ec0ca284e 100644 --- a/src/software/embedded/thunderloop.cpp +++ b/src/software/embedded/thunderloop.cpp @@ -15,8 +15,6 @@ #include "software/logger/network_logger.h" #include "software/tracy/tracy_constants.h" #include "software/util/scoped_timespec_timer/scoped_timespec_timer.h" -#include "software/world/robot_state.h" -#include "software/world/team.h" /** * https://web.archive.org/web/20210308013218/https://rt.wiki.kernel.org/index.php/Squarewave-example @@ -143,14 +141,12 @@ void Thunderloop::runLoop() struct timespec poll_time; struct timespec iteration_time; struct timespec last_primitive_received_time; - struct timespec last_world_received_time; struct timespec current_time; struct timespec last_chipper_fired; struct timespec last_kicker_fired; // Input buffer TbotsProto::PrimitiveSet new_primitive_set; - TbotsProto::World new_world; const TbotsProto::PrimitiveSet empty_primitive_set; // Loop interval @@ -162,7 +158,6 @@ void Thunderloop::runLoop() // CLOCK_REALTIME can jump backwards clock_gettime(CLOCK_MONOTONIC, &next_shot); clock_gettime(CLOCK_MONOTONIC, &last_primitive_received_time); - clock_gettime(CLOCK_MONOTONIC, &last_world_received_time); clock_gettime(CLOCK_MONOTONIC, &last_chipper_fired); clock_gettime(CLOCK_MONOTONIC, &last_kicker_fired); @@ -184,7 +179,7 @@ void Thunderloop::runLoop() // Collect jetson status jetson_status_.set_cpu_temperature(getCpuTemperature()); - // Network Service: receive newest world, primitives and set out the last + // Network Service: receive newest primitives and send out the last // robot status { ScopedTimespecTimer timer(&poll_time); @@ -199,8 +194,8 @@ void Thunderloop::runLoop() uint64_t last_handled_primitive_set = primitive_set_.sequence_number(); - // Updating primitives and world with newly received data - // and setting the correct time elasped since last primitive / world + // Updating primitives with newly received data + // and setting the correct time elasped since last primitive struct timespec time_since_last_primitive_received; clock_gettime(CLOCK_MONOTONIC, ¤t_time); diff --git a/src/software/embedded/thunderloop.h b/src/software/embedded/thunderloop.h index 33fadb2577..2804155b70 100644 --- a/src/software/embedded/thunderloop.h +++ b/src/software/embedded/thunderloop.h @@ -15,26 +15,25 @@ #include "software/embedded/services/network/network.h" #include "software/embedded/services/power.h" #include "software/logger/logger.h" -#include "software/world/robot_state.h" class Thunderloop { public: /** * Thunderloop is a giant loop that runs at THUNDERLOOP_HZ. - * It receives Primitives and World from AI, executes the primitives with - * the most recent vison data, and polls the services to interact with the hardware - * peripherals. + * It receives Primitives from AI, executes the Primitives with + * the most recent vison data, and polls the services to interact + * with the hardware peripherals. * * High Level Diagram: Service order in loop not shown * * ┌─────────────────┐ * │ │ - * │ ThunderLoop │ + * │ Thunderloop │ * │ │ * Primitives───────► │ Target Vel ┌────────────┐ * │ ├────────────► │ - * World ───────────► │ │ MotorBoard │ + * | │ │ MotorBoard │ * │ Services ◄────────────┤ │ * │ │ Actual Vel └────────────┘ * │ Primitive Exec │ @@ -107,7 +106,6 @@ class Thunderloop // Input Msg Buffers TbotsProto::PrimitiveSet primitive_set_; - TbotsProto::World world_; TbotsProto::Primitive primitive_; TbotsProto::DirectControlPrimitive direct_control_; From 3f4f5b5f86ca48f9b00f3a9dac73bdb2f32ef714 Mon Sep 17 00:00:00 2001 From: williamckha Date: Fri, 15 Nov 2024 14:18:51 -0800 Subject: [PATCH 14/18] Update README --- README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 61f9b802f0..7e9e2cbf0c 100644 --- a/README.md +++ b/README.md @@ -8,11 +8,12 @@ [![Tbots CI](https://github.com/UBC-Thunderbots/Software/actions/workflows/main.yml/badge.svg)](https://github.com/UBC-Thunderbots/Software/actions?query=workflow%3A%22Tbots+CI%22+branch%3Amaster) **Welcome to our main software and firmware repository!** +Our team is building software that controls our fleet of autonomous soccer-playing robots competing in the [RoboCup Small Size League](https://ssl.robocup.org/). -To get started with building and setting up our software, please see [Getting Started](docs/getting-started.md). Please thoroughly read this guide, along with our [style guide](docs/code-style-guide.md), before making *any* contributions. +- To get started with building and setting up our software, please see [Getting Started](docs/getting-started.md). Please thoroughly read this guide, along with our [style guide](docs/code-style-guide.md), before making *any* contributions. -For an explanation of our software layout and architecture, check out [software architecture and design](docs/software-architecture-and-design.md). +- Check out our [software architecture and design](docs/software-architecture-and-design.md) docs for an overview of how our software works and explanations of key systems and components. -Want to learn more about the RoboCup Small Size League? (teams, rules, etc.) Check out the [Official RoboCup SSL Website](https://ssl.robocup.org/). +- Want to learn more about the RoboCup Small Size League? (teams, rules, etc.) Check out the [Official RoboCup SSL Website](https://ssl.robocup.org/). -Want to edit these docs? If you're planning on editing diagrams, read the guide on [editing the docs](docs/editing-the-docs.md). +- Want to edit these docs? If you're planning on editing diagrams, read the guide on [editing the docs](docs/editing-the-docs.md). From 428eac916555cec44dab39f7024b55bdef4153ce Mon Sep 17 00:00:00 2001 From: williamckha Date: Fri, 29 Nov 2024 23:01:22 -0800 Subject: [PATCH 15/18] Lots of changes to software-architecture-and-design.md --- docs/software-architecture-and-design.md | 692 ++++++++++++----------- 1 file changed, 364 insertions(+), 328 deletions(-) diff --git a/docs/software-architecture-and-design.md b/docs/software-architecture-and-design.md index 884ff9d534..1e800ee90c 100644 --- a/docs/software-architecture-and-design.md +++ b/docs/software-architecture-and-design.md @@ -5,116 +5,100 @@ - [Table of Contents](#table-of-contents) -- [Tools](#tools) - - [SSL-Vision](#ssl-vision) - - [SSL-Gamecontroller](#ssl-gamecontroller) -- [Important Classes](#important-classes) - - [World](#world) - - [Team](#team) - - [Robot](#robot) - - [Ball](#ball) - - [Field](#field) - - [GameState](#gamestate) - - [Dynamic Parameters](#dynamic-parameters) +- [Architecture Overview](#architecture-overview) + - [League-Maintained Software](#league-maintained-software) + - [SSL Vision](#ssl-vision) + - [SSL Gamecontroller](#ssl-gamecontroller) - [Protobuf](#protobuf) - [Important Protobuf Messages](#important-protobuf-messages) - [Primitives](#primitives) - [Robot Status](#robot-status) -- [Design Patterns](#design-patterns) - - [Abstract Classes and Inheritance](#abstract-classes-and-inheritance) - - [Singleton Pattern](#singleton-pattern) - - [Factory Pattern](#factory-pattern) - - [Visitor Pattern](#visitor-pattern) - - [Observer Pattern](#observer-pattern) - - [Threaded Observer](#threaded-observer) - - [Publisher-Subscriber Pattern](#publisher-subscriber-pattern) - - [C++ Templating](#c-templating) -- [Coroutines](#coroutines) - - [What Are Coroutines?](#what-are-coroutines) - - [What Coroutines Do We Use?](#what-coroutines-do-we-use) - - [How Do We Use Coroutines?](#how-do-we-use-coroutines) - - [Coroutine Best Practices](#coroutine-best-practices) -- [Finite State Machines](#finite-state-machines) - - [What Are Finite State Machines?](#what-are-finite-state-machines) - - [Boost-ext SML Library](#boost-ext-sml-library) - - [How Do We Use SML?](#how-do-we-use-sml) - - [SML Best Practices](#sml-best-practices) - [Conventions](#conventions) - [Coordinates](#coordinates) - [Angles](#angles) - [Convention Diagram](#convention-diagram) -- [Architecture Overview](#architecture-overview) - [Fullsystem](#fullsystem) - [Backend](#backend) - [Backend Diagram](#backend-diagram) - [Sensor Fusion](#sensor-fusion) + - [World](#world) + - [Team](#team) + - [Robot](#robot) + - [Ball](#ball) + - [Field](#field) + - [Game State](#game-state) - [Filters](#filters) - [AI](#ai) - [Strategy](#strategy) - [STP Diagram](#stp-diagram) - [Skills](#skills) - [Tactics](#tactics) + - [Tactic Assignment](#tactic-assignment) + - [Hierarchical Tactic FSMs](#hierarchical-tactic-fsms) + - [Control Parameters](#control-parameters) - [Plays](#plays) - - [Navigation](#navigation) - - [Path Manager](#path-manager) - - [Path Objective](#path-objective) - - [Path Planner](#path-planner) - - [AI Diagram](#ai-diagram) + - [Finite State Machines](#finite-state-machines) + - [What Are Finite State Machines?](#what-are-finite-state-machines) + - [Boost-ext SML Library](#boost-ext-sml-library) + - [How Do We Use SML?](#how-do-we-use-sml) + - [SML Best Practices](#sml-best-practices) + - [Coroutines](#coroutines) + - [What Are Coroutines?](#what-are-coroutines) + - [What Coroutines Do We Use?](#what-coroutines-do-we-use) + - [How Do We Use Coroutines?](#how-do-we-use-coroutines) + - [Coroutine Best Practices](#coroutine-best-practices) + - [Motion Planning](#motion-planning) + - [Trajectory Planner](#trajectory-planner) + - [Trajectory Generation and Obstacle Avoidance](#trajectory-generation-and-obstacle-avoidance) - [Thunderscope](#thunderscope) - [Thunderscope GUI](#thunderscope-gui) - - [3D Visualizer](#3d-visualizer) - - [Layers](#layers) + - [3D Visualizer](#3d-visualizer) + - [Layers](#layers) + - [Inter-Process Communication](#inter-process-communication) + - [Proto Log Replay](#proto-log-replay) + - [Dynamic Parameters](#dynamic-parameters) - [Simulator](#simulator) - [Simulated Tests](#simulated-tests) - [Simulated Tests Architecture](#simulated-tests-architecture) - [Validation Functions](#validation-functions) - [Component Connections and Determinism](#component-connections-and-determinism) - [Simulated Tests Diagram](#simulated-tests-diagram) -- [Inter-process Communication](#inter-process-communication) - [E-Stop](#e-stop) +- [Design Patterns](#design-patterns) + - [Abstract Classes and Inheritance](#abstract-classes-and-inheritance) + - [Singleton Pattern](#singleton-pattern) + - [Factory Pattern](#factory-pattern) + - [Visitor Pattern](#visitor-pattern) + - [Observer Pattern](#observer-pattern) + - [Threaded Observer](#threaded-observer) + - [Publisher-Subscriber Pattern](#publisher-subscriber-pattern) + - [C++ Templating](#c-templating) -# Tools -A few commonly-used terms and tools to be familiar with: -#### SSL-Vision - * This is the shared vision system used by the Small Size League. It is what connects to the cameras above the field, does the vision processing, and transmits the positional data of everything on the field to our [AI](#ai) computers. - * The GitHub repository can be found [here](https://github.com/RoboCup-SSL/ssl-vision) -#### SSL-Gamecontroller - * Sometimes referred to as the "Referee", this is another shared piece of Small Size League software that is used to send gamecontroller and referee commands to the teams. A human controls this application during the games to send the appropriate commands to the robots. For example, some of these commands are what stage the gameplay is in, such as `HALT`, `STOP`, `READY`, or `PLAY`. - * The GitHub repository can be found [here](https://github.com/RoboCup-SSL/ssl-game-controller) - - -# Important Classes -These are classes that are either heavily used in our code, or are very important for understanding how the AI works, but are _not_ core components of the AI or other major modules. To learn more about these core modules and their corresponding classes, check out the sections on the [Backend](#backend), [Sensor Fusion](#sensor-fusion), [AI](#ai), and [Thunderscope](#thunderscope). - -## World -The `World` class is what we use to represent the state of the world at any given time. In this context, the world includes the positions and orientations of all robots on the field, the position and velocity of the ball, the dimensions of the field being played on, and the current referee commands. Altogether, it's the information we have at any given time that we can use to make decisions. - -### Team -A team is a collection of [Robots](#robot). +# Architecture Overview -### Robot -A Robot class represents the state of a single robot on the field. This includes its position, orientation, velocity, angular velocity, and any other information about its current state. +At a high-level, our system is split into several independent processes that [communicate with each other](#inter-process-communication). Our architecture is designed in this manner to promote decoupling of different features, making our system easier to expand, maintain, and test. -### Ball -The Ball class represents the state of the ball. This includes its position and velocity, and any other information about its current state. +- [**Fullsystem**](#fullsystem) is the program that processes data and makes decisions for a [team](#team) of [robots](#robot). It manages [**Sensor Fusion**](#sensor-fusion), which is responsible for processing and filtering raw data, and the [**AI**](#ai) that makes gameplay decisions. -### Field -The Field class represents the state of the physical field being played on, which is primarily its physical dimensions. The Field class provides many functions that make it easy to get points of interest on the field, such as the enemy net, friendly corner, or center circle. Also see the [coordinate convention](#coordinates) we use for the field (and all things on it). +- [**Thunderscope**](#thunderscope) is an application that provides a GUI for visualizing and interacting with our software. -### GameState -These represent the current state of the game as dictated by the Gamecontroller. These provide functions like `isPlaying()`, `isHalted()` which tell the rest of the system what game state we are in, and make decisions accordingly. We need to obey the rules! +- The [**Simulator**](#simulator) provides a physics simulation of the world (robots, ball, and field), enabling testing of our gameplay when we don't have access to a real field. This process is optional and used only for development and testing purposes; in a real match, our system will receive data from [SSL-Vision](#ssl-vision). -## Dynamic Parameters -**Dynamic Parameters** are the system we use to change values in our code at runtime. The reason we want to change values at runtime is primarily because we may want to tweak our strategy or aspects of our gameplay very quickly. During games we are only allowed to touch our computers and make changes during halftime or a timeout, so every second counts! Using Dynamic Parameters saves us from having to stop the [AI](#ai), change a constant, recompile the code, and restart the [AI](#ai). +- [**Thunderloop**](/docs/robot-software-architecture.md#thunderloop) is the software that runs onboard our robots. It is responsible for coordinating communication between our [AI](#ai) computer and the motor and power boards in our robots. It is part our robot software architecture, which is documented [here](/docs/robot-software-architecture.md). -[Thunderscope](#thunderscope) has a widget that displays all our Dynamic Parameters and lets the user change their values. Whenever a Dynamic Parameter value is changed in the widget, [Fullsystem](#fullsystem) and [AI](#ai) will be updated with the new value. For example, we can define a Dynamic Parameter called `run_ai` that is a boolean value. The `run_ai` param will show up in the Parameters widget in [Thunderscope](#thunderscope) with a checkbox that sets the value of `run_ai`. In the "main loop" for the [AI](#ai), it will check if the value of `run_ai` is true before running its logic. +## League-Maintained Software -Here's a slightly more relevant example of how we used Dynamic Parameters during a game in RoboCup 2019. We had a parameter called `enemy_team_can_pass`, which indicates whether or not we think the enemy team can pass. This parameter was used in several places in our defensive logic, and specifically affected how we would shadow enemy robots when we were defending them. If we assumed the enemy team could pass, we would shadow between the robots and the ball to block any passes, otherwise we would shadow between the enemy robot and our net to block shots. During the start of a game, we had `enemy_team_can_pass` set to `false` but the enemy did start to attempt some passes during the game. However, we didn't want to use one of our timeouts to change the value. Luckily later during the half, the enemy team took a time out. Because Dynamic Parameters can be changed quick without stopping [AI](#ai), we were quickly able to change `enemy_team_can_pass` to `true` while the enemy team took their timeout. This made our defence much better against that team and didn't take so much time that we had to burn our own timeout. Altogether this is an example of how we use Dynamic Parameters to control our [AI](#ai) and other parts of the code. +Our software is designed to interact with the following software developed and maintained by the RoboCup Small Size League: -It is worth noting that constants are still useful, and should still be used whenever possible. If a value realistically doesn't need to be changed, it should be a constant (with a nice descriptive name) rather than a Dynamic Parameter. Having too many Dynamic Parameters is overwhelming because there are too many values to understand and change, and this can make it hard to tune values to get the desired behaviour while under pressure during a game. +### SSL Vision +* This is the shared vision system used by the Small Size League. It is what connects to the cameras above the field, does the vision processing, and transmits the positional data of everything on the field to our [AI](#ai) computers. +* The GitHub repository can be found [here](https://github.com/RoboCup-SSL/ssl-vision) +### SSL Gamecontroller +* Sometimes referred to as the "Referee", this is another shared piece of Small Size League software that is used to send gamecontroller and referee commands to the teams. A human and/or [computer auto-referee](#https://ssl.robocup.org/league-software/#auto-referees) controls this application during the games to send the appropriate commands to the robots. For example, some of these commands are what stage the gameplay is in, such as `HALT`, `STOP`, `READY`, or `PLAY`. +* The GitHub repository can be found [here](https://github.com/RoboCup-SSL/ssl-game-controller) # Protobuf [Protobufs or protocol buffers](https://protobuf.dev/) are used to pass messages between components in our system. @@ -125,12 +109,12 @@ To include these files in our code, we simply include `proto/ These are [protobuf](https://developers.google.com/protocol-buffers/docs/cpptutorial) messages that we define and that are important for understanding how the [AI](#ai) works. ### Primitives -`TbotsProto::Primitive`s represent simple actions that robots blindly execute (e.g. send signals to motor drivers), so it's up to the [AI](#ai) to send `Primitives` that follow all the rules and avoid collisions with obstacles. Some examples are: -* Moving in a straight line to a position -* Pivoting around a point -* Kicking the ball at a certain direction -`Primitives` act as the abstraction between our [AI](#ai) and our robot firmware. It splits the responsibility such that the [AI](#ai) is responsible for sending a `Primitive` to a robot telling it what it wants it to do, and the robot is responsible for making sure it does what it's told. For every `Primitive` protobuf message, there is an equivalent `Primitive` implementation in our robot firmware. When robots receive a `Primitive` command, they perform their own logic and control in order to perform the task specified by the `Primitive`. +**Primitives** represent the low-level actions that a robot can execute. They are sent to the robots and can be "blindly" executed without knowledge of the [World](#world) and/or the high-level gameplay [strategy](#strategy). Primitives are understood directly by our robot software, which will translate the primitive into motor and power board inputs to make the robot move, dribble, kick, and/or chip as instructed. + +Each Primitive is a C++ class that generates an associated `TbotsProto::Primitive` protobuf message that can be sent to the robots. + +Primitives act as the abstraction between our [AI](#ai) and our robot software. It splits the responsibility such that the [AI](#ai) is responsible for sending a Primitive to a robot telling it what it wants it to do, and the robot is responsible for making sure it does what it's told. ### Robot Status The `TbotsProto::RobotStatus` protobuf message contains information about the status of a single robot. Examples of the information they include are: @@ -139,193 +123,187 @@ The `TbotsProto::RobotStatus` protobuf message contains information about the st * The capacitor charge on the robot * The temperature of the dribbler motor -Information about the robot status is communicated and stored as `RobotStatus` protobuf messages. [Thunderscope](#thunderscope) displays warnings from incoming `RobotStatus`es so we can take appropriate action. For example, during a game we may get a "low battery warning" for a certain robot, so we know to substitute it and replace the battery before it dies on the field. +Information about the robot status is communicated and stored as `RobotStatus` protobuf messages. [Thunderscope](#thunderscope) displays warnings from incoming `RobotStatus` messages so we can take appropriate action. For example, during a game we may get a "low battery warning" for a certain robot, so we know to substitute it and replace the battery before it dies on the field. -# Design Patterns -Below are the main design patterns we use in our code, and what they are used for. -## Abstract Classes and Inheritance -While not a "design pattern" per se, inheritance and related OOP paradigms are prevalent throughout of our code base. Abstract classes let us define interfaces for various components of our code. Then we can implement different objects that obey the interface, and use them interchangeably, with the guarantee that as long as they follow the same interface we can use them in the same way. +# Conventions -To learn more about inheritance in C++, read the following `learncpp.com` articles: -- [Introduction to inheritance](https://www.learncpp.com/cpp-tutorial/introduction-to-inheritance/) -- [Virtual functions](https://www.learncpp.com/cpp-tutorial/pointers-and-references-to-the-base-class-of-derived-objects/) +Below documents various conventions we use and follow in our software. -Examples of this can be found in many places, including: -* [Plays](#plays) -* [Tactics](#tactics) +## Coordinates +We use a slightly custom coordinate convention to make it easier to write our code in a consistent and understandable way. This is particularly important for any code handling gameplay logic and positions on the field. -## Singleton Pattern -The Singleton pattern is useful for having a single, global instance of an object that can be accessed from anywhere. Though it's generally considered an anti-pattern (aka _bad_), it is useful in specific scenarios. +The coordinate system is a simple 2D x-y plane. The x-dimension runs between the friendly and enemy goals, along the longer dimension of the field. The y-dimension runs perpendicular to the x-dimension, along the short dimension of the field. -Read https://refactoring.guru/design-patterns/singleton for more information. +Because we have to be able to play on either side of a field during a game, this means the "friendly half of the field" will not always be in the positive or negative x part of the coordinate plane. This inconsistency is a problem when we want to specify points like "the friendly net", or "the enemy corner". We can't simple say the friendly net is `(-4.5, 0)` all the time, because this would not be the case if we were defending the other side of the field where the friendly net would be `(4.5, 0)`. -We use the Singleton pattern for our logger. This allows us to create a single logger for the entire system, and code can make calls to the logger from anywhere, rather than us having to pass a `logger` object literally everywhere. +In order to overcome this, our convention is that: +* The **friendly half** of the field is **always negative x**, and the **enemy half** of the field is **always positive x** +* `y` is positive to the "left" of someone looking at the enemy goal from the friendly goal +* The center of the field (inside the center-circle) is the origin / `(0, 0)` +This is easiest to understand in the [diagram](#convention-diagram) below. -## Factory Pattern -The Factory pattern is useful for hiding or abstracting how certain objects are created. +Based on what side we are defending, [Sensor Fusion](#sensor-fusion) will transform all the coordinates of incoming data so that it will match our convention. This means that from the perspective of the rest of the system, the friendly half of the field is always negative x and the enemy half is always positive x. Now when we want to tell a robot to move to the friendly goal, we can simply tell it so move to `(-4.5, 0)` and we know this will _always_ be the friendly side. All of our code is written with the assumption in mind. -Read the Refactoring Guru articles on the [Factory Method pattern](https://refactoring.guru/design-patterns/factory-method) and the [Abstract Factory pattern](https://refactoring.guru/design-patterns/abstract-factory) for more information. +## Angles +Going along with our coordinate convention, we have a convention for angles as well. An Angle of `0` is along the positive x-axis (facing the enemy goal), and positive rotation is counter-clockwise (from a perspective above the field, looking at it like a regular x-y plane where +y is "up"). See the [diagram](#convention-diagram) below. -Because the Factory needs to know about what objects are available to be created, it can be taken one step further to auto-register these object types. Rather than a developer having to remember to add code to the Factory every time they create a new class, this can be done "automatically" with some clever code. This helps reduce mistakes and saves developers work. +Because of our [Coordinate Conventions](#coordinates), this means that an angle of `0` will always face the enemy net regardless of which side of the field we are actually defending. -Read http://derydoca.com/2019/03/c-tutorial-auto-registering-factory/ for more information. +## Convention Diagram +![Coordinate Convention Diagram](images/coordinate_and_angle_convention_diagram.svg) -The auto-registering factory is particularly useful for our `PlayFactory`, which is responsible for creating [Plays](#plays). Every time we run our [AI](#ai) we want to know what [Plays](#plays) are available to choose from. The Factory pattern makes this really easy, and saves us having to remember to update some list of "available Plays" each time we add or remove one. +# Fullsystem +**Fullsystem** processes data and makes decisions for a [team](#team) of [robots](#robot). It manages [Sensor Fusion](#sensor-fusion), which is responsible for processing and filtering raw data, and the [AI](#ai) that makes gameplay decisions. -## Visitor Pattern -The Visitor pattern is useful when we need to perform different operations on a group of "similar" objects, like objects that inherit from the same parent class (e.g. [Tactic](#tactics)). We might only know all these objects are a [Tactic](#tactic), but we don't know specifically which type each one is (eg. `AttackerTactic` vs `ReceiverTactic`). The Visitor Pattern helps us "recover" that type information so we can perform different operations on the different types of objects. It is generally preferred to a big `if-block` with a case for each type, because the compiler can help warn you when you've forgotten to handle a certain type, and therefore helps prevent mistakes. +Data within Fullsystem is shared between components using the [observer pattern](#observer-pattern); for instance, [Sensor Fusion](#sensor-fusion) and the [Backend](#backend) are `Subject`s that the [AI](#ai) observes. -Read https://refactoring.guru/design-patterns/visitor for more information. +## Backend +Fullsystem contains a `Backend` responsible for all communication with the "outside world". The responsibilities of the `Backend` can be broken down into communication using `SensorProto` and [Primitives](#primitives) messages: -An example of where we use the Visitor pattern is in our `MotionConstraintVisitor`. This visitor allows us to update the current set of motion constraints based on the types of tactics that are currently assigned. +* Upon receiving the following messages from the network, the `Backend` will store it in a `SensorProto` message and send it to [Sensor Fusion](sensor-fusion): + * Robot status messages + * Vision data about where the robots and ball are (typically from [SSL-Vision](#ssl-vision)) + * Referee commands (typically from the [SSL-Gamecontroller](#ssl-gamecontroller) -## Observer Pattern -The Observer pattern is useful for letting components of a system "notify" each other when something happens. Read https://refactoring.guru/design-patterns/observer for a general introduction to the pattern. +* Upon receiving [Primitives](#primitives) from the [AI](#ai), `Backend` will send the primitives to the robots or the [Simulator](#simulator). -Our implementation of this pattern consists of two classes, `Observer` and `Subject`. `Observer`s can be registered with a `Subject`, after which new values will be sent from each `Subject` to all of it's registered `Observer`s. Please see the headers of both classes for details. Note that a class can extend both `Observer` and `Subject`, thus receiving and sending out data. In this way we can "chain" multiple classes. +The `Backend` was designed to be a simple interface that handles all communication with the "outside world", allowing for different implementations that can be swapped out in order to communicate with different hardware/ protocols/programs. -### Threaded Observer -In our system, we need to be able to do multiple things (receive camera data, run the [AI](#ai), send commands to the robots) at the same time. In order to facilitate this, we extend the `Observer` to the `ThreadedObserver` class. The `ThreadedObserver` starts a thread with an infinite loop that waits for new data from `Subject` and performs some operation with it. - -> [!WARNING] -> If a class extends multiple `ThreadedObserver`s (for example, [AI](#ai) could extend `ThreadedObserver` and `ThreadedObserver`), then there will be two threads running, one for each observer. We **do not check** for data race conditions between observers, so it's entirely possible that one `ThreadedObserver` thread could read/write from data at the same time as the other `ThreadedObserver` is reading/writing the same data. Please make sure any data read/written to/from multiple `ThreadedObserver`s is thread-safe. +#### Backend Diagram +![Backend Diagram](images/backend_diagram.svg) -One example of this is [SensorFusion](#sensor-fusion), which extends `Subject` and the [AI](#ai), which extends `ThreadedObserver`. [SensorFusion](#sensor-fusion) runs in one thread and sends data to the [AI](#ai), which receives and processes it another thread. +## Sensor Fusion +`Sensor Fusion` is responsible for processing the raw data contained in SensorProto into a coherent snapshot of the [World](#world) that the [AI](#ai) can use. It invokes filters to update components of [World](#world), and then combines the components to send out the most up-to-date version. -## Publisher-Subscriber Pattern +### World +The `World` class is what we use to represent the state of the world at any given time. In this context, the world includes the positions and orientations of all robots on the field, the position and velocity of the ball, the dimensions of the field being played on, and the current referee commands. Altogether, it's the information we have at any given time that we can use to make decisions. -The publisher-subscriber pattern ("pub-sub") is a messaging pattern for facilitating communication between different components. It is closely related to the [message queue](https://en.wikipedia.org/wiki/Message_queue) design pattern. +A `World` is composed of the following classes: -In this pattern, `Publisher`s send messages without knowing who the recipients (`Subscriber`s) are. `Subscriber`s express interest in specific types of messages by subscribing to relevant topics; when a `Publisher` sends a message of a topic, the messaging system ensures that all interested subscribers receive the message. +#### Team +A `Team` class represents a collection of [Robots](#robot). -Read https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern for an introduction to the pub-sub pattern. +#### Robot +A `Robot` class represents the state of a single robot on the field. This includes its position, orientation, velocity, angular velocity, and any other information about its current state. -We use the pub-sub pattern to facilitate [inter-process communication](#inter-process-communication) in our system. Through a class called [`ProtoUnixIO`](../src/software/thunderscope/proto_unix_io.py), components can subscribe to receive certain [Protobuf](#protobuf) message types sent out by other processes or system components. +#### Ball +The `Ball` class represents the state of the ball. This includes its position and velocity, and any other information about its current state. -## C++ Templating -While debatably not a design pattern depending on who you ask, templating in C++ is a powerful tool that is very useful to understand. We use templating throughout around our codebase. `learncpp.com` has a good explanation on [function templates](https://www.learncpp.com/cpp-tutorial/function-templates/) and [class templates](https://www.learncpp.com/cpp-tutorial/class-templates/). +#### Field +The `Field` class represents the state of the physical field being played on, which is primarily its physical dimensions. The `Field` class provides many functions that make it easy to get points of interest on the field, such as the enemy net, friendly corner, or center circle. Also see the [coordinate convention](#coordinates) we use for the field (and all things on it). -# Coroutines +#### Game State +The `GameState` class represents the current state of the game as dictated by the Gamecontroller. These provide functions like `isPlaying()`, `isHalted()` which tell the rest of the system what game state we are in, and make decisions accordingly. We need to obey the rules! -## What Are Coroutines? -Coroutines are a general control structure where the flow control is cooperatively passed between two different routines without returning, by allowing execution to be suspended and resumed. This is very similar to the `yield` statement and generators in `Python`. +### Filters +Filters take the raw data from SensorProto and returns an updated version of a component of the [World](#world). For example, the `BallFilter` takes `BallDetection`s and returns an updated `Ball`. -Rather than using the `return` keyword to return data, coroutines use the `yield` keyword. The main difference is that when `return` is encountered, the data is returned and the function terminates. If the function is called again, it starts back from the beginning. On the other hand, when `yield` is encountered some data is returned, but the state of the function / coroutine is saved and the function does not terminate. This means that when the function is called again, execution resumes immediately after the `yield` statement that previously returned the data, with all the previous context (variables, etc) as if the function never stopped running. This is the "suspend and resume" functionality of coroutines. +> **Why we need to do this:** Programs that provide data like [SSL-Vision](#ssl-vision) only provide raw data. This means that if there are several orange blobs on the field, [SSL-Vision](#ssl-vision) will tell us the ball is in several different locations. It is up to us to filter this data to determine the "correct" position of the ball. The same idea applies to robot positions and other data we receive. -See the following C++ pseudocode for an example. This coroutine function computes and returns the fibonacci sequence. -```cpp -int fib(Coroutine::push_type& yield) -{ - int f1 = 1; - int f2 = 0; - while (true) - { - int fn = f1 + f2; // Compute the next value in the sequence - f2 = f1; // Save the previous 2 values - f1 = fn; - yield(fn); - } -} +Filters provide a flexible way to modularize the processing of raw data, making it easy to update filters and add new ones. Filters are sometimes stateful. For example, the `BallFilter` "remembers" previous locations of the ball in order to estimate the ball's current velocity. -int main() -{ - // Coroutine setup stuff - // Lets pretend that we have created the Coroutine and called it `yield` - std::cout << fib(yield) << std::endl; // Prints 1 - std::cout << fib(yield) << std::endl; // Prints 2 - std::cout << fib(yield) << std::endl; // Prints 3 - std::cout << fib(yield) << std::endl; // Prints 5 - std::cout << fib(yield) << std::endl; // Prints 8 - // and so on... -} -``` -Lets walk through what's happening here: -1. The first time the `fib` function is called, the variables `f1` and `f2` are initialized, and we go through the first iteration of the loop until `yield` is encountered -2. The `yield` statement is going to return the currently computed value of the fibonacci sequence (the variable `fn`) and save the state of the `fib` function - * "yielding" the data here is effectively returning it so that the code in the `main` function can print the result -3. The second time `main()` calls the `fib()` function, the function will resume immediately after the `yield()` statement. This means that execution will go back to the top of the loop, *and still remember the values of `f1` and `f2` from the last time the function was called*. Since the coroutine saved the function state, it still has the previous values of `f1` and `f2` which it uses to compute the next value in the sequence. -4. Once again when the `yield()` statement is reached, the newly computed value is returned and the function state is saved. You can think of this as "pausing" the function. -5. As `main()` keeps calling the `fib()` function, it is computing and returning the values of the fibonacci sequence, and this only works because the coroutine "remembers" the values from each previous fibonacci computation which it uses to compute the next value the next time the function is called. - * If the `yield` was replaced with a regular `return` statement, the function would only ever return the value `1`. This is because using `return` would not save the function state, so the next time it's called the function would start at the beginning again, and only ever compute the first value of the sequence. +# AI +The **AI** is the part of the [Fullsystem](#fullsystem) where all of our gameplay logic takes place, and it is the main "brain" of our system. It uses the information received from [Sensor Fusion](#sensor-fusion) to make decisions, and then sends [Primitives](#primitives) to the [Backend](#backend) for the robots to execute. Altogether, this feedback loop is what allows us to react to what's happening on the field and play soccer in real-time. -This example / pseudocode does hide away some details about how coroutines are set up and how we extract values from them, but it's most important to understand how coroutines change the flow of control in the program. +The two main components of the AI are [strategy](#strategy) and [motion planning](#motion-planning). +## Strategy +We use a framework called **STP (Skills, Tactics, Plays)** to organize and implement our gameplay strategy. The STP framework was originally proposed by Carnegie Mellon University back in 2004. The original paper can be found [here](https://kilthub.cmu.edu/articles/STP_Skills_Tactics_and_Plays_for_Multi-Robot_Control_in_Adversarial_Environments/6561002/1). -## What Coroutines Do We Use? -We use the [boost Coroutine2 library](https://www.boost.org/doc/libs/1_71_0/libs/coroutine2/doc/html/index.html). Specifically, we use Asymmetric Coroutines. +STP is a way of breaking down roles and responsibilities into a simple hierarchy, making it easier to build up more complex strategies from simpler pieces. This is the core of where our strategy is implemented. -[This Stack Overflow answer](https://stackoverflow.com/a/42042904) gives a decent explanation of the difference between Symmetric and Asymmetric Coroutines, but understanding the difference is not critical for our purposes. We use Asymmetric Coroutines because boost does not provide Symmetric Coroutines, and the hierarchical structure of Asymmetric Coroutines is more useful to us. +### STP Diagram +The STP diagram shows how this works. Functions to assign tactics to robots and build motion constraints are passed into a `Play`'s `get` function, which the `Play` uses to generate tactics with assigned robots and with updated motion constraints. +![STP Diagram](images/STP.svg) -## How Do We Use Coroutines? +### Skills +The S in STP stands for **Skills**. A Skill represents a lower-level behaviour that a robot can execute. Examples include: -> [!IMPORTANT] -> We are currently in the process of moving away from using coroutines and transitioning to using [finite-state machines](#finite-state-machines) for all our STP logic. +- Moving to a position (without colliding with anything) +- Shooting the ball at a target +- Chipping the ball towards a target -We use Coroutines to write our [strategy logic](#strategy). The "pause and resume" functionality of Coroutines makes it much easier to write [Plays](#plays). +When we refer to Skills in our AI, we typically are talking about [Primitives](#primitives), which are messages representing low-level actions that can be sent to and interpreted by our robots directly. We may also sometimes use the term Skill to describe simpler, skill-like [Tactics](#tactics) that other Tactics are composed from (see [Hierarchical Tactic FSMs](#hierarchical-tactic-fsms)). -Specifically, we use Coroutines as a way to break down our strategy into "stages". Once a "stage" completes we generally don't want to re-evaluate it, and would rather commit to a decision and move on. Coroutines makes it much easier to write "stages" of strategy without requiring complex state machine logic to check what stage we are in, and it's easier for developers to see what the intended order of operations is (eg. "Line up to take the shot" -> "shoot"). +### Tactics +The T in STP stands for **Tactics**. A Tactic represents a single robot's role on a team. Examples include: -In the past, we had issues with our gameplay logic "committing" to decisions if we were near certain edge cases. This caused robots to behave oddly, and sometimes get significantly slowed down in "analysis paralysis". Coroutines solve this problem by allowing us to write "stages" that execute top-to-bottom in a function, and once we make a decision we commit to it and move on to the next stage. +- Being a goalie +- Being an attacker +- Being a pass receiver +- Being a defender that shadows enemy robots +- Being a defender that tries to steal the ball from enemies -Here's a more specific example. In this example we are going to pretend to write a [Tactic](#tactic) that will pass the ball. -```cpp -def executeStrategy(IntentCoroutine::push_type& yield, Pass pass) -{ - do - { - yield(/* align the robot to make the pass */) - } while (current_time < pass.start_time); - - do - { - yield(/* kick the ball at the pass location */) - } while (/* robot has not kicked the ball */) -} -``` -We will pretend that this function is getting called 30 times per second to get the most up-to-date gameplay decision. +Tactics return [Primitives](#primitives) describing the low-level actions the robot should take as the Tactic. Every Tactic has an associated Tactic FSM (see [Finite State Machines](#finite-state-machines)) that it uses to decide what Primitive to execute based on the state of the game; the FSM is updated with the current [World](#world) and returns a Primitive to execute. -In this example, each `do while()` loop is a "stage". When the function is first called, we enter the first stage. In this stage, we will keep telling the robot to line up behind the ball to be ready to make the pass. The robot will continue to do this until it is time to start the pass. +#### Tactic Assignment -Once it is time to start the pass, the condition for the loop will become false and we will exit the loop. Then we enter the second loop / stage. The second stage tells the robot to kick the ball, and this continues until the ball has been kicked. Once the ball has been kicked, the loop will terminate and the function will end because the execution reaches the end of the function. +A Tactic by itself is not directly assigned to any single robot. Instead, `Tactic::get` returns a map associating each and every friendly robot with the [Primitive](#primitives) they would execute *if* that robot was assigned that Tactic. We then say that every Primitive has some *cost* quantifying how easy it is for the robot to perform the action. For example, a `MovePrimitive` may incur a larger cost depending on the distance between the robot and the `MovePrimitive`'s target position, reason being that it is in some sense "harder" for a robot to reach a faraway target successfully. With all this information, the [Play](#plays) assigns one robot to every Tactic based on the Primitives that would be executed, in such a way that the *total cost* incurred is minimized; this is a form of the classic [assignment problem](https://en.wikipedia.org/wiki/Assignment_problem) which we solve using the [Hungarian algorithm](https://en.wikipedia.org/wiki/Hungarian_algorithm). -Once we have entered the second stage, we know we don't have to look at the first stage again. Because the coroutine "remembers" where the execution is each time the function is called, we will resume inside the second stage and therefore never execute the first stage again! This makes it much easier to write and read this strategy code, because we can clearly see the 2 stages of the strategy, and we know they will be executed in order. +In order to produce the map returned by `Tactic::get`, every Tactic must have one Tactic FSM for every robot. Each FSM tracks the state of the Tactic for one robot and produces the Primitive that the robot would execute. -## Coroutine Best Practices -Coroutines are a complex feature, and the boost coroutines we use don't always behave in was we expect. We have done extensive testing on how coroutines are safe (or not safe) to us, and derived some best practices from these examples. See [coroutine_test_exmaples.cpp](coroutine_test_examples.cpp) for the full code and more detailed explanantions. +#### Hierarchical Tactic FSMs -To summarize, the best practices are as follows: -1. Avoid moving coroutines. If the absolutely must be moved, make sure they are not moved between the stack and heap. -2. Avoid using coroutines with resizable containers. If they must be used, make sure that the coroutines are allocated on the heap. -3. Pass data to the coroutine on creation as much as possible, avoid using member variables. +Tactics FSMs may make use of other simpler Tactic FSMs that implement common behaviours. These simpler Tactics can be thought of as [Skills](#skills) since they do not represent any strategic role, but instead execute a well-defined action. For example: + +- `MoveTactic` simply returns a `MovePrimitive` constructed using the `MoveTactic`'s [control parameters](#control-parameters) (which match `MovePrimitive`'s constructor parameters). +- `PivotKickTactic` approaches the ball, pivots around the ball to face towards a specified target, and then kicks the ball in that direction. + +The FSMs of these simpler Tactics are used as "sub-FSMs" and are treated as a state in more complex Tactic FSMs (read about [hierarchical FSMs in the FSM section](#what-are-finite-state-machines)). When a Tactic FSM is in one of its sub-FSM states, it should update the sub-FSM with the [World](#world) and return the Primitive returned by the sub-FSM. This means that the Tactic FSM will effectively "run" the sub-FSM and do its bidding while in the sub-FSM state, and it will leave the state once the sub-FSM terminates (e.g. `MoveTacticFSM` terminates once the robot has successfully reached the target destination). + +This pattern promotes code reuse, allowing us to compose complex Tactic FSMs from smaller, skill-like Tactic FSMs that can be reused in different contexts. + +#### Control Parameters + +Every Tactic defines its own custom `ControlParams` struct representing the specific settings and parameters we can set to influence the Tactic's behavior. At every timestep, alongside the current [World](#world), we update the Tactic's FSM with `ControlParams` carrying information about what want we want the Tactic to do (e.g. defend against a certain enemy robot). Tactics making use of other Tactics ([as sub-FSMs](#hierarchical-tactic-fsms)) can use control parameters to control the behaviour of the sub-FSM, and [Plays](#plays) can set each of its Tactics' control params to coordinate responsibilities (e.g. tell each defensive Tactic to defend against a different enemy robot) + +### Plays + +The P in STP stands for **Plays**. A Play represents a "team-wide goal" for the robots. They can be thought of much like plays in real-life soccer. Examples include: -# Finite State Machines -## What Are Finite State Machines? -A finite state machine (FSM) is a system with a finite number of states with defined transitions and outputs based on the inputs to the system. In particular, we are interested in hierarchical state machines where we can transition between states in terms of _when_ states should transition (_guards_) and _what_ should happen when transitions occur (_actions_), given a specific input (_event_). Hierarchical state machines are state machines that are composed of one or more FSMs, which we call sub-FSMs. The parent FSM can treat a sub-FSM as a state with _guards_ and _actions_ when transitioning to and from the sub-FSM. When the sub-FSM enters a terminal state, the parent FSM is able to automatically transition to another state. +- A play for taking friendly free kicks +- A play for defending enemy kickoffs +- A general defense play +- A passing-based offense play +- A dribbling-based offense play + +Plays are made up of [Tactics](#tactics). A Play chooses which Tactics it wants to assign based on the state of the game. This logic is implemented in an associated Play FSM (see [Finite State Machines](#finite-state-machines)) that gets updated with the current [World](#world) and returns a list of Tactics to assign. The Play then attempts to assign robots to these desired Tactics in an optimal manner (see [Tactic Assignment](#tactic-assignment)). + +Plays return `PrimitiveSet`s that map each robot to the [Primitive](#primitives) they should execute. These Primitives are produced by the [Tactics](#tactics) assigned by the Play to each robot. + +The AI chooses which Play to run using `PlaySelectionFSM`. `PlaySelectionFSM` is updated with the current World and returns the Play to run based on the current game state. + +## Finite State Machines + +### What Are Finite State Machines? +A finite state machine (FSM) is a system with a finite number of states with defined transitions and outputs based on the inputs to the system. A FSM is in exactly one of its states at any time, and it can change (transition) from its current state to another in response to some input. In particular, we are interested in defining _when_ a FSM should transition to another state (_guards_) and _what_ should happen when transitions occur (_actions_), given a specific input (_event_). + +Hierarchical state machines are state machines that are composed of one or more FSMs, which we call sub-FSMs. The parent FSM can treat a sub-FSM as a state with _guards_ and _actions_ when transitioning to and from the sub-FSM. When the sub-FSM enters a terminal state, the parent FSM is able to automatically transition to another state. ![Finite State Machine Diagram](images/finite_state_machine_diagram.png) [source](https://www.block-net.de/Programmierung/cpp/fsm/fsm.html) -## Boost-ext SML Library -We use [Boost-ext SML](https://github.com/boost-ext/sml), short for State Machine Library, to manage our finite state machines. This library defines state machines through a transition table, where a row indicates the transition from one state to another state using _guards_, _actions_ and _events_. The syntax of a row of the transition table looks like this: +### Boost-ext SML Library +We use [Boost-ext SML](https://github.com/boost-ext/sml), short for State Machine Library, to create our finite state machines. This library defines state machines through a transition table, where a row indicates the transition from one state to another state using _guards_, _actions_ and _events_. The syntax of a row of the transition table looks like this: ``` src_state + event [guard] / action = dest_state ``` -where the `src_state` transitions to the `dest_state`, while performing the `action`, only if the `event` is processed and the `guard` is true. _Events_ are structs of new information that FSMs receive, and _guards_ and _actions_ are functions that take events as arguments. _Guards_ must return a boolean and _actions_ must return void. An asterix (\*) at the start of a row indicates that the state is an initial state. The rows of the transition table are processed in order from top to bottom and the first row to match is executed. +where the `src_state` transitions to the `dest_state`, while performing the `action`, only if the `event` is received and the `guard` is true. _Events_ are structs of new information that FSMs receive, and _guards_ and _actions_ are functions that take events as arguments. _Guards_ must return a boolean and _actions_ must return void. An asterix (\*) at the start of a row indicates that the state is an initial state. The rows of the transition table are processed in order from top to bottom and the first row to match is executed. The library also supports hierarchical FSMs. Sub-FSMs are treated as states where an unconditional transition occurs when the sub-FSM is in the terminal state, `X`. -```cpp +```c++ const auto SubFSM_S = boost::sml::state; // ...in the transition table... SubFSM_S = next_state // Transitions to next_state only when the SubFSM is in the terminal state, X ``` In order to update a sub-FSM with an event, we need to do the following: -```cpp +```c++ const auto update_sub_fsm_action = [](auto event, boost::sml::back::process processEvent) { TypeOfSubFSMEvent sub_fsm_event = // initialize the sub-FSM event @@ -341,19 +319,19 @@ SubFSM_S + event / update_sub_fsm_action ``` The convenience of this syntax comes at the cost of hard to read error messages due to the functor and templating system. -## How Do We Use SML? -We use SML to implement our [Plays](#plays) and [Tactics](#tactics). Each state represents a stage in the play/tactic where the team/robot should be doing a particular thing or looking for certain conditions to be true. An example of this is the `MoveFSM`. While the robot is not at the destination and oriented correctly, the FSM is in the move state. Once the robot reaches its destination, it enters the terminal state, `X`, to indicate that it's done. SML also allows us to easily reuse FSMs in other tactics. For example, if a shadowing tactic needs to move to a particular destination with a certain orientation, then it can use the MoveFSM as a sub-FSM state. +### How Do We Use SML? +We use SML to implement our [Plays](#plays) and [Tactics](#tactics). Each state represents a stage in the play/tactic where the team/robot should be doing a particular thing or looking for certain conditions to be true. A simple example of this is the `MoveFSM`. While the robot is not at the destination and oriented correctly, the FSM is in the move state. Once the robot reaches its destination, it enters the terminal state, `X`, to indicate that it's done. SML also allows us to easily reuse FSMs in other tactics. For example, if a shadowing tactic needs to move to a particular destination with a certain orientation, then it can use the MoveFSM as a sub-FSM state (see [Hierarchical Tactic FSMs](#hierarchical-tactic-fsms)). -If you're having trouble understanding the SML syntax, take a look at [`docs/fsm-diagrams.md`](./fsm-diagrams.md). It contains automatically generated diagrams of the FSMs in our codebase, which can help with visualizing the FSM control flow. +If you're having trouble understanding the SML syntax, take a look at [`docs/fsm-diagrams.md`](./fsm-diagrams.md). It contains automatically generated diagrams of the FSMs in our codebase, which can help with visualizing the FSM control flow. -## SML Best Practices +### SML Best Practices Boost-ext SML is a library that supports complex functionality with similarly complex syntax and semantics. If complex syntax is misused, the complicated error messages can make development difficult. Thus, we have carefully chosen a standardized subset of the library's syntax to implement our functionality while maintaining high readability. -* Define _guards_ and _actions_ outside of the transition table: The names of _guards_ and _actions_ should be succinct so that transition tables rows fit on one line and readers can easily understand the FSM from the transition table. In other words, no inserting lambdas/anonymous functions directly in transition tables. +* Define _guards_ and _actions_ outside of the transition table: The names of _guards_ and _actions_ should be succinct so that transition tables rows fit on one line and readers can easily understand the FSM from the transition table. In other words, do not insert lambdas/anonymous functions directly in transition tables. - To aid with this, we have **macros** in [`software/util/sml_fsm/sml_fsm.h`](../src/software/util/sml_fsm/sml_fsm.h) that generate named lambda wrappers around guard and action methods you define in your FSM struct. There are also macros for generating state and events that will be compatible with the SML library. + To aid with this, we have **macros** in [`software/util/sml_fsm/sml_fsm.h`](../src/software/util/sml_fsm/sml_fsm.h) that generate named lambda wrappers around guard and action methods you define in your FSM struct. There are also macros for generating state and events that will be compatible with the SML library. - ```cpp + ```c++ struct KickFSM { // Define states inside the FSM struct @@ -399,7 +377,7 @@ Boost-ext SML is a library that supports complex functionality with similarly co fsm.process_event(KickFSM::Update()); ``` We also have macros for working with sub-FSMs: - ```cpp + ```c++ struct KickFSM { class Update; @@ -435,12 +413,12 @@ Boost-ext SML is a library that supports complex functionality with similarly co // parent FSM struct into the FSM constructor FSM fsm(KickFSM(), MoveFSM()); ``` -* Avoid entry and exit conditions: Everything that can be implemented with entry and exit conditions can easily be implemented as actions, so this rule reduces source of confusion for the reader. -* Avoid self transitions, i.e. `src_state + event [guard] / action = src_state`: self transitions call entry and exit conditions, which complicates the FSM. If we want a state to stay in the same state while performing an action, then we should use an internal transition, i.e. `src_state + event [guard] / action`. +* Avoid entry and exit actions: these are actions that are always executed when entering or exiting a state. Everything that can be implemented with entry and exit actions can easily be implemented as actions, so this rule reduces source of confusion for the reader. +* Avoid self transitions, i.e. `src_state + event [guard] / action = src_state`: self transitions call entry and exit actions, which complicates the FSM. If we want a state to stay in the same state while performing an action, then we should use an internal transition, i.e. `src_state + event [guard] / action`. * Avoid orthogonal regions: Multiple FSMs running in parallel is hard to reason about and isn't necessary for implementing single robot behaviour. Thus, only prefix one state with an asterix (\*) so that there is only one initial state. * Use callbacks in _events_ to return information from the FSM: Since the SML library cannot directly return information, we need to return information through callbacks. For example, if we want to return a double from an FSM, we can pass in `std::function callback` as part of the event and then make the _action_ call that function with the value we want returned. * When a variable needs to be shared between multiple states or can be initialized upon construction of the FSM, then define a private member and constructor in the FSM struct, and pass that in when constructing the FSM. Here's a code snippet: - ```cpp + ```c++ struct DriveForwardFSM { public: @@ -453,147 +431,129 @@ Boost-ext SML is a library that supports complex functionality with similarly co FSM fsm(DriveForwardFSM(10.0)); ``` -# Conventions -Various conventions we use and follow that you need to know. +## Coroutines -## Coordinates -We use a slightly custom coordinate convention to make it easier to write our code in a consistent and understandable way. This is particularly important for any code handling gameplay logic and positions on the field. - -The coordinate system is a simple 2D x-y plane. The x-dimension runs between the friendly and enemy goals, along the longer dimension of the field. The y-dimension runs perpendicular to the x-dimension, along the short dimension of the field. - -Because we have to be able to play on either side of a field during a game, this means the "friendly half of the field" will not always be in the positive or negative x part of the coordinate plane. This inconsistency is a problem when we want to specify points like "the friendly net", or "the enemy corner". We can't simple say the friendly net is `(-4.5, 0)` all the time, because this would not be the case if we were defending the other side of the field where the friendly net would be `(4.5, 0)`. - -In order to overcome this, our convention is that: -* The **friendly half** of the field is **always negative x**, and the **enemy half** of the field is **always positive x** -* `y` is positive to the "left" of someone looking at the enemy goal from the friendly goal -* The center of the field (inside the center-circle) is the origin / `(0, 0)` - -This is easiest to understand in the [diagram](#convention-diagram) below. - -Based on what side we are defending, [Sensor Fusion](#sensor-fusion) will transform all the coordinates of incoming data so that it will match our convention. This means that from the perspective of the rest of the system, the friendly half of the field is always negative x and the enemy half is always positive x. Now when we want to tell a robot to move to the friendly goal, we can simply tell it so move to `(-4.5, 0)` and we know this will _always_ be the friendly side. All of our code is written with the assumption in mind. - -## Angles -Going along with our coordinate convention, we have a convention for angles as well. An Angle of `0` is along the positive x-axis (facing the enemy goal), and positive rotation is counter-clockwise (from a perspective above the field, looking at it like a regular x-y plane where +y is "up"). See the [diagram](#convention-diagram) below. - -Because of our [Coordinate Conventions](#coordinates), this means that an angle of `0` will always face the enemy net regardless of which side of the field we are actually defending. - -## Convention Diagram -![Coordinate Convention Diagram](images/coordinate_and_angle_convention_diagram.svg) - -# Architecture Overview - -At a high-level, our system is split into several independent processes that [communicate with each other](#inter-process-communication). Our architecture is designed in this manner to promote decoupling of different features, making our system easier to expand, maintain, and test. - -- [**Thunderscope**](#thunderscope) is main entry point of our system and provides the GUI for our software. - -- [**Fullsystem**](#fullsystem) is the "backend" that processes data and makes decisions for a [team](#team) of [robots](#robot). It manages [Sensor Fusion](#sensor-fusion), which is responsible for processing and filtering raw data, and the [**AI**](#ai) that makes gameplay decisions. - -- The [**Simulator**](#simulator) provides a physics simulation of the [World](#world), enabling testing of our gameplay when we don't have access to a real field. This process is optional and used only for development and testing purposes; in a real match, our system will receive data from [SSL-Vision](#ssl-vision). - -- [**Thunderloop**](/docs/robot-software-architecture.md#thunderloop) is the software that runs onboard our robots. It is responsible for coordinating communication between our [AI](#ai) computer and the motor and power boards in our robots. It is part our robot software architecture, which is documented [here](/docs/robot-software-architecture.md). - -# Fullsystem - -Fullsystem processes data and makes decisions for a [team](#team) of [robots](#robot). It manages [Sensor Fusion](#sensor-fusion), which is responsible for processing and filtering raw data, and the [AI](#ai) that makes gameplay decisions. - -Data within Fullsystem is shared between components using the [observer pattern](#observer-pattern); for instance, [Sensor Fusion](#sensor-fusion) and the [Backend](#backend) are `Subject`s that the [AI](#ai) observes. +> [!IMPORTANT] +> We are currently in the process of moving away from using coroutines and transitioning to using [finite-state machines](#finite-state-machines) for all our STP logic. -## Backend -Fullsystem contains a `Backend` responsible for all communication with the "outside world". The responsibilities of the `Backend` can be broken down into communication using `SensorProto` and [Primitives](#primitives) messages: +### What Are Coroutines? +Coroutines are a general control structure where the flow control is cooperatively passed between two different routines without returning, by allowing execution to be suspended and resumed. This is very similar to the `yield` statement and generators in `Python`. -* Upon receiving the following messages from the network, the `Backend` will store it in a `SensorProto` message and send it to [Sensor Fusion](sensor-fusion): - * Robot status messages - * Vision data about where the robots and ball are (typically from [SSL-Vision](#ssl-vision)) - * Referee commands (typically from the [SSL-Gamecontroller](#ssl-gamecontroller) +Rather than using the `return` keyword to return data, coroutines use the `yield` keyword. The main difference is that when `return` is encountered, the data is returned and the function terminates. If the function is called again, it starts back from the beginning. On the other hand, when `yield` is encountered some data is returned, but the state of the function / coroutine is saved and the function does not terminate. This means that when the function is called again, execution resumes immediately after the `yield` statement that previously returned the data, with all the previous context (variables, etc) as if the function never stopped running. This is the "suspend and resume" functionality of coroutines. -* Upon receiving [Primitives](#primitives) from the [AI](#ai), `Backend` will send the primitives to the robots or the [Simulator](#simulator). +See the following C++ pseudocode for an example. This coroutine function computes and returns the fibonacci sequence. +```c++ +int fib(Coroutine::push_type& yield) +{ + int f1 = 1; + int f2 = 0; + while (true) + { + int fn = f1 + f2; // Compute the next value in the sequence + f2 = f1; // Save the previous 2 values + f1 = fn; + yield(fn); + } +} -The `Backend` was designed to be a simple interface that handles all communication with the "outside world", allowing for different implementations that can be swapped out in order to communicate with different hardware/ protocols/programs. +int main() +{ + // Coroutine setup stuff + // Lets pretend that we have created the Coroutine and called it `yield` + std::cout << fib(yield) << std::endl; // Prints 1 + std::cout << fib(yield) << std::endl; // Prints 2 + std::cout << fib(yield) << std::endl; // Prints 3 + std::cout << fib(yield) << std::endl; // Prints 5 + std::cout << fib(yield) << std::endl; // Prints 8 + // and so on... +} +``` +Lets walk through what's happening here: +1. The first time the `fib` function is called, the variables `f1` and `f2` are initialized, and we go through the first iteration of the loop until `yield` is encountered +2. The `yield` statement is going to return the currently computed value of the fibonacci sequence (the variable `fn`) and save the state of the `fib` function +* "yielding" the data here is effectively returning it so that the code in the `main` function can print the result +3. The second time `main()` calls the `fib()` function, the function will resume immediately after the `yield()` statement. This means that execution will go back to the top of the loop, *and still remember the values of `f1` and `f2` from the last time the function was called*. Since the coroutine saved the function state, it still has the previous values of `f1` and `f2` which it uses to compute the next value in the sequence. +4. Once again when the `yield()` statement is reached, the newly computed value is returned and the function state is saved. You can think of this as "pausing" the function. +5. As `main()` keeps calling the `fib()` function, it is computing and returning the values of the fibonacci sequence, and this only works because the coroutine "remembers" the values from each previous fibonacci computation which it uses to compute the next value the next time the function is called. +* If the `yield` was replaced with a regular `return` statement, the function would only ever return the value `1`. This is because using `return` would not save the function state, so the next time it's called the function would start at the beginning again, and only ever compute the first value of the sequence. -#### Backend Diagram -![Backend Diagram](images/backend_diagram.svg) -## Sensor Fusion -`Sensor Fusion` is responsible for processing the raw data contained in SensorProto into a coherent snapshot of the [World](#world) that the [AI](#ai) can use. It invokes filters to update components of [World](#world), and then combines the components to send out the most up-to-date version. +This example / pseudocode does hide away some details about how coroutines are set up and how we extract values from them, but it's most important to understand how coroutines change the flow of control in the program. -### Filters -Filters take the raw data from SensorProto and returns an updated version of a component of the [World](#world). For example, the `BallFilter` takes `BallDetection`s and returns an updated `Ball`. -> **Why we need to do this:** Programs that provide data like [SSL-Vision](#ssl-vision) only provide raw data. This means that if there are several orange blobs on the field, [SSL-Vision](#ssl-vision) will tell us the ball is in several different locations. It is up to us to filter this data to determine the "correct" position of the ball. The same idea applies to robot positions and other data we receive. +### What Coroutines Do We Use? +We use the [boost Coroutine2 library](https://www.boost.org/doc/libs/1_71_0/libs/coroutine2/doc/html/index.html). Specifically, we use Asymmetric Coroutines. -Filters provide a flexible way to modularize the processing of raw data, making it easy to update filters and add new ones. Filters are sometimes stateful. For example, the `BallFilter` "remembers" previous locations of the ball in order to estimate the ball's current velocity. +[This Stack Overflow answer](https://stackoverflow.com/a/42042904) gives a decent explanation of the difference between Symmetric and Asymmetric Coroutines, but understanding the difference is not critical for our purposes. We use Asymmetric Coroutines because boost does not provide Symmetric Coroutines, and the hierarchical structure of Asymmetric Coroutines is more useful to us. -# AI -The `AI` is the part of the [Fullsystem](#fullsystem) where all of our gameplay logic takes place, and it is the main "brain" of our system. It uses the information received from [Sensor Fusion](#sensor-fusion) to make decisions, and then sends [Primitives](#primitives) to the [Backend](#backend) for the robots to execute. Altogether, this feedback loop is what allows us to react to what's happening on the field and play soccer in real-time. +### How Do We Use Coroutines? -The two main components of the `AI` are strategy and navigation. +We use Coroutines to write some of our [strategy logic](#strategy). The "pause and resume" functionality of Coroutines makes it much easier to write [Plays](#plays). -## Strategy -We use a framework called `STP (Skills, Tactics, Plays)` to implement our gameplay strategy. The `STP` framework was originally proposed by Carnegie Mellon University back in 2004. The original paper can be found [here](https://kilthub.cmu.edu/articles/STP_Skills_Tactics_and_Plays_for_Multi-Robot_Control_in_Adversarial_Environments/6561002/1). +Specifically, we use Coroutines as a way to break down our strategy into "stages". Once a "stage" completes we generally don't want to re-evaluate it, and would rather commit to a decision and move on. Coroutines makes it much easier to write "stages" of strategy without requiring complex state machine logic to check what stage we are in, and it's easier for developers to see what the intended order of operations is (eg. "Line up to take the shot" -> "shoot"). -`STP` is a way of breaking down roles and responsibilities into a simple hierarchy, making it easier to build up more complex strategies from simpler pieces. This is the core of where our strategy is implemented. +In the past, we had issues with our gameplay logic "committing" to decisions if we were near certain edge cases. This caused robots to behave oddly, and sometimes get significantly slowed down in "analysis paralysis". Coroutines solve this problem by allowing us to write "stages" that execute top-to-bottom in a function, and once we make a decision we commit to it and move on to the next stage. -### STP Diagram -The STP diagram shows how this works. Functions to assign tactics to robots and build motion constraints are passed into a `Play`'s `get` function, which the `Play` uses to generate tactics with assigned robots and with updated motion constraints. +Here's a more specific example. In this example we are going to pretend to write a [Tactic](#tactic) that will pass the ball. +```c++ +def executeStrategy(IntentCoroutine::push_type& yield, Pass pass) +{ + do + { + yield(/* align the robot to make the pass */) + } while (current_time < pass.start_time); + + do + { + yield(/* kick the ball at the pass location */) + } while (/* robot has not kicked the ball */) +} +``` +We will pretend that this function is getting called 30 times per second to get the most up-to-date gameplay decision. -![STP Diagram](images/STP.svg) +In this example, each `do while()` loop is a "stage". When the function is first called, we enter the first stage. In this stage, we will keep telling the robot to line up behind the ball to be ready to make the pass. The robot will continue to do this until it is time to start the pass. -### Skills -The `S` in `STP` stands for `Skills`. A `Skill` represents a lower-level behaviour that a robot can execute. Examples include: +Once it is time to start the pass, the condition for the loop will become false and we will exit the loop. Then we enter the second loop / stage. The second stage tells the robot to kick the ball, and this continues until the ball has been kicked. Once the ball has been kicked, the loop will terminate and the function will end because the execution reaches the end of the function. -1. Moving to a position (without colliding with anything) -2. Shooting the ball at a target -3. Intercepting a moving ball +Once we have entered the second stage, we know we don't have to look at the first stage again. Because the coroutine "remembers" where the execution is each time the function is called, we will resume inside the second stage and therefore never execute the first stage again! This makes it much easier to write and read this strategy code, because we can clearly see the 2 stages of the strategy, and we know they will be executed in order. -Skills use [Primitives](#primitives) to implement their behaviour, so that our strategy is decoupled from the [Navigator](#navigation). +### Coroutine Best Practices +Coroutines are a complex feature, and the boost coroutines we use don't always behave in was we expect. We have done extensive testing on how coroutines are safe (or not safe) to us, and derived some best practices from these examples. See [coroutine_test_exmaples.cpp](coroutine_test_examples.cpp) for the full code and more detailed explanantions. -### Tactics -The `T` in `STP` stands for `Tactics`. A `Tactic` represents a single robot's role on a team. Examples include: -1. Being a goalie -2. Being an attacker -3. Being a pass receiver -4. Being a defender that shadows enemy robots -5. Being a defender that tries to steal the ball from enemies +To summarize, the best practices are as follows: +1. Avoid moving coroutines. If the absolutely must be moved, make sure they are not moved between the stack and heap. +2. Avoid using coroutines with resizable containers. If they must be used, make sure that the coroutines are allocated on the heap. +3. Pass data to the coroutine on creation as much as possible, avoid using member variables. -Tactics can use Skills in a hierarchical way. +## Motion Planning -Tactics use [Primitives](#primitives) to implement their behaviour, so that it can decouple strategy from the [Navigator](#navigation). +Our **motion planning** (navigation) system is responsible for trajectory planning and obstacle avoidance. -### Plays -The `P` in `STP` stands for `Plays`. A `Play` represents a "team-wide goal" for the robots. They can be thought of much like plays in real-life soccer. Examples include: +A **trajectory** (or **motion profile**) describes the ideal motion that the robot should follow to get from one point to another point. It is a function of time that returns the target (a.k.a. reference) position, velocity, and acceleration for the given timestep. For every `MovePrimitive` (see [Primitives](#primitives)) indicating a target destination, our trajectory planner generates and stores with the `MovePrimitive` a corresponding trajectory that the robot can take to reach that destination. -- A play for taking friendly free kicks -- A play for defending enemy kickoffs -- A general defense play -- A passing-based offense play -- A dribbling-based offense play +### Trajectory Planner -Plays are made up of `Tactics`. Plays can have "stages" and change what `Tactics` are being used as the state of the game changes, which allows us to implement more complex behaviour. Read the section on [FSMs](#finite-state-machines) to learn more about how we write strategy with "stages". +Our trajectory planner is heavily based off of TIGERs Mannheim's trajectory planner (read their [2019 TDP](https://ssl.robocup.org/wp-content/uploads/2019/03/2019_ETDP_TIGERs_Mannheim.pdf)). At the most basic level, our trajector planner generates trapezoidal "bang-bang" trajectories. The name comes from the shape of the profile's speed vs. time graph (which is trapezoidal), and "bang-bang" refers to how the acceleration switches abruptly between zero and a fixed limit. +We create 2D trajectories by generating two 1D trajectories to describe the motion along each Cartesian coordinate axis over time. The two 1D trajectories are synchronized such that they complete in approximately the same time. We also generate a separate trajectory for the angular motion of the robot, describing how the robot's angular position, velocity, and acceleration should change over time. -## Navigation -The `Navigator` is responsible for path planning and navigation. Once our strategy has decided what it wants to do, it passes the resulting [Intents](#intents) to the `Navigator`. The `Navigator` is then responsible for breaking down the [Intents](#intents) and turning them into [Primitives](#primitives). +The purpose of using trapezoidal trajectories is to decrease the amount of error that the [PID motor controller](https://en.wikipedia.org/wiki/Proportional%E2%80%93integral%E2%80%93derivative_controller) has to correct for by making the target velocity closer to the motor's current velocity. If we instead had a constant velocity trajectory, the distance at the start between the motor's current velocity (at standstill) and the target velocity would be large, so the PID controller would issue a large motor input in response to the large error. Large motor inputs cause *slip*, leading to loss in traction and unpredictable movement. -[DirectPrimitiveIntents](#intents) are easy to break down into [Primitives](#primitives), and can be converted directly without having to do any extra work. +### Trajectory Generation and Obstacle Avoidance -However, [NavigatingIntents](#intents) like the `MoveIntent` rely on the navigator to implement more complex behaviour like obstacle avoidance. In order for a robot to move to the desired destination of a [NavigatingIntents](#intents), the `Navigator` will use various path-planning algorithms to find a path across the field that does not collide with any robots or violate any restrictions set on the [NavigatingIntents](#intents). The `NavigatingPrimitiveCreator` then translates this path into a series of [Primitives](#primitives), which are sent to the robot sequentially so that it follows the planned path across the field. +Given a destination, the trajectory planner will generate a number of potential trajectories that will reach the destination. Each trajectory is scored based on its duration and whether it collides with any *obstacles*. The trajectory planner will return the trajectory with the best score. -### Path Manager -The `Path Manager` is responsible for generating a set of paths that don't collide. It is given a set of [Path Objective](#path-objective)s and [Path Planner](#path-planner), and it will generate paths using the given path planner and arbitrate between paths to prevent collisions. +We check whether a trajectory collides with any obstacles on the field by stepping over the trajectory in fixed steps (e.g. 100 ms) and checking whether the trajectory's position at any step lies inside an obstacle. We penalize a trajectory's score based on the amount of time until the first collision. This is because a collision that occurs earlier in a trajectory is more likely to happen (for real) compared to a collision occurring later in a trajectory, since obstacles may move and the state of the World may change by the time that later collision would have happened. That is, we cannot reliably predict where obstacles will be in the faraway future, so we are less harsh in penalizing trajectories with late collisions. -### Path Objective -A path objective is a simple datastructure used to communicate between the navigator and the path manager. It conveys information for generating one path, such as start, destination, and obstacles. Path Objectives use very simple datastructures so that Path Planners do not need to know about any world-specific datastructures, such as Robots or the Field. +Trajectories are generated by sampling intermediate *sub-destinations* around the current robot position. One trajectory is generated from the current robot position and velocity to the sub-destination, and then additional trajectories to the destination are generated starting from sampled locations along the trajectory to the sub-destination. We can then form a *trajectory path* by connecting a portion of the trajectory to the sub-destination end-to-end with the trajectory to the destination. This approach enables generation of many possible trajectory paths, with the hope being that some will avoid obstacles that would otherwise be encountered in a direct trajectory to the destination. -### Path Planner -The `Path Planner` is an interface for the responsibility of path planning a single robot around a single set of obstacles from a given start to a given destination. The interface allows us to easily swap out path planners. +# Thunderscope -## AI Diagram -![AI Diagram](images/ai_diagram.svg) +**Thunderscope** chiefly refers to the [GUI application](#thunderscope-gui) we use to visualize and interact with our robots and software. Some non-UI related functionality (namely, Robot Communication) is implemented as part of Thunderscope since it acts as a central point in our architecture, making it convenient for coordinating activities between different modules. -# Thunderscope +[`thunderscope_main.py`](/src/software/thunderscope/thunderscope_main.py) serves as the main entry point ("launcher") for our entire system. You can run the script to start up the [Thunderscope GUI](#thunderscope-gui) and a number of other optional processes, such as a [Fullsystem](#fullsystem) for each [AI](#ai) team, the [Simulator](#simulator), and [SSL Gamecontroller](#ssl-gamecontroller). -[`thunderscope_main.py`](/src/software/thunderscope/thunderscope_main.py) serves as the main entry point for our entire system. It starts up the [Thunderscope GUI](#thunderscope-gui) and other processes, such as a [Fullsystem](#fullsystem) for each [AI](#ai) team. ## Thunderscope GUI @@ -609,7 +569,7 @@ Thunderscope is implemented using [PyQtGraph](https://www.pyqtgraph.org/), a Pyt * [Layouts](https://doc.qt.io/qt-6/layout.html) * [Signals and Slots](https://doc.qt.io/qt-5/signalsandslots.html) -## 3D Visualizer +### 3D Visualizer Thunderscope has a field visualizer that uses [PyQtGraph's 3D graphics system](https://pyqtgraph.readthedocs.io/en/latest/api_reference/3dgraphics/index.html) to render 3D graphics with OpenGL. PyQtGraph handles all the necessary calls to OpenGL for us, and as an abstraction, provides a [scenegraph](https://en.wikipedia.org/wiki/Scene_graph) to organize and manipulate entities/objects within the 3D environment (the scene). @@ -619,11 +579,39 @@ Thunderscope has a field visualizer that uses [PyQtGraph's 3D graphics system](h - `/graphics` contains custom "graphics items". Graphics items (or just "graphics" for short) are objects that can be added to the [3D scenegraph](https://en.wikipedia.org/wiki/Scene_graph). Graphics should inherit from [`GLGraphicsItem`](https://pyqtgraph.readthedocs.io/en/latest/api_reference/3dgraphics/glgraphicsitem.html) and represent 3D objects that can be visualized in the scene (e.g. a robot, a sphere, a circle, etc.). - `/layers` contains all the [layers](#layers) we use to organize and group together graphics. -### Layers +#### Layers We organize our graphics into "layers" so that we can toggle the visibility of different parts of our visualization. Each layer is responsible for visualizing a specific portion of our AI (e.g. vision data, path planning, passing, etc.). A layer can also handle layer-specific functionality; for instance, `GLWorldLayer` lets the user place or kick the ball using the mouse. The base class for a layer is [`GLLayer`](../src/software/thunderscope/gl/layers/gl_layer.py). A `GLLayer` is in fact a `GLGraphicsItem` that is added to the scenegraph. When we add or remove `GLGraphicsItem`s to a `GLLayer`, we're actually setting the `GLLayer` as the parent of the `GLGraphicsItem`; this is because the scenegraph has a hierarchical tree-like structure. `GLLayer`s can also be nested within one another, i.e. a `GLLayer` can be added as a child of another `GLLayer`. +## Inter-Process Communication +Since Thunderscope runs in a separate process from [Fullsystem](#fullsystem), we use [Unix domain sockets](https://en.wikipedia.org/wiki/Unix_domain_socket) to facilitate communication between Fullsystem and Thunderscope. Unix sockets [have high throughput and are very performant](https://stackoverflow.com/a/29436429/20199855); we simply bind the unix socket to a file path and pass data between processes, instead of having to deal with TCP/IP overhead just to send and receive data on the same computer. + +The data sent between Fullsystem and Thunderscope is serialized using [protobufs](#protobuf). Some data, such as data that goes through our [Backend](#backend) (vision data, game controller commands, [Worlds](#world) from [Sensor Fusion](#sensor-fusion), etc.), is sent using unix senders owned by those parts of the Fullsystem directly. In other higher level components of the Fullsystem (such as FSMs, pass generator, navigator, etc.), we want to delegate away the responsibility of managing unix senders directly and have a lightweight way of sending protobufs to Thunderscope. To avoid needing to dependency inject a "communication" object in places we have visualizable data to send to Thunderscope, we take advantage of the [`g3log`](https://kjellkod.github.io/g3log/) logger already used throughout the codebase to log and send visualizable data. + +`g3log` is a fast and thread-safe way to log data with custom handlers called “sinks". Importantly, it gives us a static [singleton](#singleton-pattern) that can be called anywhere. Logging a protobuf will send it to our custom protobuf `g3log` sink, which lazily initializes unix senders based on the type of protobuf that is logged. The sink then sends the protobuf over the socket to listeners. + +
+Aside: calling g3log to log protobuf data +Logging protobufs is done at the VISUALIZE level (e.g. LOG(VISUALIZE) << some_random_proto;). Protobufs need to be converted to strings in order to log them with g3log. We've overloaded the stream (<<) operator to automatically pack protobufs into a google::protobuf::Any and serialize them to a string, so you don't need to do the conversion yourself. +

+ +In Thunderscope, the [`ProtoUnixIO`](../src/software/thunderscope/proto_unix_io.py) is responsible for communicating protobufs over unix sockets. `ProtoUnixIO` utilizes a variation of the [publisher-subscriber ("pub-sub")](#publisher-subscriber-pattern) messaging pattern. Through `ProtoUnixIO`, clients can register as a subscriber by providing a type of protobuf to receive and a [`ThreadSafeBuffer`](../src/software/thunderscope/thread_safe_buffer.py) to place incoming protobuf messages. The `ProtoUnixIO` can then be configured with a unix receiver to receive protobufs over a unix socket and place those messages onto the `ThreadSafeBuffer`s of that proto's subscribers. Classes can also publish protobufs (for other classes to receive or to send messages back to Fullsystem) via `ProtoUnixIO` by configuring it with a unix sender. + +## Proto Log Replay + +[Fullsystem](#fullsystem) has a `ProtoLogger` that serializes and writes all incoming and outgoing protobufs to a folder. Thunderscope can be launched in a "replay mode" that will load and play back a proto log folder, allowing us to replay old matches and [simulated tests](#simulated-tests). + +## Dynamic Parameters + +**Dynamic Parameters** are the system we use to change values in our code at runtime through Thunderscope. The reason we want to change values at runtime is primarily because we may want to tweak our strategy or aspects of our gameplay very quickly. During games we are only allowed to touch our computers and make changes during halftime or a timeout, so every second counts! Using Dynamic Parameters saves us from having to stop the [AI](#ai), change a constant, recompile the code, and restart the [AI](#ai). + +Dynamic Parameters are stored in one large [protobuf message](#protobuf) that is communicated between Thunderscope and [Fullsystem](#fullsystem). Thunderscope has a widget that displays all our Dynamic Parameters and lets the user change their values. Whenever a Dynamic Parameter value is changed in the widget, [Fullsystem](#fullsystem) and [AI](#ai) will be updated with the new value. For example, we can define a Dynamic Parameter called `run_ai` that is a boolean value. The `run_ai` param will show up in the Parameters widget in [Thunderscope](#thunderscope) with a checkbox that sets the value of `run_ai`. In the "main loop" for the [AI](#ai), it will check if the value of `run_ai` is true before running its logic. + +Here's a slightly more relevant example of how we used Dynamic Parameters during a game in RoboCup 2019. We had a parameter called `enemy_team_can_pass`, which indicates whether or not we think the enemy team can pass. This parameter was used in several places in our defensive logic, and specifically affected how we would shadow enemy robots when we were defending them. If we assumed the enemy team could pass, we would shadow between the robots and the ball to block any passes, otherwise we would shadow between the enemy robot and our net to block shots. During the start of a game, we had `enemy_team_can_pass` set to `false` but the enemy did start to attempt some passes during the game. However, we didn't want to use one of our timeouts to change the value. Luckily later during the half, the enemy team took a time out. Because Dynamic Parameters can be changed quick without stopping [AI](#ai), we were quickly able to change `enemy_team_can_pass` to `true` while the enemy team took their timeout. This made our defence much better against that team and didn't take so much time that we had to burn our own timeout. Altogether this is an example of how we use Dynamic Parameters to control our [AI](#ai) and other parts of the code. + +It is worth noting that constants are still useful, and should still be used whenever possible. If a value realistically doesn't need to be changed, it should be a constant (with a nice descriptive name) rather than a Dynamic Parameter. Having too many Dynamic Parameters is overwhelming because there are too many values to understand and change, and this can make it hard to tune values to get the desired behaviour while under pressure during a game. + # Simulator Our simulator is what we use for physics simulation to do testing when we don't have access to real field. The simulator is a standalone application that simulates the following components' functionalities: * [SSL-Vision](#ssl-vision) by publishing new vision data @@ -682,21 +670,69 @@ Notice this is very similar to the [Architecture Overview Diagram](#architecture ![Simulated Testing High-level Architecture Diagram](images/simulated_test_high_level_architecture.svg) -# Inter-process Communication -Since [Thunderscope](#thunderscope) runs in a separate process from [Fullsystem](#fullsystem), we use [Unix domain sockets](https://en.wikipedia.org/wiki/Unix_domain_socket) to facilitate communication between Fullsystem and Thunderscope. Unix sockets [have high throughput and are very performant](https://stackoverflow.com/a/29436429/20199855); we simply bind the unix socket to a file path and pass data between processes, instead of having to deal with TCP/IP overhead just to send and receive data on the same computer. +# E-Stop +The **E-Stop** allows us to quickly and manually command physical robots to stop what they are doing. It is a physical push button that is connected to the computer via a USB cable. We also have a `--keyboard_estop` flag you can use when running Thunderscope that lets you use the spacebar as the E-Stop. When Thunderscope is launched, a `ThreadedEstopReader` is initialized (within `RobotCommunication`) that is responsible for communicating and reading values from the E-Stop via UART. While running, it will poll the status of the E-Stop to determine whether it is in the `STOP` or `PLAY` state: +- If the E-Stop is in the `STOP` state, it overrides the [Primitives](#primitives) sent to the robots with `Stop` primitives. On the robot, Thunderloop is responsible for handling the primitive message and ensuring that the power & motor boards receive the correct inputs for the robot to stop. +- If the E-Stop is in the `PLAY` state, primitives are communicated as normal. -The data sent between Fullsystem and Thunderscope is serialized using [protobufs](#protobuf). Some data, such as data that goes through our [Backend](#backend) (vision data, game controller commands, [Worlds](#world) from [Sensor Fusion](#sensor-fusion), etc.), is sent using unix senders owned by those parts of the Fullsystem directly. In other higher level components of the Fullsystem (such as FSMs, pass generator, navigator, etc.), we want to delegate away the responsibility of managing unix senders directly and have a lightweight way of sending protobufs to Thunderscope. To avoid needing to dependency inject a "communication" object in places we have visualizable data to send to Thunderscope, we take advantage of the [`g3log`](https://kjellkod.github.io/g3log/) logger already used throughout the codebase to log and send visualizable data. +# Design Patterns -`g3log` is a fast and thread-safe way to log data with custom handlers called “sinks". Importantly, it gives us a static [singleton](#singleton-pattern) that can be called anywhere. Logging a protobuf will send it to our custom protobuf `g3log` sink, which lazily initializes unix senders based on the type of protobuf that is logged. The sink then sends the protobuf over the socket to listeners. +Below are the main design patterns we use in our code, and what they are used for. -
-Aside: calling g3log to log protobuf data -Logging protobufs is done at the VISUALIZE level (e.g. LOG(VISUALIZE) << some_random_proto;). Protobufs need to be converted to strings in order to log them with g3log. We've overloaded the stream (<<) operator to automatically pack protobufs into a google::protobuf::Any and serialize them to a string, so you don't need to do the conversion yourself. -

+## Abstract Classes and Inheritance +While not a "design pattern" per se, inheritance and related OOP paradigms are prevalent throughout of our code base. Abstract classes let us define interfaces for various components of our code. Then we can implement different objects that obey the interface, and use them interchangeably, with the guarantee that as long as they follow the same interface we can use them in the same way. -In Thunderscope, the [`ProtoUnixIO`](../src/software/thunderscope/proto_unix_io.py) is responsible for communicating protobufs over unix sockets. `ProtoUnixIO` utilizes a variation of the [publisher-subscriber ("pub-sub")](#publisher-subscriber-pattern) messaging pattern. Through `ProtoUnixIO`, clients can register as a subscriber by providing a type of protobuf to receive and a [`ThreadSafeBuffer`](../src/software/thunderscope/thread_safe_buffer.py) to place incoming protobuf messages. The `ProtoUnixIO` can then be configured with a unix receiver to receive protobufs over a unix socket and place those messages onto the `ThreadSafeBuffer`s of that proto's subscribers. Classes can also publish protobufs via `ProtoUnixIO` by configuring it with a unix sender. +To learn more about inheritance in C++, read the following `learncpp.com` articles: +- [Introduction to inheritance](https://www.learncpp.com/cpp-tutorial/introduction-to-inheritance/) +- [Virtual functions](https://www.learncpp.com/cpp-tutorial/pointers-and-references-to-the-base-class-of-derived-objects/) -# E-Stop -The E-Stop allows us to quickly and manually command physical robots to stop what they are doing. It is a physical push button that is connected to the computer via a USB cable. We also have a `--keyboard_estop` flag you can use when running Thunderscope that lets you use the spacebar as the E-Stop. When Thunderscope is launched, a `ThreadedEstopReader` is initialized (within `RobotCommunication`) that is responsible for communicating and reading values from the E-Stop via UART. While running, it will poll the status of the E-Stop to determine whether it is in the `STOP` or `PLAY` state: -- If the E-Stop is in the `STOP` state, it overrides the [Primitives](#primitives) sent to the robots with `Stop` primitives. On the robot, Thunderloop is responsible for handling the primitive message and ensuring that the power & motor boards receive the correct inputs for the robot to stop. -- If the E-Stop is in the `PLAY` state, primitives are communicated as normal. +Examples of this can be found in many places, including: +* [Plays](#plays) +* [Tactics](#tactics) + +## Singleton Pattern +The Singleton pattern is useful for having a single, global instance of an object that can be accessed from anywhere. Though it's generally considered an anti-pattern (aka _bad_), it is useful in specific scenarios. Read the Refactoring Guru article on the [Singleton pattern](https://refactoring.guru/design-patterns/singleton) for more information. + +We use the Singleton pattern for our logger. This allows us to create a single logger for the entire system, and code can make calls to the logger from anywhere, rather than us having to pass a `logger` object literally everywhere. + + +## Factory Pattern +The Factory pattern is useful for hiding or abstracting how certain objects are created. Read the Refactoring Guru articles on the [Factory Method pattern](https://refactoring.guru/design-patterns/factory-method) and the [Abstract Factory pattern](https://refactoring.guru/design-patterns/abstract-factory) for more information. + +Because the Factory needs to know about what objects are available to be created, it can be taken one step further to auto-register these object types. Rather than a developer having to remember to add code to the Factory every time they create a new class, this can be done "automatically" with some clever C++ code. This helps reduce mistakes and saves developers work. Read this [post about auto-registering factories](http://derydoca.com/2019/03/c-tutorial-auto-registering-factory/) for more information. + +The auto-registering factory is particularly useful for our `PlayFactory`, which is responsible for creating [Plays](#plays). Every time we run our [AI](#ai) we want to know what [Plays](#plays) are available to choose from. The Factory pattern makes this really easy, and saves us having to remember to update some list of "available Plays" each time we add or remove one. + + +## Visitor Pattern +The Visitor pattern is useful when we need to perform different operations on a group of "similar" objects, like objects that inherit from the same parent class (e.g. [Tactic](#tactics)). We might only know all these objects are a [Tactic](#tactic), but we don't know specifically which type each one is (eg. `AttackerTactic` vs `ReceiverTactic`). The Visitor Pattern helps us "recover" that type information so we can perform different operations on the different types of objects. It is generally preferred to a big `if-block` with a case for each type, because the compiler can help warn you when you've forgotten to handle a certain type, and therefore helps prevent mistakes. + +Read the Refactoring Guru article on the [Visitor pattern](https://refactoring.guru/design-patterns/visitor) for more information. + +An example of where we use the Visitor pattern is in our `MotionConstraintVisitor`. This visitor allows us to update the current set of motion constraints based on the types of tactics that are currently assigned. + +## Observer Pattern +The Observer pattern is useful for letting components of a system "notify" each other when something happens. Read the Refactoring Guru article on the [Observer pattern](https://refactoring.guru/design-patterns/observer) for a general introduction to the pattern. + +Our implementation of this pattern consists of two classes, `Observer` and `Subject`. `Observer`s can be registered with a `Subject`, after which new values will be sent from each `Subject` to all of it's registered `Observer`s. Please see the headers of both classes for details. Note that a class can extend both `Observer` and `Subject`, thus receiving and sending out data. In this way we can "chain" multiple classes. + +### Threaded Observer +In our system, we need to be able to do multiple things (receive camera data, run the [AI](#ai), send commands to the robots) at the same time. In order to facilitate this, we extend the `Observer` to the `ThreadedObserver` class. The `ThreadedObserver` starts a thread with an infinite loop that waits for new data from `Subject` and performs some operation with it. + +> [!WARNING] +> If a class extends multiple `ThreadedObserver`s (for example, [AI](#ai) could extend `ThreadedObserver` and `ThreadedObserver`), then there will be two threads running, one for each observer. We **do not check** for data race conditions between observers, so it's entirely possible that one `ThreadedObserver` thread could read/write from data at the same time as the other `ThreadedObserver` is reading/writing the same data. Please make sure any data read/written to/from multiple `ThreadedObserver`s is thread-safe. + +One example of this is [SensorFusion](#sensor-fusion), which extends `Subject` and the [AI](#ai), which extends `ThreadedObserver`. [SensorFusion](#sensor-fusion) runs in one thread and sends data to the [AI](#ai), which receives and processes it another thread. + +## Publisher-Subscriber Pattern + +The publisher-subscriber pattern ("pub-sub") is a messaging pattern for facilitating communication between different components. It is closely related to the [message queue](https://en.wikipedia.org/wiki/Message_queue) design pattern. + +In this pattern, `Publisher`s send messages without knowing who the recipients (`Subscriber`s) are. `Subscriber`s express interest in specific types of messages by subscribing to relevant topics; when a `Publisher` sends a message of a topic, the messaging system ensures that all interested subscribers receive the message. + +Read the [Wikipedia article on pub-sub](https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern) for an introduction to the pub-sub pattern. + +We use the pub-sub pattern to facilitate [inter-process communication](#inter-process-communication) in our system. Through a class called [`ProtoUnixIO`](../src/software/thunderscope/proto_unix_io.py), components can subscribe to receive certain [Protobuf](#protobuf) message types sent out by other processes or system components. + +## C++ Templating +While debatably not a design pattern depending on who you ask, templating in C++ is a powerful tool that is very useful to understand. We use templating throughout around our codebase. `learncpp.com` has a good explanation on [function templates](https://www.learncpp.com/cpp-tutorial/function-templates/) and [class templates](https://www.learncpp.com/cpp-tutorial/class-templates/). From f127f5c3a1a6559a2c46814304e7d6e3d6bbbd3d Mon Sep 17 00:00:00 2001 From: williamckha Date: Sat, 8 Mar 2025 14:55:39 -0800 Subject: [PATCH 16/18] Remove includes in primitive_executor.h --- src/software/embedded/primitive_executor.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/software/embedded/primitive_executor.h b/src/software/embedded/primitive_executor.h index 891ff31bd0..540f3d0f41 100644 --- a/src/software/embedded/primitive_executor.h +++ b/src/software/embedded/primitive_executor.h @@ -5,9 +5,6 @@ #include "software/ai/navigator/trajectory/bang_bang_trajectory_1d_angular.h" #include "software/ai/navigator/trajectory/trajectory_path.h" #include "software/geom/vector.h" -#include "software/time/duration.h" -#include "software/world/robot_state.h" -#include "software/world/team_types.h" class PrimitiveExecutor { From 7e5d73bd2a61a567436a9c1fc3b4bcc4e2586918 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci-lite[bot]" <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> Date: Sat, 8 Mar 2025 23:05:50 +0000 Subject: [PATCH 17/18] [pre-commit.ci lite] apply automatic fixes --- docs/getting-started.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/getting-started.md b/docs/getting-started.md index 267d4417b7..d180789f6d 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -31,9 +31,9 @@ - [Tracy](#tracy) - [Building for the robot](#building-for-the-robot) - [Deploying Robot Software to the robot](#deploying-robot-software-to-the-robot) + - [Testing Robot Software locally](#testing-robot-software-locally) - [Setting up Virtual Robocup 2021](#setting-up-virtual-robocup-2021) - [Setting up the SSL Simulation Environment](#setting-up-the-ssl-simulation-environment) - - [Pushing a Dockerfile to dockerhub](#pushing-a-dockerfile-to-dockerhub) - [Workflow](#workflow) - [Issue and Project Tracking](#issue-and-project-tracking) - [Issues](#issues) From 3eb22fb4ed19890d99cb40fa9c718c6ff11933b0 Mon Sep 17 00:00:00 2001 From: williamckha Date: Sat, 8 Mar 2025 15:51:30 -0800 Subject: [PATCH 18/18] Revert "Remove includes in primitive_executor.h" This reverts commit f127f5c3a1a6559a2c46814304e7d6e3d6bbbd3d. --- src/software/embedded/primitive_executor.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/software/embedded/primitive_executor.h b/src/software/embedded/primitive_executor.h index 008a0d5631..fb6ef8dd51 100644 --- a/src/software/embedded/primitive_executor.h +++ b/src/software/embedded/primitive_executor.h @@ -5,6 +5,9 @@ #include "software/ai/navigator/trajectory/bang_bang_trajectory_1d_angular.h" #include "software/ai/navigator/trajectory/trajectory_path.h" #include "software/geom/vector.h" +#include "software/time/duration.h" +#include "software/world/robot_state.h" +#include "software/world/team_types.h" class PrimitiveExecutor {