21
14-1 藍芽遙控車 14-2 機器人介紹 14-3 傳送命令 14-4 NXT 端程式 14-5 電腦程式 14-6 進階挑戰 14-7 總結

14-1 14-2 14-3 14-4 14-5 14-6 14-7epaper.gotop.com.tw/pdf/AEL010400.pdf · 14-3 表14-1 命令碼與對應動作 編號 變數 狀態 0 stop 停止 1 fwd 前進 2 back 後退 3 left

  • Upload
    others

  • View
    7

  • Download
    0

Embed Size (px)

Citation preview

Page 1: 14-1 14-2 14-3 14-4 14-5 14-6 14-7epaper.gotop.com.tw/pdf/AEL010400.pdf · 14-3 表14-1 命令碼與對應動作 編號 變數 狀態 0 stop 停止 1 fwd 前進 2 back 後退 3 left

14-1 藍芽遙控車

14-2 機器人介紹

14-3 傳送命令

14-4 NXT 端程式

14-5 電腦程式

14-6 進階挑戰

14-7 總結

Page 2: 14-1 14-2 14-3 14-4 14-5 14-6 14-7epaper.gotop.com.tw/pdf/AEL010400.pdf · 14-3 表14-1 命令碼與對應動作 編號 變數 狀態 0 stop 停止 1 fwd 前進 2 back 後退 3 left

14-2

14-1 藍芽遙控車 新版的 LEGO MINDSTORMS NXT 2.0 提供了 Remote Control 介面,讓使用者可

以遙控 NXT。除了 NXT-G 之外,BricxCC 的「Brick Joystick」工具與「NeXT Tools

for Mac」這兩套軟體也有類似的功能。然而透過 leJOS,我們也能自己製作一個

簡易的控制介面從電腦端來遙控 NXT。在開始本專題之前,建議您把第 9 章和第

10 章複習一下。由於設計控制介面會用到 Java 的 AWT 和 Swing 類別,您可以參

考坊間的正規 Java 程式設計書籍。

14-2 機器人介紹 我們將在電腦端設計一個簡單的控制介面,利用藍芽通訊來控制 NXT 機器人。機

器人可藉由收到的指令來執行前進、後退與轉彎的動作。

14-2-1 機器人本體

機器人本體為一般的雙馬達機器人,您可以自行設計或使用本書第 2 章的範例機器

人,如圖 14-1。

圖 14-1 範例機器人

14-3 傳送命令 我們先整理出被遙控的 NXT 機器人所有的動作,包含「前進」、「後退」、「左

轉」、「右轉」還有「停止」,編號整理後如表 14-1:

Page 3: 14-1 14-2 14-3 14-4 14-5 14-6 14-7epaper.gotop.com.tw/pdf/AEL010400.pdf · 14-3 表14-1 命令碼與對應動作 編號 變數 狀態 0 stop 停止 1 fwd 前進 2 back 後退 3 left

14-3

表 14-1 命令碼與對應動作

編號 變數 狀態

0 STOP 停止

1 FWD 前進

2 BACK 後退

3 LEFT 左轉

4 RIGHT 右轉

我們用一個整數型別的變數來代表這些命令,電腦將這個變數傳送給 NXT,NXT

則根據變數值來決定它所要執行的動作,如圖 14-2。例如電腦希望 NXT 前進,則

傳送命令碼「1」給 NXT,NXT 發現接收到的數字是 1,便開始前進。

Master

[命令碼]

Slave

圖 14-2 傳送指令示意圖

14-4 NXT 端程式 NXT 機器人在本專題中扮演 slave 的角色,必須不斷接收、執行命令,NXT 的程式

流程如圖 14-3。由於程式較為複雜,我們將分段說明 NXT 端程式。

開始

等待連線

接收命令

執行命令

圖 14-3 NXT 端程式流程圖

