用Java控制樂高機器人

用Java控制樂高機器人
文∕趙英傑

本文將使用Lego Mindstorms機器人套件與leJOS實作一個碰碰車。這台小車運用兩個碰撞感測器(銜接在RCX的接頭1及接頭3),以及兩個馬達(銜接在A與C接頭),如下圖所示:

樂高碰碰車

碰碰車運作的影片收錄在筆者的《碼上就會:Flash 8 動畫設計寶典》書籍光碟。當RCX的Run按鈕被按下時,碰碰車會持續前進;若左邊(接在接頭1的)碰撞感測器碰到東西時,碰碰車會先後退1秒鐘,然後在原地向右旋轉1.5秒後,再次向前行走。

使用Behavior介面

leJOS提供了一個稱為Behavior(行為)的介面(完整合法名稱:josx.robotics.Behavior),讓我們定義機器人元件的行為(例如:馬達向前進、碰撞感測器撞到東西的反應…),並撰寫出易於維護和擴充的機器人Java程式。

用Behavior定義行為後,再透過另一個Arbitrator(仲裁者)類別(完整合法名稱:josx.robotics.Arbitrator)來決定各個行為的先後執行順序。

底下先說明Behavior的方法,並撰寫碰碰車的一些行為,再說明Arbitator類別:

  • boolean takeControl():傳回代表是否讓此行為掌控機器人動作的布林值;或者說,是否要啟動此行為程式。
  • void action():行為被啟動之後所要執行的程式。
  • void suppress():事件程式執行過程中,若有另一個等級更高的事件被觸發,這個方法將被自動執行,以便取消當前執行的行為。

底下是採用Behavior介面撰寫的碰撞偵測程式。當銜接在S1接頭的感應器傳回true時,action()方法將被執行,控制馬達倒退及原地旋轉:

import josx.robotics.*;
import josx.platform.rcx.*;

public class HitS1 implements Behavior {
 public boolean takeControl() {
   // 傳回S1接頭的偵測值
   return Sensor.S1.readBooleanValue();
 }

 public void suppress() {
   Motor.A.stop();
   Motor.C.stop();
 }

 public void action() {
   // 後退
   Motor.A.backward();
   Motor.C.backward();
   try {
     // 持續1秒
     Thread.sleep(1000);
   } catch (Exception e) {
   }
   /* A(左邊的)馬達前進
      C(右邊的)馬達仍舊後退
      讓機器人在原地向右轉    */
   Motor.A.forward();
   try {
     // 持續1.5秒
     Thread.sleep(1500);
   } catch (Exception e) {
   }
  }
}

我們可以運用相同的程式結構,輕易地撰寫機器人的其他行為,例如,底下是感測銜接在S3(右邊)的碰撞感測器的行為程式:

import josx.robotics.*;
import josx.platform.rcx.*;

public class HitS3 implements Behavior {
  public boolean takeControl() {
   return Sensor.S3.readBooleanValue();
  }

  public void suppress() {
   Motor.A.stop();
   Motor.C.stop();
  }

  public void action() {
   // 後退
   Motor.A.backward();
   Motor.C.backward();
   try {
     // 持續1秒
     Thread.sleep(1000);
   } catch (Exception e) {
   }
   /* C(右邊的)馬達前進
      A(左邊的)馬達仍舊後退
	  讓機器人原地向左轉     */
   Motor.C.forward();
   try {
     // 持續1.5秒
     Thread.sleep(1500);
   } catch (Exception e) {
   }
  }
}

下面是讓機器人的左右兩邊馬達前進的程式。在一般的狀態下,我們希望這個機器人能持續前進,所以把takeControl()方法的傳回值設定成true,讓主程式一開始就先執行這個行為裡的action()方法

import josx.robotics.*;
import josx.platform.rcx.*;

public class DriveForward implements Behavior {

  public boolean takeControl() {
   return true;
  }

  public void suppress() {
   Motor.A.stop();
   Motor.C.stop();
  }

  public void action() {
   Motor.A.forward();
   Motor.C.forward();
  }
}

使用Arbitator類別決定各個行為的執行時機

Arbitator類別的建構函數能接收所有Behavior物件,並將它們存放在陣列中;位於陣列越後面的元素,其執行的優先權也越高。例如,假設S1和S3接頭的感測器同時被觸發,HitS3的action()方法將被執行。建立收集了所有Behavior物件的陣列後,再呼叫start()方法,即可啟動Arbitator的執行緒開始運行程式。

