marunomaruno-memo

marunomaruno-memo

Lego NXT - leJOS - (1.1) leJOS v0.7 のインストール

2009年04月01日 | LEGO
Lego Mindstomes NXT - leJOS - (1.1) leJOS v0.7 のインストール
================================================================================

(1) leJOS のインストール 2008-07-01 」では、leJOS のバージョンは 0.6 でした。現在、
leJOS は 0.7 になり、PC へのインストールや、NXT へのファームウェアのアップロードがかなり
楽になりました。

ここでは、(1) の補足として、v0.7 でのインストールについて記します。

leJOSは、
http://lejos.sourceforge.net/p_technologies/nxt/nxj/downloads.php
からダウンロードします。

なお、この版では、もう、リセットボタンを押さなくてもよくなりました。
PCへのインストールが終了すると、NXTへのファームウェアをアップロードするかどうか
聞いてきます。
NXTとUSBケーブルでつなげておき、電源を入れておけば、アップロードしてくれます。


1. インストーラー leJOS_NXJ_0.7-Setup.exe をクリックして leJOS をインストールし
ます。
PC へのインストールが終わったら、NXT に NXJ フレームウェアをインストールするかど
うかの画面が出てきます。

2. NXT に USB ケーブルを接続して、電源を入れておいて、[Start program] ボタンの
押下で、NXJ フレームウェアのインストールがされます。

3. NXT の電源 ON と、USB ケーブルによる接続の確認をします。(画面が出ます)

4. NXT に入っているファイルの削除が確認されます。(画面が出ます)

5. アップロードし終わったら、もう 1 度アップロードしなおすか聞かれます。
これは、「いいえ」でいいでしょう。(画面が出ます)

6. 最後に、状況を確認する画面が出て終了です。NXT も、自動的に起動します。


また、もう lejosfirmdl コマンドも使わないので、環境変数も、自動的に設定される
NXJ_HOME だけで OK のようです。


なお、NXT 本体に個別に leJOS をインストールするには、
nxjflash
コマンドを使います。これも、NXT 本体に電源が入っていれば OK です。
(2009-08-11 追記)

以上


Lego Mindstoms NXT - leJOS - (14) ジャイロセンサー

2009年03月30日 | LEGO
◆ Lego Mindstoms NXT - leJOS - (14) ジャイロセンサー

各速度を測定できるジャイロセンサーを使った例です。
なお、このジャイロセンサーは、Lego Mindstomes NXT の基本セットにも、おもちゃセッ
トにも含まれていませんので、別途購入する必要があります。

ジャイロセンサーは、HiTechnic 社の NXT Gyro Sensor (Model: NGY1044) です。
HiTechnic Product: http://www.hitechnic.com/

HiTechnic 社の説明から
---
HiTechnic社製ジャイロセンサ(NGY1044)は光センサ等と同様に10ビットの分解能を持った
A/Dデータとして取得されます。ジャイロセンサの更新レートは約300回/秒で、±360度の
測定範囲に対応します。
---

▼ジャイロセンサーから取得できる値?
---
ジャイロセンサーは、角速度(1秒間に何度動いたか)を検出するセンサー。正しくは
「ジャイロスコープ」というようで、ジャイロセンサーは和製英語らしいが、上記製品も
Gyro Sensor なので、どうなんだろう。(どうでもいいこと)

角速度自体は、スカラー値のようだが、この説明だと、当然、正負値が取得できる。
実際に、走行体に載せるとこれは3次元なので、実は各周波数を取得しているのかな? だ
としたら、非負値しか取得できないと思うが、実際には符号付値で取得できている。何か
を基準に、1次元に落としているんだろうか。その基準が、オフセット値? でも、オフセ
ット値もスカラー値なので、もう1次元分は何なのかな?
不思議な気がする。

もっとも、安い(数千円)のセンサーだから、角速度だけを取得しているだけかもしれない。
じゃあ、オフセット値は何? 何かの基準だと思われるが、0度の位置を表しているのかな?
実際のジャイロセンサーのソース(GyroSensor.java)を見ると、オフセットは 600 がデフ
ォルト値として設定されている。そして、readValue メソッドは、単に、
port.readRawValue() - offset
を返しているだけ。

□ウィキペディアからの説明の引用:

ジャイロセンサーは、運動している(ある速度をもっている)モノが回転すると、その速
度方向と垂直に「コリオリの力」が働くという物理現象を利用して角速度を検出している。
(http://ja.wikipedia.org/wiki/%E3%82%B8%E3%83%A3%E3%82%A4%E3%83%AD%E3%82%B9%E3%8
2%B3%E3%83%BC%E3%83%97)

