2011年4月2日土曜日

リモコン送信


1ヶ月ぶりに再開。赤外線リモコンの送信に挑む。

すっかり忘れているので復習に1日かかると思ったのだが、コンパイラを呼び出したら、
30分ほどで準備ができた。開発環境がシンプルなので操作を思い出すのも簡単だ。

さて、まず赤外線LED。手持ちがなかったので通販で発注したが待ちきれなくて
不要のリモコンから外した。

リモコン用のものは結構電流を流す。また到達距離を稼ぐために複数つなぐこともありそうなので、
トランジスタを入れておくことにする。
(回路は 「LED トランジスタ スイッチ」などで検索すると出てくる。)


話はそれて懐古ばなし。・・・・・・
トランジスタは 2sc372 である。古い電子工作少年には忘れられない型番だ。
10年ほど前に知人から古い部品をダンボール箱ひとつもらった。その中には、カラーコードじゃない抵抗など昭和のパーツが詰まっていて、今でもちょっとした試作には便利に使っている。

型番表示を見て左から「えみこれべ」。学生の時アナログ屋の友人に足と電極の対応を聞くと、
「372は えみこれべ」と呪文のように返事が返ってきたものだ。

30年も前の記憶なので念の為にネットで検索すると出てきた。
たしかに ECB なのでうれしくなる。
・・・・・・

ブレッドボードで組んでベースをいじるとLEDが点灯するのを確認。
確認は目では見えないのでデジカメで見るのだが、
実はデジカメもビデオも大半のものは赤外光を減衰させるフィルターが入っているので、
あまりはっきりと見えない。(古いビデオカメラなどではよく見えるが)

めんどくさいな~ とイライラしていたのだが、プログラムが出来て実際に
動かすまでは普通のLEDでチェックすればいいことに途中で気がついた。
(写真に写っている緑のLED)

ユニバーサルボードにハンダ付けで組みなおして、GEMMYのC6コネクタに接続。
開発環境で自動的に生成される点滅プログラムのポートをp21(GEMMYのC6に対応)して、
点滅を確認。OK!!

ここで
ああ!!、トランジスタ入れたら反転しちゃうよ。
と思ったのだが・・・
38kHz で変調しているので関係ないと気づく。

-----------------
プログラムだが、まずテストに使う機器のリモコンを持ってくる。
前の受信プログラムを、mbedにいれてリモコンのボタンを押し、
受信された フォーマット、ビット数、データ を メモっておく。
その内容を、送信プログラムのソースコードに写す。

我が家のTVは怪しいメーカーなので、受信がうまくいかず。
食卓用の古~いアナログ液晶TVもダメ。

HDDビデオ やCDプレーヤーがわりに使っているDVDデッキは、うまく動いた。

赤外LEDを機器に向けて、下記のプログラムでリセットのあと 白ボタンを押すと、
電源が入った。


----------------
プログラムを書けば、リモコンのシーケンサーができる。
例えば、帰宅したら、エアコンをON。ビデオの電源ON. TVの入力をビデオに切り替え、録画済みリストを表示させる。なんてのがボタン一つ。

ネット経由で外からも。

つぎは LAN だな・・・・・・

===================
#include 

#include "TransmitterIR.h"
#include "TextLCD.h"

TextLCD lcd(p11, p12, p27, p28, p29, p30); // rs, e, d4-d7
DigitalIn swWhite(p13);
TransmitterIR ir_tx(p21);

/**
* Entry point.
*/
int main(void) {


lcd.cls();
lcd.printf("IR TX TEST.");

swWhite.mode(PullUp);

RemoteIR::Format format = RemoteIR::NEC;
uint8_t buf[] = {0x00,0xFF,0x46,0xB9};
int bitcount = 32;


/*
* Execute.
*/
while (1) {
while(1){
if(swWhite==0) break;
}
wait(0.5);

if (ir_tx.getState() == TransmitterIR::Idle) {
bitcount = ir_tx.setData(format, buf, bitcount);
}

lcd.cls();
lcd.printf("#### ---- ----");

}
}

2011年3月2日水曜日

IR受信のプログラムを整理


サンプルプログラムを整理した。

display_xxxx() という下請け関数が3つあるが、処理の本質には関係ないので、
基本的には、byteの配列でバッファをつくって、receive()を呼ぶ。

