Shuichi Machida's Weblog

« 2008年Feb月月 | 月別メイン | 2008年Apr月月 »

http://blogs.sun.com/machida/date/20080428 2008年 4月 28日 月曜日

[Sun SPOT Demo(6)] OLED Display (μOLED-96-G1) を使ってみる。

 ストロベリー・リナックスで超小型のフルカラーOLED(有機EL)ディスプレイモジュールを見つけたので、Sun SPOTのeDemoボードに取り付けてみました。

# OLEDモジュール。かなり小さいです!

# 裏。microSDカードも使えます。

 以前 LCDをつないだ時にも書きましたが、Sun SPOTの eDemoボード上の汎用I/Oピン D0, D1を使うと簡単に非同期シリアル通信(UART)ができます (最大 baud rate は 38400, data 8bits, no parity, 1or2 stop bits)。

# UART で使用するI/Oピン

今回のOLEDモジュールもシリアル接続できるので、Sun SPOTで制御できそうです。ただ、OLEDモジュールは TTLレベル(0-3.3V)とのことで、そのまま Sun SPOTのRx と OLEDモジュールの Tx をつなぐとD0ピンの許容最大電圧 3.0Vを超えてしまいます。このような場合、レベルシフトバッファなどを使って電圧を調整するそうなのですが、抵抗で分圧しても良いみたいですので、今回は抵抗を使います。

# 1KΩと100Ωの抵抗で分圧。電圧計で実際に測ったところ 2.8V程度でしたが、ロジックレベル 'H' として十分認識される範囲なのでOKでしょうか。。

 

早速電子回路の作成です。 OLEDモジュールは最大で100mA以上消費するので、Sun SPOTの5Vでは危なそうなので外部電源を使います。

 # ちょっと拡大。相変わらず半田付けがてきとうです。目が悪すぎて手元が良く見えないせいということにしておきます ;-)

 作成した回路基板がSun SPOTにマウントできるように、裏にはピンヘッダを取り付けています。

 装着。

# 横から見るとこんな感じです。ArshanがUSから持ってきていたディスプレイボードとは違い、不恰好です orz

# まぁ、eProto ボードが手元にないのでしょうがないのですが。。

 。。。

ハードウェアは完成です!ここまでくれば、後は パパッと Javaでプログラムを作成してインストールするだけです。

。。。

電源を入れてみました。

# OLEDのロゴに続いて、、、 

# お約束の?メッセージが表示されました ;-) それにしても、このディスプレイ結構表示が綺麗です。

プログラムはこんな感じです。

#  メイン部分のプログラム(MIDlet)

package org.sunspotworld;

import com.sun.spot.peripheral.ISleepManager;
import com.sun.spot.peripheral.Spot;
import com.sun.spot.util.*;
import javax.microedition.midlet.MIDlet;
import javax.microedition.midlet.MIDletStateChangeException;

public class StartApplication extends MIDlet implements MicroOLEDConstants {
    private IOled oled;  // OLED
    
    protected void startApp() throws MIDletStateChangeException {
        new BootloaderListener().start();
        
        // USBケーブルでPCにつないでいない状態で電源が切れないように、
        // 自動電源管理によるdeep sleepをオフにする
        ISleepManager sleepManager = Spot.getInstance().getSleepManager();
        sleepManager.disableDeepSleep();
        
        // uOLED-96-G1 にアクセスするためのクラスのインスタンスを生成
        oled = new MicroOLED96G1();

        
        // OLED にメッセージを表示
        try {
            oled.clear();
            oled.drawString("Hi!", 0, 0, FONT_8x12, RED);
            oled.drawString("This is", 0, 2, FONT_8x12, GREEN);
            oled.drawString("a Sun SPOT!!", 0, 3, FONT_8x12, BLUE);
        } catch (Exception ex) {
            ex.printStackTrace();
            Utils.sleep(2000L);
        }

        
        while (true) {
            // TODO: ここに処理を追加
            Utils.sleep(2000L);
        }
    }
    
    protected void pauseApp() {
    }
    
    protected void destroyApp(boolean arg0) throws MIDletStateChangeException {
    }
}

IOledは、OLEDモジュールにアクセスするためのインタフェースを定義します。

package org.sunspotworld;

public interface IOled {
    /** OLEDの画面をクリア */
    void clear() throws CommandExecutionException;
    /** column, row で指定された位置に引数で指定された文字列を表示する */
    void drawString(String text, int column, int row, int font, byte[] color) throws CommandExecutionException;
}

package org.sunspotworld;

public interface MicroOLEDConstants {
    // コマンド
    // ここでは、今回実際に使用するもののみ定義
    public static final byte ACK = (byte)0x06;
    public static final byte NAK = (byte)0x15;
    