角速度は、物体や質点の回転の速さを表す量であり、角度と時間の商で定義される。量記
号は ω(ギリシャ文字の小文字のオメガ)。角速度は3次元空間ではベクトル量として定
義でき、その大きさが角周波数である(ω = |→ω|)。単位は通常ラジアン毎秒(rad/
s)を用いる。
(http://ja.wikipedia.org/wiki/%E8%A7%92%E9%80%9F%E5%BA%A6)

コリオリの力は、回転座標系(Rotating reference frame)上で移動した際に移動方向と
垂直な方向に移動速度に比例した大きさで受ける慣性力の一種。
(http://ja.wikipedia.org/wiki/%E3%82%B3%E3%83%AA%E3%82%AA%E3%83%AA%E3%81%AE%E5%8
A%9B)
---


■ジャイロセンサー値を取得するアプリケーション

取得している間の最小値と最大値も合わせて表示する。取得の間隔は 50 ミリ秒。

□GyroSensor01.java
------------------------------------------------------
import lejos.nxt.Button;
import lejos.nxt.GyroSensor;
import lejos.nxt.LCD;
import lejos.nxt.SensorPort;

/**
 * ジャイロセンサー値を取得するアプリケーション。
 * @author maruno
 * @version 1.0, 2009/03/28
 * @since 1.0
 */
public class GyroSensor01 {

    public static void main(String[] args) throws Exception {

        // ジャイロセンサー・オブジェクトをポート4で生成する。
        GyroSensor gyroSensor = new GyroSensor(SensorPort.S4);      // (1)
        
        int value = gyroSensor.readValue();    // (2)
        int min = value;
        int max = value;

        // Escapeボタンが押されるまでループ
        while (!Button.ESCAPE.isPressed()) {
            min = Math.min(min, value);
            max = Math.max(max, value);
            LCD.clear();
            LCD.drawString("value = " + value, 0, 1);
            LCD.drawString("min   = " + min, 0, 2);
            LCD.drawString("max   = " + max, 0, 3);
            Thread.sleep(50);
            value = gyroSensor.readValue();
        }
    }
}
------------------------------------------------------


プログラムのパターンは、今までのセンサー値を表示するプログラムとまったく変わりま
せん。leJOS には、はじめからジャイロセンサーを扱うクラスが用意してあります。

□ GyroSensor gyroSensor = new GyroSensor(SensorPort.S4); // (1)

ジャイロセンサーオブジェクトを、ポート4につなげて生成します。


□コンストラクター
---
GyroSensor(ADSensorPort port)
---


□ LCD.drawString("value = " + gyroSensor.readValue(), 0, 1); // (2)

ジャイロセンサーからの値を取得して、NXT 画面に表示します。

□メソッド
---
int readValue()
ジャイロセンサーの値を取得する。値は、-1000 ~ 1000 の範囲くらいか?

void setOffset(int offset)
オフセット値を設定する。
---

以上


LEGO MINDSTORMS NXTグレーブック―プログラムノツヅラ

2008年10月20日 | LEGO
LEGO MINDSTORMS NXTグレーブック―プログラムノツヅラ (単行本)
大庭 慎一郎 (著), 松原 拓也 (著)
http://journal.mycom.co.jp/news/2007/03/01/388.html
単行本: 207ページ
出版社: 毎日コミュニケーションズ (2007/02)
ISBN-10: 4839923019
ISBN-13: 978-4839923013
発売日: 2007/02
商品の寸法: 19.8 x 18.4 x 2.2 cm


Chapter1 NXT SOFTWARE
NXTソフトウェアによるプログラミング
1-1 NXTソフトウェアの基本
1-2 配列や便利な演算をマイブロック化
1-3 教示機能を使おう
1-4 配列・三角関数を使う

Chapter2 MULTIPLE NXT
複数のNXTで遊ぶ
2-1 複数のセットでできること
2-2 音がするほうを向くロボット
2-3 明るいほうに進むロボット
2-4 2つのタッチセンサーで3つの入力
2-5 ロータリーエンコーダーを作る
2-6 Bluetooth通信の基本
2-7 息の合ったダンスを踊るロボット
2-8 じゃんけんで対戦するロボット

Chapter3 UTILITIES
便利ツールを使いこなす
3-1 LEGOブロック用CADソフト「MLCad」
3-2 「LDView」で設計図を画像にする
3-3 「Wav2Rso」でオリジナルの音声ファイルを使う
3-4 「nxtRICedit」でオリジナルの画像ファイルを使う

Chapter4 NBC
NBCによるプログラミング
4-1 NBCとは?
4-2 プログラムの作成方法
4-3 センサーの入力に関する記述の方法
4-4 モーターの出力に関する記述の方法
4-5 ファイル管理に関する記述の方法

Chapter5 RCX
RCX用センサー/モーターを使う
5-1 RCXとは?
5-2 NXT用入出力ポートについて
5-3 変換ケーブルの自作1
5-4 変換ケーブルの自作2
5-5 新旧パーツ対抗玉蹴りマシン
5-6 NXTソフトウェアがRCX用パーツに対応

Chapter6 PC
PCとの通信プログラミング
6-1 プログラミング環境の入手
6-2 ダイレクトコマンドによるコントロール
6-3 インターネット経由でロボットを動かす

Chapter7 TWO-LEGGED
大型二足歩行ロボット
7-1 超大作! ベータレックス
7-2 ベータレックスの組み立て方
7-3 ベータレックスの動作原理
7-4 ベータレックスのプログラム
7-5 ベータレックスの動かし方

APPENDIX
巻末資料
A-1 LEGO MINDSTORMS NXT用オプション
A-2 LEGO MINDSTORMS NXTのプログラミング環境
A-3 ファームウェアのビルド方法

LEGO MINDSTORMS NXT オレンジブック

2008年10月16日 | LEGO
LEGO MINDSTORMS NXT オレンジブック
http://book.mycom.co.jp/book/4-8399-2186-5/4-8399-2186-5.shtml
著者:五十川芳仁
単行本: 128ページ
出版社: 毎日コミュニケーションズ (2006/10)
ISBN-10: 4839921865
ISBN-13: 978-4839921866
発売日: 2006/10
商品の寸法: 20 x 18.2 x 1.4 cm


Chapter 1 Introduction
ロボットことはじめ
1 ロボットってなに?
2 そこでMINDSTORMS NXT !
3 電源付き頭脳・NXT
4 正確に回る・止まる・サーボモーター
5 感じる・4種類のセンサー
6 動力伝達・ギア・プーリー・シャフト
7 結合する・コネクタ・とめる・ブッシュ
8 いろいろな部品
9 動作の設計図・NXTソフトウェア

Chapter 2 Sensor
センサーいろいろ活用法
1 小さな力を感知する
2 前も後ろも感知する
3 切り替えスイッチ
4 回転式スイッチ
5 差し込み式スイッチ
6 フタの開閉を感知する
7 ゆれを感知する
8 拍手の間隔でスピード調節
9 拍手の回数で仕事を分岐
10 モーターで距離測定
11 レバーでスピードをコントロール
12 NXTのボタンをセンサーに
13 伝説の電子楽器を再現

Chapter 3 Motor
モーターぐるぐる活用法
1 かんたんシンプルな車
2 ギアでスピードとパワーを変える
3 ウォームギアでパワーアップ
4 いったりきたりの反復運動
5 完全なる直線反復運動
6 動いて止まって間欠動作
7 自由な方向に回転を伝える
8 ベルトで回転を伝える
9 ベルトで軸の方向を変える
10 ギアの中心はずし技
11 上向きの何かを回す車
12 前向きの何かを回す車
13 前はまっすぐ後ろは曲がる
14 しなやかサスペンション
15 体験!ディファレンシャルギア
16 きちんとステアリングする車
17 四輪駆動で走る
18 強引に腕を回して進む車
19 てけてけ走る車
20 なんちゃって2足歩行
21 NXT牽引4足歩行
22 6本の足で歩行する
23 振動で動く
24 ボールを発射する
25 ロー/ハイ変速機
26 4軸同時同方向回転の技
27 回転方向で別作業

Chapter 4 Motor & Sensor
モーター・センサー・合わせ技
1 テーブルの端で止まる車
2 音に反応する車
3 つかずはなれずの車
4 尺取り虫の動きをまねてみる車
5 ライントレーサー入門編
6 手をたたいてギアチェンジ
7 ウィンチで巻き上げ
8 いらっしゃいませ自動ドア
9 回転センサーで重さ比べ
10 首ふり扇風機
11 明るさで閉じたり開いたり
12 表情を変えるロボット

Point
充電池のススメ
もっといろいろギア
テクニックパーツあれこれ
普通のLEGOブロックとの互換性
部品がはずれないときは?
タイヤ・たいや・Tire
ゼンマイも楽しい!
輪ゴム?
LEGOシリーズのユニバーサルジョイント?
ハードで解決する? ソフトで解決する?
ばね? スプリング?
純正のディファレンシャルギア?

Column
ちょっと勉強! ギア比のはなし
書を捨てよ、街へ出よう
身近なシロモノ
引いて放せば走り出す


Lego Mindstoms NXT - leJOS - (13) Behavior (2)

2008年10月14日 | LEGO
◆ Lego Mindstoms NXT - leJOS - (13) 振舞い(Behavior)と調停者(Arbitrator)


黒線で囲まれたところからロボットが出ずに、その中だけで障害物を避
けながらロボットを動かす」プログラムを前回は、lejos.subsumption
パッケージの API を使わずに作りました。


■lejos.subsumption をつかわない実装

再掲します。

------------------------------------------------------
import l.EscapeListener;
import lejos.navigation.Pilot;
import lejos.nxt.Button;
import lejos.nxt.LCD;
import lejos.nxt.LightSensor;
import lejos.nxt.Motor;
import lejos.nxt.SensorPort;
import lejos.nxt.Sound;
import lejos.nxt.TouchSensor;

/**
 * まっすぐ走り、障害物にぶつかったら、少しバックして方向を換えて
 * また前に進む。または、黒線をまたいだら150度方向転換するプログラム。
 * @author marunomaruno
 * @version 1.0, 2008/09/29
 * @since 1.0
 */
public class Bumper12 {

    private static final int THRESHOLD = 40;    // 黒線を判断するしきい値

    public static void main(String [] args) {

        // ESCAPE ボタンを押すとプログラム停止する
        Button.ESCAPE.addButtonListener(new EscapeListener());    
        
        // トライボットのオブジェクトを生成する
        Pilot trybot = new Pilot(5.6f, 13f, Motor.C, Motor.B);

        // タッチセンサーオブジェクトをポート1で生成する
        TouchSensor touchSensor = new TouchSensor(SensorPort.S1);

        // 光センサーオブジェクトをポート1で生成する
        LightSensor lightSensor = new LightSensor(SensorPort.S2);

        while (true) {
            trybot.forward();         // 直進する

            while (!touchSensor.isPressed() && (lightSensor.readValue() >= THRESHOLD));    // タッチされるか黒線を超えるまで待つ

            LCD.clear();
            LCD.drawString(touchSensor.isPressed() ? "true" : "false", 1, 1);
            LCD.drawInt(lightSensor.readValue(), 1, 2);

            if (touchSensor.isPressed()) {
                // 障害物にぶつかった場合
                trybot.backward();    // 後退する
                Sound.pause(500);
                trybot.rotate(90);    // 回転する

            } else {
                // 黒線を越えた場合
                trybot.stop();        // 停止する
                trybot.rotate(150);   // 回転する
            }
        }
    }
}
------------------------------------------------------


このプログラムは、
まっすぐ走る
障害物にぶつかったら少し後退して方向を換える
黒線をまたいだら、黒線をまたいだら 150 度回転して、進行方向
を逆にする
という 3 つの振舞いの複合になっており、まっすぐ走っている最中に、
障害物にぶつかる、黒線をまたぐ、といったイベントに対して、それぞ
れ、少し後退して方向を換える、150度回転する、といった振舞いを実
装しないといけないからです。

まだ、3つの振舞いだけであれば何とかなっても、ここに、別の振舞い
を入れると、プログラムのコードは飛躍的に難しくなります。


これを、上記の 3 つの振舞いを持ったオブジェクトに分解して、それ
ぞれのオブジェクトを制御する形でメインメソッドを作ると、プログラ
ムはけっこうすっきりした形になります。

このための API が、Behavior インターフェースと Arbitrator クラス
で提供されているのです。

Behavior インターフェースには、それを実装したオブジェクトの振舞
い(実行部)を記述する action メソッドと、実行すべきかどうかを判断
する条件部(takeControl メソッド)を記述します。また、他の振舞いに
制御が移るときに実行する suppress メソッドを記述します。

Arbitrator (調停者)クラスのオブジェクトは、そのコンストラクター
の引数に、Behavior オブジェクトの配列を指定して作ります。
Arbitrator クラスの start メソッドを実行することで、調停を開始し
ます。これは、ロボットの状態から、Behavior.takeControl メソッド
を実行して、ロボットの状態に合致する振舞いオブジェクトを選択し、
そのオブジェクトの action メソッドを実行します。


それでは、上記の3つの振舞いをそれぞれ
DriveForward (直進する)
HitWall (障害物にぶつかったときに後退して90度回転する)
DarkLine (黒線を超えたときに150度回転する)
クラスに記します。なお、これらのクラスは、 bhvr パッケージに入れ
ることにします。


■直進する振舞いを規定するクラス

------------------------------------------------------
package bhvr;

import lejos.navigation.Pilot;
import lejos.subsumption.Behavior;

/**
 * 直進する振舞いを規定するクラス
 * @author marunomaruno
 * @version 1.0, 2008/09/29
 * @since 1.0
 */
public class DriveForward implements Behavior {    // (1)

    private Pilot pilot;
    
    public DriveForward(Pilot pilot) {             // (2)
        this.pilot = pilot;
    }

    public boolean takeControl() {                 // (3)
        return true;
    }

    public void suppress() {                       // (4)
        pilot.stop();
    }

    public void action() {                         // (5)
        pilot.forward();
    }
}
------------------------------------------------------


□ public class DriveForward implements Behavior { // (1)

Behavior インターフェースを実装して、振舞いを規定します。


□ Behavior インターフェースのメソッド
---
void action()
ロボットの振舞い(実行するアクション)を記す。

void suppress()
このアクションが終わるときの振舞いを記す。

boolean takeControl()
action() を行うかどうかを判断する。
---


□ public DriveForward(Pilot pilot) { // (2)

Pilot オブジェクトを受け取るコンストラクター。


□ public boolean takeControl() { // (3)

action() を行うかどうかを判断します。ここでは、ひたすら直進する
だけなので、常に true を返します。


□ public void suppress() { // (4)

このアクションが終わるときの振舞いを記します。


□ public void action() { // (5)

ロボットが実行すべきアクションを記します。このオブジェクトはひた
すら直進するだけです。



■障害物にぶつかったときに後退して90度回転する振舞いを規定するクラス

------------------------------------------------------
package bhvr;

import lejos.navigation.Pilot;
import lejos.nxt.SensorPort;
import lejos.nxt.Sound;
import lejos.subsumption.Behavior;

/**
 * 障害物にぶつかったときに後退して90度回転する振舞いを規定するクラス
 * @author marunomaruno
 * @version 1.0, 2008/09/29
 * @since 1.0
 */
public class HitWall implements Behavior {

    private Pilot pilot;

    public HitWall(Pilot pilot) {
        this.pilot = pilot;
    }

    public boolean takeControl() {
        return SensorPort.S1.readBooleanValue();
    }

    public void suppress() {
        Sound.systemSound(true, 2);
        pilot.stop();
    }

    public void action() {
        pilot.backward();    // 後退する
        Sound.pause(500);
        
        pilot.rotate(90);    // 回転する
    }
}
------------------------------------------------------


□ takeControl メソッド

タッチセンサーを使って、タッチされたかどうかを判断します。タッチ
された場合、true を返し、これによって、action メソッドが動くこと
になります。


□ action メソッド

500ミリ秒後退して、90度回転します。



■ 黒線を超えたときに 150 度回転する振舞いを規定するクラス

------------------------------------------------------
package bhvr;

import lejos.navigation.Pilot;
import lejos.nxt.LCD;
import lejos.nxt.LightSensor;
import lejos.nxt.SensorPort;
import lejos.nxt.Sound;
import lejos.subsumption.Behavior;

/**
 * 黒線を超えたときに 150 度回転する振舞いを規定するクラス
 * @author marunomaruno
 * @version 1.0, 2008/09/29
 * @since 1.0
 */
public class DarkLine implements Behavior {

    private static final int THRESHOLD = 40;    // 黒線を判断するしきい値

    private Pilot pilot;
    
    private LightSensor lightSensor;

    public DarkLine(Pilot pilot) {
        this.pilot = pilot;
        lightSensor = new LightSensor(SensorPort.S2);
    }

    public boolean takeControl() {
        LCD.drawInt(lightSensor.readValue(), 1, 1);
        return lightSensor.readValue() < THRESHOLD;
    }

    public void suppress() {
        Sound.systemSound(true, 3);
        pilot.stop();
    }

    public void action() {
        pilot.stop();
        pilot.rotate(150);
    }
}
------------------------------------------------------


□ takeControl メソッド

光センサーを使って、黒線を超えたかどうかを判断します。超えた場合、
つまり、光度がしきい値(40)未満の場合は true を返し、これによって、
action メソッドが動くことになります。


□ action メソッド

ロボットを停止して、150 度回転します。



■黒線で書かれた枠の中で、障害物を避けながら走るプログラム

いよいよ、main メソッドを持つクラスです。
上記の3つの振舞いを持つオブジェクトを、Arbitrator クラスに渡して、
これらの振舞いを制御します。

------------------------------------------------------
package bhvr;

import l.EscapeListener;
import lejos.navigation.Pilot;
import lejos.nxt.Button;
import lejos.nxt.Motor;
import lejos.subsumption.Arbitrator;
import lejos.subsumption.Behavior;

/**
 * まっすぐ走る、
 * 障害物にぶつかったら少し後退して方向を換える、
 * 黒線をまたいだら、黒線をまたいだら360度回転して、進行方向を逆にする
 * 
 * @author marunomaruno
 * @version 1.0, 2008/09/29
 * @since 1.0
 */
public class Bumper21 {
    public static void main(String[] args) {

        // ESCAPE ボタンを押すとプログラム停止する
        Button.ESCAPE.addButtonListener(new EscapeListener());    

        // トライボットのオブジェクトを生成する
        Pilot trybot = new Pilot(5.6f, 13f, Motor.C, Motor.B);

        Behavior[] behaviors = {            // (1)
                new DriveForward(trybot),   // 直進する 
                new HitWall(trybot),        // 障害物にぶつかったときに後退して90度回転する
                new DarkLine(trybot),       // 黒線を超えたときに後退し、150度回転する
        };
        Arbitrator arbitrator = new Arbitrator(behaviors);   // (2)
        arbitrator.start();                                  // (3)
    }
}
------------------------------------------------------



□ Behavior[] behaviors = { // (1)
new DriveForward(trybot), // 直進する
new HitWall(trybot), // 障害物にぶつかったときに後退して90度回転する
new DarkLine(trybot), // 黒線を超えたときに150度回転する
};

振舞いを制御するオブジェクトを Behavior 配列に入れます。


□ Arbitrator arbitrator = new Arbitrator(behaviors); // (2)

Arbitrator は、このコンストラクタの引数で指定された振舞い制御オ
ブジェクトの配列の中から、現在のロボットの状態に合う振舞い制御オ
ブジェクトを選択し、それを実行します。
もし、2つの振舞いがこのロボットの状態に合う場合は、behaviors 配
列の添字の大きい方が優先されます。すなわち、ここでは
DarkLine (黒線を超えたときに150度回転する)
HitWall (障害物にぶつかったときに後退して90度回転する)
DriveForward (直進する)
オブジェクトの順になります。


□ Arbitrator クラスのコンストラクタ
---
Arbitrator(Behavior[] behaviors)
振舞いを制御するオブジェクトの配列を指定して、このインスタン
スを生成する。
---


□ arbitrator.start(); // (3)

指定された振舞いオブジェクトの調停を開始します。


□ Arbitrator クラスのメソッド
---
void start()
振舞いの制御を開始する。
---



以上


Lego Mindstoms NXT - leJOS - (12) Behavior (1)

2008年10月07日 | LEGO
◆ Lego Mindstoms NXT - leJOS - (12) Behavior と Arbitrator

複雑な動きをロボットにさせるときに、いままでのコーディングだと、
かなり難しくなります。
たとえば、黒線で囲まれたところからロボットが出ずに、その中だけで
障害物を避けながらロボットを動かす、というものです。
この複雑な動きを、単純な動きに分解して、これらを組み合わせること
で実現する API が leJOS にはあります。


■振舞い(Behavior)と調停者(Arbitrator)

lejOS には、ロボットの振舞いを規定する API があります。この
lejos.subsumption パッケージに入っている
Behavior インターフェース
Arbitrator クラス
がそうです。

ロボットに複数の振舞いをさせたいときには、それぞれの振舞いを
Behavior インターフェースを実装したオブジェクトとしてつくり、こ
れらを調停する Arbitrator クラスのオブジェクトに渡すことで、複雑
な振舞いを実現することができます。


■とりあえず、作ってみる

とりあえず、まっすぐ走り、障害物にぶつかったら、少しバックして方
向を換えてまた前に進む、というプログラムを考えます。これだけだと、
ロボットを止める手段がないので、Escape ボタンを押せばトライボッ
トは止まるようにしておきます。これは、前に作った EscapeListener
クラスを使うことにします。

ふつうに、何も考えずに main メソッドだけで作ると、こんな感じにな
ります。

------------------------------------------------------
import l.EscapeListener;
import lejos.navigation.Pilot;
import lejos.nxt.Button;
import lejos.nxt.Motor;
import lejos.nxt.SensorPort;
import lejos.nxt.Sound;
import lejos.nxt.TouchSensor;

/**
 * まっすぐ走り、障害物にぶつかったら、少しバックして方向を換えて
 * また前に進むプログラム
 * @author marunomaruno
 * @version 1.0, 2008/09/29
 * @since 1.0
 */
public class Bumper11 {
    public static void main(String [] args) {

        // ESCAPE ボタンを押すとプログラム停止する
        Button.ESCAPE.addButtonListener(new EscapeListener());    
        
        // トライボットのオブジェクトを生成する
        Pilot trybot = new Pilot(5.6f, 13f, Motor.C, Motor.B);

        // タッチセンサーオブジェクトをポート1で生成する
        TouchSensor touchSensor = new TouchSensor(SensorPort.S1);

        while (true) {
            trybot.forward();    // 直進する

            while (!touchSensor.isPressed());    // タッチされるまで待つ
            trybot.backward();    // 後退する
            Sound.pause(500);
            trybot.rotate(90);    // 回転する
        }
    }
}
------------------------------------------------------



このプログラムには、とくに難しいところはないですね。わりと素直な
プログラムだと思います。


■黒い枠線の中からロボットが出ないように改造する

このプログラムに、さらに黒線をまたいだら 150 度回転して、進行方
向を逆にするように改良するとします。
まあ、黒線で囲まれた枠の中から出ないようにするということですね。

単純なつくりだと、かなりコードが厄介になってきたのがわかるでしょ
うか。

------------------------------------------------------
import l.EscapeListener;
import lejos.navigation.Pilot;
import lejos.nxt.Button;
import lejos.nxt.LCD;
import lejos.nxt.LightSensor;
import lejos.nxt.Motor;
import lejos.nxt.SensorPort;
import lejos.nxt.Sound;
import lejos.nxt.TouchSensor;

/**
 * まっすぐ走り、障害物にぶつかったら、少しバックして方向を換えて
 * また前に進む。または、黒線をまたいだら150度方向転換するプログラム。
 * @author marunomaruno
 * @version 1.0, 2008/09/29
 * @since 1.0
 */
public class Bumper12 {

    private static final int THRESHOLD = 40;    // 黒線を判断するしきい値

    public static void main(String [] args) {

        // ESCAPE ボタンを押すとプログラム停止する
        Button.ESCAPE.addButtonListener(new EscapeListener());    
        
        // トライボットのオブジェクトを生成する
        Pilot trybot = new Pilot(5.6f, 13f, Motor.C, Motor.B);

        // タッチセンサーオブジェクトをポート1で生成する
        TouchSensor touchSensor = new TouchSensor(SensorPort.S1);

        // 光センサーオブジェクトをポート1で生成する
        LightSensor lightSensor = new LightSensor(SensorPort.S2);

        while (true) {
            trybot.forward();         // 直進する

            while (!touchSensor.isPressed() && (lightSensor.readValue() >= THRESHOLD));    // タッチされるか黒線を超えるまで待つ

            LCD.clear();
            LCD.drawString(touchSensor.isPressed() ? "true" : "false", 1, 1);
            LCD.drawInt(lightSensor.readValue(), 1, 2);

            if (touchSensor.isPressed()) {
                // 障害物にぶつかった場合
                trybot.backward();    // 後退する
                Sound.pause(500);
                trybot.rotate(90);    // 回転する

            } else {
                // 黒線を越えた場合
                trybot.stop();        // 停止する
                trybot.rotate(150);   // 回転する
            }
        }
    }
}
------------------------------------------------------


このプログラムは、
まっすぐ走る
障害物にぶつかったら少し後退して方向を換える
黒線をまたいだら、黒線をまたいだら 150 度回転して、進行方向
を逆にする
という 3 つの振舞いの複合になっており、まっすぐ走っている最中に、
障害物にぶつかる、黒線をまたぐ、といったイベントに対して、それぞ
れ、少し後退して方向を換える、150度回転する、といった振舞いを実
装しないといけないからです。

まだ、3 つの振舞いだけであれば何とかなっても、ここに、別の振舞い
を入れると、プログラムのコードは飛躍的に難しくなります。


これを、上記の 3 つの振舞いを持ったオブジェクトに分解して、それ
ぞれのオブジェクトを制御する形でメインメソッドを作ると、プログラ
ムはけっこうすっきりした形になります。

次回は、このための API が、Behavior インターフェースと
Arbitrator クラスをつかって作り直してみましょう。


以上

ロボットレースによる 組込み技術者養成講座

2008年09月28日 | LEGO
ロボットレースによる 組込み技術者養成講座
http://www.bricklife.com/weblog/cat_robot.html
単行本(ソフトカバー): 256ページ
出版社: 毎日コミュニケーションズ (2008/8/26)
言語 日本語
ISBN-10: 4839926549
ISBN-13: 978-4839926540
発売日: 2008/8/26
商品の寸法: 23.4 x 18.4 x 1.2 cm

目次

序章
動く化は面白い
1章 クイックスタート
1.1 プログラム開発の準備
1.2 ロボットを組み立てる
1.3 RCXをJavaで動かす準備
1.4 センサとモータを使おう

2章 モデリングと実装の基本
2.1 モデリングと実装の基本
2.2 UMLをちょっとお勉強
2.3 UMLモデリングツールを使おう
2.4 まずモデルを描いてみよう
2.5 よしJavaで実装しよう
2.6 さあ動かそう

3章 C言語による実装
3.1 開発環境設定(C)
3.2 スピード重視ならC

4章 開発の流れを体感しよう
4.1 要求定義
4.2 分析
4.3 設計
4.4 実装
4.5 テスト

5章 モデルの改善
5.1 モデルを改善しよう
5.2 ユースケース図(要求)の改善
5.3 クラス図(静的な側面)の改善
5.4 シーケンス図と状態図(動的な側面)の改善

6章 機能・性能向上のヒント
6.1 要素技術を理解しておこう
6.2 制御を改善しよう
6.3 難所を克服
6.4 JavaかCか

7章 歴史と実例に学ぶ
7.1 ETロボコンの歴史とコースの進化
7.2 これまでのモデルを振り返る

終章
すべての組込み技術者に

付録
ETロボコンの概要
ミニETロボコンをやろう!


Lego Mindstoms NXT - leJOS - (11) トーン

2008年09月23日 | LEGO
◆ Lego Mindstoms NXT - leJOS - (11) トーン

■ 音を鳴らす

トーンを使って、音を鳴らすことができます。これには、周波数、持続
時間、音量を指定する playTone メソッドを使います。このメソッドは、
playSample メソッドと違い、pause メソッドを使って音を鳴らす時間
を指定しなければなりません。

------------------------------------------------------
import lejos.nxt.Sound;

/**
 * PlayingMusic01.nxc
 * 「トライボット」使用
 * 音を鳴らす。
 * @author maruno
 * @version 1.0, 2008-01-12
 * @since 1.0
 */
public class PlayingMusic01 {

    public static void main(String[] args) {

        Sound.setVolume(40);    // (1)

        // 音階6 を B から C まで
        Sound.playTone(1976, 400); Sound.pause(500);    // (2)
        Sound.playTone(1865, 400); Sound.pause(500);
        Sound.playTone(1760, 400); Sound.pause(500);
        Sound.playTone(1661, 400); Sound.pause(500);
        Sound.playTone(1568, 400); Sound.pause(500);
        Sound.playTone(1480, 400); Sound.pause(500);
        Sound.playTone(1397, 400); Sound.pause(500);
        Sound.playTone(1319, 400); Sound.pause(500);
        Sound.playTone(1245, 400); Sound.pause(500);
        Sound.playTone(1175, 400); Sound.pause(500);
        Sound.playTone(1109, 400); Sound.pause(500);
        Sound.playTone(1047, 400); Sound.pause(500);
    }
}
------------------------------------------------------


□ Sound.setVolume(40); // (1)

音量を 40 に設定します。


□ Sound.playTone(1976, 400); Sound.pause(500); // (2)


周波数 1976、持続時間 400 ミリ秒でトーンを鳴らします。
ただし、このメソッドも、すぐにつぎの命令を実行してしまうので、
pause メソッドを使ってスリープ状態を作ってあげなければなりません。
多少、持続時間に余裕を持たせてあげた方がいいでしょう。


□ 周波数はつぎの表によります。

ただし、この表は NXC のマニュアルから持ってきたもので、leJOS の
API には書かれていませんので、この値でいいかどうかはわかりません。
(★)

---
Sound  3   4   5   6    7    8    9
B     247 494 988 1976 3951 7902
A#    233 466 932 1865 3729 7458
A     220 440 880 1760 3520 7040 14080
G#        415 831 1661 3322 6644 13288
G         392 784 1568 3136 6272 12544
F#        370 740 1480 2960 5920 11840
F         349 698 1397 2794 5588 11176
E         330 659 1319 2637 5274 10548
D#        311 622 1245 2489 4978 9956
D         294 587 1175 2349 4699 9398
C#        277 554 1109 2217 4435 8870
C         262 523 1047 2093 4186 8372
---



■ 実際の音楽っぽく

つぎは、ある曲を実装したものです。
楽譜を基に実装したのだが、まったく違うものらしい。
わたしの楽譜の読み方が違うのか、周波数のトーンが間違っているのか
?
(中学の音楽は 1 がついたこともあったくらいなので...)

まずは、音階関係を定数にしておいたほうが使いやすいので、これらを
ユーティリティクラスとして作っておきます。

------------------------------------------------------
package u;

import lejos.nxt.Sound;

/**
 * 音関係のユーティリティのクラス
 * @author marunomaruno
 * @version 1.0, 2008/06/29
 * @since 1.0
 */
public class SoundUtil {

    /*
     * 周波数
     */
    public static int  FR_B3 = 247;
    public static int  FR_B4 = 494;
    public static int  FR_B5 = 988;
    public static int  FR_B6 = 1976;
    public static int  FR_B7 = 3951;
    public static int  FR_B8 = 7902;

    public static int  FR_AS3 = 233;
    public static int  FR_AS4 = 466;
    public static int  FR_AS5 = 932;
    public static int  FR_AS6 = 1865;
    public static int  FR_AS7 = 3729;
    public static int  FR_AS8 = 7458;

    public static int  FR_A3 = 220;
    public static int  FR_A4 = 440;
    public static int  FR_A5 = 880;
    public static int  FR_A6 = 1760;
    public static int  FR_A7 = 3520;
    public static int  FR_A8 = 7040;
    public static int  FR_A9 = 14080;

    public static int  FR_GS4 = 415;
    public static int  FR_GS5 = 831;
    public static int  FR_GS6 = 1661;
    public static int  FR_GS7 = 3322;
    public static int  FR_GS8 = 6644;
    public static int  FR_GS9 = 13288;

    public static int  FR_G4 = 392;
    public static int  FR_G5 = 784;
    public static int  FR_G6 = 1568;
    public static int  FR_G7 = 3136;
    public static int  FR_G8 = 6272;
    public static int  FR_G9 = 12544;

    public static int  FR_FS4 = 370;
    public static int  FR_FS5 = 740;
    public static int  FR_FS6 = 1480;
    public static int  FR_FS7 = 2960;
    public static int  FR_FS8 = 5920;
    public static int  FR_FS9 = 11840;

    public static int  FR_F4 = 349;
    public static int  FR_F5 = 698;
    public static int  FR_F6 = 1397;
    public static int  FR_F7 = 2794;
    public static int  FR_F8 = 5588;
    public static int  FR_F9 = 11176;

    public static int  FR_E4 = 330;
    public static int  FR_E5 = 659;
    public static int  FR_E6 = 1319;
    public static int  FR_E7 = 2637;
    public static int  FR_E8 = 5274;
    public static int  FR_E9 = 10548;

    public static int  FR_DS4 = 311;
    public static int  FR_DS5 = 622;
    public static int  FR_DS6 = 1245;
    public static int  FR_DS7 = 2489;
    public static int  FR_DS8 = 4978;
    public static int  FR_DS9 = 9956;

    public static int  FR_D4 = 294;
    public static int  FR_D5 = 587;
    public static int  FR_D6 = 1175;
    public static int  FR_D7 = 2349;
    public static int  FR_D8 = 4699;
    public static int  FR_D9 = 9398;

    public static int  FR_CS4 = 277;
    public static int  FR_CS5 = 554;
    public static int  FR_CS6 = 1109;
    public static int  FR_CS7 = 2217;
    public static int  FR_CS8 = 4435;
    public static int  FR_CS9 = 8870;

    public static int  FR_C4 = 262;
    public static int  FR_C5 = 523;
    public static int  FR_C6 = 1047;
    public static int  FR_C7 = 2093;
    public static int  FR_C8 = 4186;
    public static int  FR_C9 = 8372;

    /**
     * 全音符
     */
    public static int  NOTE_SEMIBREVE = 1200;
    /**
     * 二分音符
     */
    public static int  NOTE_MINIM     = (NOTE_SEMIBREVE / 2); 
    /**
     * 四分音符
     */
    public static int  NOTE_CROTCHET  = (NOTE_MINIM     / 2); 
    /**
     * 八分音符
     */
    public static int  NOTE_QUAVER    = (NOTE_CROTCHET  / 2); 

    /**
     * 指定周波数、持続時間でトーンを鳴らします。このとき、指定された間隔時間を鳴らした後に取ります。
     * @param frequency 周波数
     * @param duration 持続時間
     * @param interval 間隔時間
     */
    public static void playTone(int frequency, int duration, int interval) {
        Sound.playTone(frequency, duration); 
        Sound.pause(duration + interval);
    }
    
    /**
     * 指定周波数、持続時間、音量でトーンを鳴らします。このとき、指定された間隔時間を鳴らした後に取ります。
     * @param frequency 周波数
     * @param duration 持続時間
     * @param volume 音量
     * @param interval 間隔時間
     */
    public static void playTone(int frequency, int duration, int volume, int interval) {
        Sound.playTone(frequency, duration, volume); 
        Sound.pause(duration + interval);
    }
}
------------------------------------------------------



それでは、これを基に音を鳴らしてみましょう。

------------------------------------------------------
import lejos.nxt.Sound;
import u.SoundUtil;

/**
 * 「トライボット」使用
 * 音を鳴らす。
 * @author maruno
 * @version 1.0, 2008-06-29
 * @since 1.0
 */
public class PlayingMusic03 {

    public static void main(String[] args) {

        final int INTERVAL = 80;

        Sound.setVolume(40);

        SoundUtil.playTone(SoundUtil.FR_C6,  SoundUtil.NOTE_MINIM,    INTERVAL);
        SoundUtil.playTone(SoundUtil.FR_C5,  SoundUtil.NOTE_QUAVER,   INTERVAL);
        SoundUtil.playTone(SoundUtil.FR_C4,  SoundUtil.NOTE_CROTCHET, INTERVAL);
        SoundUtil.playTone(SoundUtil.FR_C5,  SoundUtil.NOTE_CROTCHET, INTERVAL);
                           
        SoundUtil.playTone(SoundUtil.FR_AS6, SoundUtil.NOTE_CROTCHET, INTERVAL);
        SoundUtil.playTone(SoundUtil.FR_AS6, SoundUtil.NOTE_CROTCHET, INTERVAL);
        SoundUtil.playTone(SoundUtil.FR_AS6, SoundUtil.NOTE_CROTCHET, INTERVAL + SoundUtil.NOTE_CROTCHET);
                           
        SoundUtil.playTone(SoundUtil.FR_DS5, SoundUtil.NOTE_CROTCHET, INTERVAL);
        SoundUtil.playTone(SoundUtil.FR_DS5, SoundUtil.NOTE_CROTCHET, INTERVAL);
        SoundUtil.playTone(SoundUtil.FR_DS5, SoundUtil.NOTE_CROTCHET, INTERVAL + SoundUtil.NOTE_CROTCHET);
                           
        SoundUtil.playTone(SoundUtil.FR_G6,  SoundUtil.NOTE_CROTCHET, INTERVAL);
        SoundUtil.playTone(SoundUtil.FR_G8,  SoundUtil.NOTE_CROTCHET, INTERVAL);
        SoundUtil.playTone(SoundUtil.FR_G8,  SoundUtil.NOTE_CROTCHET, INTERVAL + SoundUtil.NOTE_CROTCHET);
                           
        SoundUtil.playTone(SoundUtil.FR_C6,  SoundUtil.NOTE_MINIM,    INTERVAL);
        SoundUtil.playTone(SoundUtil.FR_C5,  SoundUtil.NOTE_QUAVER,   INTERVAL);
        SoundUtil.playTone(SoundUtil.FR_C4,  SoundUtil.NOTE_CROTCHET, INTERVAL);
        SoundUtil.playTone(SoundUtil.FR_C5,  SoundUtil.NOTE_CROTCHET, INTERVAL);
                           
        SoundUtil.playTone(SoundUtil.FR_AS6, SoundUtil.NOTE_CROTCHET, INTERVAL);
        SoundUtil.playTone(SoundUtil.FR_AS6, SoundUtil.NOTE_CROTCHET, INTERVAL);
        SoundUtil.playTone(SoundUtil.FR_AS6, SoundUtil.NOTE_CROTCHET, INTERVAL + SoundUtil.NOTE_CROTCHET);
                           
        SoundUtil.playTone(SoundUtil.FR_DS5, SoundUtil.NOTE_CROTCHET, INTERVAL);
        SoundUtil.playTone(SoundUtil.FR_DS5, SoundUtil.NOTE_CROTCHET, INTERVAL);
        SoundUtil.playTone(SoundUtil.FR_DS6, SoundUtil.NOTE_MINIM,    INTERVAL);
        SoundUtil.playTone(SoundUtil.FR_DS5, SoundUtil.NOTE_QUAVER,   INTERVAL);
                           
        SoundUtil.playTone(SoundUtil.FR_C4,  SoundUtil.NOTE_SEMIBREVE, INTERVAL);

    }
}
------------------------------------------------------



以上

Lego Mindstoms NXT - leJOS - (10) ミュージック

2008年09月16日 | LEGO
◆ Lego Mindstomes NXT - leJOS - (10) ミュージック

今回は、NXT を使って音を鳴らします。

rsoファイル関係の記述を修正(2010-02-17)

■ wavrso ファイル


2 つのサウンドファイル(.rso)を鳴らします。
最初は、NTX の起動音を 2 秒間。つぎに、"Good Job" を 2 秒間繰り
返します(実際には、2回と少し)。

"ringin.wav" を鳴らします。

------------------------------------------------------
import java.io.File;

import lejos.nxt.Sound;

/**
 * 「トライボット」使用
 * wavrso ファイルを鳴らす。
 * @author maruno
 * @version 2.0, 2010-02-18
 * @version 1.0, 2008-06-26
 * @since 1.0
 */
public class PlayingFile01 {

    static final String WAV_FILE_NAME = "ringin.wav";    // ファイル名
    static final int DURATION = 400;    // 持続時間

    public static void main(String[] args) {
//        Sound.playSample(new File("! Startup.rso")); // (1)
//        Sound.playSample(new File("Good Job.rso")); // (2)

        System.out.println("Press any button to play.");
        Button.waitForPress();
        Sound.playSample(new File(WAV_FILE_NAME)); // wavファイルを鳴らす
        Sound.pause(DURATION);
    }
}

------------------------------------------------------


□ Sound.playSample(new File("! Startup.rso")); // (1)

wav ファイルを鳴らします。このメソッドの後に、
Sound.pause()を使って、時間を指定します。

もともとの NXT の起動音を鳴らします。ファイルは、File オブジェク
トにして指定します。

△ NXC との違い
---
NXC のときは、PlayFileEx 関数を使って鳴らしました。このとき、こ
の関数単独では鳴らず、後ろに、Wait 関数の指定が必須でした。leJOS
では、この playSample メソッド単独で鳴らすことができます。
ただし、繰り返しなどの指定はできないようです。(★)
---


□ Sound クラス

音を鳴らす関連のメソッドをもったクラスです。


□ Sound クラスのおもなメソッド
---
static void beep()
1 回、ビープ音を鳴らします。

static void pause(int t)
指定したミリ秒数分停止(スリープ)します。

static void playNote(int[] inst, int freq, int len)
音符を開始します。

static int playSample(File file)
wav ファイルを演奏します。戻り値は演奏時間で、エラーが発生し
たときは負数。

static int playSample(File file, int vol)
wav ファイルを指定された音量で演奏します。音量は 0-100 の間
で指定します。戻り値は演奏時間で、エラーが発生したときは負数。

static void playTone(int freq, int duration)
トーンを演奏します。

static void playTone(int aFrequency, int aDuration, int aVolume)

トーンを演奏します。

static void setVolume(int vol)
音量を設定します。
---


□ Sound.playSample(new File("Good Job.rso")); // (2)

"Good Job" を鳴らします。

ただし、これは鳴りません。指定されたサウンドファイル
"Good Job.rso" が NXT の中に入っていないからです。



---
サウンドファイルの NXT へのダウンロード方法。
java.io パッケージをつかうのだろうか?
---

このプログラムを動かす前に、wav ファイルを NXT にダウンロードします。
nxjupload wavファイル名

■ ビープ音を鳴らす

ビープ音を鳴らすだけであれば、それ用のメソッドが用意されています。

------------------------------------------------------
import lejos.nxt.Button;
import lejos.nxt.Sound;

/**
 * ビープ音を鳴らすプリケーション。
 * 
 * @author marunomaruno
 * @version 1.0, 2008/06/04
 * @since 1.0
 */
public class Beep01 {

    /**
     * @param args
     */
    public static void main(String[] args) {
        Sound.setVolume(Sound.VOL_MAX);                            // (1)
        
        System.out.println("Press any button to beep.");
        Button.waitForPress();
        Sound.beep();                                            // (2)

        System.out.println("Press any button to beep twice.");
        Button.waitForPress();
        Sound.twoBeeps();                                        // (3)

        System.out.println("Press any button to buzz.");
        Button.waitForPress();
        Sound.buzz();                                            // (4)

        System.out.println("Press any button to exit.");
        Button.waitForPress();
    }
}

------------------------------------------------------


□ Sound.setVolume(Sound.VOL_MAX); // (1)

最大音量を設定します。


□ Sound.beep(); // (2)

ビープ音を鳴らします。


□ Sound.twoBeeps(); // (3)

ビープ音を2回鳴らします。


□ Sound.buzz(); // (4)

バズ音を鳴らします。


■ システム音を鳴らす

ビープ音だけでなく、システムが用意した音を鳴らすメソッドが用意さ
れています。

------------------------------------------------------
import lejos.nxt.Button;
import lejos.nxt.Sound;

/**
 * システム音を鳴らすプリケーション。
 * 
 * @author marunomaruno
 * @version 1.0, 2008/06/04
 * @since 1.0
 */
public class SystemSound01 {

    /**
     * @param args
     */
    public static void main(String[] args) {
        Sound.setVolume(Sound.VOL_MAX);                        
        
        System.out.println("Press any button to code 0.");
        Button.waitForPress();
        Sound.systemSound(true, 0);                                // (1)

        System.out.println("Press any button to code 1.");
        Button.waitForPress();
        Sound.systemSound(true, 1);                    

        System.out.println("Press any button to code 2.");
        Button.waitForPress();
        Sound.systemSound(true, 2);                    

        System.out.println("Press any button to code 3.");
        Button.waitForPress();
        Sound.systemSound(true, 3);                            

        System.out.println("Press any button to code 4.");
        Button.waitForPress();
        Sound.systemSound(true, 4);                            

        System.out.println("Press any button to exit.");
        Button.waitForPress();
    }
}
------------------------------------------------------


□ Sound.systemSound(true, 0); // (1)

指定されたコードの音を鳴らす。


□ メソッド
---
static void systemSound(boolean aQueued, int aCode)
指定されたコードの音を鳴らす。
---

コードは、次の値を持っています。
----- -------------------- -------------
aCode システム音           代替メソッド
----- -------------------- -------------
  0   short beep           beep
  1   double beep          twoBeeps
  2   descending arpeggio  -
  3   ascending arpeggio   -
  4   long, low buzz       buzz
----- -------------------- -------------


以上

Lego Mindstoms NXT - leJOS - (9) リスナー

2008年09月02日 | LEGO
◆ Lego Mindstoms NXT - leJOS - (9) リスナー


■ タッチセンサーに対するリスナーを実装する

つぎは、タッチセンサーに対するリスナーです。
これには、TouchSensor クラスではなく、SensorPort クラスを用
いて、ポートの番号で管理することになります。

ただ、このプログラムだと、タッチしてすぐにプログラムは停止せ
ず、停止するまでに 1 秒程度のタイムラグがあります。

------------------------------------------------------
import lejos.nxt.SensorPort;
import lejos.nxt.SensorPortListener;
import tb.Trybot;
import u.NxtUtil;

/**
 * 「トライボット」使用
 * 1秒間前進し、その後1秒間停止、1秒間後退する。
 * その間に音を鳴らす。
 * エスケープ・ボタンが押されたら動きを止める。
 * @author maruno
 * @version 1.0, 2008-06-30
 * @since 1.0
 */
public class TouchListener01 {

    public static void main(String[] args) {

        // トライボットオブジェクトの生成
        Trybot trybot = new Trybot("trybot");

        SensorPort.S1.addSensorPortListener(new TouchListener());    // (1)

        while (true) {
            trybot.forward();
            NxtUtil.pause(500);
            trybot.stop();

            NxtUtil.pause(500);

            trybot.backward();
            NxtUtil.pause(500);
            trybot.stop();

            NxtUtil.pause(500);
        }
    }

    /**
     * タッチしたときに動作するリスナー
     * @author marunomaruno
     * @version 1.0, 2008/06/29
     * @since 1.0
     */
    static class TouchListener implements SensorPortListener {    // (2)
        /* (非 Javadoc)
         * @see lejos.nxt.SensorPortListener#stateChanged(lejos.nxt.SensorPort, int, int)
         */
        public void stateChanged(SensorPort aSource, int aOldValue, int aNewValue) {    // (3)
            NxtUtil.display(aSource, aOldValue, aNewValue, 2000);    // (4)
            System.exit(0);
        }
    }
}
------------------------------------------------------


ただし、これだと、タッチしていなくても、このメソッドが呼ばれ
てしまいます。
タッチセンサーの場合は、タッチされたかされないか、が返ればい
いので、2値に直して値を返す readBooleanValue メソッドを使う
必要があります。
タッチセンサーの場合は、このリスナーはすこし不便かもしれませ
ん。


□ SensorPort.S1.addSensorPortListener(new TouchListener()); // (1)

センサー・ポート S1 に、タッチセンサーのリスナーを追加します。


□ センサー・ポートの定数
---
static SensorPort[] PORTS
ポート 1 から ポート 4 まで入っている配列。

static SensorPort S1
ポート 1。

static SensorPort S2
ポート 2。

static SensorPort S3
ポート 3。

static SensorPort S4
ポート 4。
---


□ センサー・ポートの主なメソッド
---
void addSensorPortListener(SensorPortListener aListener)
指定されたリスナーをそのポートに追加します。

int getId()
ポート番号を返します。

boolean readBooleanValue()
boolean 値で値を返します。

int readRawValue()
実測値で値を返します。

int readValue()
Lego フレームワーク互換の値を返します。

---


□ static class TouchListener implements SensorPortListener { // (2)

static な内部クラスとして、SensorPortListener インタフェース
を実装します。


□ SensorPortListener インタフェースのメソッド
---
void stateChanged(SensorPort aSource, int aOldValue, int aNewValue)
センサーが指定されたポートで実測値の値が変わったときに呼
び出されます。

---


□ public void stateChanged(SensorPort aSource, int aOldValue, int aNewValue) { // (3)

センサーからの値が変わったときに呼び出されるメソッドの実装。


□ NxtUtil.display(aSource, aOldValue, aNewValue, 2000); // (4)

センサーの値を表示するメソッド display を NxtUtil クラスに用
意し、それを使います。
display メソッドの部分だけ示します。

------------------------------------------------------
    /**
     * 指定されたセンサーの情報をLCDに指定ミリ秒数表示します。
     * @param aSource センサー
     * @param aOldValue 変化がおきる前の値
     * @param aNewValue 変化後の値
     * @param milliseconds 表示ミリ秒数
     */
    public static void display(SensorPort aSource, int aOldValue, int aNewValue, int milliseconds) {
        LCD.clear();
        LCD.drawInt(aSource.getId(), 1, 1);   // ポートIDの値を表示する
        LCD.drawInt(aSource.getMode(), 1, 2); // モード値を表示する
        LCD.drawInt(aSource.getType(), 1, 3); // タイプ値を表示する
        LCD.drawInt(aOldValue, 1, 4);         // 変化がおきる前の値を表示
        LCD.drawInt(aNewValue, 1, 5);         // 変化後の値を表示する
        LCD.refresh();
        pause(milliseconds);
    }

------------------------------------------------------




■ 各センサーの値を読み取るリスナー

------------------------------------------------------
import l.EscapeListener;
import lejos.nxt.Button;
import lejos.nxt.SensorPort;
import lejos.nxt.SensorPortListener;
import tb.Trybot;
import u.NxtUtil;

/**
 * 「トライボット」使用
 * 各センサーからの値を表示する。
 * @author maruno
 * @version 1.0, 2008-06-29
 * @since 1.0
 */
public class SensorListener01 {

    public static void main(String[] args) {

        // トライボットオブジェクトの生成
        Trybot trybot = new Trybot("trybot");

        Button.ESCAPE.addButtonListener(new EscapeListener());    // (1)

        SensorPort.S1.addSensorPortListener(new Listener());    // (2) タッチセンサー
        SensorPort.S2.addSensorPortListener(new Listener());    // (3) 音センサー
        SensorPort.S3.addSensorPortListener(new Listener());    // (4) 光センサー
        SensorPort.S4.addSensorPortListener(new Listener());    // (5) 超音波センサー

        while (true) {
            trybot.forward();
            NxtUtil.pause(500);
            trybot.stop();

            NxtUtil.pause(500);

            trybot.backward();
            NxtUtil.pause(500);
            trybot.stop();

            NxtUtil.pause(500);
        }
    }

    /**
     * センサーの値に変化がおきたときに動作するリスナー
     * @author marunomaruno
     * @version 1.0, 2008/06/29
     * @since 1.0
     */
    static class Listener implements SensorPortListener {    
        /* (非 Javadoc)
         * @see lejos.nxt.SensorPortListener#stateChanged(lejos.nxt.SensorPort, int, int)
         */
        public void stateChanged(SensorPort aSource, int aOldValue, int aNewValue) {
            NxtUtil.display(aSource, aOldValue, aNewValue, 2000);
        }
    }

}
------------------------------------------------------



□ Button.ESCAPE.addButtonListener(new EscapeListener()); // (1)

また、エスケープ・ボタンで終わるようにする。


□ SensorPort.S1.addSensorPortListener(new Listener()); // (2) タッチセンサー
SensorPort.S2.addSensorPortListener(new Listener()); // (3) 音センサー
SensorPort.S3.addSensorPortListener(new Listener()); // (4) 光センサー
SensorPort.S4.addSensorPortListener(new Listener()); // (5) 超音波センサー

各ポートにつけたセンサーのリスナーを追加する。このとき、リス
ナーの動きはすべて同じなので、同じリスナーを使います。


以上


Lego Mindstoms NXT - leJOS - (8) ボタン・リスナー

2008年08月26日 | LEGO
◆ Lego Mindstoms NXT - leJOS - (8) ボタン・リスナー

leJOS では、ボタンを押す、などのイベントを拾って、そのイベン
トに対する操作を実現する仕組みが用意されています。

たとえば、トライボットが動いているときに、エスケープ・ボタン
を押したらトライボットが止まるようにしてみましょう。

トライボットは、500 ミリ秒ずつ前進と後退を繰り返します。前進、
後退の間に 500 ミリ秒間のの停止があります。


■ リスナーを使わない実装

いままでの知識だけで実装してみます。
これだと、後退して、500ミリ秒間停止しているときでないと、プ
ログラムは停止しません。すなわち、好きなときにプログラムを停
止することができないのです。

------------------------------------------------------
import lejos.nxt.Button;
import tb.Trybot;
import u.NxtUtil;

/**
 * 「トライボット」使用
 * エスケープボタンを押すと止まる。
 * (ただし、後退直後に押さないと止まらない)
 * @author maruno
 * @version 1.0, 2008-06-26
 * @since 1.0
 */
public class ButtonListener01 {

    public static void main(String[] args) {

        // トライボットオブジェクトの生成
        Trybot trybot = new Trybot("trybot");

        while (!Button.ESCAPE.isPressed()) {    // (1)
            trybot.forward();
            NxtUtil.pause(500);
            trybot.stop();

            NxtUtil.pause(500);

            trybot.backward();
            NxtUtil.pause(500);
            trybot.stop();

            NxtUtil.pause(500);

        }
    }

}
------------------------------------------------------



□ while (!Button.ESCAPE.isPressed()) { // (1)

エスケープ・ボタンが押されていない間繰り返します。



■ リスナーを使った実装

それでは、エスケープ・ボタンを押したことを検知して、そのとき
の動作をするリスナークラスを使って、先ほどのプログラムを作り
直します。

なお、リスナークラスは、パッケージ l に入れることにします。

------------------------------------------------------
import l.EscapeListener;
import lejos.nxt.Button;
import tb.Trybot;
import u.NxtUtil;

/**
 * 「トライボット」使用
 * エスケープボタンを押すと止まる。
 * @author maruno
 * @version 1.0, 2008-06-26
 * @since 1.0
 */
public class ButtonListener02 {

    public static void main(String[] args) {

        Button.ESCAPE.addButtonListener(new EscapeListener());    // (1)

        // トライボットオブジェクトの生成
        Trybot trybot = new Trybot("trybot");

        while (true) {    // (2)
            trybot.forward();
            NxtUtil.pause(500);
            trybot.stop();

            NxtUtil.pause(500);

            trybot.backward();
            NxtUtil.pause(500);
            trybot.stop();

            NxtUtil.pause(500);

        }
    }

}
------------------------------------------------------



□ Button.ESCAPE.addButtonListener(new EscapeListener()); // (1)

エスケープ・ボタンにリスナーを登録します。登録するには、ボタ
ンのオブジェクトの addButtonListener メソッドを使います。


□ addButtonListener メソッド
---
void addButtonListener(ButtonListener aListener)
ボタンイベントのリスナーオブジェクトを追加します。
---


□ while (true) { // (2)

今度は無限ループにしておきます。


□ リスナーのソースです。


------------------------------------------------------
package l;

import lejos.nxt.Button;
import lejos.nxt.ButtonListener;

/**
 * エスケープ・ボタンを押下したときに動作するリスナー
 * 
 * @author marunomaruno
 * @version 1.0, 2008/06/29
 * @since 1.0
 */
public class EscapeListener implements ButtonListener {    // (1)
    /*
     * (非 Javadoc)
     * 
     * @see lejos.nxt.ButtonListener#buttonPressed(lejos.nxt.Button)
     */
    public void buttonPressed(Button button) {    // (2)
        System.exit(0);
    }

    /*
     * (非 Javadoc)
     * 
     * @see lejos.nxt.ButtonListener#buttonReleased(lejos.nxt.Button)
     */
    public void buttonReleased(Button button) {    // (3)
        System.exit(0);
    }
}

------------------------------------------------------



□ public class EscapeListener implements ButtonListener { // (1)

エスケープ・ボタンが押されたことを処理するリスナー・クラスは、
ButtonListener インタフェースを実装します。


□ ButtonListener インタフェースのメソッド
---
void buttonPressed(Button b)
void buttonReleased(Button b)
---


□ public void buttonPressed(Button button) { // (2)

ボタンが押されたときの処理を実装します。今回は、プログラムを
終了するようにします。


□ public void buttonReleased(Button button) { // (3)

ボタンから離れたときの処理を実装します。今回は、プログラムを
終了するようにします。



■ 内部クラスを使った実装

この程度の実装のリスナーなら、わざわざ別クラスにすることもな
いでしょう。
static な内部クラスを使って実装します。


------------------------------------------------------
import lejos.nxt.Button;
import lejos.nxt.ButtonListener;
import tb.Trybot;
import u.NxtUtil;

/**
 * 「トライボット」使用
 * エスケープボタンを押すと止まる。
 * @author maruno
 * @version 1.0, 2008-06-26
 * @since 1.0
 */
public class ButtonListener03 {

    public static void main(String[] args) {

        Button.ESCAPE.addButtonListener(new EscapeListener());

        // トライボットオブジェクトの生成
        Trybot trybot = new Trybot("trybot");

        while (true) {
            trybot.forward();
            NxtUtil.pause(500);
            trybot.stop();

            NxtUtil.pause(500);

            trybot.backward();
            NxtUtil.pause(500);
            trybot.stop();

            NxtUtil.pause(500);
        }
    }

    /**
     * ボタンを押下したときに動作するリスナー
     * @author marunomaruno
     * @version 1.0, 2008/06/29
     * @since 1.0
     */
    static class EscapeListener implements ButtonListener {    // (1)
        /* (非 Javadoc)
         * @see lejos.nxt.ButtonListener#buttonPressed(lejos.nxt.Button)
         */
        public void buttonPressed(Button button) {
            System.exit(0);
        }

        /* (非 Javadoc)
         * @see lejos.nxt.ButtonListener#buttonReleased(lejos.nxt.Button)
         */
        public void buttonReleased(Button button) {
            System.exit(0);
        }
    }

}
------------------------------------------------------



□ static class EscapeListener implements ButtonListener { // (1)

内部クラスを使い、EscapeListener クラスを実装します。



以上


Lego Mindstoms NXT - leJOS - (7) トライボット・オブジェクト

2008年08月19日 | LEGO
◆ Lego Mindstoms NXT - leJOS - (7) トライボット・オブジェクト

前回、トライボットを動かすプログラムを作りました。これをもと
に、トライボット・クラスを作ってみましょう。

■ トライボットクラス

まず、「物が置かれるまで停止」や、「タッチするまで前進」など
をメソッドとして扱えるようにします。この、物を置かれるまで停
止などは、超音波センサーを使っていますが、そのようなセンサー
やモーターなどを標準のポートにつなげたトライボット・オブジェ
クトや、標準とは別のポートにつけることもできるようにします。
操作用の各メソッドは、その実行時間をミリ秒単位で返すようにし
ます。とりあえず、つけておけば何かの役に立つかもしれません。
さらに、センサーのしきい値も標準値を用意し、なにも指定しなけ
れば、しきい値として標準値を使うようにしましょう。
また、将来は複数台のトライボットを使えるようにするため、個々
のオブジェクトを識別できるように名前をつけられるようにします。
他と区別つくように、パッケージ tb としておきます。


□ 定数の概要
---
static int LIGHT_THRESHOLD
光センサーで明暗を分ける標準のしきい値

static int SOUND_THRESHOLD
音センサーで音を聞き分ける標準のしきい値

static int ULTRASONIC_THRESHOLD
超音波センサーの前に物を置いたことを検知する標準の
しきい値
---


□ コンストラクタの概要
---
Trybot(String name)
トライボットを、すべて標準ポートで生成します。

Trybot(String name, float wheelDiameter, float trackWidth,
Motor leftMotor, Motor rightMotor, Motor arm,
TouchSensor touchSensor, SoundSensor soundSensor,
LightSensor lightSensor,
UltrasonicSensor ultrasonicSensor)
トライボットを、指定されたポートで生成します。
---


□ メソッドの概要
---
long closeArm(long millis)
指定されたミリ秒間、アームを閉じます。

long forwardUntilDark()
暗くなるまで前進します。

long forwardUntilDark(long threshold)
暗くなるまで前進します。

long forwardUntilTouch()
タッチされるまで前進します。

Motor getArm()
アームを取得します。

LightSensor getLightSensor()
光センサーを取得します。

String getName()
名前を取得します。

SoundSensor getSoundSensor()
音センサーを取得します。

TouchSensor getTouchSensor()
タッチセンサーを取得します。

UltrasonicSensor getUltrasonicSensor()
超音波センサーを取得します。

long openArm(long millis)
指定されたミリ秒間、アームを開きます。

long reverseMilliSeconds(long millis)
指定されたミリ秒間後退します。

long rotetoLeftMilliSeconds(long millis)
指定されたミリ秒間左回転します。

long stopUntilAnySound()
音がするまで停止します。

long stopUntilAnySound(long threshold)
音がするまで停止します。

long stopUntilPut()
物が置かれるまで停止します。

long stopUntilPut(long threshold)
物が置かれるまで停止します。
---


□ 上記APIに基づいたクラス

------------------------------------------------------
package tb;

import lejos.navigation.Pilot;
import lejos.nxt.LightSensor;
import lejos.nxt.Motor;
import lejos.nxt.SensorPort;
import lejos.nxt.SoundSensor;
import lejos.nxt.TouchSensor;
import lejos.nxt.UltrasonicSensor;
import u.NxtUtil;

/**
 * トライボットで必要な操作を管理するクラスです。 名前を指定するだけで、すべて標準のポートでこのオブジェクトを生成できます。
 * 
 * @author marunomaruno
 * @version 1.0, 2008/06/24
 * @since 1.0
 */
public class Trybot extends Pilot {

    /**
     * 超音波センサーの前に物を置いたことを検知する標準のしきい値
     */
    public static final int ULTRASONIC_THRESHOLD = 51; // 物を置くしきい値

    /**
     * 音センサーで音を聞き分ける標準のしきい値
     */
    public static final int SOUND_THRESHOLD = 50; // 音のしきい値

    /**
     * 光センサーで明暗を分ける標準のしきい値
     */
    public static final int LIGHT_THRESHOLD = 40; // 光のしきい値

    private String name; // 名前
    private Motor arm; // アーム
    private TouchSensor touchSensor; // タッチセンサーオブジェクト
    private SoundSensor soundSensor; // 音センサーオブジェクト
    private LightSensor lightSensor; // 光センサーオブジェクト
    private UltrasonicSensor ultrasonicSensor; // 超音波センサーオブジェクト

    /**
     * トライボットを、すべて標準ポートで生成します。 標準ポートは以下のとおりです。
     * 
     * 

*

    *
  • 左モーター: ポート B *
  • 右モーター: ポート C *
  • アーム: ポート A *
  • タッチセンサー: ポート 1 *
  • 音センサー: ポート 2 *
  • 光センサー + ライト: ポート 3 *
  • 超音波センサー: ポート 4 *

*


*
* @param name 名前
*
*/
public Trybot(String name) {
this(name, 5.6f, 13f, Motor.C, Motor.B, Motor.A, new TouchSensor(
SensorPort.S1), new SoundSensor(SensorPort.S2),
new LightSensor(SensorPort.S3), new UltrasonicSensor(
SensorPort.S4));
}

/**
* トライボットを、指定されたポートで生成します。
*
* @param name 名前
* @param wheelDiameter 車輪径
* @param trackWidth トラック幅
* @param leftMotor 左モーター
* @param rightMotor 右モーター
* @param arm アーム
* @param touchSensor タッチセンサー
* @param soundSensor 音センサー
* @param lightSensor 光センサー
* @param ultrasonicSensor 超音波センサー
*/
public Trybot(String name, float wheelDiameter, float trackWidth,
Motor leftMotor, Motor rightMotor, Motor arm,
TouchSensor touchSensor, SoundSensor soundSensor,
LightSensor lightSensor, UltrasonicSensor ultrasonicSensor) {
super(wheelDiameter, trackWidth, leftMotor, rightMotor);
this.name = name;
this.arm = arm;
this.touchSensor = touchSensor;
this.soundSensor = soundSensor;
this.lightSensor = lightSensor;
this.ultrasonicSensor = ultrasonicSensor;
}

/**
* タッチされるまで前進します。
* @return このメソッドの実行にかかった時間
*/
public long forwardUntilTouch() {
long startTime = System.currentTimeMillis();
forward();
while (!touchSensor.isPressed())
;
return System.currentTimeMillis() - startTime;
}

/**
* 暗くなるまで前進します。
* @return このメソッドの実行にかかった時間
*/
public long forwardUntilDark() {
return forwardUntilDark(LIGHT_THRESHOLD);
}

/**
* 暗くなるまで前進します。
* @param threshold 暗くなるしきい値
* @return このメソッドの実行にかかった時間
*/
public long forwardUntilDark(long threshold) {
long startTime = System.currentTimeMillis();
forward();
while (lightSensor.readValue() >= threshold)
;
stop();
return System.currentTimeMillis() - startTime;
}

/**
* 指定されたミリ秒間後退します。
* @param millis 後退する時間(ミリ秒)
* @return このメソッドの実行にかかった時間
*/
public long reverseMilliSeconds(long millis) {
long startTime = System.currentTimeMillis();
backward();
NxtUtil.pause(millis);
stop();
return System.currentTimeMillis() - startTime;
}

/**
* 指定されたミリ秒間左回転します。
* @param millis 回転する時間(ミリ秒)
* @return このメソッドの実行にかかった時間
*/
public long rotetoLeftMilliSeconds(long millis) {
long startTime = System.currentTimeMillis();
getLeft().backward();
getRight().forward();
NxtUtil.pause(millis);
stop();
return System.currentTimeMillis() - startTime;
}

/**
* 指定されたミリ秒間、アームを閉じます。
* @param millis 閉じる時間(ミリ秒)
* @return このメソッドの実行にかかった時間
*/
public long closeArm(long millis) {
long startTime = System.currentTimeMillis();
arm.backward();
NxtUtil.pause(millis);
arm.stop();
return System.currentTimeMillis() - startTime;
}

/**
* 指定されたミリ秒間、アームを開きます。
* @param millis 開く時間(ミリ秒)
* @return このメソッドの実行にかかった時間
*/
public long openArm(long millis) {
long startTime = System.currentTimeMillis();
arm.forward();
NxtUtil.pause(millis);
arm.stop();
return System.currentTimeMillis() - startTime;
}

/**
* 物が置かれるまで停止します。
* @return このメソッドの実行にかかった時間
*/
public long stopUntilPut() {
return stopUntilPut(ULTRASONIC_THRESHOLD);
}

/**
* 物が置かれるまで停止します。
* @param threshold 物が置かれるしきい値
* @return このメソッドの実行にかかった時間
*/
public long stopUntilPut(long threshold) {
long startTime = System.currentTimeMillis();
stop();
while (ultrasonicSensor.getDistance() >= threshold)
;
return System.currentTimeMillis() - startTime;
}

/**
* 音がするまで停止します。
* @return このメソッドの実行にかかった時間
*/
public long stopUntilAnySound() {
return stopUntilAnySound(SOUND_THRESHOLD);
}

/**
* 音がするまで停止します。
* @param threshold 音を認識するしきい値
* @return このメソッドの実行にかかった時間
*/
public long stopUntilAnySound(long threshold) {
long startTime = System.currentTimeMillis();
stop();
while (soundSensor.readValue() <= threshold)
;
return System.currentTimeMillis() - startTime;
}

// 標準のゲッターの記載は省略します。

}
------------------------------------------------------


もちろん、これだけのメソッドでは、足りません。
「物が置かれるまで停止する」というメソッドがあれば、当然、
「物が置かれると前進する」などのメソッドも必要です。
ただ、あまり作りすぎてしまうと、メモリーが足りなくなると思い
ますので、必要なものだけを作っておいた方がいいでしょう。(も
う、すでに作りすぎているかもしれませんが。。。)



■ このクラスを作って Trybot01 を作り変えます。

かなりすっきりしました。でも、これはやりすぎかもしれません。
この調子でやっていったら、メソッドは際限なく増えてきますね。

------------------------------------------------------
import tb.Trybot;

/**
 * トライボット」使用 
 * 前進し、そこでタッチしたものをつかみ、後退、回転し、
 * 黒線があるところまで前進し、黒線のところでつかんだものを離す。
 * 
 * @author maruno
 * @version 1.0, 2008-06-20
 * @since 1.0
 */
public class Trybot02 {

    public static void main(String[] args) {

        // トライボットオブジェクトの生成
        Trybot trybot = new Trybot("trybot");    // (1)

        // 物が置かれるまで停止
        trybot.stopUntilPut();

        // タッチするまで前進
        trybot.forwardUntilTouch();

        // 音がするまで停止
        trybot.stopUntilAnySound();

        // アームを閉じる
        trybot.closeArm(500);

        // 後退
        trybot.reverseMilliSeconds(500);

        // 回転
        trybot.rotetoLeftMilliSeconds(500);

        // 黒線のところまで前進して停止
        trybot.forwardUntilDark();

        // アームを開く
        trybot.openArm(500);
    }
}

------------------------------------------------------



□ Trybot trybot = new Trybot("trybot"); // (1)

名前を指定して Trybot オブジェクトを生成します。これは、すべ
て標準のポートを利用しています。


以上


Lego Mindstoms NXT - leJOS - (6) 各種センサー

2008年08月05日 | LEGO
◆ Lego Mindstoms NXT - leJOS - (6) 各種センサー

■ 各センサーの値を読み取る

それでは、タッチセンサーだけではなく、その他のセンサーも NXT
ブロックにつけてその動きを確認してみましょう。このプログラム
は、それぞれのセンサーからの値を NXT 画面に表示するものです。
プログラムを終わらせるには、エスケープボタンを押します。


------------------------------------------------------
import u.NxtUtil;
import lejos.nxt.Button;
import lejos.nxt.LCD;
import lejos.nxt.LightSensor;
import lejos.nxt.Motor;
import lejos.nxt.SensorPort;
import lejos.nxt.SoundSensor;
import lejos.nxt.TouchSensor;
import lejos.nxt.UltrasonicSensor;

/**
 * 「トライボット」使用
 * センサーの値を読み取り、表示する。
 * 
 * @author marunomaruno
 * @version 1.0, 2008/06/04
 * @since 1.0
 */
public class Sensor01 {

    public static void main(String[] args) {

        // タッチセンサーオブジェクトをポート1で生成する。
        TouchSensor touchSensor = new TouchSensor(SensorPort.S1);

        // 音センサーオブジェクトをポート2で生成する。
        SoundSensor soundSensor = new SoundSensor(SensorPort.S2);    // (1)
        
        // 光センサーオブジェクトをポート3で生成する。
        LightSensor lightSensor = new LightSensor(SensorPort.S3);    // (2)
        
        // 超音波センサーオブジェクトをポート4で生成する。
        UltrasonicSensor ultrasonicSensor = new UltrasonicSensor(SensorPort.S4);    // (3)
        
        Motor.A.forward();
        
        while (!Button.ESCAPE.isPressed()) {    // (4)
            LCD.refresh();
            
            // タッチセンサーの値の表示
            LCD.drawString("Touch    = " + touchSensor.isPressed(), 0, 0);

            // 音センサーの値の表示
            LCD.drawString("Sound    = " + soundSensor.readValue(), 0, 1);    // (5)
            
            // 光センサーの値の表示
            LCD.drawString("Light    = " + lightSensor.readValue(), 0, 2);    // (6)
            
            // 超音波センサーの値の表示
            LCD.drawString("US       = " + ultrasonicSensor.getDistance(), 0, 3);    // (7)
            
            // モーター回転速度センサーの値の表示
            LCD.drawString("Tacho    = " + Motor.A.getTachoCount(), 0, 4);    // (8)
            
            // モーター回転センサーの値の表示
            LCD.drawString("Rotation = " + Motor.A.getStopAngle(), 0, 5);    // (9)

        }
        Motor.A.stop();
        NxtUtil.pause(1000);
    }
}

------------------------------------------------------



□ SoundSensor soundSensor = new SoundSensor(SensorPort.S2); // (1)

音センサーオブジェクトをポート2で生成する。


□ コンストラクタ
---
SoundSensor(lejos.nxt.ADSensorPort port)
音センサーオブジェクトを指定ポートで生成する。

SoundSensor(SensorPort port, boolean dba)
音センサーオブジェクトを指定ポートで生成する。このとき、
DB か DBA モードかもあわせて指定する。
---


□ 主なメソッド
---
int readValue()
現在のセンサー値を読む。

void setDBA(boolean dba)
DB か DBA モードか指定する。
---


□ LightSensor lightSensor = new LightSensor(SensorPort.S3); // (2)

光センサーオブジェクトをポート3で生成する。


□ コンストラクタ
---
LightSensor(lejos.nxt.ADSensorPort port)
光センサーオブジェクトを指定ポートで生成する。

LightSensor(lejos.nxt.ADSensorPort port, boolean floodlight)
光センサーオブジェクトを指定ポートで生成する。このとき、
投光ライトを点灯するかどうかを指定する。
---


□ 主なメソッド
---
int readNormalizedValue()
現在のセンサーの正規化値を読む。

int readValue()
現在のセンサーの値を読む。

void setFloodlight(boolean floodlight)
投光ライトの点灯 / 消灯を設定する。
---


□ UltrasonicSensor ultrasonicSensor = new UltrasonicSensor(SensorPort.S4); // (3)

超音波センサーオブジェクトをポート4で生成する。


□ コンストラクタ
---
UltrasonicSensor(lejos.nxt.I2CPort port)
超音波センサーオブジェクトを指定ポートで生成する。
---


□ 主なメソッド
---
int getDistance()
対象への距離を取得する。
---


□ while (!Button.ESCAPE.isPressed()) { // (4)

エスケープボタンが押されたらループを終了します。
Button クラスは、NXT ボタンを操作するクラスです。


□ 定数
---
static Button[] BUTTONS
エンター、エスケープ、左、右ボタンがこの順に入っているボ
タン配列

static Button ENTER
エンター・ボタン

static Button ESCAPE
エスケープ・ボタン

static Button LEFT
左ボタン

static Button RIGHT
右ボタン
---


□ 主なメソッド
---
int getId()
ボタンの ID を取得する。

boolean isPressed()
ボタンが押されたかどうかを検査する。

void waitForPressAndRelease()
ボタンから押されたり離れたりするまで待つ。
---


□ LCD.drawString("Sound = " + soundSensor.readValue(), 0, 1); // (5)
□ LCD.drawString("Light = " + lightSensor.readValue(), 0, 2); // (6)
□ LCD.drawString("US = " + ultrasonicSensor.getDistance(), 0, 3); // (7)
□ LCD.drawString("Tacho = " + Motor.A.getTachoCount(), 0, 4); // (8)
□ LCD.drawString("Rotation = " + Motor.A.getStopAngle(), 0, 5); // (9)

それぞれのセンサーの値を NXT 画面に表示します。



■ トライポッドの動きを NXC プログラムで再現する

------------------------------------------------------
import u.NxtUtil;
import lejos.navigation.Pilot;
import lejos.nxt.LightSensor;
import lejos.nxt.Motor;
import lejos.nxt.SensorPort;
import lejos.nxt.SoundSensor;
import lejos.nxt.TouchSensor;
import lejos.nxt.UltrasonicSensor;

/**
 * 「トライボット」使用 
 * 前進し、そこでタッチしたものをつかみ、後退、回転し、
 * 黒線があるところまで前進し、黒線のところでつかんだものを離す。
 * 
 * @author maruno
 * @version 1.0, 2008-06-20
 * @since 1.0
 */
public class Trybot01 {

    private static int PUT_THRESHOLD = 51; // 物を置くしきい値

    private static int SOUND_THRESHOLD = 50; // 音のしきい値

    private static int LIGHT_THRESHOLD = 40; // 光のしきい値

    public static void main(String[] args) {

        TouchSensor touchSensor = new TouchSensor(SensorPort.S1); // タッチセンサーオブジェクト
        SoundSensor soundSensor = new SoundSensor(SensorPort.S2); // 音センサーオブジェクト
        LightSensor lightSensor = new LightSensor(SensorPort.S3); // 光センサーオブジェクト
        UltrasonicSensor ultrasonicSensor = new UltrasonicSensor(SensorPort.S4); // 超音波センサーオブジェクト

        // パイロットのオブジェクトを生成する
        Pilot pilot = new Pilot(5.6f, 13f, Motor.C, Motor.B);

        // 物が置かれるまで停止
        while (ultrasonicSensor.getDistance() >= PUT_THRESHOLD)
            ;

        // タッチするまで前進
        pilot.forward();
        while (!touchSensor.isPressed())
            ;

        // 音がするまで停止
        pilot.stop();
        while (soundSensor.readValue() <= SOUND_THRESHOLD)
; // アームを閉じる Motor.A.backward(); NxtUtil.pause(500); Motor.A.stop(); // 後退 pilot.backward(); NxtUtil.pause(500); pilot.stop(); // 回転 pilot.getLeft().backward(); pilot.getRight().forward(); NxtUtil.pause(500); pilot.stop(); // 黒線のところまで前進して停止 pilot.forward(); while (lightSensor.readValue() >= LIGHT_THRESHOLD) ; pilot.stop(); // アームを開く Motor.A.forward(); NxtUtil.pause(500); Motor.A.stop(); } } ------------------------------------------------------



以上

Lego Mindstoms NXT - leJOS - (5) タッチセンサー

2008年07月29日 | LEGO
◆ Lego Mindstoms NXT - leJOS - (5) タッチセンサー

それでは、今度はタッチセンサーを使ってみましょう。

NXT には、つぎのセンサーがあります。ここに記述されているのは、
NXT ブロックにセンサーを取り付ける上での標準のポートです。

・タッチセンサー (ポート 1)
・音センサー (ポート 2)
・光センサー + ライト (ポート 3)
・超音波センサー (ポート 4)
・回転センサー (モーターA、B、C)


■ タッチセンサー

まずは、タッチセンサーの動きを確認するプログラムを作ります。

------------------------------------------------------
import lejos.navigation.Pilot;
import lejos.nxt.Motor;
import lejos.nxt.SensorPort;
import lejos.nxt.TouchSensor;

/**
 * モーターを前進させた後、タッチしたら終了する。
 * 
 * @author marunomaruno
 * @version 1.0, 2008/06/04
 * @since 1.0
 */
public class TouchSensor01 {

    public static void main(String[] args) {

        // タッチセンサーオブジェクトをポート1で生成する
        TouchSensor touchSensor = new TouchSensor(SensorPort.S1);  // (1)
        
        // パイロットのオブジェクトを生成する
        Pilot pilot = new Pilot(5.6f, 13f, Motor.C, Motor.B);

        // 前進回転する
        pilot.forward();

        // 押されるまでループする
        while (!touchSensor.isPressed())                           // (2)
            ;

        // 停止する
        pilot.stop();
    }
}

------------------------------------------------------



□ TouchSensor touchSensor = new TouchSensor(SensorPort.S1); // (1)

タッチセンサーオブジェクトをポート 1 で生成します。
Java なので、センサーなどもオブジェクトとして生成しないと使
えません。

TouchSensor クラスには次のようなコンストラクターやメソッドが
あります。


□ コンストラクター
---
TouchSensor(ADSensorPort port)
ポートを指定して、タッチセンサーのオブジェクトを生成しま
す。
---


□ メソッド
---
boolean isPressed()
センサーが押されたら true を返します。
---


なお、センサーポートは SensorPort クラスの定数で提供されてい
ます。

□ ポートを表す定数
---
static SensorPort[] PORTS センサーポートの定数が、S1, S2, S3,
S4 の順に入っている配列
static SensorPort S1 センサーポート 1
static SensorPort S2 センサーポート 2
static SensorPort S3 センサーポート 3
static SensorPort S4 センサーポート 4

---
PORTS は、配列で、S1 ~ S4 の値を持ちます。


□ while (!touchSensor.isPressed()); // (2)

タッチセンサーが押されたかどうかは、isPressed メソッドを使う
ことでわかります。この値が true のときにタッチされたことにな
るので、while ループで、false の間ループさせます。当然、この
間はモーターが動き続けることになります。



■ トライボットの「バンパー」のプログラム

これは、トライボットの 2 番目の工程で作った「バンパー (タッ
チセンサー)」のプログラムです。ただし、後退する時間は回転数
ではなく、0.5 秒という時間で行っています。


------------------------------------------------------
import lejos.navigation.Pilot;
import lejos.nxt.Motor;
import lejos.nxt.SensorPort;
import lejos.nxt.TouchSensor;
import u.NxtUtil;

/**
 * 「トライボット」使用
 * 前進し、そこでタッチしたものをつかみ、後退する。
 * 
 * @author marunomaruno
 * @version 1.0, 2008/06/04
 * @since 1.0
 */
public class Bumper01 {

    public static void main(String[] args) {

        // タッチセンサーオブジェクトをポート1で生成する。
        TouchSensor touchSensor = new TouchSensor(SensorPort.S1);

        // パイロットのオブジェクトを生成する
        Pilot pilot = new Pilot(5.6f, 13f, Motor.C, Motor.B);

        // タッチするまで前進
        pilot.forward();
        while (!touchSensor.isPressed())
            ;
        pilot.stop();
        
        // アームを閉じる
        Motor.A.backward();
        NxtUtil.pause(500);
        Motor.A.stop();

        // 0.5 秒後退
        pilot.backward();
        NxtUtil.pause(500);
        pilot.stop();
    }
}

------------------------------------------------------




■ 前進した分だけ後退する

今度は、前進した分だけ後退するようにします。
これには、前進した分の時間を計測して、これを後退するときの待
ち時間に設定すればいいです。前進した分の時間は、
停止した時刻 - 前進を始めた時刻
で取得できます。この、時刻を取得するのが、System クラスの
currentTimeMillis メソッドです。


------------------------------------------------------
import lejos.navigation.Pilot;
import lejos.nxt.Motor;
import lejos.nxt.SensorPort;
import lejos.nxt.TouchSensor;
import u.NxtUtil;

/**
 * 「トライボット」使用
 * 前進し、そこでタッチしたものをつかみ、前進した分、後退する。
 * 
 * @author marunomaruno
 * @version 1.0, 2008/06/04
 * @since 1.0
 */
public class Bumper02 {

    public static void main(String[] args) {

        // タッチセンサーオブジェクトをポート1で生成する。
        TouchSensor touchSensor = new TouchSensor(SensorPort.S1);

        // パイロットのオブジェクトを生成する
        Pilot pilot = new Pilot(5.6f, 13f, Motor.C, Motor.B);

        // タッチするまで前進
        long startTime = System.currentTimeMillis();    // (1)
        pilot.forward();
        while (!touchSensor.isPressed())
            ;
        pilot.stop();
        long forwardingTime = System.currentTimeMillis() - startTime; // (2)
        
        //    アームを閉じる
        Motor.A.backward();
        NxtUtil.pause(500);
        Motor.A.stop();

        // 前進分後退
        pilot.backward();
        NxtUtil.pause(forwardingTime);
        pilot.stop();
    }
}
------------------------------------------------------



以上