Stejně jako minulý rok se i letos zúčastníme soutěže FIRST Lego League Challenge.
Tentokrát už jsme si vyzkoušeli Pybricks.
Nečekejte ode mě shrnutí nebo nějakou recenzi, ale děti se mě zeptaly na jednu úlohu, kterou jsem v tom mumraji neodbavil okamžitou radou na místě.
Takže si plním za domácí úkol.
Jak zastavit Lego robota na černé čáře pomocí Pybricks?

Pybricks
Již loni se nám Pybricks dostal do hledáčku, že bychom tím nahradili prostředí Lego Spike.
Má nějaké zajímavé API jako například udržení rovného směru pomocí gyroskopu.
Varianta s Python kódem je zdarma, ale tím děti zatím trápit nechci.
Umožňuje používat i grafické bloky, na které jsou zvyklé, bohužel mi licence nepřijde zrovna levná.
I když použijete bloky, projekt si vyexportujete do Pythonu, což může v učení pomoci.
Zastavení
Úloha „zastav se na čáře“ je velmi praktická.
Ostatně na herní plánu je několik čar, které můžete (ale nemusíte) k orientaci využít.
Lego má barevný senzor a k němu existuje Pybricks API.
Neuvědomil jsem si, že přesnost měření barvy bude záviset na okolním osvětlení a při použití hodnoty odrazivosti nebude černá nikdy nula (přece jen něco odrazí).
Chvilku jsem debugoval, jaké hodnoty naměřím na různých površích.
Nakonec jsem pro sebe použil hodnotu 20 (20 % odrazivosti).

A pak už se k výslednému programu dostaneme poměrně přímočaře.
V blocích to může vypadat takto.