import josx.robotics.*;

public class BumperCar {
  public static void main(String [] args) {
   // 建立行為物件
   Behavior b1 = new DriveForward();
   Behavior b2 = new HitS1();
   Behavior b3 = new HitS3();
   // 把所有行為物件存入bArray陣列
   Behavior [] bArray = {b1, b2, b3};
   // 建立Arbitator物件,並傳遞bArray給它。
   Arbitrator arb = new Arbitrator(bArray);
   arb.start();
  }
}

將上面四段程式命名儲存成HitS1.java, HitS3.java, DriveForward.java及BumperCar.java,並透過lejosc指令編譯後,最後執行lejos指令上傳程式到RCX,即可進行測試。

改良碰撞感測程式

上面的HitS1與HitS3類別(偵測左、右感測器的類別)之間,僅有少部分不同,因此其實我們可以將這兩個類別合併成一個,如下所示:

import josx.robotics.*;
import josx.platform.rcx.*;

class CheckSensor implements Behavior {
 private int sensorNum;
 // 建立兩個「常數」,存放感測器接頭的編號。
 static final int S1 = 1;
 static final int S3 = 3;
 // 從建構函數決定要檢測的感測器
 CheckSensor (int sensorNum) {
  this.sensorNum = sensorNum;
 }
 public boolean takeControl() {
  boolean s = false;
  if (sensorNum == S1) {
   s = Sensor.S1.readBooleanValue();
  } else if (sensorNum == S3) {
   s = Sensor.S3.readBooleanValue();
  }
   return s;
  }
  public void suppress() {
   Motor.A.stop();
   Motor.C.stop();
  }
  public void action() {
   Motor.A.backward();
   Motor.C.backward();
   try {
     Thread.sleep(1000);
   } catch (Exception e) {
   }
   if (sensorNum == S1) {
     Motor.A.forward();
   } else if (sensorNum == S3) {
     Motor.C.forward();
   }
   try {
     Thread.sleep(1500);
   } catch (Exception e) {
   }
 }
}

修改行為程式後,主程式當然也要跟著改變。底下是運用上面的CheckSensor類別的主程式碼:

import josx.robotics.*;

public class BumperCar2 {
  public static void main(String [] args) {
   Behavior b1 = new DriveForward();
   // 檢測S1接頭的碰撞感測器
   Behavior b2 = new CheckSensor(CheckSensor.S1);
   // 檢測S3接頭的碰撞感測器
   Behavior b3 = new CheckSensor(CheckSensor.S3);
   Behavior [] bArray = {b1, b2, b3};
   Arbitrator arb = new Arbitrator(bArray);
   arb.start();
  }
}

重新編譯並上傳程式到RCX,一台簡易的樂高碰碰車就完成了!

Posts created 468

9 thoughts on “用Java控制樂高機器人

  1. 好贴
    我有个问题????请帮忙
    我的CODE , code 是关于lejo 沿着黑线走,但是 黑线上有黄点还有绿点
    lejo 当他碰到黄点和绿点时需要停下

    (I have codes about the lejo fellow the black line , there are some yellow and green dots on the black line ,when the lejo meet those dots ,it should stop ,but my code only work fellow thw line ,but can not stop on the dots .)

  2. 不好意思 請問一下
    我執行你的 合併的程式
    一開始 只會一直左轉
    不管是碰到哪一邊的碰撞感測器
    也是只會一直左轉
    請問是哪的地方出錯
    可以說一下嗎? 謝嚕

  3. 請檢查馬達的接頭位置,以及程式是否有拼寫錯誤,例如, 判斷條件中的”==”寫成”=”。

  4. 問一下~寫好的java要如何在rcx上執行,且要如何傳到rcx@@因為我嘗試了許多還是沒辦法!!感謝~

  5. I need a driver for my phillips snn6500 wireless netcard
    or smc2632 wireless net card.
    I can`t make them run on linpus linux lite.

    Please help.

    Regards,
    Steftraut

  6. Don’t know why you post such question here, however, I believe you can just google and get it.

    have a nice day!
    jeffrey

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

Related Posts

Begin typing your search term above and press enter to search. Press ESC to cancel.

Back To Top