在樂高機器人上執行Java程式(二)

在樂高機器人上執行Java程式(二)
文∕趙英傑

josx.platform.rcx套件,包含連結與控制感測器、馬達、揚聲器…等等的類別和介面(interface),本文將介紹其中的Motor(馬達)和Sensor(感測器)類別,以及相關的範例程式。完整的類別和介面說明,請參閱leJOS網站的API文件

控制馬達的Motor類別

位於josx.platform.rcx套件裡的Motor類別(完整合法名稱為:josx.platform.rcx.Motor)包含控制RCX上,標示為A, B, C的三個馬達接頭的方法。Motor類別的三個代表A, B, C接頭的靜態變數,就取名叫做A, B, C(相信沒有比這更好的名稱了吧)。

RCX的馬達接頭

每個馬達接頭都可以控制前進(forward)、後退(backward)、停止(stop)和浮動(float)。「浮動」這項功能,若用汽車的排檔來比喻,相當於「打空(N)檔」,代表不輸出電力給馬達,但是讓它能自由轉動。它們的對應方法名稱正是:forward()backward()stop()flt()。馬達的輸出功率可以透過setPower()方法來調整,分成0~7八個等級,數字越大,輸出功率也就越高。相對地,getPower()方法可傳回馬達目前的輸出功率值。

底下的範例程式會讓A和C接頭的馬達不斷前進(直到Run按鈕被按下為止):

import  josx.platform.rcx.*;


public  class MotorTest1 {
  public static void main (String[] arg) 
   throws InterruptedException {
   // 設定輸出功率 
   Motor.A.setPower(1);
   Motor.C.setPower(1);
   // 往前行駛… 
   Motor.A.forward();
   Motor.C.forward();
   // 直到RCX上的"Run"按鈕被按下為止 
   Button.RUN.waitForPressAndRelease();
  }
}

馬達本身並沒有所謂「前進」方向和「後退」方向的區別。執行上述程式後,如果機器人是向後行駛,那只要把馬達的連結線拔起來,反相180度接回去(也就是調換電源的正、負極)就可以了。

底下是另一個Motor類別的測試程式,讓A和C接頭的馬達前進3秒鐘後停止:

import josx.platform.rcx.*;


public class MotorTest2 {
  public static void main (String[] args) 
    throws InterruptedException {
    // 設定輸出功率
    Motor.A.setPower(7);
    Motor.C.setPower(7);
    // 往前行駛
    Motor.A.forward();
    Motor.C.forward();
    // 持續三秒鐘
    Thread.currentThread ().sleep (3000);
    // 停止馬達
    Motor.A.stop();
    Motor.C.stop();
  }
}

如果機器人的馬達直接銜接輪胎的話,您可以把上面兩個停止馬達的stop()敘述,換成flt()讓它在前進三秒鐘之後打空檔,機器人將往前滑行並逐漸減速停止。

讀取感測器狀態的Sensor類別

josx.platform.rcx.Sensor包含讀取RCX上,標示為1, 2, 3的三個感測器接頭狀態的方法,分別用S1, S2和S3常數來代表這三個接頭。

RCX的感測器接頭

樂高機器人有多種感測器介面,RCX可程式積木無法自動偵測,哪個接頭接上了哪一種感測器。因此,我們必須透過setTypeAndMode()方法,設定感測器的類型和模式。josx.platform.rcx.SensorConstants介面,則提供了代表感測器類型與模式的名字(常數),請參閱下表:

SensorConstants類別的「感測器類型」常數與對應的感測器:

  • SENSOR_TYPE_LIGHT:光線感測器
  • SENSOR_TYPE_TOUCH:碰撞(touch)感測器
  • SENSOR_TYPE_TEMP:溫度感測器
  • SENSOR_TYPE_ROT:角度感測器
  • SENSOR_TYPE_RAW:代表所有的感測器

底下則是SensorConstants類別的「感測器模式」常數:

  • SENSOR_MODE_ANGLE:用於角度感測器的角度測量
  • SENSOR_MODE_BOOL:讀取true或false的布林值
  • SENSOR_MODE_DEGC:攝氏溫度值,有效範圍介於-20到70度之間。
  • SENSOR_MODE_DEGF:華氏溫度值,相當於:攝氏溫度 * 9/5 + 32
  • SENSOR_MODE_EDGE:計數脈衝的edge(邊緣),每當脈衝信號改變時,例如,從0變成1或者從1變成0,計數值就加1。
  • SENSOR_MODE_PCT:百分比值,它採用這個公式計算:146-raw/7
  • SENSOR_MODE_PULSE:計數脈衝,只有當脈衝信號從0變成1時,才會計數。
  • SENSOR_TYPE_RAW:傳回0~1023之間的原始(raw),實際上,上面的數值全都是由此「原始」值轉換而成的。

