2011年6月30日木曜日

ScratchとProcessingの通信に成功

以前書いた、Scratchの「遠隔センサー接続」で、Processingのプログラムとの間で相互通信できることを確認しました。

まず、Scratchのスクリプトはこんな感じ。わりと適当。


Processing側から"mew"というメッセージが届いたら、「ニャー」と鳴きます。
また、ステージ上ではスクリプト1が回転していて、上を向いたらProcessing側へ"Turned!"というメッセージを送ります。

Processingのプログラムは以下の通り。

import processing.net.*;
Client ScratchClient;
PFont f;
int cnt = 0;
void sendtoscratch(String dataOut) {
byte [] sizeBytes = { 0, 0, 0, 0 };
  sizeBytes[3] = byte(dataOut.length());
  for (int i=0; i<4; i++) {
    ScratchClient.write(sizeBytes[i]);
  }
  ScratchClient.write(dataOut);
}
String recieveFromScratch() {
  String inString = ScratchClient.readString();
  return inString;
}
void setup() {
  ScratchClient = new Client (this, "127.0.0.1", 42001);
  f = loadFont("HiraKakuProN-W3-16.vlw");
  textFont(f);
  size(640, 480);
  background(255);
  fill(0);
}
void draw() {
  sendtoscratch("sensor-update " + "\"mouseX\"" + str(mouseX));
  sendtoscratch("sensor-update " + "\"mouseY\"" + str(mouseY));
  delay(50);
  if (ScratchClient.available() > 0) {
    text(recieveFromScratch(), 10, (cnt++)*20);
  }
}
void mouseClicked() {
  sendtoscratch("broadcast " + "\"mew\"");
}
やってることは、127.0.0.1(local loopbackですな)の42001ポートに接続して、Scratch側に送信するフォーマット(32bit長の、メッセージのバイト数+実際の文字列)を作ってやる「sendtoscratch()」という関数と、Scratch側からは単純に文字列が送られてくるのでそれを受け取る「recieveFromScratch()」という関数を用意しただけ。

で、センサ名「mouseX」と「mouseY」を用意して、Processingのウインドウ上のマウスの座標をScratch側に送りつつ、また、ウインドウ上でマウスクリックすると「mew」というメッセージを送るというお仕事。また、もしScratch側からデータがきていたら、それをウインドウ上に描くというお仕事。

動かす手順は先にScratchで「遠隔センサー接続を許可する」してポートを開いてから、Processingのほうを起動します。でないと、クライアント接続のエラーチェックしていないので、接続できないままdraw()のループに入り、Javaのexceptionが出まくってしまいます。

Scratch側でも一応センサ値も表示しておきました。これは「センサーボード」ではなくて、「[スライダー▼]の値」ブロックのセンサー名をmouseXにして、右のチェックボックスをチェックするとステージ上に現れます。mouseYも同様にすると、以下のような画面になります。

でもって、猫が回転して上向きになると、Processingのウインドウに届いたメッセージが出ます。
よくわからないけれど、日本語のメッセージはScratch側からは出せない仕様なのか、受け取ると文字化けします。ProcessingはJavaベースなのでUTF-8ならいいのかと思いましたし、Scratchの国際化もUTF-8ベースらしいので大丈夫なはずなんですが、なにかが間違っているみたい。.readString()をいろいろ変えてみたりしたけどうまくない。ヒラギノを指定したけどそれでもだめ。わからん。

2011年6月29日水曜日

ドリトルのArduino対応のバグとったつもり

先日報告した、「アナログ入力」で読んだ値が128以上で65535以下になる件、とりあえずのquick hack。

問題は、intの値をSerial.write()する際にUTF-8でどうやらドリトル側が受け取っているらしいということ。そこでいくつか試したけれど、数値を文字列化して送ってやればいいということになった。

まず、arduino_dolittle.pde側(Arduinoのスケッチ)。


34c34
<       Serial.write(analogRead(port)/4);
---
>       Serial.print(analogRead(port)/4,DEC);

というわけで、Serial.print()命令で、10進の文字列出力することにした。

続いてarduino.ini(ドリトルのオブジェクト定義)側。

26c26
<     「c>0」!なら「(_arduino!(c)値?)!文字コード」そうでなければ「0」実行。
---
>     「c>0」!なら「(0!(_arduino!(c)値?)add)」そうでなければ「0」実行。

変数「c」の値は到着したバイト数を表しているので、「(c)値」でその文字数分だけ読み込んでくれるから、そのままでもよさそうだけれど、念のため数値に変換するつもりで、整数0を足してみた。