    public static final byte COMMAND_INIT = (byte)'U';
    public static final byte COMMAND_CLS = (byte)'E';
    public static final byte COMMAND_DRAW_STRING = (byte)'s';
    
    // フォント関連
    public static final byte FONT_5x7 = (byte)0x00;
    public static final byte FONT_8x8 = (byte)0x01;
    public static final byte FONT_8x12 = (byte)0x02;
    
    // 文字列関連
    public static final byte STRING_TERMINATOR = (byte)0x00;

    // 色関連
    public static final byte[] BLACK = {(byte)0x00, (byte)0x00};
    public static final byte[] RED = {(byte)0xF8, (byte)0x00};
    public static final byte[] GREEN = {(byte)0x07, (byte)0xE0};    
    public static final byte[] BLUE = {(byte)0x00, (byte)0x1F};    
    public static final byte[] WHITE = {(byte)0xFF, (byte)0xFF};    
}

 

package org.sunspotworld;

public class CommandExecutionException extends java.lang.Exception {
    public CommandExecutionException() {
    }

    public CommandExecutionException(String message) {
        super(message);
    }
}

MicroOLED96G1 は IOled インタフェースの実装クラスで、OLEDにアクセスするための機能を実装します。なおここでは最小限の機能のみ実装しています(実際、このデバイスはかなり高機能です)。

package org.sunspotworld;

import com.sun.spot.sensorboard.EDemoBoard;
import com.sun.spot.util.Utils;
import java.io.IOException;

public class MicroOLED96G1 implements IOled, MicroOLEDConstants {
    private EDemoBoard demo;

    public MicroOLED96G1() {
        demo = EDemoBoard.getInstance();
        // baud: 38400bps, 8bits, no parity, 1 stop bit
        demo.initUART(EDemoBoard.SERIAL_SPEED_9600, false);
        initialize();
    }
   
    private void initialize() {
        send(COMMAND_INIT);
        try {
            receiveAck();
        } catch (CommandExecutionException ex) {
            ex.printStackTrace();
        }
    }

    public void clear() throws CommandExecutionException {
        send(COMMAND_CLS);
        receiveAck();
    }

   
    public void drawString(String text, int column, int row, int font, byte[] color) throws CommandExecutionException {
        byte[] data = text.getBytes();
        if (data.length > 255)
            throw new IllegalArgumentException("text length out of range: " + data.length);
       
        send(COMMAND_DRAW_STRING);
        send((byte)column);
        send((byte)row);
        send((byte)font);
        for (int i = 0; i < color.length; i++) {
            send(color[i]);
        }
        for (int i = 0; i < data.length; i++) {
            send(data[i]);
        }
        send(STRING_TERMINATOR);
       
        receiveAck();
    }

   
    private void send(final byte data) {
        demo.sendUART(data);
    }

    private byte receive(final long timeout) throws IOException {
        long startTime = System.currentTimeMillis();
        while (true) {
            try {
                byte data = demo.receiveUART();
                return data;
            } catch (IOException ex) {
                if ((timeout > 0) & (System.currentTimeMillis() - startTime) > timeout) {
                    throw ex;
                }
            }
            Utils.sleep(10L);
        }
    }

    private byte receiveAck() throws CommandExecutionException {
        int retry = 0;
        while (retry < 3) {
            Utils.sleep(20L);
            try {
                byte status = demo.receiveUART();
                if (!(status == ACK)) {
                    throw new CommandExecutionException("response -> " + Integer.toHexString(status));
                }
                return status;
            } catch (IOException ex) {
                System.out.println("Error in receiveAck: " + ex);
                retry++;
            }
        }
        throw new CommandExecutionException("No response" );
    }
}

とりあえず動かすことはできましたが、まだこのデバイスの持つ機能をほとんど使っていないので、時間があるときにもう少しいじってみようと思います。


http://blogs.sun.com/machida/date/20080425 2008年 4月 25日 金曜日

[Sun SPOT(23)] Sun SPOT SDK の'nightly builds' と SPOT Manager Tool v3.0 が公開されました。

前回のエントリで、「Sun SPOTのEmulator を試したい場合は SDK Beta プログラムに参加してみてください」と書いたのですが、その2日後ぐらいにフォーラムBlog SPOT Blog でビッグニュースが :-)

  • Sun SPOT Manager Tool v3.0 が公開されました
  • SDKの'nightly builds' がリリースされるようになりました
'nightly builds'  は2~3週間に1度リリースされるみたいですね。

Sun SPOT Manager ToolのURL:

  • http://www.sunspotworld.com/SPOTManager/


是非アクセスしてみてください。

http://blogs.sun.com/machida/date/20080422 2008年 4月 22日 火曜日

