Programování jBotBrainu II v Javě a práce s moduly

Transkript

Programování jBotBrainu II v Javě a práce s moduly
Programování jBotBrainu II v Javě a práce s moduly
© 2010, Adam Heinrich (www.adamh.cz)
Skripta Mechatronic Education
Obsah
1 Programovací jazyk Java..............................................................................................................5
1.1 Proč právě Java?....................................................................................................................5
1.2 První program.......................................................................................................................6
1.2.1 Komentáře.....................................................................................................................7
1.2.2 Třídy a objekty..............................................................................................................8
1.2.3 Metody...........................................................................................................................9
1.3 Popis jazyka Java................................................................................................................10
1.3.1 Datové typy a proměnné..............................................................................................10
1.3.1.1 Definice proměnných..........................................................................................10
1.3.1.2 Přiřazení hodnoty.................................................................................................11
1.3.1.3 Aritmetické výrazy...............................................................................................11
1.3.1.4 Pole......................................................................................................................12
1.3.2 Podmínky.....................................................................................................................14
1.3.3 Cykly...........................................................................................................................16
1.3.3.1 Cyklus while........................................................................................................16
1.3.3.2 Cyklus do-while...................................................................................................16
1.3.3.3 Cyklus for............................................................................................................17
1.3.3.4 Příkazy break a continue......................................................................................18
1.3.3.5 Nekonečný cyklus................................................................................................18
1.3.4 Metody.........................................................................................................................19
1.3.5 Třídy............................................................................................................................20
1.3.5.1 Veřejné a soukromé..............................................................................................20
1.3.5.2 Konstruktor..........................................................................................................21
1.3.5.3 Statické a dynamické metody a třídy...................................................................21
1.3.5.4 Dědičnost.............................................................................................................21
1.3.5.5 Rozhraní...............................................................................................................22
1.3.5.6 Balíky...................................................................................................................23
1.3.6 Výjimky.......................................................................................................................23
2 Popis vývojového prostředí Eclipse............................................................................................25
2.1 Vytvoření projektu krok za krokem.....................................................................................26
2.1.1 Kompilace a nahrávání programu...............................................................................28
2.2 Vytvoření nové třídy............................................................................................................29
-2-
Skripta Mechatronic Education
2.3 Automatické doplňování.....................................................................................................30
2.4 Přejmenování třídy..............................................................................................................31
2.5 Zobrazení čísel řádků..........................................................................................................32
2.6 Hledání a opravy chyb........................................................................................................33
2.7 Automatické formátování zdrojového kódu........................................................................35
3 Programování jBotBrainu II.......................................................................................................36
3.1 Rozbor prvního programu...................................................................................................36
3.2 Práce s periferiemi jBotBrainu II........................................................................................37
3.2.1 LED a čekací smyčky..................................................................................................37
3.2.2 Tlačítka........................................................................................................................39
3.2.3 Výstup do konzole.......................................................................................................41
3.2.4 Bzučák.........................................................................................................................42
3.2.5 Digitální výstupy.........................................................................................................44
3.2.6 Digitální vstupy...........................................................................................................46
3.2.7 Čítač.............................................................................................................................47
3.2.8 Analogové vstupy........................................................................................................48
3.2.9 Motory.........................................................................................................................50
3.2.10 Servomotory..............................................................................................................52
3.2.11 Bluetooth...................................................................................................................53
3.2.12 UART........................................................................................................................57
3.2.13 I2C.............................................................................................................................59
3.2.14 Vlákna.......................................................................................................................63
3.2.15 Časovače....................................................................................................................66
3.3 Práce s moduly....................................................................................................................68
3.3.1 SD 05 – Dotykový spínač............................................................................................68
3.3.2 SA 02 – Senzor atmosférického tlaku.........................................................................70
3.3.3 SA 04 – Teploměr........................................................................................................71
3.3.4 SI 01 – Akcelerometr...................................................................................................72
3.3.5 SI 02 – Světelný senzor...............................................................................................74
3.3.6 SI 03 – Ultrazvukový dálkoměr..................................................................................75
3.3.7 MI 04 – Řadič krokových motorů...............................................................................76
4 Programování pro mobilní telefony............................................................................................80
4.1 Úvod do J2ME aplikací.......................................................................................................80
4.1.1 Co budeme potřebovat?...............................................................................................80
-3-
Skripta Mechatronic Education
4.1.2 Ahoj světe!...................................................................................................................80
4.1.3 Vypisujeme na displej..................................................................................................81
4.2 Vytvoření J2ME aplikace pro dálkové ovládání.................................................................85
4.2.1 Část první....................................................................................................................85
4.2.2 Část druhá....................................................................................................................87
4.2.3 Část třetí......................................................................................................................88
4.2.4 Propojení všech částí dohromady................................................................................91
5 Závěr...........................................................................................................................................93
-4-
Skripta Mechatronic Education
1
1.1
Programovací jazyk Java
Proč právě Java?
Java je v poslední době mezi programátory velice oblíbená. Jedná se o interpretovaný jazyk – to
znamená, že kompilací programu nevzniká binární kód specifický pro danou platformu, ale jakýsi
mezikód, kterému říkáme bytecode. O spuštění a běh bytecode se pak stará tzv. Java Virtual
Machine (JVM). Díky tomuto mezikódu můžeme program vytvořit pouze jednou a spustit
na kterékoliv z platforem, pro kterou je JVM vyvinut (ve světě osobních počítačů je to například
Windows, Mac OS či Linux).
Kvůli své přenositelnosti se Java stala populární při programování různých zařízení, například set-top boxů nebo aplikací pro mobilní telefony. Existuje totiž velká řada mobilních telefonů
s odlišným hardwarem a vytvořit aplikaci, která by fungovala na více telefonech, by pro
programátora znamenalo napsat ji pro každý telefon jinak. Proto výrobci do mobilních telefonů
začali implementovat Java Virtual Machine, která hardware zařízení abstrahuje a zabaluje
do přehledné soustavy tříd a rozhraní, díky čemuž se vývoj aplikací pro mobilní telefony stal velice
jednoduchým a efektivním a umožnil tak masové rozšíření různých Java aplikací či her.
Takovouto Java Virtual Machine s celou řadou funkcí pro práci s hardwarem má v sobě i jBotBrain
II, a je tedy vhodný jak pro pokročilé programátory, tak i pro začátečníky v robotice
a mikroprocesorové technice vůbec. Nemusíme se starat o to, na jakém portu je připojeno servo, jak
máme nastavit registry pro generování servopulzů nebo jak komunikovat s I2C senzorem, protože
tyto základní metody už za nás někdo nativně implementoval v rámci JVM jBotBrainu II. Můžeme
se tak věnovat zajímavějším věcem, třeba programování algoritmu sledování čáry nebo hledání
cesty v bludišti.
Pro spouštění programů v Javě na PC potřebujete tzv. Java Runtime Environment (JRE) a pro jejich
kompilaci do bajtkódu Java Development Envirnment (JDK). Pro operační systém Windows je
můžete získat na http://java.sun.com.
Instalační soubory JDK jsou součástí vývojového prostředí jBotBrainu II, takže si s jejich instalací
nemusíme lámat hlavu. Pro vytváření prvních programů a seznámení s Javou doporučuji zdrojové
soubory vytvářet v jednoduchých textových editorech (Poznámkový blok ve Windows nebo PSPad)
namísto složitějších vývojových prostředí (například Eclipse IDE), protože vývojové prostředí by
ze začátku zbytečně odvádělo vaši pozornost.
-5-
Skripta Mechatronic Education
1.2
První program
Javu si ukážeme prakticky prvním jednoduchým programem, který vypíše na obrazovku text „Ahoj
světe!“ a následně si jej krok po kroku rozebereme. S větou „Hello World!“ se setkal asi každý, kdo
se někdy nějaký programovací jazyk učil:
/* Náš první program v Javě */
public class PrvniProgram {
public static void main(String args[]) {
System.out.println("Ahoj svete!");
}
}
Celý program uložíme do souboru PrvniProgram.java, který vytvoříme v libovolném textovém
editoru, třeba poznámkovém bloku, který je součástí Windows. Při přepisování je potřeba dbát
na velikost písmen, Java je totiž tzv. case-sensitive, to znamená, že je citlivá na zápis velkých
a malých písmen. PrvniProgram a prvnirprogram jsou tedy dva úplně odlišné identifikátory.
Poté spustíme příkazový řádek v příslušné složce a napíšeme příkaz:
javac PrvniProgram.java
Tip: Jak na příkazový řádek?
Práce s příkazovým řádkem patří mezi základní programátorské znalosti. Klíčový je pracovní
adresář, většinou je výchozím pracovním adresářem domovská složka uživatele. Abychom náš
program mohli zkompilovat a spustit, musíme se dostat do adresáře, kde máme zdrojové kódy
ulžoeny – k tomu slouží příkaz cd. Pokud máme náš příklad uložen v adresáři zdrojaky,
použijeme příkaz takto:
cd zdrojaky
Pro přesunutí do nadřezaného adrresáře slouží příkaz
cd ..
V případě, že je název adresáře příliš dlouhý, můžeme využít doplňování textu – napíšeme
prvních pár písmen a stiskneme tabulátor, název se sám doplní.
Pro výpis souborů v adresáři slouží příkaz ls, případně dir.
Příkaz javac přeloží program ze zdrojového kódu do počítači srozumitelné podoby, tzv. bajtkódu.
Program nějakou dobu poběží a po ukončení vytvoří soubor PrvniProgram.class, který obsahuje
zmíněný bajtkód. Program je hotový a můžeme ho spustit příkazem:
java PrvniProgram
Parametrem je pouze název hlavní třídy (programu), příponu .class vynecháme. Program
na obrazovku vypíše text „Ahoj svete!“ a ukončí se.
Může se stát, že u vytváření prvního programu nastanou problémy. Není třeba věšet hlavu, jejich
řešení je jednoduché.
-6-
Skripta Mechatronic Education
1. Pokud systém vypíše, že program javac neexistuje, máme dvě možnosti:
1. Ve vašem počítači není nainstalováno prostředí JDK, o kterém se zmiňuje úvodní
kapitola.
2. Cesta k adresáři s programem javac.exe není uložena v systémové proměnné PATH
(na mém počítači je to C:\Program Files\Java\jdk1.6.0_12\bin).
2. Pokud se v chybovém hlášení objeví „javac: invalid argument: PrvniProgram“, znamená
to, že jste zapomněli uvést příponu souboru .java.
3. Objeví-li se při překladu programu chybové hlášení podobné tomuto:
javac PrvniProgram.java
PrvniProgram.java:5: reached end of file while parsing
}
^
1 error
Znamená to, že jste při přepisu programu udělali takzvanou syntaktickou chybu.V našem
případě to znamená, že jsme zapomněli na posledním řádku programu napsat druhou
složenou závorku uzavírající blok hlavní třídy.
Chybové hlášení
javac PrvniProgram.java
PrvniProgram.java:4: ';' expected
System.out.println("Ahoj svete!")
^
1 error
znamená, že jsme za příkazem System.out.println zapomněli napsat středník – v tomto
případě nám program javac přesně ukázal, kde se chyba objevila a jak ji odstranit.
Středník je důležitý, ukončuje každý příkaz v Javě.
Nyní si náš první program projdeme krok za krokem a ukážeme si některé prvky jazyka Java.
1.2.1
Komentáře
První řádek programu
/* Náš první program v Javě */
je takzvaný komentář. Komentáře slouží v Javě ke psaní poznámek programátora. Jsou velice
důležité, protože bez nich by složitější program mohl být po roce nesrozumitelný a programátor by
musel u svého vlastního programu provádět tzv. Reverse engineering, což je velice neefektivní.
Výrazně také usnadní orientaci v programu druhým lidem. Další možností využití je zakomentování
kódu, který momentálně nepotřebujeme, ale někdy bychom se k němu chtěli vrátit. V Javě
rozlišujeme tři typy komentářů:
// Řádkový komentář začíná dvěma lomítky a slouží k zápisu komentáře
// pouze na jednom řádku.
/* Blokový komentář (ten, který jsme použili v našem prvním programu),
-7-
Skripta Mechatronic Education
slouží k zápisu komentářů delších, které se nám na jeden řádek nevejdou.
Začíná lomítkem a hvězdičkou a končí hvězdičkou a lomítkem. */
/**
* Dokumentační komentář
* Slouží k zápisu dokumentace programu, kterou lze vygenerovat
* ve formátu HTML programem javadoc. Má velké množství parametrů,
* například tento pro uvedení autora:
* @author Josef Novák
*/
1.2.2
Třídy a objekty
Druhý řádek programu
public class PrvniProgram {
obsahuje deklaraci třídy PrvniProgram. Klíčové slovo public znamená, že jde o třídu veřejnou
(k tomu se dostaneme později), klíčové slovo class pak značí, že se jedná o třídu. Třídy zapisujeme
způsobem CamelCase (odvozeno od velblouda, který má hrby) – první písmeno a počáteční
písmena každého slova v případě víceslovného identifikátoru jsou velká. Každou třídu ukládáme
do samostatného souboru, jehož název je tvořen jménem třídy a příponu .java – v našem případě
PrvniProgram.java.
Složené (množinové) závorky { a } se v Javě používají pro ohraničení bloku příkazů, v tomto
případě otevírá závorka blok, který se týká třídy PrvniProgram.
Angličtina
Jazykem programátorů je angličtina, všechny identifikátory a komentáře v programu by tedy měly
být psány výhradně anglicky. Důvodů je hned několik – usnadní to orientaci v programu cizincům
a pro národy užívající komplikované nebo překomplikované jazyky (jakým čeština bezesporu je)
usnadní některé gramatické jevy, například tvorbu množných čísel (v angličtině pouze přidáním
koncovky -s).
V tomto výukovém materiálu ale konvence nedodržím a budu používat identifikátory a komentáře
psané pro větší názornost česky.
Třída představuje skupinu objektů, které mají společné vlastnosti a metody. Vlastnosti jsou
proměnné, které obsahují nějakou hodnotu, metody jsou bloky operací, které může třída provádět.
Použití si ukážeme na příkladu počítačové hry, ve které se vyskytují dvě auta, trabant a barovák.
Nejprve si definujeme třídu Auto, která obsahuje společné vlastnosti cena a maxRychlost:
class Auto {
int cena;
int maxRychlost;
}
-8-
Skripta Mechatronic Education
Ve hře pak vytvořime dvě instance třidy Auto, trabant a bavorak – budeme jim řikat objekty.
Každemu objektu nastavime odlišne vlastnosti:
Auto trabant = new Auto();
Auto bavorak = new Auto();
trabant.maxRychlost = 60;
tranabt.cena = 1000;
bavorak.maxRychlost = 240;
bavorak.cena = 300000;
Příkaz
Auto trabant = new Auto();
slouží k vytvoření proměnné datového typu Auto, která se bude jmenovat trabant. Příkaz new
Auto() vytvoří novou instanci třídy Auto (objekt), který do proměnné uložíme. O datových typech si
povíme později.
Metody použité v naší hře by to mohly být například „zastav()“, „zatrub()“ nebo „zatocDoLeva()“.
Výhodou je, že při programování řízení automobilu nás nezajímá, zda hráč ovládá trabant nebo
bavorák – obě auta mají stejné metody dané třídou Auto.
K čemu je to dobré? jBotBrain II má definováno několik tříd pro práci s různým hardwarem –
například ovládání LED diod na desce, práci s I2C senzory nebo rozhraním Bluetooth. Pokud
chceme použít několik I2C ultrazvukových dálkoměrů (sonarů) s různými adresami, jednoduše si
pro každý senzor vytvoříme jinou instanci třídy jBotBrain2.sensors.SRF02Sensor s různými
adresami.
1.2.3
Metody
Třetí řádek
public static void main(String args[]) {
definuje jedinou metodu třídy PrvniProgram, a sice metodu main. Metody obsahují bloky operací,
které můžeme se třídou provádět. Metoda main je velice důležitá, neboť jde o hlavní třídu
programu, tedy místo, kde celý program začíná. Její definice musí být zapsána přesně jako v našem
příkladu, jinak ji interpret java nepozná a program se nespustí. Obsah metody je opět ohraničen
složenými závorkami.
String args[] v závorce definuje argumenty metody, tedy proměnné, které metodě předáváme
ke zpracování. Metodu main spouští přímo interpret a jako argument předá parametry, pokud jsme
nějaké v příkazovém řádku uvedli.
K významu klíčových slov static a void se dostaneme později.
Čtvrtý řádek
System.out.println("Ahoj svete!");
je voláním metody println sloužící k výpisu textu na standardní výstup, v našem případě
do obrazovky příkazového řádku.
-9-
Skripta Mechatronic Education
1.3
Popis jazyka Java
1.3.1
Datové typy a proměnné
Počítač každou hodnotu do paměti ukládá jako jedničky a nuly. Paměť se skládá z bajtů, což jsou
skupiny 8 bitů. Jeden bit může nebývat hodnot 1 nebo 0. Bajt v paměti obsahující hodnotu
10000012 tedy může být číslo 65 v desítkové soustavě, znak 'A' (podle standardu ASCII) nebo
součást většího celku obsahující větší počet bajtů. Aby počítač mohl rozlišit o jaký typ dat se jedná,
zavádíme datové typy. Datových typů v Javě je několik:
Název
Význam
Rozsah
byte
Celé číslo
-127 .. 127
short
Celé číslo
-32 768 .. 32 767
int
Celé číslo
-2 147 438 648 .. 2 147 438 647
long
Celé číslo
- 9 223 372 036 854 775 808 ..
9 223 372 036 854 775 807
float
Reálné číslo
1,4×10-45 .. 3,4×1038
double
Reálné číslo
4,9×10-324 .. 1,7×10308
boolean
Logická hodnota
char
Znak
String
Řetězec (pole znaků)
1.3.1.1
true/false (pravda/nepravda)
'A', 'B', .. 'a', 'b', …'.', ',', ..'0', '9'
“Ahoj, světe!“
Definice proměnných
Proměnnou musíme před použitím definovat. Uděláme to tak, že napíšeme datový typ a název
proměnné. Název proměnné tvoříme stylem camelCase jako u třídy s tím rozdílem, že první
písmeno je malé:
boolean mamHlad;
int hmotnost;
float desetinneCislo;
String jmeno;
char znak;
- 10 -
Skripta Mechatronic Education
1.3.1.2
Přiřazení hodnoty
Do definované proměnné můžeme přiřadit hodnotu. K tomu slouží operátor přiřazení (znak „=“)
hmotnost = 75;
Přiřazení celého čísla
mamHlad = true;
Přiřazení logické hodnoty true nebo false
(pravda a nepravda)
desetinneCislo = 0.75;
Přiřazení
desetinného
čísla
desetinnou tečku, ne čárku)
hmosnost = 0x45;
Přiřazení
celého
čísla
(hexadecimální) soustavě
hmotnost = 0113;
Přiřazení celého čísla v šestnáctkové soustavě –
číslo je uvozeno nulou
znak = 'A';
Přiřazení znaku
uvozovky)
jmeno = “Pepa“;
Přiřazení řetězce (používáme dvojité uvozovky)
(používáme
(používáme
v šestnáctkové
jednoduché
Proměnnou můžeme definovat a zároveň jí přiřadit nějakou hodnotu na jednom řádku, například:
int promenna = 42;
String s = “Hello!”;
1.3.1.3
Aritmetické výrazy
Aritmetické výrazy slouží k výpočtu číselné hodnoty. Skládají se z operandů (konstant
a proměnných) a operátorů (tedy operací, které na nich chceme provádět). Součet dvou proměnných
by v Javě vypadal takto:
int a = 10;
int b = 15;
int vysledek = a+b; // vysledek = 25
Operandů i operátorů může být ve výrazu samozřejmě více, přičemž je můžeme kombinovat
pomocí kulatých závorek. Přehled aritmetických operátorů se nachází v následující tabulce:
Operátor
Význam
+
Sčítání
-
Odčítání
*
Násobení
/
Dělení
- 11 -
Skripta Mechatronic Education
%
Modulo (zbytek po dělení)
>> a <<
Bitové posuny – výraz (a << b) posune číslo
a o b bitů doleva, výraz (a >> b) posune číslo
a o b bitů doprava:
Výraz
Výsledek
Před
Po
8 << 1
16
10002
100002
5 << 2
20
1012
101002
6 >> 1
3
1102
112
++
Inkrementace o 1 (Operace
k proměnné a hodnotu 1)
a++;
přičte
--
Dekrementace o 1
+=, -=, *=, /=, …
Složené přiřazení; a += b; znamená totéž co a =
a+b;
!
Negace
boolean a, b;
a = true;
boolean b = !a; // b má hodnotu false
1.3.1.4
Pole
Pole je množina proměnných stejného datového typu, ke které přistupujeme jako k jednomu celku.
Indexy jsou číslovány od nuly, takže v poli o N prvcích má poslední prvek index N-1, stejně jako
ve většině jiných programovacích jazyků.
První řádek příkladu ukazuje definici celočíselného pole s názvem pole, druhý řádek slouží
k vytvoření pole o třech prvcích. K vytvoření pole používáme, stejně jako při vytváření objektů,
klíčové slovo new:
int[] pole;
pole = new int[3];
Pro přístup k prvkům pole používáme indexy zapsané v hranatých závorkách:
pole[0] = 10;
pole[1] = 20;
pole[3] = 30;
System.out.println("Druhy prvek pole: "+pole[1]);
Kromě použití klíčového slova new můžeme pole inicializovat výčtem prvků v poli, pokud již
předem známe jejich hodnoty. Následující příklad vytvoří pole řetězců s názvy dnů v týdnu a vypíše
- 12 -
Skripta Mechatronic Education
název třetího dne, tedy středy:
String[] dny = {"pondeli", "utery", "streda", "ctvrtek", "patek", "sobota",
"nedele"};
System.out.println("Treti den v tydnu: "+dny[2]);
Java důsledně hlídá přístupy k neinicializovanému poli a k neexistujícím prvkům pole. V prvním
případě
vyhodí
JVM
výjimku
NullPointerException,
v druhém
případě
pak
ArrayIndexOutOfBoundsException. O výjimkách si povíme později. Pokud se chceme chybám
vyhnout, může nám pomoci složka vlastost length, kterou má každé pole a která nám udává počet
prvků v poli. Musíme ale myslet za to, že poslední prvek v poli má vždy index length- 1. Chceme li
tedy vypsat poslední den v týdnu, neděli, můžeme použít tento zápis:
System.out.println("Posledni den v tydnu: "+dny[dny.length-1]);
Pokud má pole indexů více, říkáme jim pole vícerozměrné. Dvojrozměrné pole můžeme využít
třeba v případě, kdy chceme ukládat souřadnice x a y, například pole 5×5 pro jednoduchou hru
piškvorky:
char[][] piskvokry;
piskvoky = new char[5][5];
Přístup k prvkům pole pak probíhá pomocí dvou indexů, například zápis
piskvorky[2][3]
piskvorky[2][4]
piskvorky[0][0]
piskvorky[1][4]
=
=
=
=
'x';
'x';
'o';
'o';
naplní pole piskvorky těmito hodnotami:
yx
0
0
o
1
2
3
4
1
2
3
4
x
o
x
- 13 -
Skripta Mechatronic Education
1.3.2
Podmínky
Podmíněné výrazy umožňují větvení programu na základě dané podmínky. Struktura podmínky je
následující:
if (výraz) {
// akce, která se provede pokud je výraz pravdivý
} else {
// akce, která se provede pokud je výraz nepravdivý
}
Příkaz if musíme použít pokaždé, příkaz else je nepovinný. Příkaz v bloku if se provede, pokud je
relační výraz v závorkách pravdivý. Relační výraz je takový, který vrací logickou hodnotu typu
boolean, tedy true nebo false. Nejčastěji se příkaz if používá pro porovnávání proměnných pomocí
porovnávacích
operátorů:
Operátor
Význam
.==
Test rovnosti (rovná se)
!=
Test nerovnosti (nerovná se)
< >
Test nerovnosti (menší než, větší než)
<= >=
Test nerovnosti (menší nebo rovno, větší nebo
rovno)
Následující příklad ukazuje výpis pozdravu podle věkové kategorie uživatele dané proměnnou věk:
int vek = 15;
if (vek < 18) {
System.out.prtintln("Nazdar!");
} else if (vek < 60) {
System.out.prtintln("Dobry den.");
} else {
System.out.prtintln("Uctiva poklona.");
}
- 14 -
Skripta Mechatronic Education
Relační výrazy můžeme v podmínce spojovat použitím logických operátorů a sdružovat je pomocí
kulatých závorek. Místo true je pro přehlednost použita hodnota 1, místo false hodnota 0:
Operátor
Význam
&&
||
^^
Logický součin (AND, a) – konjunkce:
A
B
A && B
1
1
1
1
0
0
0
1
0
0
0
0
Logický součet (OR, a/nebo) – disjunkce:
A
B
A || B
1
1
1
1
0
1
0
1
1
0
0
0
Exkluzivní logický součet (XOR, nebo) –
exkluzivní („ostrá“) disjunkce:
A
B
A ^^ B
1
1
0
1
0
1
0
1
1
0
0
0
- 15 -
Skripta Mechatronic Education
Pokud tedy chceme naši podmínku z prvního příkladu opravit tak, aby pozdravem „Ahoj“ zdravila
i rodinné příslušníky, zavedeme si další proměnnou rodinnyPrislusnik datového typu boolean:
int vek = 60;
boolean rodinnyPrislusnik = true;
if (vek < 18 || rodinnyPrislusnik == true) {
System.out.prtintln("Nazdar!");
} else if (vek < 60) {
System.out.prtintln("Dobry den.");
} else {
System.out.prtintln("Uctiva poklona.");
}
1.3.3
Cykly
Cyklus je blok příkazů, který se opakuje dokud platí daná podmínka. Cykly jsou výhodné
v okamžiku, kdy chceme provést několik stejných či podobných operací za sebou. Jazyk Java
rozlišuje tři typy cyklů:
1.3.3.1
Cyklus while
Struktura cyklu while je následující:
while (podmínka) {
// blok příkazů
}
Pokud platí podmínka, provede se blok příkazů ohraničený složenými závorkami. Po provedení
bloku příkazů se znovu otestuje, zda podmínka (opakovací podmínka) platí a pokud ano, provede
se blok příkazů znova – a tak dále.
Cyklus while si ukážeme na jednoduchém příkladu, který vypíše dny v týdnu uložené v poli:
String[] dny = {"pondeli", "utery", "streda", "ctvrtek", "patek", "sobota",
"nedele"};
int i = 0;
while (i < dny.length) {
System.out.println((i+1)+". den v tydnu je "+dny[i]);
i++;
}
Index pole jsou číslovány od nuly, proto je výchozí hodnota proměnné i nula. Při každé iteraci
cyklu (průchodu cyklem) je hodntoa proměnné i zvýšena o 1.
1.3.3.2
Cyklus do-while
Struktura cyklu do-while je velilice podobná cyklu while:
do {
// blok příkazů
} while (podmínka);
Rozdíl je ten, že oproti cyklu while se nejprve provede blok příkazů a až pak je kontrolováno, zda
podmínka platí. Blok příkazů se tedy provede aspoň jednou.
- 16 -
Skripta Mechatronic Education
Vypsání prvků pole s použitím cyklu do-while by vypadalo takto:
int i = 0;
do {
System.out.println((i+1)+". den v tydnu je "+dny[i]);
i++;
} while (i < dny.length);
1.3.3.3
Cyklus for
Cyklus for je pro vypisování obsahu pole asi nejvýhodnější, má totiž inicializaci výchozí hodnoty
proměnné, podmínku i inkrementaci hodnoty zadanou přímo v deklaraci cyklu:
for (inicializace; podmínka; inkrementace) {
// blok příkazů
}
Ač se může zdát na první pohled komplikovaným, je pro vypisování prvků pole nejvýhodnější.
Navíc je i přehlednější, protože podmínka a inkrementace proměnné je na jednom místě
a programátorovi se nemůže stát, že by inkrementaci proměnné zapomněl a dostal tak nekonečný
cyklus (o tom si povíme později).
Vše si opět ukážeme na příkladu výpisů dnu v týdnu:
for (int i = 0; i < dny.length; i++) {
System.out.println((i+1)+". den v tydnu je "+dny[i]);
}
Jak vidíte, čítací proměnnou i můžeme definovat i přímo v inicializaci cyklu for. Pokud bychom
dny chtěli vypsat s opačným pořadím, tedy od neděle do pondělí, upravíme cyklus takto:
for (int i = (dny.length-1); i >= 0; i--) {
System.out.println((i+1)+". den v tydnu je "+dny[i]);
}
Hodnotu proměnné i musíme nastavit na dny.length-1, protože poslední index pole o N prvcích má
hodnotu N-1, v našem případě 7-1 = 6.
- 17 -
Skripta Mechatronic Education
1.3.3.4
Příkazy break a continue
Pokud bychom chtěli cyklus předčasně ukončit, můžeme použít příkaz break:
String s = “Ahoj svete”;
char z = 'h';
int i;
for (i = 0; i < s.length; i++) {
if (s.charAt(i) == z) {
break;
}
}
if (i == s.length) {
i = -1;
}
Příklad vyhledá pozici znaku v řetězci a uloží ji do proměnné i. Pokud znak není nalezen, je
hodnota proměnné i rovna -1. Pro přerušení cyklu po nálezu znaku je použit příkaz break, aby
cyklus zbytečně nezatěžoval počítač, když už znak našel.
Kromě příkazu break můžeme pro ovládání cyklů použít příkaz continue, který ukončí vykonávání
bloku příkazů a přeskočí na další iteraci cyklu (na rozdíl od příkazu break, který cyklus ukončí
úplně).
1.3.3.5
Nekonečný cyklus
S nekonečným cyklem se budeme při programování jBotBrainu II setkávat často, bude totiž tvořit
hlavní smyčku programu, kde chceme, aby se blok příkazů opakoval neustále, dokud není zařízení
vypnuto. Pro realizaci nekonečného cyklu nejčastěji používáme cyklus while, který se provádí,
dokud platí podmínka (dokud má výraz logickou hodnotu true):
while (true) {
// Tento blok příkazů se bude provádět donekonečna
}
Kromě toho je nekonečný cyklus jednou z nejčastějších programátorských chyb, která vznikne
nesprávnou volbou podmínky a vede k „zamrznutí“ programu.
- 18 -
Skripta Mechatronic Education
1.3.4
Metody
Metody jsou bloky příkazů, operace, které můžeme se třídou provádět. Metodu si můžeme
představit jako funkci – může mít několik vstupních argumentů a vracet výstupní hodnotu. Definice
metody vypadá takto:
(modifikátory) datovýTyp názevMetody(seznam argumentů) {
// blok příkazů
}
Pokud bychom si chtěli vytvořit metodu soucet, která sečte dvě čísla a a b a vrátí jejich výsledek,
použijeme tento zápis:
int soucet(int a, int b) {
a = a+b;
return a;
}
– int před názvem metody je návratový datový typ, tedy hodnota, kterou metoda vrací.
– int a, int b v závorkách za názvem metody je sezman argumetů, tedy definování
proměnných ,tkeré musíme metodě předat.
– Klíčové slovo return slouží k ukončení metody a vrácení návratové hodnoty.
Volání metody soucet, která sečte čísla 10 a 5 pak vypadá následovně:
int vysledek = soucet(10, 5);
System.out.prtintln("10+5 = "+vysledek);
Metoda nemusí pokaždé vracet hodnotu, můžeme je využít pouze pro provedení nějaké akce.
Ukázková metoda pozdrav vypíše jméno uživatele a věk, které předáme argumentem. Pro definici
metody bez návratové hodnoty použijeme klíčové slovo void (prázdný datový typ):
void pozdrav(String jmeno, int vek) {
System.out.prtintln("Uzivatel se jmenuje "+jmeno+" a ma "+vek+" let.");
}
V rámci jedné třídy můžeme mít definováno několik metod se stejným názvem, klíčový je pčoet,
datové typy a pořadí argumentů. Tomu říkáme přetěžování metod:
void pozdrav(String jmeno) {
System.out.prtintln("Uzivatel se jmenuje "+jmeno);
}
void pozdrav(String jmeno, int vek) {
System.out.prtintln("Uzivatel se jmenuje "+jmeno+" a ma "+vek+" let.");
}
- 19 -
Skripta Mechatronic Education
1.3.5
Třídy
O třídách jsme si pověděli v úvodní kapitole. Zde se zaměříme na pokročilou práci s nimi. Vše si
vysvětlíme na ukázkové třídě Auto:
public class Auto {
private int maxRychlost;
private String znacka;
private boolean nastartovano;
public Auto(String znacka, int maxRychlost) {
this.znacka = znacka;
this.maxRychlost = maxRychlost;
}
public void nastartuj() {
nastartovano = true;
}
public String getZnacka() {
return znacka;
}
public void setMaxRychlost(int maxRychlost) {
this.maxRychlost = maxRychlost;
}
}
1.3.5.1
Veřejné a soukromé
Před definicí vlastností (proměnných) vidíme modifkátor private, před definicí metod modifikátory
public. Co to znamená? Private značí, že jde o soukromou vlastnost, která je přístupná pouze
metodám třídy, ne „zvenku“. Pokud bychom se k vlastnosti znacka snažili přistoupit z jiné třídy,
například zápisem (předpokládejme, že v proměnná auto je instancí třídy Auto):
System.out.println("Znacka: "+auto.znacka);
dostali bychom chybové hlášení.
V Javě a OOP obecně je totiž zvykem nepřistupovat k vlastnostem přímo, ale pomocí metod,
například takzvaných getterů a setterů (v našem případě metoda getZnacka() pro získání značky
a metoda setMaxRychlost(int maxRychlost) pro nastavení maximální rychlosti), které mají
modifikátor public a jsou veřejné. Tomuto přístupu říkáme zapouzdření a slouží k oproštění
programátora od implementace třídy, která ho v daném případě nezajímá. Pokud bychom značku
automobilu nastavovali přímým přístupem k vlastnosti znacka, měli bychom velice omezené
možnosti. Co kdyby bylo v průběhu vývoje programu rozhodnuto, že se značka musí při nastavení
porovnat s databází známých značek aut? V případě použitá přímého přístupu bychom museli
všechny výskyty nastavení značky v programu složitě vyhledávat a přepisovat, kdežto v případě
použití standardního getteru nemusíme vyhledávat nic a stačí nám pouze upravit jednu metodu.
Podobným případem může být použití soukromých (privátních) metod, pokud nechceme, aby měl
programátor možnost spouštět metody pro vnitřní použití třídy, jejímž neuváženým použitím by
mohl něco poškodit.
- 20 -
Skripta Mechatronic Education
1.3.5.2
Konstruktor
Řekli jsme si, že metodu definujeme udáním návratového datového typu před názvem, který začíná
vždy malým písmenem. Proč tedy hned první metodě návratový typ chybí a název začíná velkým
písmenem?
public Auto(String znacka, int maxRychlost) {
Jedná se o konstruktor – metodu, která je zavolána při vytvoření nové instance třídy. Můžeme ho
využít například pro nastavení výchozích hodnot, v našem případě značky a maximální rychlosti.
Vytvoření nové instance (objektu) třídy Auto pak může vypadat takto:
Auto fazol;
fazol = new Auto("Favorit", 80);
Pokud bychom parametry neuvedli a použili inicializaci
fazol = new Auto();
vyhodila by JVM chybové hlášení, protože konstruktor bez parametrů není definován.
1.3.5.3
Statické a dynamické metody a třídy
Dynamická třída je třída, která nám umožní vytvoření své instance, objektu – například třída Auto
(můžeme dle libosti vytvářet objekty trabant, velorex, zigulik a další). Statická třída vytvoření
objektu neumožňuje. Statická metoda je pak metoda, kterou můžeme volat i bez vytvoření instance
třídy, příkladem jsou metody v třídě Math, které implementují důležité matematické operace
(Math.sin(double a) pro sinus, Math.sqrt(double a) pro druhou odmocninu atd). Dalším
příkladem statické metody je metoda main z našeho prvního programu.
Statickou metodu, třídu nebo vlastnost definujeme modifikátorem static umístěným před datovým
typem a názvem.
Pokud bychom se snažili dynamickou metodu zavolat statickým přístupem, například
Auto.setZnacka("Velorex");
dostali bychom chybové hlášení.
Pomocí modifikátoru static můžeme definovat konstanty, například konstanta PI v třídě Math
(veřejná statická vlastnost, jejíž hodnotu již nemůžeme změnit):
public static final PI = 3.14159;
1.3.5.4
Dědičnost
Velikou výhodou tříd je, že můžeme vytvářet třídy, které vycházejí z jiných – rozšiřují jejich
metody nebo vlastnosti. Říkáme, že tyto vlastnosti dědí.
Nově vytvořená třída je potomek, třída, ze které dědíme se nazývá rodič. K definování rodiče slouží
klíčové slovo extends umístěné za název potomka. Dědění si ukážeme na příkladu třídy Nakladak,
které vychází z dříve definované třídy Auto a zavádí nové metody a vlastnosti typické pro nákladní
auta. Výhodou je, že můžeme použít již jednou vytvořený kód a nevytvářet vše znova, protože
osobní a nákladní auta mají některé vlastnosti společné.
- 21 -
Skripta Mechatronic Education
public class Nakladak extends Auto {
private String naklad;
public Nakladak(String znacka, int maxRychlost, String naklad) {
super(znacka, maxRychlost);
this.naklad = naklad;
}
public void vylozNaklad() {
System.out.println("Vykladam "+naklad);
}
}
Všimněte si konstruktoru, kde se nachází volání metody super, což je volání konstruktoru
rodičovské třídy – v našem případě třídy Auto. Třída Nakladak zavádí novou privátní vlastnost
naklad, upravuje konstruktor a přidává veřejnou metodu vylozNaklad(), která vypíše obsah
nákladního prostoru. Kromě toho můžeme samozřejmě použít i veřejné metody definované
rodičovskou třídou Auto:
Nakladak auto = new Nakladak("Tatra", 150, "pivo");
System.out.println("Nase auto je "+auto.getZnacka());
auto.vylozNaklad(); // Vypíšeme náklad
1.3.5.5
Rozhraní
Rozhraní je předpis, který určuje, jaké metody musí třída implementovat. Můžeme je využít
například pokud chceme několik tříd sjednotit, typicky pokud chceme, aby všechny třídy pracující
s dálkoměry vracely hodnotu v centimetrech a aby se metoda jmenovala stejně, třeba getDistance().
Výhodou oproti dědění je, že třída může implementovat více rozhraní, dědit ale můžeme pouze
z jedné třídy. K definování rozhraní slouží klíčové slovo interface (všimněte si, že v definici
rozhraní Rangefinder chybí blok příkazů, zajímají nás pouze definice metod), k implementování
do třídy pak klíčové slovo implements:
interface Rangefinder {
public int getDistance();
}
class InfraredRangefinder implements Rangefinder {
public int getDistance() {
// Náš vlastní kód
}
}
class UltrasonicRangefinder implements Rangefinder {
public int getDistance() {
// Náš vlastní kód
}
}
class LaserRangefinder implements Rangefinder {
public int getDistance() {
// Náš vlastní kód
}
}
Pokud bychom neimplementovali všechny metody dané rozhraním, dostali bychom chybové
hlášení.
- 22 -
Skripta Mechatronic Education
1.3.5.6
Balíky
V rozsáhlejších projektech je občas potřeba použít více tříd ze stejným názvem nebo třídy roztřídit
podle toho, co dělají. K tomu slouží balíky (packages). Můžeme si je představit jako adresáře.
K určení balíku, do kterého třída patří, slouží příkaz package. Použití balíku si ukážeme
na jednoduchém příkladu. Vytvoříme si adresář kalendar, do kterého uložíme třídu s názvem Datum
(soubor Datum.java):
package kalendar;
class Datum {
private String[] dny = {"pondeli", "utery", "streda", "ctvrtek", "patek",
"sobota", "nedele"};
public static String denVTydnu(int den) {
return dny[den];
}
}
Statická metoda denVTydnu vrací název dne v týdnu podle zadaného indexu. Třídu Datum
umístěnou v balíku kalendar použijeme takto:
String den = kalendar.Datum.denVTdynu(6);
System.out.prtintln("Den v tydnu: "+den);
Druhou možností je použití příkazu import, který se umisťuje před deklaraci třídy a slouží
k importování určité třídy:
import kalendar.Datum;
Potom již můžeme třídu Datum použít bez uvedení názvu balíku. Příkaz import umožňuje
i importování všech tříd v balíku, pokud místo názvu třídy použijeme hvězdičku:
import kalendar.*;
Každý balík může obsahovat další balíky, což umožňuje vytváření složitějších „adresářových
struktur“. Názvy balíků a „podbalíků“ se oddělují tečkami. Podle konvencí Javy se názvy balíků
tvoří malými písmeny.
1.3.6
Výjimky
Výjimka (Exception) je chyba, která vznikla za běhu programu. Může jít o soubor, který nebyl
nalezen, dělení nulou nebo přístup k neexistujícímu prvku pole. V případě, že se výjimka objeví,
běh programu se pozastaví a JVM začne hledat handler, což je místo v programu, které
se o ošetření výjimky stará. Pokud není žádný handler definován, použije se handler výchozí.
V našem případě, kdy programujeme konzolové aplikace pro operační systém Windows nebo Linux
a používáme JRE firmy Sun, je to zpravidla vypsání chybové hlášky a ukončení běhu programu.
- 23 -
Skripta Mechatronic Education
Jak taková výjimka vypadá, si ukážeme na následujícím příkladu:
public class ZkouskaPole {
public static void main(String args[]) {
String[] dny = {"pondeli", "utery", "streda", "ctvrtek", "patek",
"sobota", "nedele"};
System.out.println("1. den v tydnu: "+dny[0]);
System.out.println("8. den v tydnu: "+dny[7]);
System.out.println("3. den v tydnu: "+dny[2]);
}
}
Pokud program spustíme, dostaneme v příkazovém řádku tento výpis:
1. den v tydnu: pondeli
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 7
at ZkouskaPole.main(ZkouskaPole.java:6)
Chybové hlášení nám říká, že se na 6. řádku programu (ZkouskaPole.java:6) objevila výjimka
ArrayIndexOutOfBoundsException, která znamená, že jsme přistoupili k neexistujícímu prvku pole
s indexem 7 – poslední prvek našeho pole sedmi dnů v týdnu má index 6.
Pokud je použit výchozí handler, program se po výskytu výjimky ukončí. V našem případě to
znamená, že se nevypíše poslední řádek s 3. dnem v týdnu. Zabránit tomu můžeme definováním
vlastního handleru, k tomu slouží příkaz try-catch (všimněte si toho, že ona výjimka není nic
jiného než objekt třídy ArrayIndexOutOfBoundsException odvozené od třídy Exception):
try {
System.out.println("8. den v tydnu: "+dny[8]);
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Zachycena vyjimka!");
e.printStackTrace();
}
Pokud program spustíme teď, dostaneme tento výpis:
1. den v tydnu: pondeli
Zachycena vyjimka!
java.lang.ArrayIndexOutOfBoundsException: 8
at ZkouskaPole.main(ZkouskaPole.java:8)
3. den v tydnu: streda
Jak vidíte, výjimka byla zachycena naším vlastním handlerem a běh programu se po zachycení
nezastavil, pouze jsme vypsali chybové hlášení.
Další možností, jak se výjimky zbavit, je zahodit ji pomocí klíčového slova throws zapsaného
za definicí metody. Tím předáme výjimku o úroveň dál a budeme ji muset ošetřit na jiném místě
programu. V našem případě bychom se jí mohli zbavit zápisem:
public static void main(String args[]) throws ArrayIndexOutOfBoundsException
{
Se zahazováním výjimek se při programování jBotBrainu II setkáme například když budeme chtít
využít čekací smyčku Thread.sleep().
- 24 -
Skripta Mechatronic Education
2
Popis vývojového prostředí Eclipse
Pokud vývojové prostředí Eclipse IDE spustíte a zavřete uvítací obrazovku, uvidíte okno, které
vypadá přibližně takto:
– V seznamu projektů se budou postupně objevovat vámi vytvořené projekty a zdrojové
soubory.
– Pracovní plocha je prostor, který slouží k editaci zdrojových kódů.
– Ve výpisu chybových hlášení se během psaní zdrojových kódů objevují chyby a varovná
hlášení, které musíme opravit.
– Struktura třídy nabídne přehledný seznam metod a vlastností právě upravované třídy.
Jednotlivá okna můžeme po hlavním pracovním okně různě přetahovat a přepínat podle našeho
uvážení
- 25 -
Skripta Mechatronic Education
2.1
Vytvoření projektu krok za krokem
Nejprve klikneme na File → New → Project:
Po otevření okna vybereme z nabídky C-bot device projects možnost jBotBrain2 application
a klikneme na tlačítko Next:
- 26 -
Skripta Mechatronic Education
V dalším kroku zadáme název projektu (v našem případě HelloWorld). Název hlavní třídy
HelloWorldMain se doplní automaticky, pokud necháme volbu Create main class zaškrtnutou:
Po stisknutí tlačítka Finish se nově vytvořený projekt objeví v seznamu Package Explorer
a v pracovním okně se otevře hlavní třída třída projektu HelloWorldMain se základní strukturou
(metoda main). Všimněte si, že metoda main se objevila i ve výpisu struktury třídy v pravém okně
Outline:
- 27 -
Skripta Mechatronic Education
Do editačního okna vepíšeme zdrojový kód naší první aplikace pro jBotBrain II, která rozbliká
zelenou LED diodu s periodou 500 ms:
Podrobný rozbor celého programu je uveden v kapitole, která se věnuje programování jBotBrainu
II. Upravený soubor uložíme ikonkou v horním panelu nebo klávesovou zkratkou Ctrl+S.
2.1.1
Kompilace a nahrávání programu
Ke kompilaci a nahrání programu do jBotBrainu Ii slouží tlačítko Upload project ve vrchní liště
prostředí Eclipse:
Po stisku tlačítka se objeví okno zobrazující stav nahrávání, které se po dokončení samo zavře:
- 28 -
Skripta Mechatronic Education
2.2
Vytvoření nové třídy
Novou
třídu
vytvoříme
pravím kliknutím na název
balíku
(v našem případě
jBotBrain2.HelloWorld) a výběrem New → Class. Stejným způsobem můžeme vytvářet nové
balíky, rozhraní (Interface) a soubory:
Po vyplnění názvu třídy (v našem případě Pozdrav) a stisknutí tlačítka Finish se nově otevřená
třída sama otevře v editoru:
- 29 -
Skripta Mechatronic Education
2.3
Automatické doplňování
Velkou výhodou vývojového prostředí Eclipse je automatické doplňování, které během psaní
zdrojového kódu nabízí metody, které jsou k dispozici. Pokud tedy napíšeme „System.out.“,
vyskočí nabídka všech metod, které jsou v této třídě obsaženy a které můžeme použít. Vybereme-li
metodu println, zobrazí se i malá kontextová nápověda s výpisem dokumentace metody:
Kromě toho automatické doplňování napovídá také pořadí a popis parametrů, což se velice hodí
v případě, že jich má daná metoda více. Zde vidíme, že jediným parametrem metody println je
řetězec, který chceme vypsat:
- 30 -
Skripta Mechatronic Education
2.4
Přejmenování třídy
Pokud se rozhodneme třídu Pozdrav přejmenovat na Zdraveni, vybereme v kontextové nabídce
třídy možnost Refractor → Rename:
V okně, které se otevře, jen změníme název na Zdraveni. Pokud necháme všem možnostem jejich
výchozí nastavení a stiskneme tlačítko Finish, vývojové prostředí automaticky přejmenuje třídu,
změní její zdrojový kód tak, aby se jmenovala Zdraveni a vyhledá i všechny výskyty starého názvu
Pozdrav, což nám práci výrazně ulehčí:
- 31 -
Skripta Mechatronic Education
2.5
Zobrazení čísel řádků
Čísla řádků zpřehledňují orientaci ve zdrojovém kódu. Zapnout je můžeme kliknutím na šedou
postranní lištu editačního okna a výběrem možnosti Show Line Numbers:
- 32 -
Skripta Mechatronic Education
2.6
Hledání a opravy chyb
Kromě automatického doplňování nabízí prostředí Eclipse upozorňování na chyby přímo v průběhu
psaní zdrojového kódu a u některých nabídne i jejich opravu. V našem případě se jedná
o zapomenutý středník, který ukončuje příkaz:
Druhý typ chyby může nastat, pokud zapomeneme implementovat všechny metody rozhraní nebo
pokud neošetříme výjimku, pokud to nějaká metoda vyžaduje. Příkladem může být metoda
Thread.sleep(), která slouží k pozastavení běhu programu na dobu danou v milisekundách:
Pokud myší najedeme na ikonku žárovky, objeví se zpráva, že metoda může vyhodit výjimku
InterruptedException, kterou jsme neošetřili.
- 33 -
Skripta Mechatronic Education
Po kliknutí na ikonku nám Eclipse nabídne dvě možnosti – zahození výjimky prostřednictvím
příkazu throws nebo ošetření blokem try-catch:
Pokud jednu z možností vybereme, vývojové prostředí automaticky doplní potřebný kód a chyba je
odstraněna:
- 34 -
Skripta Mechatronic Education
2.7
Automatické formátování zdrojového kódu
Někdy se stane, že nedáváme pozor na správné odsazování zdrojového kódu a ten se tak stane
velice nepřehledným. Zkrášlit jej můžeme použitím příkazu Source → Format po kliknutí
do prostoru editovaného zdrojového kódu pravým tlačítkem myši:
- 35 -
Skripta Mechatronic Education
3
Programování jBotBrainu II
3.1
Rozbor prvního programu
První program, který jsme do jBotBrainu II nahráli, měl jen několik řádků a vypadal takto:
package jBotBrain2.HelloWorld;
import jBotBrain2.hw.*;
public class HelloWorldMain {
public static void main(String[] args) {
Led.GREEN1.set(Led.MODE_BLINK, 500);
while (true) {
}
}
}
– Příkaz package definuje název balíku, se kterým pracujeme. Eclipse automaticky vytvoří
balík jBotBrain2.<NÁZEV_PROJEKTU>.
– Příkaz import slouží k improtu tříd, které budeme potřebovat. V našem případě
importujeme všechny třídy (*) z balíku jBotBrain2.hw, který obsahuje důležité třídy
pracující s periferiemi jBotBrainu II a kde je také umístěna třída Led, kterou v příkladu
používáme. Kromě balíku hw nabízí jBotBrain II ještě několik alších:
– jBotBrain2.comm pro komunikaci pomocí Bluetooth modulu a UARTu.
– jBotBrain2.devices obsahuje třídy pro práci s různými zařízeními na sběrnici I2C.
– jBotBrain2.sensors ukrývá třídy pracující se senzory jako jsou ultrazvukový dálkoměr
nebo elektromagnetický kompas.
– jBotBrain2.util implementuje důležité systémové nástroje, jako je časovač (Timer).
– Třída HelloWorldMain je hlavní a jednou třídou programu. Protože jde o hlavní třídu,
obsahuje ještě statickou metodu main, která je zavolána po spuštění jBotBrainu II.
– Příkaz Led.GREEN1.set(Led.MODE_BLINK, 500); slouží k rozblikání první zelené LED
diody s periodou 500 ms. Třída Led je popsána v kapitole LED a čekací smyčky.
– Příkaz while(true) {} je nekonečný cyklus a tvoří hlavní smyčku programu (main loop).
Ta zaručuje, že program po spuštění jBotBrainu II poběží pořád a svévolně se neukončí.
- 36 -
Skripta Mechatronic Education
3.2
3.2.1
Práce s periferiemi jBotBrainu II
LED a čekací smyčky
Jak rozblikat LED diodu jsme si ukázali v prvním příkladu. Kromě blikání nabízí třída Led v balíku
jBotBrain2.hw i metody pro rozsvícení a zhasnutí jedné nebo všech LED diod:
Třída jBotBrain2.hw.Led
static Led GREEN1, GREEN2, ORANGE, Přístup ke dvěma zeleným, oranžové a červené
RED
LED diodě.
void on()
Rozsvícení LED diody.
void off()
Zhasnutí LED diody.
void set(int mode, int time)
Nastavení stavu LED diody podle parametru
mode:
Led.MODE_ON
Rozsvícení,
hodnota
parametru time není
podstatná.
Led.MODE_OFF
Zhasnutí,
hodnota
parametru time není
podstatná.
LED.MODE_BLINK Blikání, parametr time
nastavuje
periodu
blikání
v milisekundách.
static void ledSetAll(boolean on)
Rozsvícení nebo zhasnutí všech LED diod –
pokud má parametr on hodnotu true, všechny
LED svítí, v opačném případě LED zhasnnou.
Čekací smyčka se nám hodí, pokud potřebujeme program na několik okamžiků zastavit nebo
pozdržet. Slouží k tomu statická metoda Thread.sleep(int ms), kde parametr ms je čas
v milisekundách (jedna vteřina má 1000 milisekund), po který program čeká. Metoda v případě
neúspěchu vyvolá výjimku InterruptedException. Tu musíme buď ošetřit pomocí bloku try/catch
nebo zahodit připsáním výrazu throws InterruptedException za deklaraci metody, ve které čekací
smyčku používáme – v našem případě metoda main().
- 37 -
Skripta Mechatronic Education
Následující příklad pojmenovaný LedExample na začátku na půl vteřiny rozsvítí všechny diody,
poté je zhasne a rozbliká oranžovou LED. V nekonečné smyčce pak bliká červenou LED diodou
pomocí metod on() , off() a čekací smyčky Thread.sleep():
package jBotBrain2.LedExample;
import jBotBrain2.hw.*;
public class LedExampleMain {
public static void main(String[] args) throws InterruptedException {
Led.ledSetAll(true);
Thread.sleep(500);
Led.ledSetAll(false);
Led.GREEN1.set(Led.MODE_ON, 300);
boolean on = false;
while (true) {
if (on) {
Led.ORANGE.off();
on = false;
} else {
Led.ORANGE.on();
on = true;
}
Thread.sleep(300);
}
}
}
- 38 -
Skripta Mechatronic Education
3.2.2
Tlačítka
Čtyři tlačítka S1-S4 na jBotBrainu II můžeme použít k ovládání naší aplikace. Třída Button
v balíku jBotBrain2.hw umožňuje číst stav všech tlačítek najednou nebo každého tlačítka zvlášť
a čekat na jejich stisknutí:
Třída jBotBrain2.hw.Button
static Button S1, S2, S3 a S4
Přístup ke čtyřem tlačítkům S1-S4.
static int readButtons()
Přečte stav tlačítek jako číslo. Každému tlačítku
odpovídá jiná číselná hodnota:
Button.S1_BUTTON
0x08
Button.S1_BUTTON
0x04
Button.S1_BUTTON
0x02
Button.S1_BUTTON
0x01
Pokud není stisknuto ani jedno tlačítko, vrátí
metoda hodnotu 0.
static int waitForPress()
Vyčká na stisknutí tlačítka a vrátí jeho hodnotu
stejně jako metoda readButtons().
boolean isPressed()
V případě, že je tlačítko stisknuto, vátí metoda
hodnotu true, v opačném případě vrací false.
- 39 -
Skripta Mechatronic Education
Práci s tlačítky si ukážeme na příkladu ButtonsExample. Program přepíná blikající LED diodu
podle aktuálně stisknutého tlačítka:
package jBotBrain2.ButtonsExample;
import jBotBrain2.hw.*;
public class ButtonsExampleMain {
public static void main(String[] args) {
Led.GREEN1.set(Led.MODE_BLINK, 200);
while (true) {
if (Button.S1.isPressed()) {
Led.ledSetAll(false);
Led.GREEN1.set(Led.MODE_BLINK, 200);
while (Button.S1.isPressed());
}
if (Button.S2.isPressed()) {
Led.ledSetAll(false);
Led.GREEN2.set(Led.MODE_BLINK, 200);
while (Button.S2.isPressed());
}
if (Button.S3.isPressed()) {
Led.ledSetAll(false);
Led.ORANGE.set(Led.MODE_BLINK, 200);
while (Button.S3.isPressed());
}
if (Button.S4.isPressed()) {
Led.ledSetAll(false);
Led.RED.set(Led.MODE_BLINK, 200);
while (Button.S4.isPressed());
}
}
}
}
- 40 -
Skripta Mechatronic Education
3.2.3
Výstup do konzole
Během vytváření projektů pro jBotBrain II budeme často potřebovat programy ladit vypisováním
hodnot proměnných nebo toho, co právě program dělá. K tomu slouží jConsole, která je součástí
vývojového prostředí. Do ní můžeme vypisovat zprávy metodami System.out.print(String s)
a System.out.println(String s). Rozdíl v nich je jednoduchý – metoda println za vypsaným
řetězcem ještě odřádkuje.
Příklad ConsoleExample čeká na stisknuté tlačítko a po každém stisku vypíše do konzole na nový
řádek jeho číselnou hodnotu:
package jBotBrain2.ConsoleExample;
import jBotBrain2.hw.*;
public class ConsoleExampleMain {
public static void main(String[] args) {
Led.GREEN1.set(Led.MODE_BLINK, 300);
int status;
while (true) {
status = Button.waitForPress();
System.out.println("Stisknute tlacitko: "+status);
}
}
}
V některých případech potřebujeme hodnoty vypisovat v krátkých intervalech a pokud bychom pro
každý výpis přidali nový řádek, stalo by se okno konzole rychle nepřehledným. Proto můžeme
využít metodu print, která na rozdíl od println nový řádek nepřidá. Pokud bude řetězec končit
znakem '\r' (CR = Carriage Return, návrat vozíku – ASCII kód 13), znamená to, že se kurzor vrátí
na začátek řádku. Za takto vypsaný řetězec je dobré napsat několik mezer, aby na řádku nezůstávaly
znaky z předchozího výpisu:
while (true) {
status = Button.waitForPress();
System.out.print("Stisknute tlacitko : "+status+"
}
\r");
- 41 -
Skripta Mechatronic Education
3.2.4
Bzučák
Bzučák, který se nachází přímo na desce jBotBrainu II, můžeme využít k oživení našich aplikací –
například k ozvučení stisknutých tlačítek nebo k varovným signálům. Práci s bzučákem zajišťuje
třída Sound v balíku jBotBrain2.hw:
Třída jBotBrain2.hw.Sound
static void beep(int tone, int delay)
Zahraje tón tone po dobu delay milisekund.
Hodnota parametru tone může být jedna
z následujících:
Sound.C4
Sound.C5
Sound.D4
Sound.D5
Sound.E4
Sound.E5
Sound.F4
Sound.F5
Sound.G4
Sound.G5
Sound.A4
Sound.A5
Sound.H4
Sound.H5
Sound.B4
Sound.B5
Sound.C6
Metoda není blokující – to znamená, že zvuk
hraje „na pozadí“ a další příkazy se zpracovávají
ihned, ne až po doznění tónu.
- 42 -
Skripta Mechatronic Education
Jednoduchý příklad SoundExample po spuštění zahraje na půl sekundy tón A4 (440 Hz). Tlačítka
jBotBrainu II S1 – S4 mají přiřazené tóny a jBotBrain II tak může sloužit jako improvizovaný
hudební nástroj:
package jBotBrain2.SoundExample;
import jBotBrain2.hw.*;
public class SoundExampleMain {
public static void main(String[] args) {
Led.GREEN1.set(Led.MODE_BLINK, 300);
Sound.beep(Sound.A4, 500);
while (true) {
if (Button.S1.isPressed()) {
Sound.beep(Sound.A4, 300);
while(Button.S1.isPressed());
}
if (Button.S2.isPressed()) {
Sound.beep(Sound.H4, 300);
while(Button.S2.isPressed());
}
if (Button.S3.isPressed()) {
Sound.beep(Sound.C5, 300);
while(Button.S3.isPressed());
}
if (Button.S4.isPressed()) {
Sound.beep(Sound.D5, 300);
while(Button.S4.isPressed());
}
}
}
}
- 43 -
Skripta Mechatronic Education
3.2.5
Digitální výstupy
Při práci s jBotBrainem II máme k dispozici celkem osm digitálních výstupů, na kterých můžeme
nastavit vysokou nebo nízkou úroveň (5 V a 0) a které můžeme využít i k připojení modelářského
servomotoru.
Přístup k digitálním výstupům zajišťuje třída DigitalOutput v balíčku jBotBrain2.hw a umožňuje
jak nastavení celého portu (všech osmi výstupů zároveň), tak i přístup k jednotlivým pinům
prostřednictvím pole PINS (mějme na paměti že jsou číslovány od nuly, osmému pinu tedy
odpovídá číslo 7) nebo označení písmeny A-H.
Třída jBotBrain2.hw.DigitalOutput
static DigitalOutput A, B, C, D, E, F, G, H
Digitální výstupy A-H odpovídající pinům 1-8.
static DigitalOutput[] PINS
Pole obsahující digitální výstupy 0-7.
void setValue(boolean value)
Nastavení logické úrovně výstupního pinu (true
nebo false):
void portWrite(int value)
true
1 H (high = vysoká uroveň) 5 V
false
0 L (low = nízká úroveň)
0V
Nastavení hodnoty celého portu, tedy všech osmi
pinů zároveň podle prvních osmi bitů parametru
value.
Následující dva příklady budou postupně rozsvěcet LED diody připojené na digitálních výstupech
a vytvoří efekt „světelného hada“, lišit se budou v použití tříd DigitalOutput.
- 44 -
Skripta Mechatronic Education
V prvním příkladu, pojmenovaném DigitalOutExample, použijeme metodu setValue() a budeme
přistupovat jednotlivým pinům. Na to si zavedeme dvě proměnné, pin a prevPin (previous znamená
anglicky předchozí), které budeme při každé iteraci nekonečného cyklu (při každém průchodu
cyklem) zvyšovat o hodnotu 1:
package jBotBrain2.DigitalOutExample;
import jBotBrain2.hw.*;
public class DigitalOutExampleMain {
public static void main(String[] args) throws InterruptedException {
Led.GREEN1.set(Led.MODE_BLINK, 300);
// Nastav všechny piny na nulu
DigitalOutput.portWrite(0);
int prevPin = 0;
int pin = 0;
while (true) {
// shození předchozího pinu
DigitalOutput.PINS[prevPin].setValue(false);
// nastavení aktuálního pinu
DigitalOutput.PINS[pin].setValue(true);
// Přejdi na další pin
pin++;
prevPin = pin;
// Znovu od začátku…
if (pin == 8) {
pin = 0;
}
Thread.sleep(200);
}
}
}
Druhý příklad bude vycházet z prvního, proto je ve výpisu zdrojového kódu zobrazena jen část
s definicí proměnných a nekonečným cyklem. K nastavení digitálních výstupů je použita metoda
portWrite(int value), která najednou nastaví logické úrovně celého portu, tedy všech osmi pinů
podle parametru value. K nastavování jednotlivých bitů slouží bitové operace.
int pin = 0;
while (true) {
DigitalOutput.portWrite(1 << pin); // shození předchozího pinu
pin++; // Přejdi na další pin
// Znovu od začátku…
if (pin == 8) {
pin = 0;
}
Thread.sleep(200);
}
- 45 -
Skripta Mechatronic Education
3.2.6
Digitální vstupy
Kromě digitálních výstupů máme na jBotBrainu II k dispozici také šest digitálních vstupů. Ty
můžeme využít ke čtení logické úrovně (1 nebo 0) a k počítání pulsů. K jejich obsluze slouží třída
DigitalInput, která se nachází v balíku jBotBrain2.hw a nabízí obdobný přístup jako třída
Digitaloutput – k pinům můžeme přistupovat jak pomocí pole PINS, tak i za použití písmen A-F.
Třída jBotBrain2.hw.DigitalInput
static DigitalInput A, B, C, D, E, F
Digitální vstupy A-F odpovídající pinům 1-6.
static DigitalInput[] PINS
Pole obsahující digitální výstupy 0-5.
boolean getValue()
Přečtení logické úrovně vstupního pinu (true
nebo false):
int portRead()
true
1 H (high = vysoká uroveň) 5 V
false
0 L (low = nízká úroveň)
0V
Čtení celého vstupního portu, stav je uložen
do horních šesti bitů.
Příklad pojmenovaný DigitalInExample ukazuje vypisování stavu tlačítka připojeného na prvním
digitálním vstupu proti napájení 5V do konzole. Kromě toho se při stisku tlačítka rozsvítí oranžová
LED:
package jBotBrain2.DigitalInExample;
import jBotBrain2.hw.*;
public class DigitalInExampleMain {
public static void main(String[] args) {
Led.GREEN1.set(Led.MODE_BLINK, 300);
while (true) {
if (DigitalInput.PINS[0].getValue()) {
System.out.print("Tlacitko stisknuto. \r");
Led.ORANGE.on();
} else {
System.out.print("Tlacitko rozpojeno. \r");
Led.ORANGE.off();
}
}
}
}
- 46 -
Skripta Mechatronic Education
3.2.7
Čítač
K počítání pulsů na vstupním pinu slouží třída Counter. Umožňuje jak počítání náběžných hran, tak
i přepočet na frekvenci v Hertzech. Stejně jako třída DigitalInput se nachází v balíku
jBotBrain2.hw a nabízí celkem čtyři metody:
Třída jBotBrain2.hw.Counter
Counter(DigitalInput pin)
Konstruktor třídy, parametrem se nastavuje,
s jakým pinem bude čítač pracovat.
int getEdgeCount()
Vrací počet načítaných náběžných hran.
int getFrequency()
Vrací frekvenci pulsů v Hz.
void setEdgeCount(int count)
Nastavení stavu čítače na hodnotu count.
void resetEdgeCount()
Vynulování čítače.
Ve druhém příkladu připojíme k digitálnímu vstupu IN1 optozávoru (modul SD 01 – Optocoupler)
a budeme do konzole vypisovat počet impulsů a frekvenci:
package jBotBrain2.DigitalInExample;
import jBotBrain2.hw.*;
public class DigitalInExampleMain {
public static void main(String[] args) throws InterruptedException {
Led.GREEN1.set(Led.MODE_BLINK, 300);
Counter cnt = new Counter(DigitalInput.A);
while (true) {
System.out.print("Pocet impulsu: "+cnt.getEdgeCount()+",
frekvence: "+cnt.getFrequency()+" Hz
\r");
Thread.sleep(300);
}
}
}
- 47 -
Skripta Mechatronic Education
3.2.8
Analogové vstupy
Analogové vstupy můžeme využít k připojení senzorů s analogovým výstupem (infračervené
dálkoměry, čidla teploty, tlaku, …), potenciometru nebo k prostému měření napětí v rozsahu 0-5
V s desetibitovým rozlišením. To znamená, že měřené napětí reprezentuje číslo v rozsahu 0-1024
(1024 = 210) a rozlišení je tedy 5000/1024 = necelých 5 mV.
Analogových vstupů najdeme na desce celkem šest a přistupujeme k nim obdobnou logikou jako
k digitálním vstupům nebo výstupům, pomocí třídy AnalogInput, která se nachází v balíčku
jBotBrain2.hw. Ke čtení pinů slouží konstanty A-F nebo pole INPUTS[0-5]:
Třída jBotBrain2.hw.AnalogInput
static AnalogInput A, B, C, D, E, F
Analogové vstupy A-F odpovídající vstupům 05.
static AnalogInput[] INPUTS
Pole obsahující analogové vstupy (0-5).
int readValue_mV()
Měření napětí v milivoltech jako celé číslo
v rozsahu 0-5000, kde 5000 mV odpovídá 5 V.
float readValue_V()
Měření napětí ve voltech jako číslo s desetinným
místem.
Následující příklad, AnalogExample, bude číst stav potenciometru připojeného na analogový vstup
0 a do konzole vypisovat jak hodnotu napětí v milivoltech, tak i polohu osy potenciometru
v procentech. Zároveň umožní potenciometrem regulovat periodu blikání oranžové LED diody.
- 48 -
Skripta Mechatronic Education
Pokusně bylo zjištěno, že pro krajní polohy potenciometru naměří jBotBrain II hotnody 5 a 4950
mV. Proto je u přepočtu napětí na procenta použit tento vztah:
percent = ((voltage-5)*100/4950);
Proměnná delta v sobě uchovává změnu polohy a slouží k tomu, abychom blikání LED diody
nastavili jen v případě, kdy jsme s osou potenciometru skutečně pohli (delta je různá od nuly):
package jBotBrain2.AnalogExample;
import jBotBrain2.hw.*;
public class AnalogExampleMain {
public static void main(String[] args) throws InterruptedException {
AnalogInput analog = AnalogInput.Inputs[0];
Led.GREEN1.set(Led.MODE_BLINK, 300);
int voltage;
int percent = 0;
int delta = 0;
while (true) {
voltage = analog.readValue_mV();
delta = percent;
percent = ((voltage-5)*100/4950);
delta -= percent;
if (delta != 0) {
Led.ORANGE.set(Led.MODE_BLINK, percent*3);
}
System.out.print("Poloha: "+percent+"% (U = "+voltage+" mV)
\r");
Thread.sleep(10);
}
}
}
- 49 -
Skripta Mechatronic Education
3.2.9
Motory
jBotBrain II umožňuje připojení celkem dvou stejnosměrných motorů, které jsou označeny A a B.
Alternativně můžeme použít výstupy pro ovládání čtyř stejnosměrných motorů připojením jedné
svorky motoru na výstup jBotBrainu II a druhé svorky na zem nebo napájecí napětí z akumulátoru –
musíme ale počítat se sníženým proudovým limitem a s tím, že přijdeme o možnost změnit směr
otáčení motoru. Přístup k motorům zajišťuje třída Motor v balíku jBotBrain2.hw:
Třída jBotBrain2.hw.Motor
static Motor A, B
Přístup k motorům A a B.
void setSpeed(int speed)
Nastavení rychlosti motoru v rozsahu 0-255 (0 =
motor stojí, 255 je maximální rychlost).
void setDirection(int direction)
Nastavení směru otáčení motoru. Hodnoty
proměnné direction jsou popsány v tabulce níže.
Možné hodnoty parametru metody setDirection(int direction) jsou následující:
Motor.MOTOR_CLOCKWISE
Otáčení po směru chodu hodinových ručiček.
Motor.MOTOR_ANTICLOCKWISE
Otáčení v opačném směru.
Motor.MOTOR_STANDBY
Odpojení motoru – žádný proud neprochází, hřídel
se volně protáčí.
Motor.MOTOR_STOP
Brzda, motor je zkratován (stále jím prochází proud) –
hřídelí motoru nelze volně otáčet.
- 50 -
Skripta Mechatronic Education
Ovládání motorů ukazuje následující příklad. Tlačítky S2 a S3 se mění směr otáčení motorů,
tlačítka S4 a S1 slouží k přidávání/ubírání rychlosti (je nutné ohlídat, aby rychlost nebyla menší než
0 a větší než 255):
package jBotBrain2.MotorsExample;
import jBotBrain2.hw.*;
public class MotorsExampleMain {
public static void main(String[] args) {
int speed = 0;
Led.GREEN1.set(Led.MODE_BLINK, 300);
Motor.A.setDirection(Motor.MOTOR_STANDBY);
Motor.A.setDirection(Motor.MOTOR_STANDBY);
while (true) {
if (Button.S3.isPressed()) {
while (Button.S3.isPressed());
Motor.A.setDirection(Motor.MOTOR_ANTICLOCKWISE);
Motor.B.setDirection(Motor.MOTOR_ANTICLOCKWISE);
} else if (Button.S2.isPressed()) {
while (Button.S2.isPressed());
Motor.A.setDirection(Motor.MOTOR_CLOCKWISE);
Motor.B.setDirection(Motor.MOTOR_CLOCKWISE);
}
if (Button.S4.isPressed()) {
while (Button.S4.isPressed());
speed -= 20;
if (speed < 0) {
speed = 0;
}
Motor.A.setSpeed(speed);
Motor.B.setSpeed(speed);
} else if (Button.S1.isPressed()) {
while (Button.S1.isPressed());
speed += 20;
if (speed > 255) {
speed = 255;
}
Motor.A.setSpeed(speed);
Motor.B.setSpeed(speed);
}
}
}
}
- 51 -
Skripta Mechatronic Education
3.2.10 Servomotory
K připojení standardních modelářských servomotorů můžeme využít jeden z osmi digitálních
výstupů. O řízení serva se stará třída ServoMotor, ukrytá v balíčku jBotBrain2.hw a má kromě
konstruktoru jedinou metodu sloužící k nastavení polohy výstupní osy.
Třída jBotBrain2.hw.ServoMotor
ServoMotor(DigitalOutput output)
Konstruktor sloužící k nastavení digitálního pinu (output),
ke kterému je servomotor připojen.
void setValue(int value)
Nastavení polohy serva v rozsahu 1-254. Hodnota 127 je
krajní poloha odpovídající pulsu o šířce 1,5 ms.
Následující příklad, pojmenovaný ServoExample, pracuje se servem připojeným na digitální
výstup 1, které se po stisku tlačítka natáčí do poloh postupně 0°, 90° a 180°:
package jBotBrain2.ServoTest;
import jBotBrain2.hw.*;
public class ServoExampleMain {
public static void main(String[] args) {
ServoMotor servo = new ServoMotor(DigitalOutput.PINS[0]);
Led.GREEN1.set(Led.MODE_BLINK, 300);
int pos = 1;
while (true) {
servo.setValue(pos);
Button.waitForPress();
pos += 126;
if (pos > 255) {
pos = 1;
}
}
}
}
- 52 -
Skripta Mechatronic Education
3.2.11 Bluetooth
Abychom mohli s Bluetooth rozhraním jBotBrainu II pracovat, musíme mít Bluetooth modul
zapnutý a spárovaný s naším počítačem. Práci s Bluetoothem v režimu SPP (Serial Port Profile –
to znamená, že se v počítači hlásí jako běžný sériový COM port) zajišťuje třída BTCommport
v balíku jBotBrain2.comm.
Kromě ní se v balíku nachází ještě třída UARTCommPort, která slouží k práci se sériovým portem
(UART) a která je popsána v následující kapitole. Obě třídy implementují rozhraní CommPort,
takže práce s nimi je podobná. Ve výpisu metod jsou zahrnuty pouze metody, které využijeme
a které nejsou implementovány jen kvůli kompatibilitě s rozhraním CommPort (například metoda
open(), jejíž použití nemá žádný vliv):
Třída jBotBrain2.comm.BTCommPort
int getStatus()
Zjištění stavu Bluetooth modulu:
CommPort.DEVICE_OFF
Modul je vypnut.
CommPort.DEVICE_ON
Modul je zapnut.
CommPort.DEVICE_WAIT_ Čekání na spojení.
CONN
CommPort.DEVICE_CONN
ECTED
Spojení
s dalším
Bluetooth zařízením bylo
navázáno.
int write(bytes[] buffer, int offset, int Pošle length bajtů z pole buffer od indexu offset. Pro
length)
odeslání řetězce znaků „ahoj” použijeme metodu
následovně:
BTCommPort comm = new BTCommPort();
byte[] buffer = {'a', 'h', 'o', 'j'};
comm.write(buffer, 0, buffer.length);
Metoda vrací počet odeslaných bajtů.
int read(bytes[] buffer, int offset, int Načte length přijatých bajtů do pole buffer od indexu offset
length)
a vrací počet přečtených bajtů bajtů.
int writeString(String s)
Odešle řetězec a vrátí počet odeslaných bajtů.
- 53 -
Skripta Mechatronic Education
Příjem a odesílání dat si ukážeme na jednoduchém příkladu vozítka s diferenciálním řízením (jako
tank) a dvěma motory připojenými přímo k jBotBrainu II, které budeme ovládat dálkově rozhraním
Bluetooth. Celý příklad se vejde do jediné třídy RemoteControlMain:
package jBotBrain2.RemoteControl;
import jBotBrain2.hw.*;
import jBotBrain2.comm.BTCommPort;
public class RemoteControlMain {
public static void main(String[] args) {
Led.GREEN1.set(Led.MODE_BLINK, 300);
// Přijímací buffer
byte[] buffer = new byte[1];
// Příkaz – maximálně 5 znaků
char[] command = new char[5];
// Počet přijatých bajtů
int bytesCount = 0;
// Počet bajtů příkazu
int count = 0;
// Vytvoření instance BT komunikačního portu
BTCommPort comm = new BTCommPort();
while (true) {
// Načtení bajtů z Bluetoothu
bytesCount = comm.read(buffer, 0, 1);
// Uložení bajtů do pole command
if (bytesCount > 0) {
command[count] = (char) buffer[0];
count++;
// Zpracuj příkaz, pokud je ukončen novým řádkem
// nebo pokud počet bajtů přetekl
if (command[count – 1] == '\n' || count ==
command.length) {
count = 0;
commandReceived(command);
comm.writeString("OK\n");
}
}
}
}
/**
* Zpracování příkazu
*/
public static void commandReceived(char[] command) {
System.out.println("Command received: " + command[0] + " " +
command[1]);
- 54 -
Skripta Mechatronic Education
// Levý motor
switch (command[0]) {
case 'F':
Motor.A.setSpeed(255);
Motor.A.setDirection(Motor.MOTOR_CLOCKWISE);
break;
case 'B':
Motor.A.setSpeed(255);
Motor.A.setDirection(Motor.MOTOR_ANTICLOCKWISE);
break;
default:
Motor.A.setSpeed(0);
break;
}
// Pravý motor
switch (command[1]) {
case 'F':
Motor.B.setSpeed(255);
Motor.B.setDirection(Motor.MOTOR_CLOCKWISE);
break;
case 'B':
Motor.B.setSpeed(255);
Motor.B.setDirection(Motor.MOTOR_ANTICLOCKWISE);
break;
default:
Motor.B.setSpeed(0);
break;
}
}
}
Program v nekonečné smyčce načítá data z Bluetooth modulu (k tomu slouží třída
jBotBrain2.comm.BTCommPort) do pole command. Pokud narazí na znak nového řádku nebo
pokud hrozí přetečení pole command, je zavolána metoda commandReceived, která zajišťuje
zpracování příkazu přepínačem (switch). Využity jsou první dva bajty příkazu, první pro levý motor
a druhý pro motor pravý. Směr otáčení motoru může být buď F (forward – otáčení vpřed), B
(backward – otáčení vzad) nebo S (stop – zastavení). Příkaz „FF“ tedy slouží k jízdě vpřed, příkaz
„FB“ pak k otáčení na místě doprava. Po přijetí příkazu jBotBrain II odešle zprávu „OK“
a odřádkuje, abychom se přesvědčili, že byl příkaz přijat. Kromě toho vypisuje přijaté příkazy
do konzole.
- 55 -
Skripta Mechatronic Education
Bluetooth modul je nastavený na komunikaci rychlostí 115200 baudů. Dálkové ovládání bude
fungovat třeba v Hyperterminálu, stačí se připojit ke správnému portu a posílat příkazy popsané
výše a oddělené novým řádkem.
Protože ovládání z terminálu nepatří mezi nejpohodlnější, napsal jsem jednoduchou aplikaci
v Delphi, která se připojí k danému sériovému portu a odesílá příkazy. Vozítko je možné ovládat
buď šipkami nebo klikáním na tlačítka. Ovládací aplikaci najdete v příloze.
- 56 -
Skripta Mechatronic Education
3.2.12 UART
Jak jsem zmínil v minulé kapitole, práci se sériovým portem (UART) jBotBrainu II zajišťuje třída
UARTCommPort v balíku jBotBrain2.comm, která má stejně jako třída BTCommPort
implementováno rozhraní CommPort a její použití je obdobné. Ve výpisu metod tedy zmíním jen
metody, které nejsou ve třídě pro práci s Bluetooth modulem zahrnuty nebo které se mírně liší:
Třída jBotBrain2.comm.UARTCommPort
int getStatus()
int writeString(String s)
Zjištění stavu UART portu:
CommPort.DEVICE_OFF
Port je uzavřen (odpojen).
CommPort.DEVICE_CONN
ECTED
Port je otevřen.
Otevře spojení s UART portem a nastaví komunikační
rychlost (baudrate) a paritu dat (parity) a vrací true
v případě úspěchu. Komunikační rychlosti můžeme vybrat
následující:
CommPort.BR_1200
1,2 kBd (1200 baudů)
CommPort.BR_2400
2,4 kBd
CommPort.BR_4800
4,8 kBd
CommPort.BR_9600
9,6 kBd
CommPort.BR_19200
19,2 kBd
CommPort.BR_38400
38,4 kBd
CommPort.BR_57600
57,6 kBd
CommPort.BR_115200
115,2 kBd
Parmetr parity mastavuje chování paritního bitu a může
- 57 -
Skripta Mechatronic Education
nabývat těchto hodnot:
CommPort.PARITY_ODD
Počet
v odeslaném
lichý.
jedniček
bajtu je
CommPort.PARITY_EVEN
Počet
v odeslaném
sudý-
jedniček
bajtu je
CommPort.PARITY_MARK
Paritní bit
hodnotu 1.
má
vždy
CommPort.PARITY_SPACE
Paritní bit
hodnotu 0.
má
vždy
CommPort.PARITY_NONE
Paritní bit není posílán.
Parity MARK a SPACE jsou výhodné v případě, že chceme
pracovat se zařízením, které vyžaduje devítibitovou
komunikaci namísto osmibitové.
void close()
Ukončí práci s UART portem a uzavře jej.
Protože třídy BTCommPort a UARTCommPort můžeme jednoduše zaměnit, ukážeme si použití
třídy UARTCommPort na úpravě příkladu dálkového ovládání s Bluetoothem z předchozí kapitoly.
Stačí pouze změnit třídu importovanou z balíku jBotBrain2.comm a řádek s vytvoření instance
třídy BTCommPort
BTCommPort comm = new BTCommPort();
změnit na
UARTCommPort comm = new UARTCommPort();
comm.open(CommPort.BR_115200, CommPort.PARITY_NONE);
Nyní můžeme vozítko ovládat z počítače prostřednictvím USB ←→ TTL UART převodníku nebo
převodníku z RS232 na UART v TTL úrovních. Stačí jen změnit číslo COM portu v terminálu nebo
ovládacím programu.
Úrovně RS232C
Proč je pro připojení ke COM portu počítače potřeba převodník? Sériový COM port na počítači
pracuje s úrovněmi až ± 10 V, které by jBotBrain II pracující s TTL úrovněmi 0 a 5 V spolehlivě
zničily. Kromě toho je potřeba logické úrovně invertovat – k tomu slouží převodníky například
s integrovaným obvodem MAX232.
- 58 -
Skripta Mechatronic Education
3.2.13 I2C
Hardware jBotBrainu II umožňuje práci s I2C zařízeními, přičemž jBotBrain II je brán jako master.
Přímo na desce jsou vyvedeny čtyři konektory pro připojení zařízení.
Co je to I2C?
Sběrnice I2C (IIC, Inter-Integrated Circuit, čteme [I- squared-C]) je multimasterová sběrnice
vyvinuta firmou Philips, umožňující připojení až 127 zařízení pomocí dvou obousměrných linek.
Linka SCL tvoří hodinový signál, po lince SDA se přenášejí data. U jiných výrobců se kvůli
licenční politice můžeme setkat s označením TWI (Two-Wire Interface). Je používána
ke komunikaci s různými zařízeními jak v počítačích, tak i v mobilních telefonech a dalších
zařízeních – například paměti, obvody reálného času, A/D převodníky. Díky implementaci
v mikrokontrolérech se stala populární pro připojování různých modulů, jako jsou různé senzory
a další zařízení.
Pro přístup k I2C portu slouží třída I2CPort ukrytá v balíku jBotBrain2.hw. Kromě metod
uvedených v tabulce obsahuje ještě nízkoúrovňové metody pro zapnutí a vypnutí I2C portu, ty pro
nás ale nejsou zajímavé.
Třída jBotBrain2.hw.I2CPort
static int i2cBusy()
Zjištění vytíženosti I2C portu – pokud je hodnota větší než
0, port právě odesílá neb o přijímá data.
static int i2cStart(
Statická metoda pro zahájení zápisu nebo čtení dat.
int address,
int internalAddress,
– address je adresa I2C zařízení.
int numInternalBytes,
– internalAddress je číslo registru, kam chceme
zapisovat, nebo ze kterého chceme číst.
byte[] buffer,
int numBytes,
int transferType
)
– numInternalBytes je počet bajtů, které chceme
ze zařízení přečíst nebo zapsat.
– buffer je pole bajtů, do kterého chceme data načíst
nebo které chceme do zařízení zapsat.
– numBytes je počet bajtů (délka) bufferu.
– transferType určuje typ operace –
I2CPort.I2C_READ pro čtení nebo
I2CPort.I2C_WRITE pro zápis.
- 59 -
Skripta Mechatronic Education
Ač může vypadat použití metody i2cStart složitě, není tomu tak. Práci s I2C portem si ukážeme
na příkladu, kdy vytvoříme třídu pracující s elektromagnetickým kompasem CMPS03. Ta bude jen
ukázková, protože jBotBrain II obsahuje třídy pro práci s mnoha senzory, kompas CMPS03
nevyjímaje (konkrétně jde o třídu jBotBrain2.sensors.CMPS03Sensor).
Pár slov o CMPS03
Modul kompasu CMPS03 vyrábí firma Devantech a slouží k určení směru, kterým je robot
otočen. Využívá k tomu dvou navzájem kolmých senzorů magnetického pole KMZ51. S okolím
komunikuje pomocí sběrnice I2C, kterou jsme se začali zabývat v minulém dílu. Pro správné
měření by měl být kompas správně zkalibrován a na robotovi umístěn co možná nejdále od zdrojů
rušení, hlavně motorů a feromagnetických látek. Kromě toho musí být umístěn vodorovně, náklon
senzoru či poskakování robota po dlažebních kostkách má na výsledek měření špatný vliv.
Sběrnice I2C se dá využít pro komunikaci master zařízení (zde je to jBotBrain II) se slave
zařízeními (SRF02, CMPS03, EEPROM 24C04 atd.). Každé z těchto zařízení má svou adresu
a několik vnitřních registrů, ze kterých můžeme číst nebo do kterých můžeme zapisovat. Podrobný
popis komunikace se zařízením bývá uveden v jeho dokumentaci, modul CMPS03 ji má dostupnou
v angličtině na webu
http://www.robot-electronics.co.uk/htm/cmps3tech.htm. Z ní vyplývá,
že kompas má celkem 16 registrů:
Registr
Význam
0
Verze software
1
Natočení jako bajt, 0-255
2,3
Natočení jako word (2 bajty), 0-3599 – reprezentuje 0-359,9°
4,5
Interní test (slouží k testování ve výrobě)
6,7
Interní test (slouží k testování ve výrobě)
8,9
Nezpracovaná data prvního senzoru
10,11
Nezpracovaná data druhého senzoru
12, 13 a 14
Odemykací kód (unlock code)
15
Příkazový registr
Registry 4-11 jsou pro nás nezajímavé, slouží ke zkouškám ve výrobě. Natočení kompasu budeme
získávat z registrů 2 a 3, které obsahují natočení s rozlišením na desetiny stupně a stačí je pouze
přečíst, o nic víc se starat nemusíme (na rozdíl od sonaru SRF02, kde je před přečtením hodnoty
nutné zahájit měření a vyčkat 80 milisekund). Registr 15 slouží ke kalibraci kompasu (o té si
povíme později) a ke změně adresy – tu využijeme, pokud již na sběrnici nějaké jiné zařízení
s adresou 0xC0 (výchozí adresa CMPS03) používáme. Předtím ale musíme do registru 15 zapsat
kód, kterým kompas odemkneme a změnu adresy povolíme.
- 60 -
Skripta Mechatronic Education
Hlavní třída programu, ComppasMain, slouží jen k vytvoření instance třídy Compass a vypisování
hodnot do konzole:
package jBotBrain2.Compass;
import jBotBrain2.hw.Led;
public class CompassMain {
public static void main(String[] args) throws InterruptedException {
Led.ORANGE.set(Led.MODE_BLINK, 200);
Compass compass = new Compass();
while (true) {
System.out.print("Uhel: "+compass.getAngle()+"°
\r");
Thread.sleep(200);
}
}
}
Klíčovou je až třída Compass, kterou postupně rozebereme:
package jBotBrain2.Compass;
import jBotBrain2.hw.I2CPort;
public class Compass {
private int address;
public Compass(int address) {
this.address = address;
}
public Compass() {
address = 0xC0;
}
// Ostatní metody jsou popsány níže
Pro práci s I2C zařízením budeme potřebovat třídu jBotBrain2.hw.I2CPort, kterou musíme
importovat. Naše třída Compass má jednu privátní vlastnost address pro uložení adresy zařízení.
Adresa je nastavena konstruktorem. Pokud adresu nezadáme, je použita výchozí adresa kompasu
CMPS03, hodnota 0xC0.
- 61 -
Skripta Mechatronic Education
public void calibrate() {
byte buffer[] = {(byte)0xff};
I2CPort.i2cStart(address, 15, 1, buffer, 1, I2CPort.I2C_WRITE);
}
Ke kalibraci kompasu slouží následující postup (světové strany musí být určeny přesně, například
pomocí klasického kompasu či buzoly – pokud je pouze odhadneme, bude kalibrace víceméně
zbytečná a měření velice nepřesné):
1) Natočíme kompas směrem na sever a zapíšeme hodnotu 255 (0xFF) do registru 15
2) Natočíme kompas směrem na východ a zapíšeme hodnotu 255 (0xFF) do registru 15
3) Natočíme kompas směrem na jih a zapíšeme hodnotu 255 (0xFF) do registru 15
4) Natočíme kompas směrem na západ a zapíšeme hodnotu 255 (0xFF) do registru 15
Při kalibraci by měl modul kompasu ležet vodorovně. Nemusíme ji provádět pokaždé, hodnoty
zůstanou uloženy v paměti. K zápisu hodnoty 255 (0xFF) do registru 15 (příkazový registr)
použijeme metodu I2CPort.i2cStart(), která je popsaná v tabulce výše.
public void changeAddress(int newAddress) {
byte buffer[] = {(byte)0xA0, (byte)0xAA, (byte)0xA5, (byte)newAddress};
I2CPort.i2cStart(address, 12, 4, buffer, 4, I2CPort.I2C_WRITE);
address = newAddress;
}
Změna adresy funguje původně jako kalibrace, jen zapíšeme více bajtů, které jsou uloženy v poli
buffer. První tři (0xA0, 0xAA a 0xA5) jsou odemykací kód a zapisují se do registrů 12-14. Poslední
bajt je adresa, která se zapíše do registru 15. Protože budeme zapisovat všechny čtyři bajty
najednou, nastavíme internalAddress na 12 a numInternalBytes (počet bajtů) na 4. Pozor, pokud
z nějakého důvodu potřebujete adresu změnit, nezapomeňte si tu novou poznačit. Adresu modulu
můžete vybírat z hodnot 0xC0, 0xC2, 0xC4, 0xC6, 0xC8, 0xCA, 0xCC nebo 0xCE.
public int getAngle() {
byte buffer[] = {0x00, 0x00};
I2CPort.i2cStart(address, 2, 2, buffer, 2, I2CPort.I2C_READ);
int angle = (buffer[0] << 8) | (buffer[1] & 0xFF);
return angle/10;
}
Poslední metoda slouží k přečtení naměřené hodnoty, která je uložena v registrech 2 a 3. Budeme
tedy číst 2 bajty počínaje registrem 2, uložíme je do pole buffer a spojíme. Kompas sice poskytuje
rozlišení na desetiny stupně (proto je natočení uloženo ve dvou registrech – každý registr obsahuje
jeden bajt), my se ale spokojíme s celým číslem. Hodnotu angle vydělíme deseti a protože je
datového typu int, bude obsahovat pouze celé číslo bez desetinných míst.
- 62 -
Skripta Mechatronic Education
3.2.14 Vlákna
JVM jBotBrainu II umožňuje tzv. multithreading, tedy paralelní zpracování dvou či více částí
programu (pro upřesnění – použitý procesor samozřejmě fyzicky neumožňuje běh několika vláken
současně, JVM se stará o jejich přepínání a jednotlivá vlákna se tak o procesor dělí podle pravidel,
která jim přiděluje plánovač (scheduler) na základě nastavitelné priority). Práci s vlákny zajišťuje
třída Thread, kterou najdeme v balíku java.lang. Balík je jedním ze základních a importuje
se automaticky.
Vytvoření vlákna je velice jednoduché. Buď vytvoříme třídu s implementovaným rozhraním
Runnable, nebo třídu, která je od třídy Thread odvozená dědením. Ukážeme si druhý způsob:
public class MyThread extends Thread {
public void run() {
// Náš kód
}
}
Do metody run() pak patří kód, který vlákno zpracovává, například nekonečná smyčka bliakjící
LED diodou.
TIP: Pokud v Eclipse založíme novou třídu MyThread a do kódu napíšeme, že má dědit z třídy
Thread (extends Thread), objeví se v levém postranním proužku editoru ikonka oznamující chybu.
To proto, že v kódu nemáme zahrnuty metody, které musíme povinně implementovat. Můžeme je
buď napsat ručně (v našem případě jde pouze o metodu run()), nebo stačí na ikonku kliknout,
v nabídce zvolit položku „add unimplemented methods“ a Eclipse metodu run() doplní sám:
Vlákno pak spustíme zavoláním metody start():
MyThread myThread = new MyThread();
myThread.start();
- 63 -
Skripta Mechatronic Education
Vše si ukážeme na příkladu dálkového ovládání dvoukolového vozítka z kapitoly o Bluetoothu,
který doplníme o bezpečnostní brzdu realizovanou tlačítkem S4. Pokud bude tlačítko S4 stisknuto,
vozítko se zastaví a ovládat je budeme moci až po opětovném stisknutí tlačítka. Brzda se hodí
v okamžiku, kdy vozítko půjčíme někomu, komu řízení příliš nejde a nechceme, aby nabouralo
do skříně nebo zdi.
Nejprve vytvoříme třídu BrakeThread, což je vlákno, které kontroluje stav tlačítka S4 a po jeho
stisku zavolá metodu hlavní třídy RemoteControlMain.brakeStop(), která se bude starat o zastavení
vozítka:
package jBotBrain2.RemoteControl;
import jBotBrain2.hw.Button;
public class BrakeThread extends Thread {
public void run() {
while (true) {
if (Button.S4.isPressed()) {
RemoteControlMain.brakeStop();
while (Button.S4.isPressed());
}
}
}
}
- 64 -
Skripta Mechatronic Education
Druhou úpravou bude vytvoření metody brakeStop() v hlavní třídě a vlastnosti stop, která bude
hlídat zastavení vozítka. Kromě toho také musíme vytvořit instanci vlákna BrakeThread, spustit je
pomocí metody start() a do hlavního cyklu přidat podmínku, která při změně hodnoty proměnné
stop na true zastaví motory, rozsvítí červenou LED diodu a čeká, dokud se její hodnota nezmění
opět na false. Původní kód je zobrazen šedou barvou:
package jBotBrain2.RemoteControl;
import jBotBrain2.hw.*;
public class RemoteControlMain {
private static boolean stop = false;
public static void brakeStop() {
if (stop) {
stop = false;
} else {
stop = true;
}
}
public static void main(String[] args) {
// …Původní kód
BrakeThread brake = new BrakeThread();
brake.start();
while (true) {
if (!stop) {
// Původní kód
} else {
Motor.A.setSpeed(0);
Motor.B.setSpeed(0);
Led.RED.on();
while (stop);
Led.RED.off();
}
}
}
}
- 65 -
Skripta Mechatronic Education
3.2.15 Časovače
Blikáním LED diodou se zabývá jedna z prvních kapitol, slouží k tomu metoda setMode(int mode,
int delay), například příkaz Led.RED.setMode(Led.MODE_BLINK, 100) rozbliká červenou
LED diodu s periodou 100 milisekund. Ale co když chceme na jBotBrainu II, kde již máme v hlavní
smyčce nějaký kód (třeba zpracování a příjem příkazů z rozhraní Bluetooth) rozblikat další LED
diody připojené na digitální výstup? Použijeme časovač.
Časovač (Timer) je nástroj umožňující jednou za uplynutí zadané periody volat určitou metodu.
Inicializuje se jednoduše:
Timer myTimer = new Timer(100, timerListener);
myTimer.start();
Prvním parametrem je prodleva v milisekundách, druhým je instance třídy s implementovaným
rozhraním TimerListener. Rozhraní TimerListener má definovanou metodu timedOut, která je
volána právě při uplynutí zadané prodlevy. Ke spuštění časovače slouží metoda start(). Periodu
můžeme změnit medotou setDelay(int delay) a metoda stop() slouží k zastavení časovače.
Praktické použití si ukážeme na příkladu s dvěma LED diodami připojenými na digitální výstup,
stejně jako v příkladu se semaforem. Nezapomeňte k LED diodě zapojit ochranný rezistor!
Třída Blinker.java, která se o přepínání LED diody stará, bude obsahovat tento kód:
package jBotBrain2.TimerExample;
import jBotBrain2.util.TimerListener;
import jBotBrain2.hw.DigitalOutput;
public class Blinker implements TimerListener {
private boolean on = false;
private int pinNumber;
public Blinker(int pinNumber) {
this.pinNumber = pinNumber;
}
public void timedOut() {
if (on) {
DigitalOutput.PINS[pinNumber].setValue(false);
on = false;
} else {
DigitalOutput.PINS[pinNumber].setValue(true);
on = true;
}
}
}
- 66 -
Skripta Mechatronic Education
Třída Timer a rozhraní TimerListener jsou umístěny v balíku jBotBrain2.util, proto je nesmíme
zapomenout importovat. Celý kód je velice jednoduchý, klíčová je metoda timedOut(), která má
v sobě uloženou obsluhu „přerušení“ časovače.
Kód v hlavní třídě příkladu TimerExampleMain.java pak bude následující:
package jBotBrain2.TimerExample;
import jBotBrain3.hw.*;
import jBotBrain2.util.Timer;
public class TimerExampleMain {
public static void main(String[] args) {
Led.GREEN1.set(Led.MODE_BLINK, 100);
Timer red = new Timer(500, new Blinker(0));
Timer orange = new Timer(1000, new Blinker(1));
red.start();
orange.start();
Button.waitForPress();
}
}
Objekty red a orange, instance časovače Timer, se starají o blikání dvou LED diod připojených
na digitálním výstupu, každé s jinou periodou. Připomenu, že digitální výstup 0 odpovídá výstupu
1, číslo 1 pak výstupu 2.
- 67 -
Skripta Mechatronic Education
3.3
3.3.1
Práce s moduly
SD 05 – Dotykový spínač
Dotykový spínač SD 05 – Limit switch se připojuje k jednomu ze šesti digitálních vstupů
jBotBrainu II a dá se použít jako zpětná vazba v různých pohyblivých aplikacích.
Třída TactileSensor v balíku jBotBrain2.sensors nabízí metody, které nám práci se spínači
zjednoduší:
Třída jBotBrain2.sensors.TactileSensor
TactileSensor(DigitalInput input)
Konstruktor, slouží k vytvoření nové instance.
Parametr input určuje, na který digitální vstup je
senzor připojen.
boolean isPressed()
Vrací hodnotu true, pokud je spínač sepnut.
boolean waitForPress(int timeout)
Vyčká na stisknutí spínače nebo vypršení
časového
limitu
timeout
zadaného
v milisekundách. Pokud má parametr timeout
hodnotu 0, je časový limit ignorován a čeká
se pouze na sepnutí spínače.
Metoda vrací hodnotu true v případě, že byla
ukončena stisknutím spínače nebo false
v případě, že byla ukončena po vypršení
časového limitu.
- 68 -
Skripta Mechatronic Education
Příklad TactileSwitchExample používá spínač jako nárazník u podvozku dvoukolového vozítka
s motory připojenými k jBotBrainu II. Vozítko se po spuštění programu rozjede a pokud narazí
nárazníkem (spínačem) do překážky nebo pokud vyprší čas 5 sekund (5000 ms), motory se zastaví
a rozsvítí se červená LED dioda, která svítí dokud není stisknuto libovolné tlačítko na desce
jBotBrainu II. Jeho stiskem se vozítko znovu rozjede:
package jBotBrain2.TactileSwitchExample;
import jBotBrain2.hw.*;
import jBotBrain2.sensors.TactileSensor;
public class TactileSwitchExampleMain {
public static void main(String[] args) {
Led.GREEN1.set(Led.MODE_BLINK, 300);
TactileSensor ts = new TactileSensor(DigitalInput.A);
Motor.A.setDirection(Motor.MOTOR_CLOCKWISE);
Motor.B.setDirection(Motor.MOTOR_CLOCKWISE);
while (true) {
Motor.A.setSpeed(200);
Motor.B.setSpeed(200);
ts.waitForPress(5000);
Led.RED.on();
Motor.A.setSpeed(0);
Motor.B.setSpeed(0);
Button.waitForPress();
Led.RED.off();
}
}
}
- 69 -
Skripta Mechatronic Education
3.3.2
SA 02 – Senzor atmosférického tlaku
Senzor SA 04 – Atmospheric pressure sensor měří atmosférický tlak v rozsahu 15 – 115 kPa.
Připojujeme jej k jednomu ze šesti analogových vstupů jBotBrainu II a práci s ním zajišťuje třída
PressureMeter v balíku jBotBrain2.sensors:
Třída jBotBrain2.sensors.PressureMeter
PressureMeter(AnalogInput input)
Konstruktor, slouží k vytvoření nové instance.
Parametr input určuje, na který analogový vstup
je senzor připojen.
float getPressure()
Vrátí naměřenou hodnotu tlaku v kPa jako
desetinné číslo.
Následující příklad PressureMeterExample bude každých 200 milisekund do konzole vypisovat
aktuální hodnotu atmosférického tlaku naměřenou senzorem připojeným k analogovému vstupu
AIN1:
package jBotBrain2.PressureMeterExample;
import jBotBrain2.hw.*;
import jBotBrain2.sensors.PressureMeter;
public class PressureMeterExampleMain {
public static void main(String[] args) throws InterruptedException {
Led.GREEN1.set(Led.MODE_BLINK, 300);
PressureMeter pressure = new PressureMeter(AnalogInput.A);
while (true) {
System.out.print("Atmosfericky tlak:
"+pressure.getPressure()+" kPa
\r");
Thread.sleep(200);
}
}
}
- 70 -
Skripta Mechatronic Education
3.3.3
SA 04 – Teploměr
Teploměr SA 04 – Thermometer slouží k měření teploty okolí ve stupních Celsia (°C)
a připojujeme jej na jeden z šesti analogových vstupů jBotBrainu II. Měřící rozsah je -45 – 125 °C.
Práci s teplotním čidlem zajišťuje třída Thermometer v balíku jBotBrain2.sensors:
Třída jBotBrain2.sensors.Thermometer
Thermometer(AnalogInput input)
Konstruktor, slouží k vytvoření nové instance.
Parametr input určuje, na který analogový vstup
je teploměr připojen.
float getTemperature()
Vrátí naměřenou hodnotu ve stupních Celsia
jako číslo s desetinným místem (°C).
Jednoduchý příklad ThermometerExample bude do konzole každých 200 milisekund vypisovat
naměřenou teplotu teploměru připojeného k analogovému vstupu AIN1:
package jBotBrain2.ThermometerExample;
import jBotBrain2.hw.*;
import jBotBrain2.sensors.TemperatureSensor;
public class ThermometerExampleMain {
public static void main(String[] args) throws InterruptedException {
Led.GREEN1.set(Led.MODE_BLINK, 300);
TemperatureSensor temp = new TemperatureSensor(AnalogInput.A);
while (true) {
System.out.print("Teplota: "+temp.getTemperature()+" °C
\r");
Thread.sleep(200);
}
}
}
- 71 -
Skripta Mechatronic Education
3.3.4
SI 01 – Akcelerometr
Akcelerometr (modul SI 01 – Accelerometer) je zařízení měřící zrychlení ve třech osách, které
může být způsobeno gravitací nebo nerovnoměrným zrychlením. Hodnoty můžeme využít k zjištění
náklonu nebo rychlosti integrací všech tří os. Rozsah měření akcelerometru je ±5 g, kde g odpovídá
přibližně 9,81 m/s2. V případě nulového zrychlení je hodnota měření příslušné osy 0 g.
Senzor s jBotBrainem II komunikuje pomocí sběrnice I2C a pro přístup k němu používáme třídu
Accelerometer umístěnou v balíku jBotBrain2.sensors:
Třída jBotBrain2.sensors.Accelerometer
Accelerometer(int address)
Konstruktor, slouží k vytvoření nové instance.
Parametr
address
použijeme
v případě,
že chceme použít jinou adresu než výchozí 0xB0
float[] lastValues
Pole o třech prvcích obsahující poslední
naměřené hodnoty získané metodou getAllAxis():
lastValues[0]
Osa X
lastValues[1]
Osa Y
lastValues[2]
Osa Z
void getAllAxis()
Přečte zrychlení všech tří os a uloží je do pole
lastValues.
float getX()
Vrací zrychlení na ose X.
float getY()
Vrací zrychlení na ose Y.
float getZ()
Vrací zrychlení na ose Z.
Příklad AccelerometerExample bude v nekonečném cyklu číst zrychlení na ose Y a nastavovat
polohu servomotoru připojeného k digitálnímu výstupu OUT1 podle náklonu desky akcelerometru
– pokud je hodnota zrychlení 0, nastaví se výstupní osa do středové polohy, jinak se vychýlí podle
velikosti zrychlení. Zrychlení vynásobené číslem 100 (abychom dostali celé číslo) je pak vypsáno
do konzole.
- 72 -
Skripta Mechatronic Education
Mějme na paměti, že hodnota natočení serva metody ServoMotor.setValue(int value) musí být
v rozsahu 1-254, proto musíme zrychlení přepočítat metodou limitServo(int value):
package jBotBrain2.AccelerometerExample;
import jBotBrain2.hw.*;
import jBotBrain2.sensors.Accelerometer;
public class AccelerometerExampleMain {
public static int limitServo(int val) {
if (val < 1) {
return 1;
} else if (val > 254) {
return 254;
}
return val;
}
public static void main(String[] args) {
Led.GREEN1.set(Led.MODE_BLINK, 300);
Accelerometer acc = new Accelerometer();
ServoMotor servo = new ServoMotor(DigitalOutput.A);
int val = 0;
while (true) {
val = (int)(acc.getY()*100);
servo.setValue(limitServo(127+val));
System.out.print("Zrychleni: "+val+"
\r");
}
}
}
- 73 -
Skripta Mechatronic Education
3.3.5
SI 02 – Světelný senzor
Světelný senzor SI 02 – Light Sensor slouží k měření intenzity záření (anglicky Irradiance,
značka Ee), která je udána v jednotkách µW/cm2. Čím více světla na senzor dopadá, tím je měřená
hodnota vyšší. Pokud je senzor v úplné tmě (například přikryjeme-li ho rukou), vrací nulovou
hodnotu. Nejvyšší měřitelná hodnota je přibližně 100 000 µW/cm2.
Senzor s jBotBrainem II komunikuje pomocí sběrnice I2C a pro přístup k němu používáme třídu
LightSensor umístěnou v balíku jBotBrain2.sensors:
Třída jBotBrain2.sensors.LightSensor
LightSensor(int address)
Konstruktor, slouží k vytvoření nové instance.
Parametr
address
použijeme
v případě,
že chceme použít jinou adresu než výchozí 0xC0
void setDeviceAddress(int address)
Změní I2C adresu senzoru.
int getIrradiance()
Přečte hodnotu intenzity záření v µW/cm2.
Jednoduchý příklad LigthSensorExample bude do konzole každých 200 milisekund vypisovat
hodnotu intenzity záření:
package jBotBrain2.LightSensorExample;
import jBotBrain2.hw.*;
import jBotBrain2.sensors.LightSensor;
public class LightSensorExampleMain {
public static void main(String[] args) throws InterruptedException {
Led.GREEN1.set(Led.MODE_BLINK, 300);
LightSensor light = new LightSensor();
while (true) {
System.out.print("Intenzita zareni: "+light.getIrradiance()
+" µW*cm^-2
\r");
Thread.sleep(200);
}
}
}
- 74 -
Skripta Mechatronic Education
3.3.6
SI 03 – Ultrazvukový dálkoměr
Ultrazvukový dálkoměr SI 03 – Ultrasonic range finder (sonar) slouží k měření vzdálenosti
předmětů na principu vyslání ultrazvukového signálu a měření doby odrazu, podobně jako netopýři.
Rozsah měření je 5-100 cm, na velkou vzdálenost ale zachytí jen velkou plochu.
Senzor s jBotBrainem II komunikuje pomocí sběrnice I2C a pro přístup k němu používáme třídu
UltraSonicRangeFinder umístěnou v balíku jBotBrain2.sensors:
Třída jBotBrain2.sensors.UltraSonicRangeFinder
LightSensor(int address)
Konstruktor, slouží k vytvoření nové instance.
Parametr
address
použijeme
v případě,
že chceme použít jinou adresu než výchozí 0xA0
void setDeviceAddress(int address)
Změní I2C adresu senzoru.
int getDistance()
Přečte vzdálenost k překážce v centimetrech.
Pokud ultrazvukový dálkoměr žádnou překážku
nedetekuje, vrací hodnotu 0 cm.
Příklad SonarExample vypisuje v nekonečné smyčce s periodou 200 milisekund naměřenou
vzdálenost do konzole:
package jBotBrain2.SonarExample;
import jBotBrain2.hw.*;
import jBotBrain2.sensors.UltraSonicRangeFinder;
public class SonarExampleMain {
public static void main(String[] args) throws InterruptedException {
Led.GREEN1.set(Led.MODE_BLINK, 300);
UltraSonicRangeFinder us = new UltraSonicRangeFinder();
while (true) {
System.out.print("Vzdalenost: "+us.getDistance()+" cm
\r");
Thread.sleep(200);
}
}
}
- 75 -
Skripta Mechatronic Education
3.3.7
MI 04 – Řadič krokových motorů
Modul MI 04 – Stepper motor driver slouží k řízení dvou bipolárních krokových motorů
s maximálním proudem 1,4 A na fázi. Napájecí napětí motorů se může pohybovat od 8 do 16 V.
Řadič komunikuje s jBotBrianem pmocí sběrnice I2C a práci s ním zajišťují dvě třídy,
StepperMotor pro přístup k jednotlivým motorům a StepperMotorDriver pro přístup k zařízení
jako celku. Obě třídy se nachází v balíku jBotBrain2.devices:
Třída jBotBrain2.devices.StepperMotorDriver
StepperMotorDriver(int address)
Konstruktor, slouží k vytvoření nové instance.
Parametr
address
použijeme
v případě,
že chceme použít jinou adresu než výchozí 0xF0
void setDeviceAddress(int address)
Změní I2C adresu senzoru.
Třída jBotBrain2.devices.StepperMotor
StepperMotor(StepperMotorDriver driver, int Konstruktor, slouží k vytvoření nové instance.
port)
Parametr driver slouží k přiřazení řadiče, kterým
chceme motor ovládat.
Parametr port určije port řadiče, ke kterému je
motor připojen. Řadič má dva porty,
StepperMotorDriver.STEPPER_PORT_A a
StepperMotorDriver.STEPPER_PORT_B.
boolean isMotorActive()
Zjištění stavu motoru. Metoda vrací logickou
hodnotu:
true Motor se otáčí.
false Motor stojí nebo se otáčí v nekonečné
smyčce.
- 76 -
Skripta Mechatronic Education
boolean set(
)
int speed,
Nastaví rychlost a směr otáčení, krokování
a počet kroků:
int direction,
Parametr speed – rychlost:
int stepType,
StepperMotor.SPEED_STOP
Motor stojí
int stepCount
StepperMotor.SPEED_7_5HZ
7,5 Hz
StepperMotor.SPEED_15HZ
15 Hz
StepperMotor.SPEED_30HZ
30 Hz
StepperMotor.SPEED_60HZ
60 Hz
StepperMotor.SPEED_120HZ
120 Hz
StepperMotor.SPEED_250HZ
250 Hz
StepperMotor.SPEED_400HZ
400 Hz
StepperMotor.SPEED_650HZ
650 Hz
StepperMotor.SPEED_1000HZ 1 kHz
Parametr direction – směr otáčení:
StepperMotor.DIRECTION_CLOCKWISE
StepperMotor.DIRECTION_
COUNTERCLOCKWISE
Parametr stepType – krokování:
StepperMotor.STEP_HALF Poloviční krok.
StepperMotor.STEP_FULL
Plný krok.
Parametr stepCount udává počet kroků. Pokud je
nastaven na hodnotu 0, otáčí se motor
kontinuálně (nekonečná smyčka).
Metoda vrací v případě
rychlosti hodnotu false.
špatně
nastavené
- 77 -
Skripta Mechatronic Education
Inicializace řadiče s připojenými dvěma krokovými motory, které se kontinuálně otáčejí proti sobě
s krokovací frekvencí 30 Hz a polovičním krokováním by vypadala takto:
StepperMotorDriver driver = new StepperMotorDriver();
StepperMotor motorA = new StepperMotor(driver,
StepperMotorDriver.STEPPER_PORT_A);
StepperMotor motorB = new StepperMotor(driver,
StepperMotorDriver.STEPPER_PORT_B);
motorA.set(StepperMotor.SPEED_30HZ, StepperMotor.STEP_HALF,
StepperMotor.DIRECTION_CLOCKWISE, 0);
motorB.set(StepperMotor.SPEED_30HZ, StepperMotor.STEP_HALF,
StepperMotor.DIRECTION_COUNTERCLOCKWISE, 0);
Následující příklad StepperMotorExample slouží k ovládání jednoho krokového motoru
připojeného na portu A. K řízení slouží tlačítka na jBotBrainu II (výchozí rychlost je 0, takže motor
po zapnutí stojí):
– Tlačítko S1 slouží k přepínání mezi nekonečným krokováním a zadaným počtem kroků
(v našem případě 40).
– Tlačítko S2 přepíná mezi polovičním a plným krokováním.
– Tlačítko S3 přepíná směr otáčení motoru.
– Tlačítko S4 slouží ke zvyšování rychlosti. Výchozí rychlost je 0 Hz.
package jBotBrain2.StepperMotorExample;
import jBotBrain2.hw.*;
import jBotBrain2.devices.*;
public class StepeprMotorExampleMain {
public static void main(String[] args) throws InterruptedException {
Led.GREEN1.set(Led.MODE_BLINK, 300);
StepperMotorDriver driver = new StepperMotorDriver();
StepperMotor motor = new StepperMotor(driver,
StepperMotorDriver.STEPPER_PORT_A);
int
int
int
int
direction = StepperMotor.DIRECTION_CLOCKWISE;
speed = 0;
stepping = StepperMotor.STEP_FULL;
count = 0;
Led.RED.on();
while (true) {
Button.waitForPress();
- 78 -
Skripta Mechatronic Education
// Změna směru otáčení
if (Button.S3.isPressed()) {
if (direction == StepperMotor.DIRECTION_CLOCKWISE) {
direction =
StepperMotor.DIRECTION_COUNTERCLOCKWISE;
} else {
direction = StepperMotor.DIRECTION_CLOCKWISE;
}
while (Button.S3.isPressed());
}
// Nastavení krokování
if (Button.S2.isPressed()) {
if (stepping == StepperMotor.STEP_FULL) {
stepping = StepperMotor.STEP_HALF;
} else {
stepping = StepperMotor.STEP_FULL;
}
while (Button.S2.isPressed());
}
// Nastavení rychlosti
if (Button.S4.isPressed()) {
speed++;
if (speed > StepperMotor.SPEED_1000HZ) {
speed = 0;
}
while (Button.S4.isPressed());
}
// Nastavení počtu kroků
if (Button.S1.isPressed()) {
if (count == 0) {
count = 40;
Led.ORANGE.on();
Led.RED.off();
} else {
count = 0;
Led.ORANGE.off();
Led.RED.on();
}
while (Button.S1.isPressed());
}
motor.set(speed, stepping, direction, count);
}
}
}
- 79 -
Skripta Mechatronic Education
4
4.1
Programování pro mobilní telefony
Úvod do J2ME aplikací
Jak se píše v úvodu, Java je jazykem určeným k programování různých zařízení, například
mobilních telefonů. Tak proč naše znalosti Javy nevyužít k vytvoření jednoduchého dálkového
ovládání naší konstrukce?
Nejdříve si popíšeme základní stavební kameny aplikace pro mobilní telefony, později
se seznámíme s prací s Bluetooth rozhraním.
4.1.1
Co budeme potřebovat?
První věcí, kterou budeme potřebovat, je mobilní telefon vybavený Bluetoothem a podporující Javu.
Je dobré si zjistit, kterou verzi MIDP (Mobile Information Device Profile) a CLDC (Connected
Limited Device Configuration) váš telefon podporuje. Třída CLDC definuje JVM pro malá,
převážně bateriově napájená zařízení, MIDP ji rozšiřuje a upravuje profil převážně pro mobilní
telefony. Většina moderních telefonů podporuje MIDP 2.1 a CLDC verze 1.1.
Nejčastěji používanými vývojovými prostředími IDE) jsou Eclipse a NetBeans. Pro vývoj aplikací
pro jBotBrain se používá Eclipse, na programování aplikace pro mobilní telefon použijeme
NetBeans. Je to čistě kvůli osobním preferencím autora článku.
Vývojové prostředí je, stejně jako eclipse, volně ke stažení na www.netbeans.org. IDE je k dispozici
v několika verzích, nás zajímá verze Java, která v sobě obsahuje balík Java ME (Mobile Edition).
4.1.2
Ahoj světe!
První aplikace bude tak trošku podvod, protože nám ji celou vygeneruje počítač, potažmo vývojové
prostředí. Ve spuštěném okně NetBeans klikneme na File → New Project, v levé polovině okna
vybereme Java ME, v pravé pak Mobile Application. Tlačítkem Next se dostaneme na další
obrazovku, která se nás zeptá na název projektu (můžeme zadat například HelloWorld). Důležité je
nechat zaškrtnutý checkbox „Create Hello MIDlet“, který se nám postará o vygenerování ukázkové
aplikace. Tlačítkem Next se dostaneme na poslední obrazovku, kde máme možnost zvolit si
konfiguraci mobilního telefonu, pokud nám nevyhovuje ta výchozí. Posledním krokem je stisknutí
tlačítka Finish, které nám nový projekt vytvoří.
V otevřeném okně můžeme vidět jednoduchý diagram, který ukazuje blokové schéma našeho
nového programu, který hned po spuštění zobrazí formulář „form“.
- 80 -
Skripta Mechatronic Education
Jeho funkčnost si ověříme spuštěním programu v emulátoru (zelené tlačítko Run – F6). Spuštěný
program vypíše na obrazovku telefonu obligátní „Hello World“ a nabídne tlačítko pro ukončení.
Přestože klikací rozhraní NetBeans vývoj aplikací značně ulehčuje, zkusíme si nyní napsat
jednoduchý program ručně, abychom se seznámili se základními principy.
4.1.3
Vypisujeme na displej
Pro druhý program založíme úplně nový projekt. Pojmenujeme jej třeba TestApplication a jediným
rozdílem oproti předchozímu bude, že checkbox „Create Hello MIDlet“ necháme nezaškrtnutý.
Po vytvoření projektu založíme dvě třídy. První z nich bude MainMidlet odvozená od třídy MIDlet.
MIDlet je označení pro mobilní aplikaci, která využívá profil MIDP, o kterém jsem se zmínil
na začátku. Třída MIDlet má definováno několik metod, které musíme implementovat. Třídu
vytvoříme kliknutím pravým tlačítkem na název projektu → New → MIDlet (jako na obrázku),
pojmenujeme ji jako MainMidlet a umístíme do ní následující kód:
import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;
public class MainMidlet extends MIDlet {
Display display;
MyCanvas mc;
Thread mcThread;
public void startApp() {
display = Display.getDisplay(this);
mc = new MyCanvas(this);
mcThread = new Thread(mc);
mc.repaint();
display.setCurrent(mc);
mcThread.start();
}
public void pauseApp() {
}
public void destroyApp(boolean unconditional) {
}
}
- 81 -
Skripta Mechatronic Education
Jak vidíte, třída slouží pouze ke spuštění třídy MyCanvas. Po startu aplikace si vyžádá přístup
k displeji, spustí MyCanvas jako vlákno a nastaví jeho výstup na displej. Ostatní metody můžeme
zatím nechat prázdné.
Z předchozích kapitol víme, že třída spouštěná jako vlákno musí implementovat rozhraní Runnable
s metodou run(). Nejinak tomu bude u naší zobrazovací třídy MyCanvas, která kromě něj ještě
rozšíří výchozí třídu Canvas, díky které získá možnost vykreslování na displej. Třídu Canvas
vytvoříme podobně, jen místo New MIDlet vybereme New Class:
import javax.microedition.lcdui.Canvas;
import javax.microedition.lcdui.Graphics;
public class MyCanvas extends Canvas implements Runnable {
private MainMidlet mid;
private int lastKey;
private int width, height;
public MyCanvas(MainMidlet mid) {
width = getWidth();
height = getHeight();
this.mid = mid;
}
protected void paint(Graphics graphics) {
graphics.setColor(0, 0, 0);
graphics.fillRect(0, 0, width, height);
graphics.setColor(255, 255, 255);
graphics.drawString("Klávesa: "+lastKey, width/2, 0,
Graphics.HCENTER|Graphics.TOP);
}
public void run() {
while (true) {
repaint();
try { Thread.sleep(50); } catch (Exception e) { }
}
}
protected void keyPressed(int Code) {
lastKey = Code;
// zero (0) for exit
if (Code == 48) {
mid.destroyApp(false);
mid.notifyDestroyed();
}
}
protected void keyReleased(int Code) {
lastKey = 0;
}
}
- 82 -
Skripta Mechatronic Education
Celý kód je opět velice jednoduchý. V konstruktoru si uložíme instanci MainMidletu, abychom jej
mohli později vypnout a zjistíme šířku a výšku displeje v pixelech.
Metoda run pak už jen v nekonečném cyklu s prodlevou 50 ms (jak je ta Java krásná – na prodlevu
použijeme úplně ten stejný příkaz jako u jBotBrainu II) překresluje displej.
Metoda paint() nám pomocí objektu graphics umožní vykreslovat na displej, co si zamaneme.
Pokud se podíváme do dokumentace třídy Graphics nebo pokud v editoru napíšeme graphics.
A chvilku počkáme, můžeme zjistit, jaké metody pro kreslení jsou dostupné – možní nám kreslit
kružnice, přímky či vykreslovat obrázky.
První volání metody setColor(r, g, b) nastaví barvu kreslení na černou, což následně využije
metoda fillRect(x1, y1, x2, y2) pro vykreslení černého pozadí – obdélníku s barevnou výplní přes
celou plochu displeje.
Druhé volání metody setColor změní barvu kreslení na bílou, abychom mohli metodou
drawString(string, x, y, align) vykreslit řetězec s aktuálně stisknutou klávesou. Zajímavý je
především parametr align, který určuje zarovnání vykresleného objektu, tedy bod s nulovými
souřadnicemi. Použitím hodnoty Graphics.HCENTER|Graphics.TOP zajistíme, že se řetězec
zobrazí vycentrovaný a nulová ypsilonová souřadnice středu bude při horním okraji textu.
Metody keyPressed(code) a keyReleased(code) se zavolají vždy, když je stisktnuto (pressed) nebo
uvolněno (released) nějaké tlačítko a vrátí jeho číselný kód.
Po spuštění se nám zobrazí černá obrazovka s bílým textem ukazujícím číselný kód právě stisknuté
klávesy. Klávesa s kódem 48 je nula, tu využijeme pro ukončení aplikace.
Pokud chceme vykreslovat pohyblivý obdélník, musíme si zavést proměnnou x, která bude určovat
jeho x-ovou sourřadnici:
private int x;
V konstruktoru MyCanvas ji musíme za zjištěním rozlišení displeje přiřadit nějakou hodnotu, aby
se obdélník zobrazil na středu (jeho šířka bude 20):
x = width/2-10;
- 83 -
Skripta Mechatronic Education
A nakonec přidat do metody paint kód, který se bude starat o posunování modrého obdélníčku
šipkami 4 a 6 doleva a doprava tak, aby nevyjel z displeje:
graphics.setColor(0, 0, 255);
graphics.fillRect(x, height/2, 20, 20);
if (lastKey == Canvas.KEY_NUM4 && x > 0) {
x -= 5;
} else if (lastKey == Canvas.KEY_NUM6 && x < width-20) {
x += 5;
}
Třída Canvas umožňuje použít konstanty, které zjednodušují přístup ke klávesám, abychom si
jejich číselné kódy nemuseli pamatovat – například hodnota Canvas.KEY_NUM0 je 48 – o tom
se také můžeme přesvědčit v aplikaci, která číselné kódy vypisuje.
Jak vidíte, tvorba aplikací (MIDletů) pro mobilní telefony není nic složitého a se znalostí několika
základních příkazů si můžeme pěkně pohrát.
- 84 -
Skripta Mechatronic Education
4.2
4.2.1
Vytvoření J2ME aplikace pro dálkové ovládání
Část první
Nejdříve si v Netbeans založíme nový projekt, který pojemnujeme třeba jBotControl. Při vytváření
necháme zaškrtnutou možnost „Create Hello MIDlet“, která nám vytvoří základní aplikaci. Hlavní
MIDlet přesuneme do námi vytvořeného balíku application, abychom měli celou aplikaci
přehlednější. Vygenerovaný formulář smažeme a na pracovní plochu si z palety umístěné na pravé
straně prostředí přetáhneme potřebné prvky (najdeme je v Pallete → Displayable), v našem případě
jsou to tři komponenty List:
Pro přehlednost je dobré si objekty pojmenovat stejně jako na výsledném obrázku níže. Ukázková
aplikace je v angličtině, protože jde o jazyk, který se k počítačům náramně hodí a každý správný
programátor by ji měl ovládat.
ApplicationMenu je hlavní menu celé aplikace, které se uživateli zobrazí po spuštění aplikace.
Nabídne možnost ukončit aplikaci nebo spustit vyhledávání Bluetooth zařízení.
Nabídka searchDevices slouží k hledání dostupných zařízení Bluetooth a jejich zobrazení
na displeji. Po kliknutí na zařízení se zobrazí další nabídka, conenctedMenu. Ta umožňuje
odpojení od zařízení a návrat zpět k vyhledaným zařízením nebo otevření Ovladače
(CommanderCanvas).
- 85 -
Skripta Mechatronic Education
Ovladač bude obrazovka vykreslená v grafickém režimu, kterou si naprogramujeme později
(podobně jako v příkladu s posunujícím se čtverečkem v minulém dílu). Přejmenování provedeme
pravým kliknutím na objekt → Properties → Instance Name:
Do připravených nabídek musíme přidat potřebné položky. Položka nabídky (List) se jmenuje
ListElement a najdeme ji v paletě na pravé straně prostředí ve skupině Elements. Položky můžeme
libovolně přetahovat a upravovat jejich popisky.
Kromě položek využijeme ještě tzv. Commands, což jsou příkazy určující chování funkčních
kláves telefonu (typicky OK, zpět, další atd.). Použité položky menu a povelová tlačítka najdete
na následujícím obrázku:
- 86 -
Skripta Mechatronic Education
Posledním krokem vizuálního návrhu bude pospojování objektů, čímž vytvoříme celkovou
strukturu aplikace. Pro propojení elementů slouží šipky, které můžeme natáhnout kliknutím
a tažením myší. První bude vycházet z položky Mobile Device → Started a bude směřovat
k položce applicationMenu. Tím jsme určili, že prvním, co se uživateli po spuštění aplikace zobrazí,
bude hlavní menu aplikace. Podobně pospojujeme i další objekty. Šipka vychází vždy z položky
menu nebo příkazového tlačítka (Command) a směřuje k objektu, na který chceme přejít (zobrazit
na displeji).
4.2.2
Část druhá
Třídy pro práci s Bluetoothem budou umístěny v balíčku bluetooth. V zásadě jde jen o zapouzdření
rozhraní JSR-82 do příjemnějšího kabátku. Výpisy jejich zdrojových kódu zde nebudu uvádět,
můžete si je stáhnout z adresy uvedené v závěru článku.
– Třída BTDiscovery slouží k vyhledání dostupných Bluetooth zařízení. Implementuje
rozhraní DiscoveryListener z JSR-82 a obsahuje tyto metody:
– BTDiscovery(BTDiscoveryListener listener) je konstruktorem celé třídy. Parametrem
se předá BTDiscoveryListener (rozhraní, které implementuje naše hlavní třída a které
se stará o předání informací o nalezených zařízeních).
- 87 -
Skripta Mechatronic Education
– searchDevices() zahájí vyhledávání Bluetooth zařízení.
– stopSearching() ukončí vyhledávání zařízení.
– deviceDiscovered(…) je metoda volaná po nalezení zařízení a předává informace o něm
do hlavní třídy. Metoda je sice kvůli kompatibilitě s rozhraním veřejná, my ji ale
používat nebudeme, je volána automaticky.
– inquiryCompleted(int type) je metoda zavolaná po dokončení vyhledávání a platí pro
ni to co v předchozím případě.
–
getUrl(int id) vrací URL Bluetooth zařízení, abychom je mohli použít k sériové
komunikaci.
– BTDiscoveryListener je rozhraní (interface), které se postará o předání informace
o nalezených zařízeních mezi třídou BTDiscovery a naší aplikací. Definuje dvě metody:
– deviceFound(String name, String addr) předává název a adresu právě nalezeného
zařízení.
– discoveryStatusChanged(int status) je metoda volná po změně stavu vyhledávání
(BTDiscovery.SEARCHING, SEARCHING_FINISHED nebo DEVICE_FOUND
pro vyhledávání, konec vyhledávání a konec vyhledávání s nalezenými zařízeními).
– BTSPP je třída zajišťující komunikaci v režimu SPP (Serial Port Profile). Komunikace je
pouze jednosměrná (posílání dat z mobilního telefonu do zařízení), protože přijímat data
zatím nepotřebujeme. Obsahuje tyto metody:
– BTSPP(String url) se spojí s Bluetooth zařízením (adresa je dána parametrem url)
profilem BTSPP.
– close() ukončí spojení se zařízením.
– send(byte b), send(byte[] b) a send(String s) slouží k odeslání jednoho bajtu (znaku),
pole bajtů nebo textového řetězce do zařízení.
4.2.3
Část třetí
Ještě před propojením s „vizuální“ částí aplikace si vytvoříme Ovladač, což bude obrazovka
sloužící k posílání příkazů do robota. Směr jízdy budeme ovládat tlačítky 2, 4, 6, 8 a 5 a celá
obrazovka bude velice jednoduchá. Třídu pojmenujeme CommanderCanvas a umístíme ji
do balíku application:
package application;
import javax.microedition.lcdui.*;
import bluetooth.*;
public class CommanderCanvas extends Canvas implements Runnable,
CommandListener {
private boolean isRunning = true;
private MainMIDlet fParent;
private Command backCmd;
private BTSPP comm;
private String cmd = "stop";
- 88 -
Skripta Mechatronic Education
public CommanderCanvas(MainMIDlet m, BTSPP comm) {
fParent = m;
backCmd = new Command("back", Command.BACK, 0);
this.addCommand(backCmd);
this.setCommandListener(this);
this.comm = comm;
}
public void start() {
Thread runner = new Thread(this);
runner.start();
}
public void run() {
while (isRunning) {
repaint();
}
}
public void commandAction(Command c, Displayable d) {
if (c == this.backCmd) {
fParent.getDisplay().setCurrent(fParent.getConnectedMenu());
}
}
protected void keyPressed(int code) {
switch (code) {
case KEY_NUM2:
comm.send("FF\n");
cmd = "forward";
break;
case KEY_NUM5:
comm.send("SS\n");
cmd = "stop";
break;
case KEY_NUM8:
comm.send("BB\n");
cmd = "backward";
break;
case KEY_NUM4:
comm.send("BF\n");
cmd = "left";
break;
case KEY_NUM6:
comm.send("FB\n");
cmd = "right";
break;
}
}
- 89 -
Skripta Mechatronic Education
protected void paint(Graphics g) {
// Barva pozadí
g.setColor(0x000000);
g.fillRect(0, 0, getWidth(), getHeight());
// Titulek
g.setColor(0xff0000);
g.setFont(Font.getFont(Font.FACE_SYSTEM, Font.STYLE_BOLD,
Font.SIZE_LARGE));
g.drawString("jBot control 1.0", 2, 2, Graphics.TOP |
Graphics.LEFT);
// Ovládání
g.setFont(Font.getDefaultFont());
g.setColor(0x00ff00);
g.drawString("Command: " + cmd, 2, 40, Graphics.TOP |
Graphics.LEFT);
g.drawString("Commands: 2, 4, 6, 8, 5 = stop ", 2, 60, Graphics.TOP
| Graphics.LEFT);
}
}
V konstruktoru je třídě předán rodič, v našem případě objekt třídy MainMIDlet a objekt třídy
BTSPP zajišťující komunikaci. Dále je vytvořen příkaz back (zpět) pro návrat do předchozí
nabídky.
Metoda start() slouží ke spuštění Canvasu jako vlákna.
V metodě run() se Canvas v nekonečné smyčce překresluje.
CommandAction() se stará o provádění příkazů, v našem případě je to jen tlačítko Back, sloužící
k návratu do nabídky připojeného zařízení (connectedMenu).
Nejdelší metoda, keyPressed(), pouze odchytává stisknuté tlačítka, ukládá poslední směr jízdy
robota a posílá příkazy třídou BTSPP.
Poslední metoda, paint() slouží k vykreslení krátké nápovědy k ovládání robota a posledního
odeslaného příkazu.
- 90 -
Skripta Mechatronic Education
4.2.4
Propojení všech částí dohromady
Nakonec musíme vše propojit dohromady, tedy donutit MainMIDlet, aby spolupracoval s třídami
z balíčku bluetooth a aby v případě potřeby spustil Ovladač. K tomu bude nutné upravit zdrojový
kód MainMIDletu přepnutím na záložku „Code“. Nebudu zde uvádět výpis celé třídy, protože ta je
díky spoustě vygenerovaných metod poměrně rozsáhlá.
První úpravou bude import tříd z balíčku bluetooth, implementace rozhraní BTDiscoveryListener
a definování několika proměnných:
import bluetooth.*;
public class MainMIDlet extends MIDlet implements CommandListener,
BTDiscoveryListener {
private boolean midletPaused = false;
private BTDiscovery discovery;
private BTSPP comm;
private CommanderCanvas btMid; // Ovladač (Commander) pro posílání
příkazů k řízení robota
Dále potřebujeme přiřadit některým položkám menu a tlačítkům jiné akce než jen přechod mezi
obrazovkami. To můžeme udělat buď definováním nových metod (toto řešení by bylo čistší při
použití většího množství příkazů) nebo přímým vepsáním do vygenerovaného kódu. Použijeme
druhou možnost, a proto upravíme následující vygenerované metody (vždy tak, že metodu
rozbalíme tlačítkem s ikonkou + a kód vpíšeme do volného místa označeného „write pre/post-action code here“). Doplněné příkazy jsou vyznačeny tučně:
public void commandAction(Command command, Displayable displayable) {
if (displayable == applicationMenu) {
if (command == List.SELECT_COMMAND) {
applicationMenuAction();
}
} else if (displayable == connectedMenu) {
if (command == List.SELECT_COMMAND) {
connectedMenuAction();
} else if (command == disconenctAndBackCommand) {
// Odpojení a návrat na hlavní menu
comm.close();
comm = null;
discovery = null;
switchDisplayable(null, getApplicationMenu());
}
} else if (displayable == searchDevices) {
if (command == List.SELECT_COMMAND) {
searchDevicesAction();
} else if (command == backFromSearchingCommand) {
discovery.stopSearching();
switchDisplayable(null, getApplicationMenu());
} else if (command == stopSearchingCommand) {
discovery.stopSearching();
}
}
}
- 91 -
Skripta Mechatronic Education
public void searchDevicesAction() {
String __selectedString =
getSearchDevices().getString(getSearchDevices().getSelectedIndex());
// Připojí se k vybranému zařízení
getSearchDevices().setTitle("Connecting…");
discovery.stopSearching();
comm = new
BTSPP(discovery.getUrl(getSearchDevices().getSelectedIndex()));
getConnectedMenu().setTitle("Connected: "+__selectedString);
switchDisplayable(null, getConnectedMenu());
}
public void connectedMenuAction() {
String __selectedString =
getConnectedMenu().getString(getConnectedMenu().getSelectedIndex());
if (__selectedString != null) {
if (__selectedString.equals("Open commander :-)")) {
// Spustí Ovladač pro posílání příkazů
this.startCommanderCanvas();
}
}
}
A nakonec do třídy přidáme tyto metody (dvě z nich jsou vygenerovány automaticky, protože je
zahrnuje rozhraní BTDiscoveryListener):
public void discoveryStatusChanged(int status) {
if (status == BTDiscovery.SEARCHING_FINISHED) {
this.getSearchDevices().setTitle("Searhing finished.");
}
}
public void deviceFound(String name, String address) {
this.getSearchDevices().append(name, null);
}
private void startCommanderCanvas() {
Display d = Display.getDisplay(this);
btMid = new CommanderCanvas(this, comm);
btMid.start();
d.setCurrent(btMid);
}
První metoda, discoveryStatusChanged(), je volána po změně stavu vyhledávání zařízení. Pokud
je vyhledávání ukončeno, změníme titulek obrazovky. Metoda deviceFound() přidá do seznamu
nalezených zařízení další prve a metoda startCommanderCanvas() slouží ke spuštění Ovladače
(třída CommanderCanvas) a jeho zobrazení na displeji telefonu.
Celou aplikaci můžeme spustit pomocí tlačítka Run (F6). Zdrojové kódy najdete v příloze.
- 92 -
Skripta Mechatronic Education
5
Závěr
Pokud se se znalostmi získanými v těchto skriptech nespokojíte, může vám posloužit dokumentace
tříd jBotBrainu II, kterou najdete pod položkou Java API Documentation v nabídce Start → C-Bot
Development Environment, případně v adresáři, kde se vývojové prostředí nainstalovalo. Jde
o HTML výstup dokumentačních komentářů javadoc.
Kromě toho můžete sáhnout po učebnici jazyka Java jako takového, vřele doporučuji knihu Java
pro zelenáče1.
1
VIRIUS, Miroslav. Java pro zelenáče. 2. upravené vydání. Praha : Neocortex, 2005. 268 s.
ISBN 80-86330-17-6.
- 93 -

Podobné dokumenty

ALBATROS D.ll (LVG)

ALBATROS D.ll (LVG) maxrychlost 164 km/h, vystup do 4500 m za 37 minut, vyzbroj dva kulomety LMG 08/15 raze 7.92 mm.

Více

Objektov↓ orientovan← programov£n

Objektov↓ orientovan← programov£n výslovnosti a na konci publikace je zařazen oboustranný slovníček.

Více

Programování Lego robotů pomocí NQC

Programování Lego robotů pomocí NQC V programu je jeden příkaz repeat() uvnitř druhého. Tuto konstrukci nazýváme vnořený cyklus. Můžete do sebe vkládat repeat cykly, jak se Vám zlíbí. Pouze dávejte pozor na správné uzávorkování a ods...

Více

závěrečné práci.

závěrečné práci. 2.6. Řídící software na PC Zde je výběr programovacích jazyků mnohem větší. Používají se vyšší programovací jazyky, protože v assembleru se ručně programují již pouze části operačních systémů a ov...

Více

Významné zdroje http:// java.sun.com Historie

Významné zdroje http:// java.sun.com Historie ● v závorkách je specifikace formálního parametru (String[] args), který zpočátku nevyužijeme ■ zdrojový soubor musí mít jméno shodné se jménem veřejné třídy a příponu .java, tedy PrvniProgram.java...

Více

Trigger - vjj root page

Trigger - vjj root page • postupně jsou volány všechny handlery od elementu, pro který byla událost vyvolána, až do kořene stromu objektů uživatelského rozhraní

Více

Řízení robota MINDSTORMS NXT pomocí PC PC Controlling of

Řízení robota MINDSTORMS NXT pomocí PC PC Controlling of Možnosti programování se vždy odvíjejí od znalostí programátora a od zadání každého problému. Nejjednodušším způsobem je použití dodaného SW a pomocí grafické prostředí a několika bloků vytvořit ce...

Více

Optické jevy

Optické jevy Parhelia jsou po malém halu nejčastějším halovým jevem. Jde o dvě skvrny, které se nacházejí vpravo a vlevo od Slunce. Někdy mohou být téměř bílá, ale většinou mají duhové barvy, z nichž nejvýrazně...

Více

Návod na obsluhu (30. května 2016 / 6,71 MB)

Návod na obsluhu (30. května 2016 / 6,71 MB) Opacimeter AT 605 LCS 2400 od verze software – 2.00 CZ (instalace z USB DISKU)

Více

FC 51 Danfoss

FC 51 Danfoss Instalaci, spuštění a údržbu smí provádět pouze kvalifikovaná osoba. Pokud by instalaci, spuštění a údržbu neprováděla kvalifikovaná osoba, hrozí nebezpečí smrti nebo vážného úrazu. Vysoké napětí M...

Více