一応、以下のような適当なプログラム

システム! "arduino"使う。
a=arduino! 作る "/dev/tty.usbmodem26221"ひらけごま。
アナログ値=フィールド!作る。
pot = a!0 アナログ入力。
タイマー!作る  「アナログ値!(pot!読む)書く」実行。

でなんとかなっている感じ。

2011年6月23日木曜日

Wiimote手ごわい

自宅からWiimoteとNunchakを持参してMacとペアリングしようとしたのだが、できない。

名前は出るのだが、Webでは機器の種類として「ジョイスティック」と出るとあるが、「不明なデバイス」と出てしまい、その先に進めない。passcodeについて、4択あるのだがどれも不可。

とりあえずきょうは諦めた。

ちなみに、Mac上でWiimoteと通信するJavaのライブラリは動いているみたい(後日ちゃんと書きます)。

それではとArduinoのUSB Host Shieldにたまたま持っていた非常に古い(Vista以後のドライバが存在しない)BTドングルを接続して、シリアルコンソールにパラメータの表示ができたところで今日は時間切れ。USB深い。

ドリトルのArduino対応のバグ?

ドリトルV2.2のArduinoからのアナログ入力で、127を超えると65535になるのを確認。

byteで送られたデータを符号付きで解釈して16bitのintにしているのかな、と想像。

ちょっときょうはバグ取りの時間がなかった。

2011年6月20日月曜日

ゲームコントローラ関係のブックマーク

PS2コントローラとWiimote/ヌンチャク等のArduinoライブラリへのリンクを記録。

PS2コントローラ

もはやなんでもありですな。

Kinectまでくると、ちょっとした実験というレベルじゃなくなりそう。 

Scratchの外部通信機能を参考にする

Wiimore(Wiiリモコン)関係を調べていて、ScratchではTCP 42001 portで双方向通信する機能が1.3版から含まれていることを知った。

参考:「Scratchに外から値を送ってみた」by いー ドット ぷりんとすったくとれーす さん

これを有効にするには、例によって「[スライダー▼]センサーの値」ブロックを長押しして現れる以下のメニュー


で「遠隔センサー接続を有効にする」を選択する。と、画面中央にこんなダイアログ


が出て、Scratchが42001番ポートをlistenするようになる。

フォーマットは単純な文字列(UTF-8エンコード)なのだが、その前に32bit幅のデータ長をペイロードとしてつけてやる必要がある。

通信は、以下のコマンドが定義されているので、それを文字列の最初に置く(大文字小文字区別なし、コマンドと引数の間は空白文字0x20)。

  • broadcast
  • update-sensor
「broadcast」コマンドは、Scratchにおけるメッセージ送信になる。外部からScratchのスクリプトを起動するのに使う。一方、「update-sensor」コマンドは、引数にとった文字列名の変数に、続く引数の値を代入する指令を送信する。例えばこんな感じ。Wiimoteの3軸加速度センサーの値を送るコマンドの例。

update-sensor "X軸傾き" 20 "Y軸傾き" -120 "Z軸傾き" 45