[Sun SPOT(22)] Q: 「まだ購入していないけど Emulator を使って Sun SPOTプログラムを試してみたい!」

以前、こちらのエントリ等でSun SPOT SDK のインストールや SPOT Managerツール、エミュレータの使用方法について紹介したのですが、書いた時点ではこれらのツールは Sun SPOT Java Development Kit (つまり実機)を購入頂いた方のみ使用可能ということで、途中からツールの配布URLを削除していました。

フォーラムDavidさんのブログでアナウンスされていますが、最新版の Software-only Beta の配布が始まっております。まだ購入していないけどエミュレータを使ってSun SPOTプログラムを試してみたい!という方は、是非 Beta プログラムに参加してみてください!

参加方法は David のブログを参照してください。ブログにあるアドレスにメールを送ればOKです。メールのSubject(件名)に "SDK Beta" と書くのを忘れずに、とのことです。

ツールに対する改善点やご要望などのフィードバックも、是非よろしくお願いいたします!

ツールのインストールや設定方法は  David のこのエントリでも詳しく紹介されています。


# Sun SPOTアプリケーションをエミュレータで実行中。。。


[Sun SPOT で"デューク神棚(Duke Temple)" を動かそう(3)] 距離センサー(Distance Sensor)で人を検出して扉を開閉する。

前回のエントリで扉の開閉までできましたので、次は神棚に距離センサーを取り付けて、

  • 前に人が立った時に自動的に扉が開く
  • 人が立ち去った時に扉が閉まる
ような動作を実装してみます。

# 距離センサーを取り付けたところ↓

前回作成した回路に、距離センサーを追加します。Sun SPOT の 5V、GNDに距離センサーの5V、GNDを、またアナログ入力ピンA0に距離センサーの出力を接続します。

# 接続の図。

 # ちょっと拡大。

ちょっと長いですが、プログラムはこんなかんじです↓

扉の開閉を安定させるために、3回以上連続して人を検出した/しなかった時に扉を開閉しています。

 package org.sunspotworld;

import com.sun.spot.peripheral.Spot;
import com.sun.spot.sensorboard.EDemoBoard;
import com.sun.spot.sensorboard.io.IOutputPin;
import com.sun.spot.util.*;
import java.io.IOException;
import javax.microedition.midlet.MIDlet;
import javax.microedition.midlet.MIDletStateChangeException;

public class TempleDemoSpot extends MIDlet {
    private DoorController doorController;  // 扉開閉制御スレッド
    
    protected void startApp() throws MIDletStateChangeException {
        try {
            initAndRun();
        } catch (IOException ex) {
            ex.printStackTrace();
        } finally {
            if (doorController != null) {
                doorController.terminate();
            }
        }
    }
    
    private void initAndRun() throws IOException {
        new BootloaderListener().start();
        Spot.getInstance().getSleepManager().disableDeepSleep();
        
        doorController = new DoorController();
        doorController.start();
        
        while (true) {
            // TODO:
            // 後でここに処理を追加する
            Utils.sleep(2000L);
        }
    }
    
    /**
     * DoorController クラスは、アナログ入力ピンA0に接続した距離センサーから
     * 定期的(DETECTION_INTERVAL間隔)に値を取得して、以下の動作を実行します:
     *  o COUNT_THRESHOLD 回連続して10cm~80cmの間に物体を検出した場合に扉を開きます
     *  o COUNT_THRESHOLD 回連続して物体を検出しなかった場合に扉を閉じます
     */
    class DoorController extends Thread {
        private final long DETECTION_INTERVAL = 1000L;
        private final int COUNT_THRESHOLD = 3;
        private TempleManager templeManager;    // 神棚の扉の開閉を制御するクラス
        private DistanceSensor distanceSensor;  // 距離計測用クラス

        private int countInRange;      // 連続して物体を検出した回数
        private int countOutOfRange;   // 連続して物体を検出しなかった回数
        
        private volatile boolean  running = true;
        private boolean doorOpened = false;   // 扉の状態(開: true, 閉: false)
        
        DoorController() throws IOException {
            // 大電流出力ピンH0、H1を使用する
            IOutputPin[] pins = EDemoBoard.getInstance().getOutputPins();
            templeManager = new TempleManager(
                    pins[EDemoBoard.H0],pins[EDemoBoard.H1]);
            
            // アナログ入力ピンA0を使用する
            distanceSensor = new DistanceSensor(EDemoBoard.A0);
        }
        
