2008年3月31日月曜日

gainer clone (互換機)でサーボを動かす

LEDばかりでは面白くないのでgainer を使ってラジコン用のサーボを動かしてみることにした。このサーボモータはもともとはラジコン自動車、飛行機などでつかわれていたが、最近ではロボコンブームのおかげでその基幹パーツとして多種大量に供給されるようになってきている。

一般的なラジコン用サーボモータはアナログのPWM信号によって移動角を制御している。基準として 1msecから2msecのパルス幅を投入すると、その幅に応じた角度にサーボモータの軸が回転する。これを周期的に与えてやることでその角度を維持したり、動作角度を変更したりすることが出来る。ロボットの場合には、この周期をどこまで早められるか、応答速度や、トルクといったメカトロてきな要素が非常に重要になるのだが、インタラクションデザインのためのサーボにはそこまでの精度は要求されないのが一般的だ。今回はgainerのアナログ出力が実際には電圧変化ではなく、PWM信号を用いていることを利用し、サーボモータの駆動を試してみることとする。

アナログサーボには個体差があるので、両端のぎりぎりの部分を使うためには、それぞれのサーボに応じたパルス幅を調べる必要がある。Aout(0) にサーボの信号線を繋ぎ込んで利用する前提で作成したコードは以下のとおり。
 
コントロールなしのダイアモンドカーソルでサーボの稼働角を調整できる。 E/X で 5ステップづつS/D で1ステップずつの稼働となっている。

コンソールに現在の数字が出るので幅を記録していこう。一般的な安いサーボモータは最大と最小で180度前後の回転角を得ることができる。Analogoutが最大で8ch までとることが出来るので、8個のサーボなら同時に動かすことが出来るはずだ。ただしその場合には、電力が足りなくなると思われるので、サーボ駆動の電源を別途用意する必要があるだろう。

手元のサーボで試したところパルス幅が 8から30程度ということで 180度を20分割程度にはできるようだ。回転角がシビアな用途でない、見せるための作品であれば十分に実用的な範囲だと考えられる。






import processing.gainer.*;
Gainer gainer ;
int i ;

void setup() {
gainer = new Gainer(this) ;
frameRate(5) ;
i = 20 ;
}

void keyPressed() {

switch(key) {
case 'x':
i -=5 ;
break ;

case 'e':
i +=5 ;
break ;

case 's':
i -- ;
break ;

case 'd':
i ++ ;
break ;
default:
}
}

void draw() {
gainer.analogOutput(0,i) ;
println("NOW: " + i + "..." ) ;
}

2008年3月12日水曜日

Gainer Clone でwebcamを操作する

前回はハードウェアをブレッドボード上にならべて満足したので次は簡単な実装としてgainer備え付けのボタンを押すとシャッターが切れてwebcamから写真がとれる、というものをつくってみた。基本的にはボタンだけでは面白くないがこのボタンを光電センサやドアの開け閉めに連動させればパソコンのキーボードを押してwebcamを操るのとは違うことができるはずだ。単純にボタンだけであっても長いUSBケーブルさえ用意すれば、レリーズのように遠隔でシャッターをおすことも可能だ。玄関のドアやブースの外側といったところにカメラをむけてセンサーをおけば、監視カメラとしての役割くらいは十分にこなせる。

コードは非常に簡単で写真を撮るためのcaptureオブジェクトの read をボタンが押されたときのハンドラに登録し画面に表示するだけだ。ほとんど何の処理もしていないが、サンプルコードは以下に示す。撮られた画像は画面に表示するだけなので、セーブが必要ならばそのようなルーチンを書き足す必要がある。
動作確認は OSX10.5 で内蔵の isight をつかって行った。カメラとgainerがうごけばwindowsでも動作するだろう。

この発展であるセンサーのアナログ値を使ったカメラの駆動はまた後ほどということで。



/*
capture by button

*/

import processing.gainer.*;
import processing.video.*;

Gainer gainer ;
Capture cam ;

void setup() {

size(320,240) ;
frameRate(24) ;
background(0) ;

cam = new Capture(this,320,240) ;
gainer = new Gainer(this) ;
delay(100) ;
cam.read() ;

}

void draw() {

if ( gainer.buttonPressed ) {
cam.read() ;
}
image(cam,0,0) ;
}

2008年2月28日木曜日

Gainer clone on BreadBoard


基板をつくる前にはブレッドボードである程度試作するのが最近の一般的な?流儀だとおもうが、ブレッドボード遊びに興じてしまったのでそちらの結果を先に。

PSoC を使った製品といえば、 iPod やGameboy microが有名だが、PSoCを使った「作品」となると gainer だろう。gainerはメディアアーティストのためのフィジカルコンピューティングデバイスとして設計されており、 Processing Flash MAX/MSPといった作品作りによく使われる環境に適応するためのライブラリが提供されており、親和性が非常に高い。