receive() は 受信ステータスが立つのを待って ir_rx.getData()で
データを取り出す。

LCD には 上段にフォーマットとステータス。
下段に 受信データが表示される。

リモコンのボタンをいろいろ押すと、受信データが変わるので、
この値を比較して、対応する処理を呼び出すようにすると、
リモコンでコントロール出来る車ができたりする。

ややこしくなるので、このプログラムでは対応処理を呼び出す部分を書いていないが、
ボタンとコードの対応を調べるために、とっておくと良い。


#include

#include "ReceiverIR.h"
#include "TextLCD.h"


ReceiverIR ir_rx(p10); //GEMMY IR RECEIVER

TextLCD lcd(p11, p12, p27, p28, p29, p30); // rs, e, d4-d7


/**
* Receive.
*
* @param format Pointer to a format.
* @param buf Pointer to a buffer.
* @param bufsiz Size of the buffer.
*
* @return Bit length of the received data.
*/
int receive(RemoteIR::Format *format, uint8_t *buf, int bufsiz, int timeout = 100) {
int cnt = 0;
while (ir_rx.getState() != ReceiverIR::Received) {
cnt++;
if (timeout < cnt) {
return -1;
}
}
return ir_rx.getData(format, buf, bufsiz * 8);
}

/**
* Display a current status.
*/
void display_status(char *status, int bitlength) {
lcd.locate(8, 0);
lcd.printf("%-5.5s:%02d", status, bitlength);
}

/**
* Display a format of a data.
*/
void display_format(RemoteIR::Format format) {
lcd.locate(0, 0);
switch (format) {
case RemoteIR::UNKNOWN:
lcd.printf("????????");
break;
case RemoteIR::NEC:
lcd.printf("NEC ");
break;
case RemoteIR::NEC_REPEAT:
lcd.printf("NEC (R)");
break;
case RemoteIR::AEHA:
lcd.printf("AEHA ");
break;
case RemoteIR::AEHA_REPEAT:
lcd.printf("AEHA (R)");
break;
case RemoteIR::SONY:
lcd.printf("SONY ");
break;
}
}

int bit2CharLen(int bitlen) {
return bitlen / 8 + (((bitlen % 8) != 0) ? 1 : 0);
}


/**
* Display a data.
*
* @param buf Pointer to a buffer.
* @param bitlength Bit length of a data.
*/
void display_data(uint8_t *buf, int bitlength) {
lcd.locate(0, 1);

const int n = bit2CharLen(bitlength);

for (int i = 0; i < n; i++) {
lcd.printf("%02X", buf[i]);
}
for (int i = 0; i < 8 - n; i++) {
lcd.printf("--");
}
}



//void getStr(uint8_t *buf, int bitlength)


/**
* Entry point.
*/
int main(void) {


lcd.cls();
lcd.printf("IR RECEIVE TEST.");

/*
* Execute.
*/
while (1) {
uint8_t buf1[32];
memset(buf1, 0x00, sizeof(buf1));

RemoteIR::Format format;

int bitlen = receive(&format, buf1, sizeof(buf1));

if (bitlen < 0) {
continue;
}


display_status("RECV", bitlen);
display_data(buf1, bitlen);
display_format(format);

}
}

2011年3月1日火曜日

GEMMYの赤外線受光部 しょうもないことでハマってしまった。


焦電センサーで失敗して悔しいので、赤外線つながりでGEMMYについている受光部を使ってみることにした。

RemoteIR というライブラリを使う。
使い方が書いていないので、ソースを読んであたりをつけるが、
めんどくさくなって とりあえず 作者の作成したサンプルプログラムを
コンパイルして動かしてみる。

ありゃ動かない。

家じゅうのリモコンを持ってきて試すが、これはフォーマットうんぬんではなくて、
全然入力がきていない。

例えば、サンプルプログラムとは使うピンが違っているので、ディレクションやアナログ、デジタルモードの設定をしなければならないのか・・・・などなど 2時間ほど格闘。

受光デバイスの出力波形を当たってみようかな~~と 眺めていると気がついた。

あ~電源ね!

mbed USBからの給電でLCDも表示されるし、ボード上のものは動くと思い込んでしまった。

電源をつなぐと正常に動作。
リモコンを向けてボタンを押すと、コードが表示された。