        public void run() {
            while (running) {
                try {
                    doDetect();    // 物体の検出を実行
                    updateDoorStatus();    // 扉の状態(開/閉)を更新
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
                Utils.sleep(DETECTION_INTERVAL);
            }
        }
        
        /*
         * 物体の検出を実行する
         */
        private void doDetect() throws IOException {
            // 距離センサーから値を取得
            float distance = distanceSensor.getValue();
            if (distance >= 10.0f && distance <= 80.0f) {
                // 物体を検出した
                updateCountInRange();
            } else {
                // 物体を検出しなかった
                updateCountOutOfRange();
            }
        }
        
        /*
         * 扉の状態(開/閉)を更新する
         */
        private void updateDoorStatus() {
            if (countInRange >= COUNT_THRESHOLD) {
                // 連続COUNT_THRESHOLD回以上物体を検出した
                if (!isDoorOpened()) {
                    // 扉が閉じているので開く
                    templeManager.openSesame();
                    setDoorOpened(true);
                }
                countInRange = 0;
            } else if (countOutOfRange >= COUNT_THRESHOLD) {
                // 連続COUNT_THRESHOLD回以上物体を検出しなかった
                if (isDoorOpened()) {
                    // 扉が開いているので閉じる
                    templeManager.shutSesame();
                    setDoorOpened(false);
                }
                countOutOfRange = 0;
            }
        }
        
        private void updateCountInRange() {
            countInRange++;
            countOutOfRange = 0;
            System.out.println("updateCountInRange(countInRange=" + countInRange);
        }
        
        private void updateCountOutOfRange() {
            countOutOfRange++;
            countInRange = 0;
            System.out.println("updateCountOutOfRange(countInRange=" + countOutOfRange);
        }
        
        private boolean isDoorOpened() {
            return doorOpened;
        }
        
        private void setDoorOpened(boolean doorOpened) {
            this.doorOpened = doorOpened;
        }
        
        public void terminate() {
            running = false;
        }
        
        public void destroy() {
            templeManager.destroy();
        }
    }
    
    protected void pauseApp() {
    }
    
    protected void destroyApp(boolean arg0) throws MIDletStateChangeException {
        if (doorController != null) {
            doorController.destroy();
        }
    }
}

 package org.sunspotworld;

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 float 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
        float distance = 23.333f / (voltage - 0.236f) - 0.420f;
        System.out.println("Distance=" + distance);
        return distance;
    }
}

 

 package org.sunspotworld;

import com.sun.spot.sensorboard.io.IOutputPin;
import com.sun.spot.util.Utils;

public class TempleManager {
    private final long DURATION = 6000L;
    
    private IOutputPin out1;
    private IOutputPin out2;
    
    public TempleManager(IOutputPin out1, IOutputPin out2) {
        this.out1 = out1;
        this.out2 = out2;
        
        stop(1L);
    }
    
    /**
     * 扉を開く
     */
    public void openSesame() {
        System.out.println("openSesame()" );
        stop(1L);
        out1.setHigh();
        Utils.sleep(DURATION);
        out1.setLow();
    }
    
    /**
     * 扉を閉じる
     */
    public void shutSesame() {
        System.out.println("shutSesame()" );        
        stop(1L);
        out2.setHigh();
        Utils.sleep(DURATION);
        out2.setLow();
    }
    
    /**
     * ストップ
     */
    public void stop(long duration) {
        out1.setLow();
        out2.setLow();
        Utils.sleep(duration);
    }
    
    public void destroy() {
        out1.setLow();
        out2.setLow();
    }
}

 

それでは実行してみます。

。。。

# デューク登場 ;-)


http://blogs.sun.com/machida/date/20080421 2008年 4月 21日 月曜日

[Sun SPOT で"デューク神棚(Duke Temple)" を動かそう(2)] Hello Crystal Duke!!

 前回のエントリでDCモータの制御回路の簡単な動作確認まで行ったので、いよいよ神棚 の作成に取り掛かります。もともと工作セットのパーツで組み立て説明書が付いているのできっと簡単でしょう。

。。。

二時間経過。。

。。。 

く、結構めんどい。。。

。。。

か、完成! ;-)

# 神棚 

前回と同じように回路を接続します。

 # ちょっと拡大

さて、扉を開閉するプログラムはどうしましょう。元々付いていた音センサーを利用してもよいのですが、そういえば以前距離センサーを使ったことがあったので、これは使えそうです。 かしわ手で反応するのではなく、人が10cm~80cmの距離に近づいた時に扉が開いているように制御する、というのは良いかもです。ただ、そろそろ昼時も近づいてきたのでこれは後日の課題として、今日のところは単純に、扉の開閉を繰り返すSun SPOTプログラムを作成して動作確認だけすることにします。

こんな感じです↓

package org.sunspotworld;

import com.sun.spot.peripheral.Spot;
import com.sun.spot.sensorboard.EDemoBoard;
import com.sun.spot.sensorboard.io.IOutputPin;
import com.sun.spot.util.*;
import javax.microedition.midlet.MIDlet;
import javax.microedition.midlet.MIDletStateChangeException;