このキット オープンソースなHWであるが、焼かれた基板にパーツをつけて8500円という価格で売られている。8500円という値段は、ほとんど手作りに近い状態で作られて会社で売られるにはまっとうな値段だと思うが、ちょっと一瞬遊んでみるには一瞬躊躇する値段かもしれない。


どうせブレッドボードで使うのなら、最初っからパーツをブレッドボード上にくんでしまったら安上がりでは?とおもったので手持ちのパーツを使ってやってみた。回路図を見る限り USB-UARTに PSoCがつながれて、 LEDとSwitchが1つづつオマケにつながっているだけだ。LEDはアクティブハイにドライブされており、SWは内部 pulldownでVCCに直結されている。回路図をみながらとりあえずそのままボード上で再現してみた。

なにも難しいところはないけど、パズルのように配線をおこなって、まあ、これでいいんじゃないか?というところまではたどりついたので晒しておこうとおもう。

モジュールが秋月なのですべて秋月電子でそろえるとして、トータルコストとしては、
AKI-UM232R 950円
CY8C29466 500円
ブレッドボード EIC-102BJ 700円

とまあブレッドボードをいれても2000円強といったところ。

ブレッドボードには余分があるのでこの上に簡単な回路なら足すことはもちろん可能だ。そのためにベースは片側に寄せてくみ上げてある。

互換とするにはさらに電流制限抵抗とLEDとタクトスイッチが必要だが、電子工作をするものならこれくらいはパーツ箱から出てくるであろうということで、コストには加算していない。

これで合計2150円である。PSoCライターがない場合は PSOCのライターであるCY3210-MiniProg1 4000円が必要となるが、この場合にはminiprogにサンプルとして29466がついてくる。

とりあえずサンプルプログラムが動いたので、満足して作品として完成させるのはまた次回ということで。

2008年2月27日水曜日

(メモ)DoCoMo A2502の制御ポートアクセス

ずいぶん間があいてしまったけど「NetBSDでDoCoMo A2502をつかう」の続き。

DoCoMoのA2502は、正しくアタッチするとシリアルポートが3本生成される、ということは前回のエントリーで書いた。最初の一本は通信するためのモデムポートだが、残りの2本は通信以外に利用されている。

3本目のシリアルポートは通信制御や各種情報を取得するために利用されているようなので、少し中身を見ていたが、まとまったのでメモとしてここに書いておくことにする。

3本目のシリアルポートの使い方

D02HWなどと違って、atコマンドを受理したりはしてくれない。バイナリを送るとバイナリで返事をくれる、という仕様になっているようだ。(コマンドを全部解析したわけではないが、とりあえずアンテナレベルの取得くらいははできる。)

処理シーケンス

  • シリアルポートをオープンする
  • {0xcf, 0x18, 0x00, 0xc0, 0xdd, 0x7e}を書き込む。
  • 12バイトの返事がくるので読む(解析していない)
  • {0xcf, 0x00, 0x00, 0x91, 0x86, 0x7e}を書き込む
  • 14バイトの返事がくるので読む(解析していない)
ここまでで準備はおしまい。その後に適切なコマンドを送ると、いろいろな情報を取れる。
  • {0xcf, 0x07, 0x00, 0x99, 0xcb, 0x7e}を送ると、自分の電話番号などが含まれた51バイトの情報が返ってくる。(電話番号は5から16バイトの間)
  • {0xcf, 0x01, 0x00, 0x49, 0x9f, 0x7e}を送ると、シグナルレベルや、つながっているネットワークのIDが含まれた58バイトの情報が返ってくる(シグナルレベルは7バイト目、ネットワークIDは26から40バイト目)
みたいな感じ。ほかにもショートメッセージサービスへのアクセスができたりするようだが、そこはまだ見ていない。

rubyを用いたサンプルコード

というわけで、アンテナレベルと繋がっているネットワークの名前を出力するサンプルコードを載せておく。今回はrubyで書いてみた。シリアルポートのサポートライブラリにruby-serialを使っているので動かす場合にはインストールしておくこと。


require "serialport"

# open control serial port 38400/N81
sp = SerialPort.new("/dev/ttyU2", 38400, 8, 1, SerialPort::NONE)
sp.flow_control= SerialPort::NONE

cmd0 = [0xcf, 0x18, 0x00, 0xc0, 0xdd, 0x7e].pack('C*')
cmd1 = [0xcf, 0x00, 0x00, 0x91, 0x86, 0x7e].pack('C*')
telno = [0xcf, 0x07, 0x00, 0x99, 0xcb, 0x7e].pack('C*')
antcmd = [0xcf, 0x01, 0x00, 0x49, 0x9f, 0x7e].pack('C*')
cnt = 0