--------------------------
ライブラリのソースを見るとSONYとNEC などが出てくるので、
最初、SONYとNECしかつかえないのかいね~?
と思ったのだが調べると、
IRリモコンの下位レイヤーのフォーマットとして NECタイプ SONYタイプ AEHA タイプ
などがあり、家電のリモコンは概ねこれのどれかに属するということだ。
この上位レイヤーにメーカー識別や独自のコードが乗るということらしい。

焦電センサーに敗北す


焦電センサーというのは自動ドアやセンサー付きライトに入っていて、人間の発する赤外線に反応する。
これを振るとか、左右に2個付けて差を見るとかしたら人の動きを追うようなことができないかと考えた。

実験キットを取り寄せた。センサー付きライトそのままの回路で、アンプと一定時間リレーをオンにする回路が入っている。リレー部分は不要なので、アンプ部分だけ利用する。

組み立ててオシロをつなぐと反応するのだがどうも思うような結果にならない。
変化量しか検出していない感じ。
まあ、用途を考えれば当然だ。センサーライトに適した動きをするように、フィルターが入っているのだろう。
アナログはあまり良くわからないのだが、アンプ部分に2段階に微分回路があるらしい。
これを外してみる。入力には積分回路らしきものがあって細かい変動もキャンセルしているらしいので、これも外す。
状況は変わってノイズっぽい変動も出てくるのだが、以前大勢は変化量しか検出しないことに変りなし。

ひと休みして
焦電センサーについて調べてみる・・・・・

ええええ~~~ そうなんだ~~

なんてこったい。デバイスそのものが変化量しか検出しないものらしい。

センサーを振れば変化するのだが、どうも出てくる出力を見ると、
位置検出できるような安定した結果は得られそうにない。

ということで、GEMMYにつなぐまでもなく失敗である。

もちろん、人が近づいたら何か動着始めるといったセンサーライトまがいのことは簡単にできる。

2011年2月22日火曜日

シャープの赤外線のほうが便利だった


MAXSONAR と GP2Y0A21YK をつないでみた。

MAXSONAR は電源 3.3V 5V どちらでもOKだ。A/Dが3.3Vなので一応3.3V電源にしてみる。
昨日つないだVRとすげかえてみた。
正常に動作しているらしいが部屋が狭いので、半分くらいしか振らない。
まあいいや。

続いて、シャープの赤外線のやつ。GP2Y0A21YK。
データシートを見ると、電源5V で出力は 概ね3V強まで。 ということは、GEMMYのコネクタに直接つなぐのに便利だ。
サーボ用のコネクターと線をハンダ付けしてアナログ入力に挿す。

なんなく動いた。

プログラムは昨日の短いやつそのままで良い。

GP2Y0A21YKの方が簡単だった。
=================
超音波タイプは当然指向性があるのだが、狭い部屋では余計な反射が入って不安定である。
つまり音波のマルチパス。

シャープの超音波センサーはロングレンジタイプもあるので、近距離用と遠距離用2つくっつけて
プログラムで切り替えるのがいいかもしれない。
ショートレンジは10cmから60cmぐらい、ロングレンジは 50cmから2mぐらいまでつかえる。
(データシートではもう少し広い範囲で書かれている)

=================
PINGもつなごうとおもってライブラリを検索してみたが意外にも見つからなかった。
もう、過去のものなったか・・・・

=================
話は横道にそれる。

GEMMYをいじり始めるとサーボ用のケーブルが結構必要になる。
GEMMYを購入するときにはサーボ延長ケーブルの長さを変えて
何本か一緒に買っておくと良い。オス~オスタイプの方が使うかな。

自分は飛行機で古くなったやつを流用しているが、その在庫も尽きてきたので、
次回なにか注文するときにまとめ買いすることにしよう。

距離センサーを考える


手元にある距離センサーを引っ張り出してみる。

左から "PING" "MAXSONAR EZ1" "SRF10" "GP2Y0A21YK"(ごちゃごちゃの基板についているやつ)
最初の3つは超音波、4番目は赤外線。