public class StartApplication extends MIDlet {
    private TempleManager templeManager;    // 神棚の扉の開閉を制御するクラス
    
    protected void startApp() throws MIDletStateChangeException {
        new BootloaderListener().start();
        Spot.getInstance().getSleepManager().disableDeepSleep();
        
        // 大電流出力ピンH0、H1を使用する
        IOutputPin[] pins = EDemoBoard.getInstance().getOutputPins();
        templeManager = new TempleManager(
                pins[EDemoBoard.H0],pins[EDemoBoard.H1]);

        while (true) {
            templeManager.openSesame();    // 扉を開く
            templeManager.stop(1000L);      // ストップ
            templeManager.shutSesame();    // 扉を閉じる
            templeManager.stop(1000L);      // ストップ
        }
    }
    protected void pauseApp() {
    }

    protected void destroyApp(boolean arg0) throws MIDletStateChangeException {
        if (templeManager != null) {
            templeManager.destroy();
        }
    }
}

package org.sunspotworld;

import com.sun.spot.sensorboard.io.IOutputPin;
import com.sun.spot.util.Utils;

/**
 * 神棚の扉の開閉を制御するクラス
 */
public class TempleManager {
    private final long DURATION = 6000L;
    
    private IOutputPin out1;
    private IOutputPin out2;
    
    public TempleManager(IOutputPin out1, IOutputPin out2) {
        this.out1 = out1;
        this.out2 = out2;
        
        stop(1L);
    }
    
    /**
     * 扉を開く
     */
    public void openSesame() {
        stop(1L);
        out1.setHigh();
        Utils.sleep(DURATION);
        out1.setLow();
    }
    
    /**
     * 扉を閉じる
     */
    public void shutSesame() {
        stop(1L);
        out2.setHigh();
        Utils.sleep(DURATION);
        out2.setLow();
    }    

    /**
     * ストップ
     */
    public void stop(long duration) {
        out1.setLow();
        out2.setLow();
        Utils.sleep(duration);
    }    
    
    public void destroy() {
        out1.setLow();
        out2.setLow();
    }
}

Sun SPOT にプログラムをインストールして実行してみましょう。

。。。

# 扉が開き始めました!;-) なにやら透明な物体が。。。

 # クリスタルデューク登場!

 # 拡大。


http://blogs.sun.com/machida/date/20080420 2008年 4月 20日 日曜日

[Sun SPOT で"デューク神棚(Duke Temple)" を動かそう(1)] DC Motor を駆動してみる。

今朝は休日だというのになぜか6時に目が覚め、また寝るのも勿体無いので午前中を使って Sun SPOTで遊ぶことにしました。昼ぐらいまでに何か動くものを作れるでしょうか。ちょうど手近に神だな工作セット(TAMIYA製)が転がっていたので、これを改造して Duke 神棚 を作ることにします ;-)

# sound activated temple (TAMIYA)

この工作セットには元々音センサースイッチ回路がついており、かしわ手を打つと扉が開いて神さまが出てくる、という動作をします。扉の開閉の制御には FA-130 というDCモータを1つ使用しています。

# 付属している音センサースイッチ回路とDCモータ。今回は音センサー回路は使わず、Sun SPOTを使って扉の開閉を制御します。

DCモータでは数100mAの大電流が流れるため、Sun SPOTの出力ポートでは直接駆動することができません。またDCモータを1つの電源で正逆回転させるためには Hブリッジなどの回路を組む必要があります。そこで、今回はモータドライバICを使って制御回路を作成して、この回路を Sun SPOTの出力ポートで制御することにします。

モータドライバICとしては TA7291P などが書籍などでよく紹介されていますが、今回はそれより少しだけスペックが下(で安価: 100円ぐらい)なTA7291SG というICがちょうど転がっていたので、これを使用します。

# TA7291SG の外観

 

1時間半ぐらい半田ごてを動かして、以下のようなモータ制御回路を作成しました。

データシートや書籍、Webサイトを参考にすれば、比較的容易だと思います)

# モータ制御回路の外観 (パスコンが抜けてる。。4/22追記)

 # 裏。半田付けが下手で恥ずかしいので縮小。まぁ、動けば。。。

 

IN1, IN2 に、Sun SPOTの出力ポートを2つ接続して制御します。また、OUT1, OUT2 にモータを接続します。

さらに、モータ動作用の電源として1.5Vの単三電池x2、ドライバICとSun SPOTのVH用としてACアダプタ5V電源を使用します。ACアダプタのジャックは、CK-23 という電源コネクタ変換基板を使って2.54mm に変換してケーブルを引き出せるようにします。

# CK-23

 DCモータを動かすための準備が整ったので、ちょっとテストしてみることにします。