Page 4: 14-1 14-2 14-3 14-4 14-5 14-6 14-7epaper.gotop.com.tw/pdf/AEL010400.pdf · 14-3 表14-1 命令碼與對應動作 編號 變數 狀態 0 stop 停止 1 fwd 前進 2 back 後退 3 left

14-4

14-4-1 宣告變數、等待連線

PART1:首先定義各個命令碼,同時宣告裝置命令的容器「cmd」來接收命令

碼。

12 int STOP = 0, FWD = 1, BACK = 2, LEFT = 3, RIGHT = 4, cmd;

PART2:接著在第 14 行等待藍芽連線,接收到連線要求後在第 15 行建立輸入

串流。

13

14

15

16

LCD.drawString("Waiting...", 0, 0);

NXTConnection connection = Bluetooth.waitForConnection();

DataInputStream dataIn = connection.openDataInputStream();

LCD.drawString("Connected", 0, 1);

14-4-2 處理命令

完成連線後,NXT 用無窮迴圈不斷接收電腦的命令。一開始在第 23 行接收電腦的

命令,接下來從 24 到 48 行判斷命令的類型並執行應有的動作。如果發生了某些狀

況迫使連線中斷就會拋出 IOException 例外,再用 try…catch 結構來抓取例外並結束

程式。

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

try{

while(true)

{

cmd = dataIn.readInt(); //接收命令

if(cmd==STOP) //停止

{

Motor.B.stop();

Motor.C.stop();

}//if

if(cmd==FWD) //前進

{

Motor.B.forward();

Motor.C.forward();

}//if

if(cmd==BACK) //後退

{

Page 5: 14-1 14-2 14-3 14-4 14-5 14-6 14-7epaper.gotop.com.tw/pdf/AEL010400.pdf · 14-3 表14-1 命令碼與對應動作 編號 變數 狀態 0 stop 停止 1 fwd 前進 2 back 後退 3 left

14-5

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

Motor.B.backward();

Motor.C.backward();

}//if

if(cmd==LEFT) //左轉

{

Motor.B.backward();

Motor.C.forward();

}//if

if(cmd==RIGHT) //右轉

{

Motor.B.forward();

Motor.C.backward();

}//if

}//while

} catch(IOException e) {System.exit(1);}

14-4-3 完成程式

綜合以上說明,我們很快就完成 NXT 的程式了,請看<Sample14_1>。它不僅適用

電腦作為 Master 的情況,您如果想用一台 NXT 作為 Master,只要命令碼規格相符

也可以直接套用。

<Sample14_1.java>

01

02

03

04

05

06

07

08

09

10

11

12

13

14

import java.io.*;

import lejos.nxt.*;

import lejos.nxt.comm.*;

class Sample14_1

{

public static void main(String args[])

{

Button.ESCAPE.addButtonListener(new ButtonListener() {

public void buttonPressed(Button b) {System.exit(0);}

public void buttonReleased(Button b) {}

});

int STOP = 0, FWD = 1, BACK = 2, LEFT = 3, RIGHT = 4, cmd; //宣告命令碼

LCD.drawString("Waiting...", 0, 0);

NXTConnection connection = Bluetooth.waitForConnection(); //等待連線

Page 6: 14-1 14-2 14-3 14-4 14-5 14-6 14-7epaper.gotop.com.tw/pdf/AEL010400.pdf · 14-3 表14-1 命令碼與對應動作 編號 變數 狀態 0 stop 停止 1 fwd 前進 2 back 後退 3 left

14-6

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

DataInputStream dataIn = connection.openDataInputStream();//取得輸入串流

LCD.drawString("Connected", 0, 1);

try{

while(true)

{

cmd = dataIn.readInt(); //接收命令

if(cmd==STOP) //停止

{

Motor.B.stop();

Motor.C.stop();

}//if

if(cmd==FWD) //前進

{

Motor.B.forward();

Motor.C.forward();

}//if

if(cmd==BACK) //後退

{

Motor.B.backward();

Motor.C.backward();

}//if

if(cmd==LEFT) //左轉

{

Motor.B.backward();

Motor.C.forward();

}//if

if(cmd==RIGHT) //右轉

{

Motor.B.forward();

Motor.C.backward();

}//if

}//while

} catch(IOException e) {System.exit(1);}

}//main

}//Sample14_1