sp.write(cmd0)
buf = sp.read(12)
sp.write(cmd1)
buf = sp.read(14)

sp.write(telno)
buf = sp.read(51)
data = buf.unpack('C*')
telno = data[5..16].map!{|c| c.chr}.join
print "tel no:" , telno, "\n"

while (cnt < 20)
sp.write(antcmd)
buf = sp.read(58)
data = buf.unpack('C*')
network = data[26..40].map!{|c| c.chr }.join
print "signal level:" , data[17], " [network:" , network , "]\n"
cnt+=1
sleep 1
end
出力は

$ ruby a2502ant.rb
tel no:080XXXXXXX
signal level:20 [network:]
signal level:20 [network:]
signal level:20 [network:]
signal level:20 [network:]
signal level:20 [network:]
signal level:18 [network:]
signal level:18 [network:NTT DoCoMo]
signal level:19 [network:NTT DoCoMo]
[省略]

のようになる。アプリケーションを作る場合などにそれなりに使えるかな。

2008年2月17日日曜日

(メモ)DUS01まとめ

忘れる前にワンセグチューナーDUS-01の挙動についてメモしておく。半分は自分のため、あとの半分は「24時間ワンセグコミュニティ(?)」のため。Linuxやwindowsで使うときにどうぞ。

ハードウェア

  • CPU: Silicon Laboratories C8051F342
  • チューナー: sharp VA1A5JZ9902A (参考リンク:ascii24)
  • アンテナ:ロッドアンテナ
  • インターフェイス: USB1.1
シャープの9902Aは1-2世代前のワンセグモジュール。最新版には及ばないが感度が-107dbmは優秀なんじゃないかと思う。googleで探したけど仕様書等は見つからなかった。残念。

USBデバイス情報
USBデバイスとしては、こんな感じ。ほかに何をかけばいいのかな。
  • Vendor ID:0x1bc8 , Product ID:0x0001
  • endpointは0,1,2,3の4本。
  • EP1は制御用のバルク転送エンドポイント(読み書き可能)。
  • EP3はMPEG2TS転送用のアイソクロナス転送エンドポイント(読み込み専用)
  • EP2は使っているのを見たことないけど、ファームウェアアップデートなどに使うのじゃないかと推測
  • 起動時にファームウェアロードなどは発生しない。電源を入れれば動く。

さらに詳しく知りたい人のためにNetBSDのusbgenの出力を載せておく。
CONFIGURATION descriptor index 0:
bLength=9 bDescriptorType=2 wTotalLength=46 bNumInterface=1
bConfigurationValue=1 iConfiguration=0 bmAttributes=80 bMaxPower=150 mA

INTERFACE descriptor index 0, alt index 0:
bLength=9 bDescriptorType=4 bInterfaceNumber=0 bAlternateSetting=0
bNumEndpoints=4 bInterfaceClass=0 bInterfaceSubClass=0
bInterfaceProtocol=0 iInterface=0

ENDPOINT descriptor index 0:
bLength=7 bDescriptorType=5 bEndpointAddress=1-out
bmAttributes=2 wMaxPacketSize=64 bInterval=5

ENDPOINT descriptor index 1:
bLength=7 bDescriptorType=5 bEndpointAddress=1-in
bmAttributes=2 wMaxPacketSize=64 bInterval=5

ENDPOINT descriptor index 2:
bLength=7 bDescriptorType=5 bEndpointAddress=2-out
bmAttributes=2 wMaxPacketSize=64 bInterval=5

ENDPOINT descriptor index 3:
bLength=7 bDescriptorType=5 bEndpointAddress=3-in
bmAttributes=1 wMaxPacketSize=188 bInterval=1


制御コマンド
制御コマンドはEP1をつかってやりとりする。今のところ分かっているコマンドはこれだけ。全部推測なので正しいかはわからないけど。
  • ファームウェアバージョンチェック (0x9f) - 現在のファームウェアのバージョン(1.0.0)が返ってくる。
  • チャネル設定 (0x10) - これに加えてKHz単位の周波数をくべるとチューナーが設定される。
  • 入力検出(0x11) - 電波が受信できていたら0x1、受信できなければ0x0が返ってくる。
  • ストリームモードチェック(0x12) - たぶんMPEG2TSストリームを出しているかしないかをチェック。
  • ストリームスタート (0x20) - EP3へのMPEG2TS出力を開始する。
  • ストリームストップ(0x21) - EP3へのMPEG2TS出力を停止する。
  • シリアル番号チェック(0x43) - デバイス固有のシリアル番号を返す。
(2008/2/18 1:30修正:miroさんありがとうございました。)