# ケーブルを接続したところ

Sun SPOTのVH ピンに5V電源、GNDにドライバ制御回路のGND、そして H0、H1 に制御回路の IN1、IN2をそれぞれ接続しています。

# 拡大

 あ、もちろんモータ制御用のSun SPOTアプリケーションも必要ですね。こんな感じで作成しました↓

package org.sunspotworld;

import com.sun.spot.peripheral.Spot;
import com.sun.spot.sensorboard.EDemoBoard;
import com.sun.spot.sensorboard.io.IOutputPin;
import com.sun.spot.util.*;
import javax.microedition.midlet.MIDlet;
import javax.microedition.midlet.MIDletStateChangeException;

public class StartApplication extends MIDlet {
    private IOutputPin h0;
    private IOutputPin h1;
    
    protected void startApp() throws MIDletStateChangeException {
        new BootloaderListener().start();
        Spot.getInstance().getSleepManager().disableDeepSleep();
        
        // 大電流出力ピンH0、H1を使用する
        IOutputPin[] pins = EDemoBoard.getInstance().getOutputPins();
        h0 = pins[EDemoBoard.H0];
        h1 = pins[EDemoBoard.H1];

        stop(1L);
        while (true) {
            forward(6000L);    // 6秒間正転
            stop(1000L);       // 1秒間ストップ
            reverse(6000L);    // 6秒間逆転
            stop(1000L);       // 1秒間ストップ
        }
    }

    /**
     * 正転
     */
    private void forward(long duration) {
        stop(1L);
        h0.setHigh();
        Utils.sleep(duration);
        h0.setLow();
    }
    
    /**
     * 逆転
     */
    private void reverse(long duration) {
        stop(1L);
        h1.setHigh();
        Utils.sleep(duration);
        h1.setLow();
    }    

    /**
     * ストップ
     */
    private void stop(long duration) {
        h0.setLow();
        h1.setLow();
        Utils.sleep(duration);
    }
        
    protected void pauseApp() {
    }

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


最後に、制御回路のOUT1,OUT2にモータ(と羽根)を取り付けて早速実行してみます。。。

 

 

 。。。

回転しました ;-)


http://blogs.sun.com/machida/date/20080416 2008年 4月 16日 水曜日

[Sun SPOT(21)] SDC SQUARE 4月号 Sun SPOT連載第3回: 今回のテーマはSun SPOTアプリケーション開発です。

SDC SQUARE 4月号に、大野さんNetBeans 6 (Mobility)寺田さんGlassFish の記事とともに

が掲載されています。

。。。。

Sun SPOT :無線センサーデバイスの新潮流

第3回:Sun SPOT で Hello World!

シリーズ第3回となる今回のテーマは「Sun SPOTアプリケーション開発」です。
NetBeans IDEでプログラムを作成して、Sun SPOT上で動かしてみましょう。
センサーや入出力ピン、無線通信などの機能を使うためのAPIライブラリに
ついても見ていきます。最後に、これらの機能を使った簡単なアプリケーション
を紹介します。

。。。。

今回は、ちょっとしたソースコードも紹介しています。是非ご覧下さい! m(_ _)m

http://blogs.sun.com/machida/date/20080415 2008年 4月 15日 火曜日

[Sun SPOT(20)] 4/18(金)の Sun Business .Next 2008 & Japan ERC で Sun SPOT展示します。

2008年4月18日 (金) に同時開催されるサン・マイクロシステムズ株式会社主催のイベント:

o Sun Business .Next 2008 ~ビジネスフィールドに革新的なIT環境を~

o Japan Education & Research Conference

で Sun SPOT も展示予定になっております。

場所: 東京ミッドタウン


どちらのイベントも、サンが提供する最先端のテクノロジやソリューションをご覧いただけます(Japan ERCは教育研究機関向けのイベントです)。

参加費は無料ですが、事前登録制となっております。是非、御参加下さい!

 


[Sun SPOT で2足歩行ロボットを作ろう(2)] Dancing Duke? 何となくヘッドバンギングさせてみた。

 前回のエントリでDukeをかぶせた4軸ロボットですが、いざ歩かせようとすると中々上手くいかず。。。本などでいろいろ調べたのですが、やはりこのサーボの配置では歩行は難しそう。。ということで、来月の小遣いで8軸まで増強して再トライしようと思います。

せっかく作ったので、Melody SPOT デモとコラボしてみました。Melody SPOTからメロディーが流れ出すと、ロボットDukeが動きます。

 # ヘッドバンギング Duke。

 

 # 激しすぎて体が回転してしまいました。。 orz

 


http://blogs.sun.com/machida/date/20080414 2008年 4月 14日 月曜日

[Sun SPOT で2足歩行ロボットを作ろう(1)] 本体を組み立て、Dukeをかぶせてみる。

