Úpravy dálkového ovládání
Jak upravit to, co vidíte na telefonu nebo počítači v aplikaci RBController?
Tato kapitola předpokládá, že upravuješ rbcontroller-android-app
z našeho balíku
příkladů pro Robotku, viz Dálkové ovládání.
Ovládání na telefonu pouze zobrazuje to, co mu pošle tvoje Robotka. V příkladu dálkového ovládání je to pouze jeden joystick, ale to můžeš rychle změnit. K ovládacímu rozhraní totiž existuje “návrhář”:
Otevři si ho v prohlížeči.
Layout
Layout je popis celého ovládacího rozhraní - kde všechny prvky (widgety) jsou,
jak se jmenují a jaké mají parametry. Layout je výstupem z návrháře a v projektu
už jeden máš jako soubor src/layout.h
. Najdi si ho ve VSCode, otevři, a
zkopíruj celý jeho obsah do schránky (ctrl+c).
Poté přejdi do návrháře a
klikni na žluté tlačítko Import layout vlevo nahoře. Do dialogu vlož (ctrl+v) obsah souboru
src/layout.h
, který máš ve schránce.
Výsledek by měl vypadat takto:
Zkus do layoutu přetáhnout z levého sloupce jeden Button (tlačítko), prozatím mu nic dalšího nenastavuj.
Upravený layout dostaneš do programu zpátky tak, že klikneš na Copy to Clipboard
vpravo nahoře v boxu Generated C++, předeš zpátky do VSCode do souboru src/layout.h
,
a celý jeho obsah nahradíš tím, co máš ve schránce (ctrl+a ctrl+v).
Poté nahraj program do Robotky, připoj se přes RBController aplikaci a tam obnov stránku. Přidané nové tlačítko by mělo být vidět, zatím ale nic nedělá.
Reakce na události
Některé widgety (např. Button, Checkbox, Joystick…) vytvářejí určité události: tlačítko stisknuto, checkbox odšrtnut/zaškrtnut nebo joystick se pohl.
Na tyto události můžeš v kódu reagovat, viz joystick v příkladu rbcontroller-android-app
:
1
2
3
4
5
6
7
8
auto builder = Layout.begin();
builder.Joystick1
.onPositionChanged([&](Joystick &joy) {
rkMotorsJoystick(joy.x(), joy.y());
});
builder.commit();
Zde si všimni prvního a posledního řádku - ty musí být v každém programu používající RBController a dálkové ovládání. Mezi nimy je prostor pro zpracovávání událostí. Pojďmě si rozebrat, co se v kódu děje:
-
1
builder.Joystick1.onPositionChanged(...
Tato konstrukce říká, že chceme pracovat s prvkem, který má ID
Joystick1
, a že chceme zpracovat událostPositionChanged
. ID se nastavuje v návrháři, zkuste vybrat některý z widgetů a ID bude žlutě zvýrazněné napravo ve sloupci Properties. -
1 2 3
[&](Joystick &joy) { rkMotorsJoystick(joy.x(), joy.y()); }
Události využívají tzv. lambda funkce - malinkaté funkce, které vytvoříte syntaxí
[&](<parametry>){ <kód> }
. V případě návrháře budou parametry vždy(<Typ widgetu> &widget)
- v tomto případě je typJoystick
. Kód, který je pak v těle funkce, se vykoná vždy, když daná událost nastane.
Zde nastavujeme výkon motorů podle toho, v jaké poloze jeJoystick1
.
Příklad: reagování na stisknutí tlačítka
Do layoutu jsme přidali jedno tlačítko. Přejdi zase do návrháře, vyberte ho, a v pravém sloupci
Properties změňte ID na něco jiného, například prepniLed
. Layout opět nakopíruj do svého projektu
ve VSCode.
Přejdi do src/main.cpp
a přidej do zpracování událostí tvé tlačítko. Všimni si, že
VSCode ti po napsání builder.
začne napovídat ID widgetů, které jsou v tvém layoutu.
Stejně tak začne po napsání builder.prepniLed.
napovídat, co všechno lze s tlačítkem dělat.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
auto builder = Layout.begin();
builder.Joystick1
.onPositionChanged([&](Joystick &joy) {
rkMotorsJoystick(joy.x(), joy.y());
});
builder.prepniLed
.onPress([&](Button& b) {
rkLedGreen(true);
})
.onRelease([&](Button& b) {
rkLedGreen(false);
});
builder.commit();
Nahrej program do Robotky a vyzkoušej, jestli funguje. Výsledkem by mělo být, že zelená LED svítí, dokud držíš tlačítko v aplikaci stisknuté.
Zobrazování dat z Robotky
Komunikace může probíhat i druhým směrem, můžeš tak zobrazovat informace z Robotky na tvém telefonu. Zkusíme to nejprve s napětím baterie.
V návrháři přidej do layoutu jeden Text widget a nastav mu ID, například
napetiMv
. Layout opět zkopíruj do svého projektu.
Kód bude vypadat takto (reagování na události vynecháno):
1
2
3
4
5
6
7
8
auto builder = Layout.begin();
...
builder.commit();
while(true) {
Layout.napetiMv.setText(fmt::format("{} mV", rkBatteryVoltageMv()));
delay(500);
}
Přidali jsme nekonečnou smyčku, která každých 500 ms (půl vteřiny) nastaví obsah Textu s ID napetiMv
.
- Posílání dat do telefonu přijde, narozdíl od zpracování událostí, až pod řádek
builder.commit();
. - Lze nastavovat spoustu jiných parametrů, zkus napsat
Layout.napetiMv.
a bude ti napovězeno, co všechno můžeš použít. - Funkce
fmt::format
převede výsledek funkcerkBatteryVoltageMv()
, což jeint
, na textový řetězec (std::string
) a přidá za něj jednotku mV (millivolty). fmt:format
má jako první parametr “šablonu”, v našem případě"{} mV"
. Všechny{}
v šabloně jsou nahrazeny hodnotou dalších parametrů, v našem případě je{}
nahrazeno výsledkemrkBatteryVoltageMv()
. V šabloně může být vice než jeden{}
.
Data lze zobrazovat i ze zpracování událostí. Následující kód také funguje, protože lambda funkce událostí jsou volány
až po té, co proběhne builder.commit();
.
1
2
3
4
5
6
7
8
auto builder = Layout.begin();
builder.Joystick1
.onPositionChanged([&](Joystick &joy) {
Layout.textJoystick.setText(fmt::format("{}x{}", joy.x(), joy.y()));
});
builder.commit();
Dokumentace
- Seznam všech možných událostí
- Seznam widgetů - po kliknutí na určitý typ je vidět, co všechno na něm jde nastavovat.