Page 7: 14-1 14-2 14-3 14-4 14-5 14-6 14-7epaper.gotop.com.tw/pdf/AEL010400.pdf · 14-3 表14-1 命令碼與對應動作 編號 變數 狀態 0 stop 停止 1 fwd 前進 2 back 後退 3 left

14-7

14-5 電腦程式 電腦端程式牽涉到的東西就比較多了,包含視窗介面、事件、物件概念以及 NXT

連線設定。若您沒學過 Java 的視窗程式設計,請不用著急,我們會一步步告訴您如

何設計簡易的視窗介面。首先先看看我們要設計的簡易 NXT 控制介面,如圖 14-4。

圖 14-4 簡易 NXT 控制介面

14-5-1 圖形使用者介面

圖形使用者介面(Graphical User Interface,簡稱 GUI)顧名思義就是圖形化的操作

介面。相較於生硬的序列式程式,例如早期的 MS-DOS,圖形化介面程式的好處是

使用直覺化且方便使用,較為大多數使用者接受。

序列式程式的特色就是程式的動作依照固定的排程執行,使用上比較沒有彈性,下

面是 leJOS 的 PC 工具「nxjflash」執行範例。

C:\Documents and Settings\XP\桌面>nxjflash

Building firmware image.

VM file: C:\Program Files (x86)\leJOS NXJ\bin\lejos_nxt_rom.bin

Menu file: C:\Program Files (x86)\leJOS NXJ\bin\StartUpText.bin

VM size: 52752 bytes.

Menu size: 38016 bytes.

Total image size 91008/94208 bytes.

Page 8: 14-1 14-2 14-3 14-4 14-5 14-6 14-7epaper.gotop.com.tw/pdf/AEL010400.pdf · 14-3 表14-1 命令碼與對應動作 編號 變數 狀態 0 stop 停止 1 fwd 前進 2 back 後退 3 left

14-8

圖形化介面程式的特色就是事件導向(Event-Driven Programming),我們把使用者

的動作當成不同的事件來執行各種動作,也就是說我們必須針對不同事件來定義不

同的處理方式,如圖 14-5。

前進

退後 右轉左轉

圖 14-5 圖形化介面對應的動作

Java 用來設計視窗介面的套件分別有 AWT 和 Swing,這些套件可以讓我們定義各

式各樣的元件,例如按鈕、視窗、文字欄位、滑桿與面板等等,每一種元件都代表

一個類別,我們可以自由定義。我們把元件所對應的類別整理如表 14-2。由於 Java

的視窗介面繁多,我們僅列出在本書中會使用到的套件,有興趣的讀者可以參考正

規的 Java 程式設計書籍。

表 14-2 圖形化元件所對應的類別

元件 AWT 套件 Swing 套件

視窗 Frame JFrame

對話框 Dialog JDialog

按鈕 Button JButton

面板 Panel JPanel

滑桿 Slider JSlider

清單 List JList

標籤 Label Jlabel

Page 9: 14-1 14-2 14-3 14-4 14-5 14-6 14-7epaper.gotop.com.tw/pdf/AEL010400.pdf · 14-3 表14-1 命令碼與對應動作 編號 變數 狀態 0 stop 停止 1 fwd 前進 2 back 後退 3 left

14-9

AWT 和 Swing 套件的關係 AWT(Abstract Window Toolkit)和 Swing 都可以建立與設計視窗元件,但

是為何要作兩套同樣功能的套件?

Sun 公司從 JDK 1.0.2 版開始推出 AWT 套件,使 Java 語言可以設計圖形化

