Shuichi Machida's Weblog

« 前の日(Feb月 26日, 2008年) | 日付別メイン | 次の日(Feb月 28日, 2008年) »

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

[Sun SPOT で外付けLEDを点滅させよう(1)] LEDのつなぎ方を考える。

今回は、マイコン制御の "Hello World" 、 外付けのLEDを点滅させてみたいと思います。一見簡単そうですが、やってみると結構奥が深いです(私は電子回路の専門家ではないので一から勉強しながらやってます)。

# 今回はソード型のLEDを使います(順電圧: 3.3V、電流: 20mA

LEDを点灯させるための回路は例えばこのようになります↓

左側の図だと分かりにくいかもしれませんが、基本的には右の図と同じ意味で、電源と抵抗をつないで回路を作れば電流が流れて点灯します。

ここで、LEDに電源をつなぐ際の注意点を。LEDは流れる電流の量で光の明るさが変わるのですが、特定の電圧以下ではごくわずかな電流しか流れな い(ので当然光らない)という特性があります。順電圧というのはLEDが光るのに必要な電圧で、このとき流れる電流量がLEDの特性としてマニュアルに掲載されています。さらに、LEDに順電圧を超える電圧をかけると、急激に電流の値が増加して簡単に破損してしまいます(例えば順電流3.3VのLEDに10Vをかけるなど)。そこで、たいていの場合は、LEDに電流が流れすぎないようにするために回路に抵抗を追加します

下の写真は、3Vの電池をつないだ状態です(このLEDの順電圧は3.3Vで、3Vの電源の場合は電流が流れすぎる心配が無いので抵抗はつないでいません)

# 当たり前ですが、光ります 


このままだとLEDは光り続けるだけですし、仮にスイッチを付けても手でOn、Offしなければならないので、面白くないです。左図のスイッチと同じ働きをSun SPOTで実現するにはどうすればいいでしょう?

Sun SPOTを含め、マイコンには汎用I/Oポートというインタフェースが用意されていて、I/Oポートの出力をプログラムから制御することで、このI/Oポートに接続した負荷(LEDなど)を駆動することができます。ここで、出力値としてはHigh、Lowの2値を表す電圧をとります(例えば、High(5V)、Low(0V)など)。

一般に、マイコンのI/Oポートに負荷を直接接続して駆動するのには注意が必要です。なぜかというと、I/Oポートに流せる電流の最大値は決まっていて、一般に小さいからです。例えば、DCモータなどは必要な電流量が大きいので、直接接続して駆動することは普通のI/Oポートではできません。最大値を超えると、最悪壊れてしまいます。

電流の流し方には、流す方向によってソースシンクの2種類あり、I/Oポートから流れ出る方向がソース、流れ込む方向がシンクです。それぞれに最大許容電流値が決まっています。

上図のように、例えばソース電流を流す場合には、プログラムからI/Oポートの出力をHighにすると、負荷のもう一方がGND(0V)のため電位差が発生して電流が流れます。このとき、負荷がLEDであれば光ります。一方、シンク電流の場合はI/Oポートの出力をLowにすると、もう一方がVcc(5Vなど)のため電位差が発生して電流が流れます。このように、I/Oポートの電圧を切り替えて、スイッチのように動作させます。

LEDを点滅させる回路のイメージがつかめた所で、Sun SPOTのI/Oポートの出力特性についても見てみましょう。と思いましたが、長くなってきたので続きはまた。

[Sun SPOT(13)] Sun SPOT@OSC 2008 Tokyo/Spring

お知らせです。

今週末 2/29, 3/1 に開催される オープンソースカンファレンス 2008 Tokyo/Spring のサンのブースで Sun SPOT を展示致します!

また、寺田さんGlassFish 加藤さんOpenSolaris のセッションでの講演を予定しております。

是非、お立ち寄り下さい!

 


[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時間ぐらいかかりました。。


Valid HTML! Valid CSS!

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