V Pythonu takto.
<noscript><pre># pybricks blocks file:{"blocks":{"languageVersion":0,"blocks":[{"type":"blockGlobalSetup","id":"bjK,wS1MYO7aiYkFSwd{","x":4,"y":51,"deletable":false,"next":{"block":{"type":"variables_set_prime_hub","id":"{)WuTTGMSJwLS.H*~PKI","extraState":{"optionLevel":1},"fields":{"VAR":{"id":"0ac8)M*M0@okqL6j*T]k"}},"inputs":{"AXIS_TOP":{"shadow":{"type":"blockParametersAxis","id":"G~~=qPiIM)z4Qy;ugq.J","fields":{"VALUE":"z"}}},"AXIS_FRONT":{"shadow":{"type":"blockParametersAxis","id":"=O,F=r_j:y!5C6~`*A2D","fields":{"VALUE":"y"}}}},"next":{"block":{"type":"variables_set_motor","id":"S?(a.C=~LVoJ~3YRo;}.","fields":{"VAR":{"id":"9-KY1{EjNJxUixuEoYJ?"}},"inputs":{"PORT":{"shadow":{"type":"blockParametersPort","id":"pE~{$Zwzpz`i_VDqm^ab","fields":{"NAME":"A"}}},"POSITIVE_DIRECTION":{"shadow":{"type":"blockParametersDirection","id":"VrW-zLpmx[j,+8v+,L[1","fields":{"SELECTION":"Direction.COUNTERCLOCKWISE"}}}},"next":{"block":{"type":"variables_set_motor","id":"3,Y?*Mn1@v9fJ`yYW6Sf","fields":{"VAR":{"id":"@(Mc?VKF9P+IVA!,)0R;"}},"inputs":{"PORT":{"shadow":{"type":"blockParametersPort","id":"r`9bbROX1dwatV7O$.:`","fields":{"NAME":"E"}}},"POSITIVE_DIRECTION":{"shadow":{"type":"blockParametersDirection","id":"Fk;M%s,~BY}0ww1j30bP","fields":{"SELECTION":"Direction.CLOCKWISE"}}}},"next":{"block":{"type":"variables_set_motor","id":"^b]cQj|TmdV%cZJhl0gI","fields":{"VAR":{"id":"#~*U;Y3)}OaA),GbQ/cW"}},"inputs":{"PORT":{"shadow":{"type":"blockParametersPort","id":"?.^x_gX%wU.Xv.#3wRPP","fields":{"NAME":"D"}}},"POSITIVE_DIRECTION":{"shadow":{"type":"blockParametersDirection","id":"0Np/F+n#MjwgBk{6MrPK","fields":{"SELECTION":"Direction.CLOCKWISE"}}}},"next":{"block":{"type":"variables_set_motor","id":"I#`Wxj%/1]|h{X+ZQ;3Y","fields":{"VAR":{"id":"xE_y9@2/n%+##W#h*hFj"}},"inputs":{"PORT":{"shadow":{"type":"blockParametersPort","id":"j1eKhU`bdoHdh)~]Hl2b","fields":{"NAME":"C"}}},"POSITIVE_DIRECTION":{"shadow":{"type":"blockParametersDirection","id":"|$c/*_TuT!~8{cQFN{[f","fields":{"SELECTION":"Direction.CLOCKWISE"}}}},"next":{"block":{"type":"variables_set_drive_base","id":"B@6q{(N{H$OlQN@o(=#7","fields":{"VAR":{"id":"/@.Q%T4BjtqKCq7$UAbr"}},"inputs":{"VAR":{"shadow":{"type":"variables_get_motor_device","id":"h-`^(Zu#NTvZ*mW#2vcD","fields":{"VAR":{"id":"9-KY1{EjNJxUixuEoYJ?","name":"kolo leve","type":"Motor"}}}},"VAR2":{"shadow":{"type":"variables_get_motor_device","id":"CD5,af-R[yO,bE]-?Uf_","fields":{"VAR":{"id":"@(Mc?VKF9P+IVA!,)0R;","name":"kolo prave","type":"Motor"}}}},"VALUE0":{"shadow":{"type":"unit_distance","id":"GNgo@U(M|24Obsy~%4x{","fields":{"VALUE0":88}}},"VALUE1":{"shadow":{"type":"unit_distance","id":"cIT+~l^nylC1%}(,bsKB","fields":{"VALUE0":144}}}},"next":{"block":{"type":"variables_set_color_sensor","id":"0]Gny{r@pu-me0u.qL+H","extraState":{"optionLevel":0},"fields":{"VAR":{"id":"4q7cl%:FR{.%!.~b;=4j"}},"inputs":{"PORT":{"shadow":{"type":"blockParametersPort","id":"HrOt9)|o*,]VPV8SDZ9E","fields":{"NAME":"B"}}}},"next":{"block":{"type":"variables_set_color_sensor","id":"x.AGwFp0|}^R*%F(%TcG","extraState":{"optionLevel":0},"fields":{"VAR":{"id":"^z-R_D5t#~Oky5)7@fjS"}},"inputs":{"PORT":{"shadow":{"type":"blockParametersPort","id":"I!+TlWLqzTDYY6^$uKdf","fields":{"NAME":"F"}}}}}}}}}}}}}}}}}}}}},{"type":"blockGlobalStart","id":"3tJe|AWl0baN(wH9a$@.","x":990,"y":44,"deletable":false,"next":{"block":{"type":"blockDriveBaseUseGyro","id":"W=Lm:RpeA}v?nKUf*^6.","fields":{"METHOD":"DRIVEBASE_USE_GYRO_TRUE"},"inputs":{"VAR":{"shadow":{"type":"variables_get_drive_base_device","id":"i{6(E*p~D3tY|M-^UtvG","fields":{"VAR":{"id":"/@.Q%T4BjtqKCq7$UAbr","name":"drive base","type":"DriveBase"}}}}},"next":{"block":{"type":"blockDriveBaseConfigure","id":"g3I/xPp1/oeRSee5-LA^","extraState":{"optionLevel":1},"fields":{"METHOD":"DRIVEBASE_STRAIGHT_SPEED"},"inputs":{"VAR":{"shadow":{"type":"variables_get_drive_base_device","id":"Z+6V|uC*Z3_Z4Pd$0di/","fields":{"VAR":{"id":"/@.Q%T4BjtqKCq7$UAbr","name":"drive base","type":"DriveBase"}}}},"ARG0":{"shadow":{"type":"unit_speed","id":"oc%m!QtUlj%nS}0wUkdH","fields":{"VALUE0":500}}}},"next":{"block":{"type":"blockFlowWhile","id":"^w![3wsmge-,nl%)9)_2","fields":{"MODE":"WHILE"},"inputs":{"BOOL":{"shadow":{"type":"blockLogicTrue","id":"|%RuaCQaVxPi_*BB*Hea"},"block":{"type":"blockLogicCompare","id":"0-l;i-(OX+f@B$[%Nv?7","fields":{"OP1":"GT"},"inputs":{"A":{"shadow":{"type":"blockMathNumber","id":"0R9k4vfG#^mUZ#xuV!Yy","fields":{"NUM":3}},"block":{"type":"blockLightReflection","id":"xPaTrirocgrfw:z($hfN","inputs":{"VAR":{"shadow":{"type":"variables_get_light_intensity_device","id":"DOR_9uhk=S}7mpH~6ny:","fields":{"VAR":{"id":"4q7cl%:FR{.%!.~b;=4j","name":"senzor levy","type":"ColorSensor"}}}}}}},"B":{"shadow":{"type":"blockMathNumber","id":"=Fis}(OW{eVsQ%GL+Xv?","fields":{"NUM":20}}}}}},"DO":{"block":{"type":"blockDriveBaseDrive2","id":"e!qh#u{yRC]5T}d88!wD","extraState":{"optionLevel":2},"fields":{"METHOD":"DRIVEBASE_DRIVE_STRAIGHT"},"inputs":{"VAR":{"shadow":{"type":"variables_get_drive_base_device","id":"Fn3J0txHNG:z99+vK!pI","fields":{"VAR":{"id":"/@.Q%T4BjtqKCq7$UAbr","name":"drive base","type":"DriveBase"}}}},"ARG0":{"shadow":{"type":"unit_distance","id":"Zf;zZ*m@T_Mm5%_U]r.u","fields":{"VALUE0":50}}},"ARG1":{"shadow":{"type":"parameters_stop_4","id":"m4%XtpLADnb=l]x@*bmt","fields":{"VALUE":"Stop.NONE"}}}}}}},"next":{"block":{"type":"blockDriveBaseStop","id":"FQcgVD9TN#4W;ib{Q}Dj","inputs":{"VAR":{"shadow":{"type":"variables_get_drive_base_device","id":"sJ%~bnFg:!9s?/VX*/M(","fields":{"VAR":{"id":"/@.Q%T4BjtqKCq7$UAbr","name":"drive base","type":"DriveBase"}}}},"VALUE0":{"shadow":{"type":"parameters_stop_3","id":"ELOu@BWpK(Ie4(+d)AL_","fields":{"VALUE":"Stop.HOLD"}}}}}}}}}}}}}]},"variables":[{"name":"red","id":"^TRnlnrf1|b]54?=RSAE","type":"ColorDef"},{"name":"orange","id":"T/Ga=6s={mOa/4,vyj]{","type":"ColorDef"},{"name":"yellow","id":"z6p)=?w#+g|y@lU:VFt*","type":"ColorDef"},{"name":"green","id":"PQR$ys-f%#*T_4`Rx0fH","type":"ColorDef"},{"name":"cyan","id":"n3GEOv6@N!|xg_x}=GL+","type":"ColorDef"},{"name":"blue","id":"G_|mnBi;ov8st$C/z;$W","type":"ColorDef"},{"name":"violet","id":"MMX}YsyH/D)kVHpH2a/t","type":"ColorDef"},{"name":"magenta","id":"@4TT%Ad^Qyn!IQ9HhF{H","type":"ColorDef"},{"name":"white","id":"Yknl*y[~$s;/3RGi{ju1","type":"ColorDef"},{"name":"none","id":"e|_}L8nQoa5[!)|??9+L","type":"ColorDef"},{"name":"prime hub","id":"0ac8)M*M0@okqL6j*T]k","type":"PrimeHub"},{"name":"drive base","id":"/@.Q%T4BjtqKCq7$UAbr","type":"DriveBase"},{"name":"kolo leve","id":"9-KY1{EjNJxUixuEoYJ?","type":"Motor"},{"name":"kolo prave","id":"@(Mc?VKF9P+IVA!,)0R;","type":"Motor"},{"name":"motor predni","id":"#~*U;Y3)}OaA),GbQ/cW","type":"Motor"},{"name":"motor zadni","id":"xE_y9@2/n%+##W#h*hFj","type":"Motor"},{"name":"motor","id":"4f^oLh]vR?;f9cEyqLvm","type":"Motor"},{"name":"senzor levy","id":"4q7cl%:FR{.%!.~b;=4j","type":"ColorSensor"},{"name":"senzor pravy","id":"^z-R_D5t#~Oky5)7@fjS","type":"ColorSensor"},{"name":"sensor","id":"-BWH)YE(r`_KzM)7#.kx","type":"ColorSensor"}],"info":{"type":"pybricks","version":"1.3.2"}}
from pybricks.hubs import PrimeHub
from pybricks.parameters import Axis, Direction, Port, Stop
from pybricks.pupdevices import ColorSensor, Motor
from pybricks.robotics import DriveBase
# Set up all devices.
prime_hub = PrimeHub(top_side=Axis.Z, front_side=Axis.Y)
senzor_levy = ColorSensor(Port.B)
senzor_pravy = ColorSensor(Port.F)
kolo_leve = Motor(Port.A, Direction.COUNTERCLOCKWISE)
kolo_prave = Motor(Port.E, Direction.CLOCKWISE)
motor_predni = Motor(Port.D, Direction.CLOCKWISE)
motor_zadni = Motor(Port.C, Direction.CLOCKWISE)
drive_base = DriveBase(kolo_leve, kolo_prave, 88, 144)
# The main program starts here.
drive_base.use_gyro(True)
drive_base.settings(straight_speed=500)
while senzor_levy.reflection() > 20:
drive_base.straight(50, then=Stop.NONE)
drive_base.straight(0)
</pre></noscript>
Všimněte si, že bloku pohybu lze v then nastavit, co dělat na konci bloku, což ovlivní, jak (ne)plynule pojede.
Stejně tak na konci nastavuji způsob zastavení.
Závěr
Pybricks nabízí pokročilejší funkce oproti Lego Spike prostředí.
Varianta psaní v Pythonu je zdarma, za grafické bloky si připlatíte.
Spouštění programů ve fyzickém světě dokáže vždycky něčím překvapit, třeba zjištěním, že i černá barva odrazí nějaké světlo.
Související