介面,是 Java 的重要的里程碑,然而 AWT 卻引來不少批評,以下是最具爭

議的缺點:

1. 跨平台性極差,違反 Java「一次編寫,到處運行」的精神。

2. 功能薄弱,例如:只有 4 種字型。

3. 所產生的介面不具一流水準。

其缺陷主要根源是 AWT 的介面仰賴作業系統生成,功能受作業系統限制。

後來 JDK 1.2 版後,Sun 推出 Swing 套件取代 AWT,同時 Swing 為了避免

AWT 的弊端,介面改用自行用圖形產生不再依賴作業系統,不但解決了跨

平台問題,也提高設計的自由度。除了 Sun 公司的 AWT 和 Swing 套件之外,

IBM 也有自己開發同性質的套件「SWT(Standard Widget Toolkit)」。

14-5-2 程式架構

我們把電腦端程式的流程圖畫出來,其中最主要的部分是「連線 NXT」和「顯示視

窗」。請看下列分段說明:

開始

失敗顯示錯誤訊息

結束

成功

顯示視窗

連線到 NXT?

圖 14-6 電腦端程式流程圖

Page 10: 14-1 14-2 14-3 14-4 14-5 14-6 14-7epaper.gotop.com.tw/pdf/AEL010400.pdf · 14-3 表14-1 命令碼與對應動作 編號 變數 狀態 0 stop 停止 1 fwd 前進 2 back 後退 3 left

14-10

PART1:首先載入要用到的套件,包含專門用來製作 Java 設計圖形化介面的

AWT 和 Swing 套件。

01

02

03

04

05

06

import lejos.pc.comm.*;

import java.io.*;

import java.awt.*; //AWT視窗套件

import java.awt.event.*; //AWT視窗事件套件

import javax.swing.*; //Swing視窗套件

import javax.swing.event.*; //Swing視窗事件套件

PART2:透過繼承 Swing 套件的 JFrame 類別來建立視窗,在 main 之中利用

本身建立物件。由於 main 前面有 static,表示 main 和類別關係密切,以本身

建立物件時,main 不屬於物件之中,宣告物件的同時會觸發第 60 行的建構

子。

<Sample14_2>的架構如下:

46

47

56

57

99

100

101

102

103

class Sample14_2 extends JFrame //繼承 JFrame

{

//宣告區(48~54行)

public Sample14_2() //建構子

{

//連線到 NXT(58~65行)

//設定視窗(68~73行)

//設定視窗元件(76~97行)

//顯示視窗(99行)

this.setVisible(true);

}//建構子

public static void main(String args[])

{

Page 11: 14-1 14-2 14-3 14-4 14-5 14-6 14-7epaper.gotop.com.tw/pdf/AEL010400.pdf · 14-3 表14-1 命令碼與對應動作 編號 變數 狀態 0 stop 停止 1 fwd 前進 2 back 後退 3 left

14-11

104

105

106

Sample14_2 com = new Sample14_2();

}//main

}//Sample14_2

14-5-3 連線到 NXT

第 50~56 行中把命令碼、NXTConnector 類別的 conn、DataOutputStream 類別的

dataOut 以及各項視窗元件逐一宣告出來,等到觸發建構子時再定義物件。

進入建構子處理的第一件事是建立與 NXT 的連線。第 60 行宣告 NXTConnector

物件並在第 61 行連線到 NXT,同時判斷成功與否;一旦成功,便在第 67 行取得

輸出串流。

50

56

58

59

60

61

62

63

64

65

66

67

int STOP = 0, FWD = 1, BACK = 2, LEFT = 3, RIGHT = 4;

DataOutputStream dataOut;

public Sample14_2() //建構子

