Shuichi Machida's Weblog

« [Sun SPOT でリモコンカーを作ろ... | メイン | [Sun SPOT(13)] Sun... »

http://blogs.sun.com/machida/date/20080228 2008年 2月 28日 木曜日

[Sun SPOT Demo(1)] 距離センサー(Distance Sensor)を使ってみる。

最近のプレゼンで使っているネタですが、Sun SPOTと距離センサーを使った簡単なデモをご紹介します。今回のターゲットは、

  • Duke人形とセンサー間の距離を計測
  • 計測結果をホストPC上のGUIにリアルタイム表示

です。

# こんなイメージです

 

距離センサーは、ロボット工作などでもよく使われている SHARP GP2D12 を使用します。


GP2D12はアナログ電圧出力タイプで、測定距離10cm~80cmの範囲で距離に応じた電圧値を出力します。また、マニュアルによると最大消費電力は50mA程で、コネクタの外観と出力特性はこんな感じです↓


今回は、この距離センサーをSun SPOTにつないで、Vo(出力)から読み取った電圧値を距離に変換してホストPCに無線で送信し、GUI上でリアルタイムに表示すればよいわけです。

配線は次のようになります。今回は、Sun SPOTが供給する+5V電源を使用することにします。


。。。

 

完成です!(下の写真ではブレッドボードを使って配線していますが、距離センサーからの3本の線は上図のようにはSun SPOTに直接配線して大丈夫です)


ではいよいよデモの実行です。ホストPC上のGUIを起動して、Sun SPOTの電源を入れてみます。そしてDukeを前後に移動させると。。

。。。

Dukeが動きました :-)



。。。

Sun SPOT上で動作するアプリケーションは非常に単純です。メイン部分は 携帯電話アプリでおなじみの、Java ME MIDletベースです。

package com.sun.jp.sunspot.demos.distance;

import com.sun.spot.sensorboard.EDemoBoard;
import com.sun.spot.util.Utils;
import java.io.IOException;
import javax.microedition.midlet.MIDlet;
import javax.microedition.midlet.MIDletStateChangeException;

public class DistanceSensorDemoSpot extends MIDlet {
  private static final String MESSAGE_DISTANCE = "DISTANCE";

  DistanceSensor sensor;    // 距離計測用クラス
  DatagramSender sender;    // データ送信用クラス

  protected void startApp() throws MIDletStateChangeException {
    try {
      initAndRun();
    } catch (IOException ex) {
      ex.printStackTrace();
    }
  }    
    
  private void initAndRun() throws IOException {
    // アナログ入力ピンA0のバインド
    sensor = new DistanceSensor(EDemoBoard.A0);
    // 通信プロトコル、出力パワー、最大ホップ数を指定
    sender = new DatagramSender("radiogram://broadcast:170", 31, 3);        

    while (true) {
      try {
        // 距離データの取得
        String distance = sensor.getValue();
        // ホストPCへのデータ送信
        sender.send(MESSAGE_DISTANCE + "," + distance);
                
        Utils.sleep(200L);
      } catch (Exception ex) {
        ex.printStackTrace();
      }
    }
  }
    
  protected void pauseApp() {
  }

  protected void destroyApp(boolean arg0) throws MIDletStateChangeException {
  }
}

DistanceSensorは距離計測クラスです。IScalarInputインスタンスのgetValue() メソッド呼び出しだけで、簡単にアナログピンに接続されたセンサーからの電圧値をA/D変換後のデジタル値として取得できます。なお、電圧値から距離を計算している部分は私がマニュアルに載っている特性のグラフから出したもので、あまり正確ではないです。また、アナログ入力は変動が大きいので、より安定した距離を測定するためには、数回測定した値の平均値を取るなどする必要があると思います。

package com.sun.jp.sunspot.demos.distance;

import com.sun.spot.sensorboard.EDemoBoard;
import com.sun.spot.sensorboard.io.IScalarInput;
import java.io.IOException;

public class DistanceSensor {
  private static final float MAX_VOLTAGE = 3.0f;
    
  private IScalarInput input;
  private int range;
    
  public DistanceSensor(int pinId) throws IOException {
    input = EDemoBoard.getInstance().getScalarInputs()[pinId];        
    range = input.getRange();        
    System.out.println("DistanceSensor init: range=" + range);
    }
    
    public String getValue() throws IOException {
        int value = input.getValue();
        float voltage = (float)value / range * MAX_VOLTAGE;
        System.out.println("A/D value -> " + value + ", voltage -> " + voltage);
        
        // calculates the distance
        String distance = "-1";
        float d = 23.333f / (voltage - 0.236f) - 0.420f;
        if (d >= 10 && d <= 80) {
            distance = Integer.toString((int)d);
        }
        
        return distance;
    }    
}

データ送信部分も非常に単純です。

package com.sun.jp.sunspot.demos.distance;

import com.sun.spot.io.j2me.radiogram.RadiogramConnection;
import com.sun.spot.peripheral.ISpot;
import com.sun.spot.peripheral.Spot;
import java.io.IOException;
import javax.microedition.io.Connector;
import javax.microedition.io.Datagram;
import javax.microedition.io.DatagramConnection;

public class DatagramSender {
    private DatagramConnection conn;
    
    public DatagramSender(String protocol, int power, int maxHops) throws IOException {
        ISpot spot = Spot.getInstance();
        spot.getRadioPolicyManager().setOutputPower(power);
        conn = (DatagramConnection)Connector.open(protocol);
        ((RadiogramConnection)conn).
                setMaxBroadcastHops(maxHops);             
    }

    public void send(String message) throws IOException {
        Datagram datagram = conn.newDatagram(conn.getMaximumLength());
        datagram.writeUTF(message);
        conn.send(datagram);
    }    
}

今回は高機能なアナログセンサーを使ったので自分で回路を組む必要はなかったのですが、時にはちょっとした回路を組む必要もあるかと思います。ただ、ハードウェア的につなげてしまえば、Sun SPOTのプログラムから見た場合は IScalarInput の getValue()メソッド呼び出しだけで値を取得できますので、非常に簡単です。

。。。

GUI の 3D表示部分(Java 3D使ってます)のソースコードは、通信部分以外は普通のJava SEプログラミングなので省略します。。

# 実はSun SPOT側のプログラムは20分ぐらいでできたのですが、距離センサーの表示部分を少し凝ったためにGUI側は3時間ぐらいかかりました。。

投稿されたコメント:

コメント
  • HTML文法 不許可

Valid HTML! Valid CSS!

This is a personal weblog, I do not speak for my employer.