それぞれのコマンドは10byte長で、先頭にコマンドを、引数がないものは0x0で埋めて送る。
チャネルを変えるときのシーケンスは
  • ストリームが出ていたら止める
  • 止まったかモードをチェックする
  • チャネル変更リクエストを出す
  • ちょっと待つ
  • 入力検出リクエストを出す
  • 返り値をチェックして0x0だったら「ちょっと待つまで戻る」。0x1が出るまでがんばる。(もしくはタイムアウトする)
  • ストリームを出力する
って感じ。チャネル設定コマンドは、{0x10, 0x04, 0x00, A, B, C, 0x00, 0x00, 0x00, 0x00} というフォーマットで、A,B,CにKHz単位の周波数を指定する。たとえば、521.43MHz(チャンネル21)なら{0x07, 0xf3, 0xb7}を埋め込めば良い。
(2008/2/19修正:チャネル設定コマンドの例の先頭バイトをtypoしていたので修正)

出力ストリーム
EP3からはMPEG2TSもどきが出力される。先頭はMPEG2TSで規定された同期ビット列(0x47)でかつ、パケット長が188Byteというのは良いのだが、MPEG2TSとして解釈すると全部エラーになる、という変な状態。きっと、プログラムミスでこうなってしまっているのだろうとおもう。あまりにも不憫なので正しいストリームに治してあげよう。
「先頭の0x47を除いて、他のバイト列に対して0xb5を排他的論理和を取る。」
すると、普通のMPEG2TSになる。

まとめ
USB的には、「USBデバイスとしてのJ200への不満」、はほぼ解決されているようなデバイスだった。最初はストリームが見えるか少しどきどきしたが、まあすぐにわかってよかった。
まだ入手性もよいみたいだし、ここにある情報を使えば他にも対応ソフトを作れそうな人がいると思うので、いけているデバイスじゃないかと思う。明日もう少し補充を(自分用に)買っておこう。。

NetBSDで「24時間ワンセグ野郎」(新デバイス)(3)

新デバイスさらに続き。

バイトストリームを眺め続ける人生にもちょっとだけ疲れたので、ここらで絵(と音)でも見てみたい、という願望が大きくなってきた。というわけで、ちょっと真面目に絵と音声を見る部分を書いてみることにした。もし絵とか音声が見えたら、それがちゃんとしたMPEG2TSストリームとして扱えているか?っていう検証になるし。(バイトストリームを検証するためにはちゃんとパーサーと表示系をいちいち書かないといけないから、すぐには対応できないし)
というわけで、新デバイスでも生TSをキャプチャして録画までできることを確認できた。(絵は今とったらこれだった、てだけ、意味はないです)。ワンセグチューナさわっていて初めてまともに絵を見たよ。

下手に書いちゃって動かないのに買っちゃう人がいたら災難だから「新デバイス」とだけ書いていたけど、これで今まで伏せていた製品名をかける。写真のRockridgesoundのDitune(DUS-01)が最近触っていたデバイス。秋葉原だと3000円弱で買える&結構店頭に並んでいるので見たことがある人も多いかもしれない。
外部アンテナはつながらないけど、選択肢の一つとしてはいいかな、と思っている。

NetBSDで「24時間ワンセグ野郎」(新デバイス)(2)

新デバイスの話再び。

前回のエントリー(NetBSDで「24時間ワンセグ野郎」(新デバイス))に、生TSっぽいのが出ているとかいてしまったが、ちょっと寝てから冷静に見直してみると、なんか変だということに気がついた。

簡単にいえば、「先頭の0x47以降は本来受信したはずのデータ列と異なっている」ようだ。キャプチャされたTSの解析結果も載せてあったので、鋭い人なら一目で気がつくような気もするけど、異様にフラグが多かったり、アダプテーションフィールド長が255だったり、(あそこには含まれていないけど、PIDが0x1fffを超えていたり)、していた。

また、

  • だいぶ感度が悪そう。ちょっと、置き場所を変えるだけで、MPEG2TSのパケットでTS_ERRORフラグが立ってしまう。あんまり頻度が高いと、TS_ERROR付きでも眺めてみる、みたいな処理に変えないといけないかもしれない。
とも書いていたが、これもTS_ERRORビットの値がずれているのが問題だったようだ。値を読み替えてからみてみると、感度はそんなに問題ないみたい。

幸いにもMPEG2TSヘッダは固定長で単純かつ、特定の部分に決まった情報が出やすいという特徴があるので、しばらく眺めていると変換のパターンは見えてくる。もう少し解析しないとだめだけど、今のところ、「各バイト単位で特定の値で排他的論理和をとる」っていう単純なルールでもとに戻るようだ。(コンティニュティカウンタの値が1->0->3->2->5と進むところで、XORじゃないか、って推測できたのが決め手だった)。

というわけで、今度こそ生TSだと思われる出力。それっぽくなった。
これで、MPEG2TSパーサーに戻れる。