{

conn = new NXTConnector();

if(!conn.connectTo("", "", NXTCommFactory.BLUETOOTH))

{

JOptionPane.showMessageDialog(null, "Cannot connect to NXT",

"Error", JOptionPane.ERROR_MESSAGE); //連線失敗訊息

System.exit(1);

}//if

dataOut = conn.getDataOut(); //取得輸出串流

14-5-4 設定視窗

接下來設定視窗相關的參數並定義視窗的行為。程式中的「this」表示物件本身,可

以省略不寫。

Page 12: 14-1 14-2 14-3 14-4 14-5 14-6 14-7epaper.gotop.com.tw/pdf/AEL010400.pdf · 14-3 表14-1 命令碼與對應動作 編號 變數 狀態 0 stop 停止 1 fwd 前進 2 back 後退 3 left

14-12

70

71

72

73

74

75

this.setTitle("COM"); //視窗標題為「COM」

this.setSize(320, 240); //視窗大小為 320×240

this.setResizable(false); //固定視窗大小

this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //視窗被關閉時自動結束程式

this.getContentPane().setLayout(null); //視窗的 Layout Manager為 null

this.setLocationRelativeTo(null); //視窗在螢幕置中

14-5-5 加入視窗元件

電腦螢幕的座標系統一律以左上角為原點(0,0),以向右、向下為正向;同樣的,任

何視窗元件的座標都是以左上角為準。我們將所有按鈕的長寬都設為 100 像素,就

可以求得每個按鈕的座標,如圖 14-7。

前進鍵:(100,0)

後退鍵:(100,100)

右轉鍵:(200,100)

左轉鍵:(0,100)

圖 14-7 按鈕座標示意圖

每個按鈕都是一個物件,我們用 Swing 的 JButton 類別分別建立「前進」、「後退」、

「左轉」、「右轉」四個按鍵。最初從 51~54 行宣告按鈕元件,再從 77 行開始定

義按鈕元件。

以前進按鈕為例,第 78 行建立 JButton 物件,設定按鈕上的文字為「↑」。在 79

行使用 setBounds()方法設定位置和大小,語法為 setBounds(X 座標, Y 座標, 寬,

高)。第 80 行為按鈕加入事件,最後在 81 行把前進按鈕加入視窗之中。之後的後退、

左轉、右轉按鈕依此類推。

Page 13: 14-1 14-2 14-3 14-4 14-5 14-6 14-7epaper.gotop.com.tw/pdf/AEL010400.pdf · 14-3 表14-1 命令碼與對應動作 編號 變數 狀態 0 stop 停止 1 fwd 前進 2 back 後退 3 left

14-13

51

52

53

54

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

098

099

JButton btForward;

JButton btBackward;

JButton btLeft;

JButton btRight;

//前進按鈕

btForward = new JButton("↑"); //宣告 JButton物件

btForward.setBounds(100, 0, 100, 100); //設定大小位置

btForward.addMouseListener(new MouseAction(dataOut, FWD)); //加入滑鼠事件

this.getContentPane().add(btForward); //將按鈕加入視窗

//後退按鈕

btBackward = new JButton("↓");

btBackward.setBounds(100, 100, 100, 100);

btBackward.addMouseListener(new MouseAction(dataOut, BACK));

this.getContentPane().add(btBackward);

//左轉按鈕

btLeft = new JButton("←");

btLeft.setBounds(0, 100, 100, 100);

btLeft.addMouseListener(new MouseAction(dataOut, LEFT));

this.getContentPane().add(btLeft);

//右轉按鈕

btRight = new JButton("→");

btRight.setBounds(200, 100, 100, 100);

btRight.addMouseListener(new MouseAction(dataOut, RIGHT));

this.getContentPane().add(btRight);

14-5-6 定義按鈕事件

按鍵有被壓下、放開兩種動作。以前進按鍵為例,按鍵被壓下時送出前進命令;放

開時送出停止命令。在第 10 章已經提到若要使用事件,必須實作 Listener,和滑鼠

事件有關的 Listener 是 MouseListener 介面。因此我們建立一個類別,命名為

Page 14: 14-1 14-2 14-3 14-4 14-5 14-6 14-7epaper.gotop.com.tw/pdf/AEL010400.pdf · 14-3 表14-1 命令碼與對應動作 編號 變數 狀態 0 stop 停止 1 fwd 前進 2 back 後退 3 left

14-14

MouseAction 來實作 MouseListener 介面,表 14-3 是 MouseListener 介面需要實作的

方法。

表 14-3 實作 MouseListener 介面需要的方法

方法 觸發事件

mousePressed() 滑鼠壓下

mouseReleased() 滑鼠放開

mouseClicked() 滑鼠點擊

mouseEntered() 滑鼠游標移入

mouseExited() 滑鼠游標移出

MouseAction 類別架構如下:

08

09

13

19

31

43

44

45

46

class MouseAction implements MouseListener

{

public MouseAction() {} //建構子

public void mousePressed(MouseEvent e) {…}

public void mouseReleased(MouseEvent e) {…}

public void mouseClicked(MouseEvent e) {}

public void mouseEntered(MouseEvent e) {}

public void mouseExited(MouseEvent e) {}

}//MouseAction

接下來分段說明 MouseAction 類別架構:

PART1:按鍵在送出命令的過程中需要用到輸出串流,因此我們透過建構子來

取得用來傳遞 dataOut 物件以及按鍵所屬的命令碼。

10

11

12

13

14

15

16

17

DataOutputStream dataOut;

int cmd;

public MouseAction(DataOutputStream _dataOut, int _cmd) //建構子

{

dataOut = _dataOut; //取得 DataOutputStream物件

cmd = _cmd; //取得命令類型

} //建構子

Page 15: 14-1 14-2 14-3 14-4 14-5 14-6 14-7epaper.gotop.com.tw/pdf/AEL010400.pdf · 14-3 表14-1 命令碼與對應動作 編號 變數 狀態 0 stop 停止 1 fwd 前進 2 back 後退 3 left

14-15

PART2:當滑鼠壓下或放開時,都要送出一個不同的命令給 NXT 機器人。以

前進按鈕為例,我們將對應的動作列如圖 14-8:

被壓下時→觸發 mousePressed()→送出前進命令→dataOut.writeInt(FWD)

被放開時→觸發 mouseReleased()→送出停止命令→dataOut.writeInt(STOP)

壓下(Press) 放開(Release)

前進 停止

圖 14-8 滑鼠壓下、放開時所要執行的動作

PART3:我們定義的 MouseAction 類別中,利用建構子得到命令碼,以及可用

來傳送命令的 dataOut 物件。第 31 行的 mouseReleased()會在按鍵被壓下時被

觸發,這時就把命令傳送給 NXT,同時為了處理 NXT 可能會突然斷線等等因

素而拋出 IOException 例外,我們用 try…catch 結構來抓取例外。

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

class MouseAction implements MouseListener //滑鼠事件

{

DataOutputStream dataOut;

int cmd;

public MouseAction(DataOutputStream _dataOut, int _cmd)

{

dataOut = _dataOut;

cmd = _cmd;

}//建構子

public void mousePressed(MouseEvent e) //滑鼠壓下事件

{

try{

dataOut.writeInt(cmd); //送出命令

dataOut.flush();

} catch(IOException i) {

Page 16: 14-1 14-2 14-3 14-4 14-5 14-6 14-7epaper.gotop.com.tw/pdf/AEL010400.pdf · 14-3 表14-1 命令碼與對應動作 編號 變數 狀態 0 stop 停止 1 fwd 前進 2 back 後退 3 left

14-16

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

JOptionPane.showMessageDialog(null, "Communication disconnected",

"Error", JOptionPane.ERROR_MESSAGE); //斷線錯誤警告

System.exit(1);

}

}//mousePressed

public void mouseReleased(MouseEvent e) //滑鼠放開事件

{

try{

dataOut.writeInt(0); //送出停止命令

dataOut.flush();

} catch(IOException i) {

JOptionPane.showMessageDialog(null, "Communication disconnected",

"Error", JOptionPane.ERROR_MESSAGE); //斷線錯誤警告

System.exit(1);

}

}//mouseReleased

public void mouseClicked(MouseEvent e) {}

public void mouseEntered(MouseEvent e) {}

public void mouseExited(MouseEvent e) {}

}//MouseAction

PART4:回到<Sample14_2>的建構子,使用 addMouseListener()把定義好的

MouseAction 加入各按鍵中。

58

59

80

86

92

98

102

public Sample14_2()

{

btForward.addMouseListener(new MouseAction(dataOut, FWD));

btBackward.addMouseListener(new MouseAction(dataOut, BACK));

btLeft.addMouseListener(new MouseAction(dataOut, LEFT));

btRight.addMouseListener(new MouseAction(dataOut, RIGHT));

}

Page 17: 14-1 14-2 14-3 14-4 14-5 14-6 14-7epaper.gotop.com.tw/pdf/AEL010400.pdf · 14-3 表14-1 命令碼與對應動作 編號 變數 狀態 0 stop 停止 1 fwd 前進 2 back 後退 3 left

14-17

14-5-7 電腦端程式完成

經過一番激戰後終於完成電腦端程式了,<Sample14_2>的長度也是相當驚人,請小

心輸入別打錯字了。

<Sample14_2.java>

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

import lejos.pc.comm.*;

import java.io.*;

import java.awt.*;

import java.awt.event.*;

import javax.swing.*;

import javax.swing.event.*;

class MouseAction implements MouseListener //滑鼠事件

{

DataOutputStream dataOut;

int cmd;

public MouseAction(DataOutputStream _dataOut, int _cmd)

{

dataOut = _dataOut;

cmd = _cmd;

}//建構子

public void mousePressed(MouseEvent e) //滑鼠壓下事件

{

try{

dataOut.writeInt(cmd); //送出命令

dataOut.flush();

} catch(IOException i) {

JOptionPane.showMessageDialog(null, "Communication disconnected",

"Error", JOptionPane.ERROR_MESSAGE); //斷線錯誤警告

System.exit(1);

}

}//mousePressed

public void mouseReleased(MouseEvent e) //滑鼠放開事件

{

Page 18: 14-1 14-2 14-3 14-4 14-5 14-6 14-7epaper.gotop.com.tw/pdf/AEL010400.pdf · 14-3 表14-1 命令碼與對應動作 編號 變數 狀態 0 stop 停止 1 fwd 前進 2 back 後退 3 left

14-18

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

try{

dataOut.writeInt(0); //送出停止命令

dataOut.flush();

} catch(IOException i) {

JOptionPane.showMessageDialog(null, "Communication disconnected",

"Error", JOptionPane.ERROR_MESSAGE); //斷線錯誤警告

System.exit(1);

}

}//mouseReleased

public void mouseClicked(MouseEvent e) {}

public void mouseEntered(MouseEvent e) {}

public void mouseExited(MouseEvent e) {}

}//MouseAction

class Sample14_2 extends JFrame

{

int STOP = 0, FWD = 1, BACK = 2, LEFT = 3, RIGHT = 4; //宣告命令碼

JButton btForward;

JButton btBackward;

JButton btLeft;

JButton btRight;

NXTConnector conn;

DataOutputStream dataOut;

public Sample14_2()

{

conn = new NXTConnector();

if(!conn.connectTo("", "", NXTCommFactory.BLUETOOTH)) //連線到 NXT

{

JOptionPane.showMessageDialog(null, "Cannot connect to NXT",

"Error", JOptionPane.ERROR_MESSAGE); //連線失敗訊息

System.exit(1);

}//if

dataOut = conn.getDataOut(); //取得輸出串流

//設定視窗

this.setTitle("COM"); //視窗標題為「COM」

Page 19: 14-1 14-2 14-3 14-4 14-5 14-6 14-7epaper.gotop.com.tw/pdf/AEL010400.pdf · 14-3 表14-1 命令碼與對應動作 編號 變數 狀態 0 stop 停止 1 fwd 前進 2 back 後退 3 left

14-19

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

this.setSize(320, 240); //視窗大小為 320×240

this.setResizable(false); //固定視窗大小

this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //視窗關閉時結束程式

this.getContentPane().setLayout(null); //視窗的 Layout Manager為 null

this.setLocationRelativeTo(null); //視窗在螢幕置中

//前進按鈕

btForward = new JButton("↑"); //宣告 JButton

btForward.setBounds(100, 0, 100, 100); //設定大小位置

btForward.addMouseListener(new MouseAction(dataOut, FWD));//加入滑鼠事件

this.getContentPane().add(btForward); //將按鈕加入視窗

//後退按鈕

btBackward = new JButton("↓");

btBackward.setBounds(100, 100, 100, 100);

btBackward.addMouseListener(new MouseAction(dataOut, BACK));

this.getContentPane().add(btBackward);

//左轉按鈕

btLeft = new JButton("←");

btLeft.setBounds(0, 100, 100, 100);

btLeft.addMouseListener(new MouseAction(dataOut, LEFT));

this.getContentPane().add(btLeft);

//右轉按鈕

btRight = new JButton("→");

btRight.setBounds(200, 100, 100, 100);

btRight.addMouseListener(new MouseAction(dataOut, RIGHT));

this.getContentPane().add(btRight);

this.setVisible(true); //顯示視窗

}//建構子

public static void main(String args[])

{

Sample14_2 com = new Sample14_2();

}//main

}//Sample14_2

Page 20: 14-1 14-2 14-3 14-4 14-5 14-6 14-7epaper.gotop.com.tw/pdf/AEL010400.pdf · 14-3 表14-1 命令碼與對應動作 編號 變數 狀態 0 stop 停止 1 fwd 前進 2 back 後退 3 left

14-20

在電腦上輸入 nxjpcc 指令來編譯<Sample14_2>程式。

C:\>nxjpcc Sample14_2.java

接著 NXT 執行<Sample14_1>,請注意 NXT、電腦都要開啟藍芽,且電腦已將 NXT

加入藍芽裝置清單中。最後在電腦上用 nxjpc 指令執行<Sample14_1>程式。

C:\>nxjpc Sample14_2

<Sample14_2>執行後出現如圖 14-9 的圖形化視窗,按下按鈕來遙控 NXT 吧,是不

是非常有成就感呢?

圖 14-9 執行程式後出現的圖形化視窗

Page 21: 14-1 14-2 14-3 14-4 14-5 14-6 14-7epaper.gotop.com.tw/pdf/AEL010400.pdf · 14-3 表14-1 命令碼與對應動作 編號 變數 狀態 0 stop 停止 1 fwd 前進 2 back 後退 3 left

14-21

14-6 進階挑戰 請在 NXT 前方加上超音波感應器來偵測障礙物,除了可透過電腦來控制 NXT

外,並同時以電腦視窗來顯示超音波感應器值,如果 20 公分內出現障礙物則響

起警示音。

14-7 總結 本章教您如何設計 Java 的圖形化介面並透過藍芽來控制 NXT 機器人,內容用到了

藍芽、圖形化介面、事件以及物件概念,可以說是之前所有章節的集大成。您應該

體會到 leJOS 與 NXT 結合之後,不但給使用者高度的揮灑空間,威力更是無窮。

您或許會覺得本章的 NXT 控制介面看起來有點陽春,但是俗話說得好:「萬丈高

樓平地起」。您可以加入更多按鈕來加強機器人的功能,例如夾取物體或投球等等。

甚至您可以在機器人身上裝上小型攝影機來整合機器人視覺運算,這都是可以做得

到的。