ネギを買いに行ったついでに面白そうなものを物色していたら、何と9800円で2足歩行ロボットが作成できるセットを発見!まぁ、4軸ではまともに歩かないかも、という疑念はありますが、Sun SPOTとセットで教材になりそうなので、試しに購入して作ってみることにしました。

いつものように、できるだけ半田付けをしないで作るという方針の元、今回もブレッドボードとジャンプワイヤーを使って結線。 2時間ほどで組み上がりました。

# Sun SPOT ロボット


# 裏はこんな感じです。

 

最後に Duke 巾着をかぶせて 完成!

# Dukeロボット  powered by Sun SPOT

試しにちょこっとJavaでプログラムを書いて前進させようとしたら、思いっきりコケました。。orz..

これからロボットの歩かせ方を学ばないと。。。

 

[Sun SPOT(19)] ネギ好きDukeのネギ

4/11(金) に開催された第2回 Sun SPOT日本発売記念セミナーですが、前回同様、沢山の方にお越しいただき、盛況のうちに終了することができました。お忙しい中、御参加下さった皆様、本当にありがとうございました!

。。。

リアル偽ネギ、Getしました! > 草薙さん

4/30 の JJUG クロスコミュニティカンファレンス はこのネギでどうでしょう?

# ネギ。



http://blogs.sun.com/machida/date/20080408 2008年 4月 08日 火曜日

[Sun SPOT メモ] プリント文デバッグで ant echo コマンドを使う。

Sun SPOTでは、アプリケーションのソースコード中に記述したプリント文出力(System.out.printlnなど)を表示する方法が幾つかあります。例えば、

  • NetBeans IDEを使う

  • SPOT World ツールを使う

などです。NetBeansの場合は、Sun SPOTをUSBケーブルでホストPCに接続した状態で「実行」すると、下部の出力ウィンドウに表示されます。一方、SPOT Worldツールの場合はGUI上でSun SPOTを選択して、リモートのSun SPOTの出力を無線経由で表示することができます。

では、既にアプリケーションを実行状態の Sun SPOTがリモートにあって、SPOT Worldをいちいち起動するのも面倒、というときはどうするか。*コマンドライン* を使いましょう!

Sun SPOT SDK のベースディレクトリに移動して、以下のコマンドを実行します。

 # ant -DremoteId=<Sun SPOTのIEEE拡張MACアドレス> echo
 

例)

しばらくすると、リモートにある Sun SPOTのプリント文出力が端末エミュレータ上に表示されはじめます ;-)

Sun SPOT Owner's Manual の P.28~34 辺りに、プリント文デバッグを含めた OTA(Over The Air) Debugging について詳しく載っています。

P.S. ホストPCにベースステーションを接続するのを忘れずに!また、Sun SPOT のOTA機能はEnable にしておく必要があります(SPOT Manager Tool か "ant enableota" コマンドを使って有効にします)。

[Sun SPOTトラブルシューティング] Sun SPOTs SDKを付属CDで初期インストールした後に SPOT Manager が起動しない時の対処法

最近になって

「Sun SPOTs SDKを付属CDでインストールした後、SPOT Manager が起動できない」

というお問い合わせを何件か頂きましたので、以下に対処方法をまとめておきます。なお、これは既知の問題として、フォーラムの以下の投稿で原因及び解決方法が示されています(英語ですが):

。。。

# Sun SPOT Java Development Kit にはこのようなCDが付属してます↓

 

インストーラを起動してSun SPOT SDKやサンプルプログラムをインストールする手順は単純です。ほとんどクリックのみで完了します。

# インストーラ

最後の画面に「SPOT Manager」というボタンがあり、このボタンをクリックすると SPOT Managerが起動する*はず*ですが。。。(あるいは Sun SPOT SDKのインストールディレクトリ以下にある SPOTManager.jnlp というファイルをダブルクリックしてもよいです)

この、CDに付属しているSPOTManagerを起動しないでください!!うまく動きません(ある時点以降は直っている可能性もありますが)。

 SPOT Manager が Java Web Start で起動され、jar ファイルのダウンロードまでは順調に行われますが。。

 「JNLPファイルないのJARリソースが単一の証明書によって署名されていません」というエラーが(殆どの環境で)出ます。

# エラー!

 # なにやらスタックトレースが表示されています。

SPOT Manager を起動するためには、フォーラムに書かれているようにSPOT Managerのダウンロード/スタートのためのWebページに行って、そのページにあるリンクから起動して最新版をダウンロードしてください。ここにそのサイトのリンクを直接書くことはできませんが、SunSPOTWorldにあるドキュメントを読めば書いてあります。

。。。