請注意,銜接需要接通電源的感測器時(例如:光線感測器),必須要呼叫activate()方法,代表開啟RCX接頭上的電源。相對地,無須電源的感測器(如:碰撞感測器),要不要呼叫passivate()(代表不通電)都沒關係,因為這是預設值。

下表列出Sensor類別的一些方法,完整的方法請參閱leJOS網站的API文件

  • setTypeAndMode(類型, 模式):設定使用的感測器類型及模式
  • readValue():讀取已經從raw(原始值)轉換成對應的感測器的數值
  • readRawValue ():讀取原始資料值(傳回介於0~1023之間的數值)
  • readBooleanValue():讀取布林值(true或false)
  • activate():使用需要通電的「主動式」感測器
  • passivate():使用不需要通電的「被動式」感測器
  • setPreviousValue (數值):設定感測器的預設值,例如,替某個使用「碰撞感測」的計數器設定10,讓它從第11次碰撞開始算起。
  • addSensorListener(偵聽器):替指定的感測器接頭,添加一個SensorListener(感測器偵聽器),參閱下文說明。

感測器程式的寫法有兩種,一種叫做「輪詢(poll)」,讓程式不斷地檢測每個感測器是否產生變化;另一種比較好的方式稱為「事件偵聽器(event listener)」,程式無須主動偵測每個感測器的狀態:檢測器會在發生變化時自行回報狀態。

底下是「輪詢」類型的程式範例,採用while迴圈不停地偵測接頭1的「碰撞感測器」,一旦它碰到東西(亦即,感測器的值為true),RCX就會發出「嗶(beep)」聲:

import josx.platform.rcx.*;

public class TouchTest1 {
  public static void main (String[] args) 
  throws InterruptedException {
    // 設定S1接頭,採用碰撞感測器,其傳回值類型為「布林」。
    Sensor.S1.setTypeAndMode(
    SensorConstants.SENSOR_TYPE_TOUCH,
    SensorConstants.SENSOR_MODE_BOOL);
    
    // 代表是否碰撞的變數
    boolean hit = false;
    while (true) {
     // 讀取S1接頭的布林值
     hit = Sensor.S1.readBooleanValue();
     // 如果碰到了(傳回true)…
     if (hit) {
       hit =  false;
       // 發出「嗶」聲
       Sound.beep();
     }
     // 暫停3毫秒,
     // 避免此迴圈持續佔用CPU資源。
     Thread.currentThread ().sleep(3);
    }
  }
}

leJOS沿用了Java的「事件偵聽程式(event listener)」技術,如需聆聽感測器的狀態,請在事件處理程序類別中實作(implements)SensorListener介面,並且實作public void stateChanged(Sensor aSource, int aOldValue, int aNewValue)方法SensorListener介面負責接收和處理感測器所產生的事件,而SensorListener類別物件的stateChanged()方法,將會在指定的感測器狀態改變時收到通知。

底下是改用「事件偵聽器」寫法,但是作用和上面的程式一樣的範例:

import josx.platform.rcx.*;

public class TouchTest2 {
  // 處理碰撞感測器事件的類別
  // 實作SensorListener介面
  public static class TouchHandler 
    implements SensorListener {
    // 實作stateChange()方法
    public void stateChanged(Sensor source, 
                int oldValue, int newValue) {
     boolean hit = source.readBooleanValue();
     if (hit) {
       Sound.beep();
     }
    } 
  }
  // 主程式
  public static void main(String[] args) 
    throws InterruptedException {
    // 設定接頭1使用的感測器類型和模式
      Sensor.S1.setTypeAndMode(
      SensorConstants.SENSOR_TYPE_TOUCH,
      SensorConstants.SENSOR_MODE_BOOL);
   
      // 設定接頭1的事件偵聽程式
      Sensor.S1.addSensorListener(new TouchHandler());
   
      // 當"Run"按鈕被按下時,結束程式。
      Button.RUN.waitForPressAndRelease();
    }
}
Posts created 483

One thought on “在樂高機器人上執行Java程式(二)

  1. 请问能举一个感光头的例子么?
    最近在摸索这个~
    如果您方便的话请给我发个邮件~
    有些问题想咨询您~
    谢谢

發佈留言

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

Related Posts

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

Back To Top