PING
超音波では一番ポピュラー。といっても以前はお手軽なのがこれしかなかったからだ。
ディスカバリーチャンネルの工作系番組でも時々見かける。
使い方はやや面倒で、発信トリガーを送ったらピンを入力に切り替えてパルスの長さを測る。
このパルス幅が音速での往復時間になる。
mbedならば、たぶん誰かが簡単に使えるライブラリを書いているだろうから簡単かもしれない。

遠い方は3m ぐらい、近い方は10cm ぐらいまで取れる。

このセンサーでハマるのは、なにも考えずにループでパルス幅をカウントしたりすると、
近い時にはループが速く回り、遠くでは遅くなる。
微分して速度を求めようとしたりするとトンチンカンなことになる。

まあ、障害物があったらよける程度の制御ではあまり難しいことを考えなくても大丈夫である。

MAXSONAR
PINGと同じだがスピーカーとマイクが兼用になっている。
アナログ(電圧)出力、シリアル出力、パルス出力があって、アナログでつなぐととても簡単。
電圧も3.3V 5V どちらでも良い。
ハマるポイントはPINGと同じなのだが、アナログ出力の場合気がつかないまま使える。

SRF10
これはI2C。 小さくて性能は上記2つに比べて少し良い。
といってももらったままお蔵になっていたので、使ったことはない。
あとでI2Cの勉強するときにやってみよう。

GP2Y0A21YK
これは赤外線センサーである。片方の目から赤外線を発して、もうひとつの目で受ける。
光の速度はあまりに速いのでこの程度のセンサーでは往復時間を測ることはできない。
このセンサーは、対象が近くにあるときと遠くにあるときで反射した赤外線の入射角が異なることを
利用している。
ゆえに、出力が線形ではなく離れると分解能が低下する。
大体 10cm~50cmが実用域なので、障害物よけなどに使える。

前述の超音波センサーは意外と感度がよく棒などでも拾えるが、こいつは仕組の関係で
面をセンスするのが得意である。

===========
一番簡単な、MAXSONARのアナログ入力でもやってみようかな。

2011年2月21日月曜日

A/Dは3.3Vなのね


A/Dのお試し。VRの両端に電源電圧をかけて、真ん中の端子から分圧された電圧を取り出して使うのが常套手段であります。
サーボのコネクタはVRと順番が異なるが電源電圧と信号線があるので都合がいい。
(順番は入れ替えねばならない)

で、
5VがVRの両端にかかるようにしてGEMMYのアナログ入力ピンに接続して動いた。
VRを回すと0.0-->1.0の値が表示されサーボが然るべき角度になる。

あれ・・・・?

VRの上のほうが余っている。回しきらないのに 値が1.0になって当然サーボもそれ以上回らない。

はは~んと、VRから出る電圧をあたる。やはり3.3V で値が1.0になる。
A/Dの入力がフルスケールで3.3V。

テストだから理由がわかればそれでおしまいなのだが、そこは趣味だから、
好きなところまでやってみる。

A/Dコンバータに外から基準電圧を入れる方法があるのだがmbedのデータシートを見ても見つからない。
これは安易に信号の方を3.3Vにしたほうが良さそうだ。電流も僅かなのでVRの両端にかける電圧を  5Vから分圧すれば十分である。例えば、33KΩのVRに17KΩの抵抗を直列に入れれば良い。

なのだが、このあと3.3V動作のセンサーをつなぐことも多そうなので、簡単な電源を作っておくことにした。と言っても5Vに3.3Vの3端子レギュレータをつなぐだけである。
ワークベンチにユニバーサル基板をくっつけたが、この前リセットボタン用にGEMMYにくっつけた
基板でも十分乗る。

実はmbedに3.3v出力があるのだがショートでもさせてレギュレータを焼失すると、まるごと使用不能は痛いのでこのようにした。
実際に使うときセンサーの消費電流がはっきりわかっていればmbedからとっていいだろう。

VR式のサーボテスター。
プログラムは、たったこれだけ。

#include "mbed.h"
#include "TextLCD.h"
#include "Servo.h"

TextLCD lcd(p11, p12, p27, p28, p29, p30); // rs, e, d4-d7

Servo myservo(p26); //GEMMY C1 CONNECTOR

AnalogIn ad(p15);   //GEMMY A1 CONNECTOR

int main() {


while(1){
double a = ad.read();
myservo = a;
lcd.cls();
lcd.printf("AD TEST %4.2f",a);
wait(0.1);
}

}