すると、これを受け取ったScratchは3つのセンサーに対応する変数「X軸傾き」「Y軸傾き」「Z軸傾き」を内部に作成し、値をそれぞれ20, -120, 45にする。値が数値の場合は10進数、文字列の場合はダブルクォート(")で囲む、真偽値の場合は直接trueまたはfalseと書く。また、上の例のように複数の変数の値をいちどに変更することができる。

使い方としては、まず「update-sensor」で値を送っておいて、「broadcast」で指示を送る。Scratchのブロックで、「[ ▼]を受け取ったとき」というもの


があるが、この下に、受け取った値を使って処理すべきことを書くことになる。例えば、
broadcast "移動"
というメッセージが外から送られてきたら、対応するスプライトをさきほどのX, Y, Zの傾きにしたがってすべるような移動をさせる、という感じ。

Scratchは、メッセージを使うことでイベント駆動のようなプログラムを作ることができる。だから、Wiimoteのボタンを押したら何かが起きる、といったスクリプトを作成するのは簡単だ。

一方ドリトルは、メッセージを監視するような機能を持たないので、例えばタイマーなどを使ってポーリングすることになる。それでもよければ、サーバ機能をオンにしたドリトルを立てておけば、そこが共有黒板になるので、Scratchと同じような形で値の受け渡しやコマンド送信ができるだろう。ScratchはP2Pで直接通信できるのに対して、ドリトルはサーバを介する必要がある点が異なる。

2011年6月14日火曜日

ArduinoとGPS

先日のエントリで広げた風呂敷を徐々に実現していく段階。

ひとまず、NewSoftSerialから。GPSを接続して、NEMA形式のデータが取得できることを確認。これでシリアル接続のデバイスが試せることと、GPSをどう扱うかの検討課題が見えてきた。

まず、ドリトルのいまの実装に対する課題が、引数がひとつしかとれないこと。現在は1バイトのコマンドに1バイトの返答をする実装のため、新しいシリアルポートを作成するために必要な、RX, TXの2つの引数を渡すことができない。

もうひとつ重要なのは、返答も1バイトなので、GPSのデータのような不定長の文字列をドリトル側に渡すことができない。

また、例えばシリアルLCDなどに文字列を出力することを考えれば、ドリトルから送信するデータも不定長を許すことにしなければならない。

というわけで、まずコマンド(というよりもバイトコード)の再設計と、ハンドシェイクを行い確実に通信できる実装が課題ということがわかった。ドリトル側の送信タイミングは環境によっていろいろあることが予想されるので、あまりナイーブな実装はするべきではなさそうに思う。

次にGPSなのだが、生のNEMAフォーマットの文字列をドリトル側で処理するのはコストが見合うのかどうか考えたほうがよいと思った。なぜなら、GPSが1度に送信するデータの行数は様々で、補足できる衛星の数も機種によって様々、ロックできる衛星の数は場所による、データ送信間隔も毎秒1セットから5セット(1/5秒ごとに送信)までいろいろあるから。

率直なところ、屋内で衛星が見えない状態では意味のある情報は得られない。だから、衛星をロックしたかどうかを確認してから値を取得する必要がある。ドリトル側にそれを調べる命令を用意すべきか、Arduino側がお世話を焼くかも検討課題。

また、コンマ区切りの長い文字列をドリトルが受け取っても、いくらV2.2で文字列処理命令が充実したといっても効率的にどうか、ということもある。実用を考えればすべての情報はドリトル側には不要なのではないか、というのが現在の予想。日付、時刻、緯度、経度、高度、方角ぐらいあれば十分ではないだろうか。速度などは車載でもしなければ不要ではないか、など。そうなると、Arduino側で実用的なデータに整理してから単純なフォーマットで送るべきではないか、ということになる。幸いNewSoftSerialの作者がTinyGPSというライブラリを作成していて、これを追加したペナルティは100バイト程度とのことだから、これを使ってみたいと思っている。

とりあえずいまの段階はそこまで。あとはあした考えるつもり。

2011年6月3日金曜日

ドリトルのArduino対応を改善するたくらみ(まだ構想段階)

たまには自作の話も書かねばと。

以前のエントリでも書いたけれど、ドリトルのArduino対応の改善について。

1. シリアルデバイスの接続

GPSを想定しているけれど、シリアルLCDとかも入るかもしれない。

AVRのサポートする端子以外でのシリアル接続は、NewSoftwareSerialを使うのが定番みたい。関数は標準のSerial互換にしてあるようなので、
  1. シリアルポート作成(ついでにbegin()してしまおうか)
  2. available()
  3. read()
  4. write()
に対応する4つのコマンドを作ればいいような気がする。デジタル/アナログ入出力の設定コマンドで上書きしても壊れないように、ポート番号の管理と、上書きするときには作ったシリアルポートオブジェクトをdealloc()しないといけないかもしれない。

2. I2C, SPI対応

悩ましいのだが、そういうデバイスをたくさん持っているので使えるようにしなければならない。SPIは設定と転送の2つのコマンドだけでよさそう。I2CはWireライブラリを使うようだがちょっと面倒そうだ。今後検討。

3. 音命令

スピーカーから音が出ないと子どもが楽しくないだろうから、Toneライブラリを入れてみるつもり。所詮Arduinoなので、これ以上の機能は入れられないだろう。

5. SDカード

GPS使う場合、結構なデータ量になるのでSDカードは必要かなと。データロガーに徹するなら命令数は減らせそう。汎用にすると面倒そうだ。

6. EEPROM

AVR上の未使用のEEPROM領域にアクセスするライブラリが標準であるので、命令列をここに書きこんで、リセット時に何らかの操作で再生するようにすれば自律モードのできあがり。これでPCから切り離しができる。あるいは、簡易データロガーの領域にする手もあるかも。

ただ問題は、上記のライブラリを全部入れても168のArduino(Unoとか)に入るのかどうか。やってみないとわからない。

2011年6月2日木曜日

Scratch+Arduinoを試してみた(追記あり2015年2月17日)

(2015年2月17日追記:たいへん古いエントリですが検索上位に上がるため、いまでもよく読まれているようです。現在ではいろいろと相違がありますので、阿部先生が配布されているScratchへのチェンジファイルとArduinoに書き込むスケッチがセットになった「SensorBoardWirhMotor」(ページの上から6番目の項目です)をご利用ください。下記の問題も解決しているとのことです。阿部先生の所属もかわっており、現在津田塾大学のほか多くの活動をされています。詳しくは最近の各著書「わくプロ」「どきプロ」「すくプロ」などを参照してください。)


ArduinoをPicoBoard互換にしてさらにWeDo的使い方もできる、というScratchの拡張(サイバー大の阿部和広先生作)を試してみました。

使い方は、ヱンガワシステムズさんのエントリにある通りなのですが、このページに置かれている「全部入り」をダウンロードして、それに含まれているArduinoのスケッチをArduino IDEで書きこんで、いっしょに入っているScratch 1.4 modを起動するという手順です。

標準のScratchでも、PicoBoard用の

  • スライダー
  • ボタン
  • 光センサ
  • マイク

入力に対応しているので、入力装置にするだけなら同ページにあるスケッチ(SensorBoardWithMotor.pde)の書き込みだけでよいのですが、「Lチカ」をやりたかったので、WeDo拡張を含むこのパッケージにしました。

Arduinoを接続して、手順通りに「調べる」タブの「センサーの値」ブロックを長押しするとメニューが出て、たしかにステージに、センサの値をリアルタイム表示する「ScratchBoard監視盤」が現れました。なかなか感激です。

Arduinoの端子との対応は、

  • スライダー - A0
  • 明るさ - A1
  • 音 - A2
  • 抵抗A - A3
  • 抵抗B - A4
  • 抵抗C - A5
  • 抵抗D - A5 (抵抗Cと同じ)
  • ボタン - D2


なので、それにしたがってボタンの回路やPOD(半固定抵抗)などをブレッドボードで組んでやると、ちゃんと値が出ます。

ちなみに、ボタンは押すとGNDに落ちる回路。つまり、LOWのときにScratchはtrueを返します(HIGHがfalse)。PODの値は適当なのを適当につないでも0〜100になるようになっていて、よくできてるなーと思いました。

で、Lチカさせるために、
  • モーター - D11-(PWM)

に接続して、こんなスケッチ

を書いてみたんですが、LEDは点きっぱなしで、チカチカしてくれません。

おかしいなーと思って他のモーター関係の命令を試していて気づきました。例えばこんなのだったらうまく動きます。

PODを回すと、LEDの明るさがそれに応じてかわります。

それでようやく気づいたのですが、ミソは「PWM」ということなんですね。つまり、こんなスクリプトならLチカします。

Arduinoのプログラミングをある程度やった人ならわかると思いますが、この「モーターのパワーを( )にする」というブロックは、analogWrite()に相当するわけです。つまり、Lチカの例題
#define LED 11
void setup() {
   pinMode(LED, OUTPUT);
}
void loop() {
  digitalWrite(LED, HIGH);
  wait(1000);
  digitalWrite(LED, LOW);
  wait(1000);
}
これとは違うわけです。

念のために、スケッチを確認したところ、setup()のなかではpinMode(PWM_PIN, OUTPUT);しているのですが、loop()のなかはanalogWrite(PWM_PIN, motorPower);としか書いていないので、「D11-」ではないのですね。でもその直後に、

      digitalWrite(THISWAY_PIN, motorDirection & isMotorOn);
      digitalWrite(THATWAY_PIN, ~motorDirection & isMotorOn);
と書いてあります。つまり、「モーターの回転を[ こちら向き ▼]にする」ブロックに対応する、この記述が「モーターをオンにする」「モーターをオフにする」ブロックに効いてくるわけです。

ちなみに、

  • THISWAY_PIN - D4
  • THATWAY_PIN - D7

なので、D4にLEDをつなぎなおして確かめてみると、
video
うまいぐあいにLチカしてくれました。

このあたり、PWM端子でもdigitalWrite()するように書くことができるドリトルのほうがわかりやすいのかな、と思いました。(前回のエントリ参照)