1度でもCDに付属する古いバージョンの SPOT Managerを起動しようとして失敗している場合、Java Web Start のキャッシュに残ってしまっていて最新版を起動しようとしてもエラーが起きるかもしれません。その場合、キャッシュビューアを起動してアプリケーションを一旦削除してから最新版を改めてダウンロードしてください。

キャッシュビューアですが、Linux の場合は端末エミュレータ上で

 # javaws -viewer

Solaris の場合は

 # javaws

などとコマンドを打てば起動すると思います。Windows XPの場合はコントロールパネルで「Java(TM)コントロールパネル」を起動して、

 「インターネット一時ファイル」の「表示」を選択します。

あとは、ダウンロードされたアプリケーションを削除してください。

http://blogs.sun.com/machida/date/20080407 2008年 4月 07日 月曜日

[Sun SPOT メモ] プロパティ(Properties)をリソースファイル(Resource Files)から読み込む。

JukeBox デモの実装を検討していて、アプリケーションで使うプロパティの値を外部リソースファイルから読み込みたくなり、ドキュメントでやり方を調べたので、忘れないよう以下にメモしておきます。

例えば、メロディを演奏するクラスを曲毎に用意することにして、これらを以下のキー/値の組:

 <ユニークな曲番>=<クラス名>
 
のリストとして外部リソースファイル(melodyplayers.properties)に保存するとします。このような感じです↓

各メロディ演奏クラスは以下のインタフェースを implements しています。 

package org.sunspotworld;

public interface MelodyPlayer {
    void play();
}

また、DefaultPlayer、PolkkaPlayer、FF6ButtlePlayer クラスはそれぞれ次のような感じで実装します。

package org.sunspotworld;

// デフォルトのメロディを演奏する Player
public class DefaultPlayer implements MelodyPlayer {
    public void play() {
        System.out.println("DefaultPlayer: playing notes..." );
        // ... 以下、メロディを演奏
    }
}

package org.sunspotworld;

// Polkka を演奏する Player
public class PolkkaPlayer implements MelodyPlayer {
    public void play() {
        System.out.println("PolkkaPlayer: playing notes..." );    
        // ... 以下、メロディを演奏
    }
}

 package org.sunspotworld;

// FF6 のバトル音楽を演奏する Player
public class FF6ButtlePlayer implements MelodyPlayer {
    public void play() {
        System.out.println("FF6ButtlePlayer: playing notes..." );
        // ... 以下、メロディを演奏
    }
}

 

アプリケーションから利用するリソースファイルは、resources ディレクトリ以下に格納します。 今回は、下図のように melodyplayers.properties をresources ディレクトリ直下に配置しました。

 

リソースファイルは、getResourceAsStream メソッドを使って 読み込むことができます。

 InputStream in =
    getClass().getResourceAsStream("/somefilename" );
 

それでは、melodyplayers.properties ファイルを読み込んでメロディを演奏する簡単なSun SPOTアプリケーションを作成して、実行してみましょう。

以下にソースコードを示します:

 package org.sunspotworld;

import com.sun.spot.util.*;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import javax.microedition.midlet.MIDlet;
import javax.microedition.midlet.MIDletStateChangeException;

public class ResourceFileTestSpot extends MIDlet {
    protected void startApp() throws MIDletStateChangeException {
        new BootloaderListener().start();   // monitor the USB (if connected) and recognize commands from host

        Properties props = extractProps("/melodyplayers.properties" );

        System.out.println("TestSpot: Begin" );
        play(props);
        System.out.println("TestSpot: End" );        
        
        while (true) {
            Utils.sleep(2000L);
        }
    }
    
    // プロパティで指定された Playerの演奏を実行
    private void play(Properties props) {
        Enumeration keys = props.propertyNames();

        while (keys.hasMoreElements()) {
            try {
                String key = (String)keys.nextElement();    // キー: 1,2,3...
                String playerName = props.getProperty(key); // Playerのクラス名

                // クラス名を指定して、Playerの新しいインスタンスを生成
                MelodyPlayer player =
                        (MelodyPlayer)Class.forName(playerName).newInstance();
                
                // 演奏の実行
                player.play();
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    }
    
    // Propertiesインスタンスへのプロパティの読み込み
    private Properties extractProps(String filename) {
        Properties props = new Properties();
        
        InputStream in = null;
        try {
            // リソースファイルのオープン
            in = getClass().getResourceAsStream(filename);
            if (in != null) {
                // プロパティのロード
                props.load(in);
            } else {
                System.out.println("in == null" );
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException ignored) {}
            }
        }
        return props;
    }


    protected void pauseApp() {
    }

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

アプリケーションをSun SPOTに配備して実行します。。。

。。。

リソースファイルの読込みに成功しました ;-)

 


Valid HTML! Valid CSS!

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