ラベル RFM12B の投稿を表示しています。 すべての投稿を表示
ラベル RFM12B の投稿を表示しています。 すべての投稿を表示

2012年1月28日

RFM12Bのアンテナを考える

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

前記事でさらりと流していましたが、RFM12Bにアンテナを付けてテストしてみました。

今回は1/4波長モノポールを考える。
このモジュールは434MHzなので、(300/434)/4 = 0.17281106 m、およそ172mmになる。
これをセンサー側とデータ収集側の双方に172mmのアンテナ(ビニール線)を付けてテスト。

先生のご協力の下、学校のグラウンドで歩数を元に大雑把に調べてみると... 50m〜100mくらい飛ぶので前の記事で触れたとおり、電波法的にマズイ。
逆に、アンテナを付けない状態だと1m〜2mくらいが限界なので、アンテナの有無でこれだけの差が出る事にビックリ。

というわけで、アンテナの長さを調節 or アンテナを付けないという処置で調整する必要があるようです。

2012年1月27日

RFM12B + MCP9701

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

久々のRFM12Bネタ。

微弱無線モジュール RFM12B と 温度センサー MCP9701 を使った遠隔計測。
温度センサーは特に指定した訳ではなく、たまたまあったやつ(MCP9701)を使うことに。

センサー側はこんな感じ。MCP9701を5V、GND、アナログ5ピンに接続し、RFM12Bも前の記事の通りに接続。


受信側はRFM12Bのみ、同様に接続。


MCP9701は0℃の時400mVなので0.4Vのオフセット、1℃あたりの電圧の変化は19.53mVである。
アナログ入力は0〜5Vを0〜1023の1024段階で表現するので、以上を踏まえて下記のような感じで温度を得られる。
double sensorVal;
double temp = 0;
double offset = 0.4; //オフセット(V)
double tc = 19.53; //温度係数(mV)

temp = (( 5.0 / 1024 * sensorVal ) - offset ) / ( tc / 1000 );
これを前のプログラムに適当に突っ込むと完成。とっても簡単。

センサー側のプログラムはこんな感じ。
#include <rf12.h>
#include <ports.h>

#define NODE_ID   1
#define LED_PIN   7
#define TEMP_SENSOR  5

#define LED_OUTPUT() pinMode(LED_PIN,OUTPUT) 
#define LED_ON()  digitalWrite(LED_PIN, HIGH) 
#define LED_OFF() digitalWrite(LED_PIN, LOW) 

MilliTimer sendTimer;
byte needToSend;
double sensorVal;
double temp = 0;
double offset = 0.4; //オフセット(V)
double tc = 19.53; //温度係数(mV)

void setup () {
    Serial.begin(9600);
    rf12_initialize(NODE_ID, RF12_433MHZ, 33);
}

void loop () {
  
    sensorVal = analogRead( TEMP_SENSOR ); //温度取得
    temp = (( 5.0 / 1024 * sensorVal ) - offset ) / ( tc / 1000 );
  
    if (rf12_recvDone() && rf12_crc == 0 && *(int*) rf12_data) {
        LED_ON();
        Serial.println("Send check OK!");
        Serial.println();
        delay(200);
        LED_OFF();
    }
    
    if (sendTimer.poll(3000)) // ポーリングタイマー3000ミリ秒
        needToSend = 1;

    if (needToSend && rf12_canSend()) {
        LED_ON();
        Serial.print("send temp:");
        Serial.println(temp);
        rf12_sendStart(0, &temp, sizeof temp);
        delay(200);
        needToSend = 0;
        LED_OFF(); 
    }
    
}
受信側のプログラム(一部省略)はこんな感じ。
温度を受信したら1を送信。
int num = 1;

void loop () {
  
    if (rf12_recvDone() && rf12_crc == 0) {
        LED_ON();
        Serial.print("receive temp:");
        Serial.println(*(double*) rf12_data);
        delay(200);
        LED_OFF();
    }
    
    if (sendTimer.poll(3000)) // ポーリングタイマー3000ミリ秒
        needToSend = 1;

    if (needToSend && rf12_canSend() && *(double*) rf12_data) {
        LED_ON();
        rf12_sendStart(0, &num, sizeof num);
        Serial.println("receive check send.");
        Serial.println();
        delay(200);
        needToSend = 0;
        LED_OFF(); 
    }
}
コンパイルして転送。
とりあえず両方ともMacBook Airの2つのUSBポートに接続。
CoolTermで9600を見る。



↑receiveの綴りが間違っている事に今更気づく(;゜ロ゜)

やりとりの内容は至って簡単。
送信側が気温を送信(send temp)→受信側が気温を受信(receive temp)→受信側が1を返信(receive check send.)→送信側が受信側の受信を確認(Send check OK!)

Arduino UNO(ATmega328)だとアナログ入力が0〜5ピンの6個あるので、単純なセンサー(温度、照度、気圧 etc...)を6個接続できる。

ここまでで創造実験は一旦終了。
ADKでAndroidから値の読み出しなど、続きは卒業研究。

のつもりだったんだけど、学生研究奨励金で3万取れたのでUNOとMegaとEthernet Shield*2個で少しだけ発展したものを作るつもり。
具体的なことは進捗状況と一緒に書いていく予定です。

2011年11月26日

RFM12Bと電波法

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
ちょっと気になったので今更ながら電波法の微弱無線とRFM12B(433MHz版)について再確認。
総務省のホームページを読むと、322MHz〜10GHzは3mで35μV/m以下なら免許不要と書いてある。

マクスウェルの方程式から得られる自由空間における電界強度の公式

E=√(30GP)/d
d=送受信の距離(m)、E=電界強度(μV)、G=アンテナ利得(dB)、P=送信出力(W)

距離dは3m、電界強度Eは35μV、利得の基準を半波長ダイポールアンテナとすると0dBdなので利得Gは1とする。

求めたいのはPなので
P=(Ed)^2/30G
と変形して、これに各値を入れてあげると...

((35 * (10^(-6)) * 3)^2) / (30 * 1) = 3.67500 × 10^(-10)

= 0.3675nW

えっと... ナノワットですか...

今は手元にモジュールが無いので測定できないのですが、0.3675nWなんぞ普通に超えているはず。
これはちょっとマズい気がするので来週金曜日にちゃんと確認することにします。

315MHzタイプなら3mで500μV以下の範囲なので、まだ使えるかも。
それとも、多少高くても法的に問題ないZigBeeを使う方が安心・安全かな?

2011年11月18日

RFM12Bで双方向通信

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

とりあえず、RFM12B libraryのサンプルプログラムPingPongを参考にして双方向通信できました。
例のサンプルプログラムは "Hello" と送り受信成功で "OK" → "Hello" を送信というループ。
シリアルモニターで見ていても通信している感がなくて面白くないので少し弄りました。

nodeIDが1のArduinoにint num=0、IDが2のArduinoにint num=1をセット。
受信した数字を自分が持つ数値と足して送信するというもの。
0,1,1,2,3,5,8,13,21,34... という感じで通信を繰り返します。ただそれだけです。
#include <rf12.h>
#include <ports.h>

#define NODE_ID   1
#define GROUP   212
#define LED_PIN   6

#define LED_OUTPUT() pinMode(LED_PIN,OUTPUT) 
#define LED_ON()  digitalWrite(LED_PIN, HIGH) 
#define LED_OFF() digitalWrite(LED_PIN, LOW) 

MilliTimer sendTimer;
byte sendFlag;
int num = 0;
void setup () {
    Serial.begin(9600);
    rf12_initialize(NODE_ID, RF12_433MHZ, GROUP);
}

void loop () {
  
    if (rf12_recvDone() && rf12_crc == 0) {
        LED_ON();
        Serial.println(num);
        num += *(int*) rf12_data;
        delay(200);
        LED_OFF();
    }
    
    if (sendTimer.poll(3000))
        sendFlag = 1;

    if (needToSend && rf12_canSend()) {
        LED_ON();
        rf12_sendStart(0, &num, sizeof num);
        rf12_sendWait(2);
        delay(200);
        sendFlag = 0;
        LED_OFF(); 
    }
}
割りとシンプル。
送受信データはunsigned charの配列で扱っているので1要素の最大値は8bit(0〜255)。
1回のrf12_sendStartで送れるのはリファレンスでは65byteまで。
接続は前々回の通り。これを2つ用意する。


次回はノードが複数存在する場合のプログラミング。ここからネットワーク化していきます。
特定のノードに対してのデータ通信は受信側にてNODE_IDで条件分けするだけ。
受信側が正常にデータを受信できたら、送信側に受信完了の合図を送って通信終了。
来週は試験期間なので続きは再来週です。

2011年11月11日

RFM12B library

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

Jean-Philippe Lang氏のRFM12B libraryについて。
Google先生で調べる限りではリファレンスの日本語訳は見つからなかったので適当(自分用)に翻訳。
あと、本家のwikiは個人的に見づらいので、一覧にするという意味も。

RFM12Bについては前の記事にまとめました。

初期化関数
  • rf12_initialize()
  • 受信/送信用にモジュールを初期化する。
    #include <rf12.h>
    #include <ports.h>
    byte rf12_initialize(byte nodeId, byte freqBand, byte netGroup =212);
    
    パラメータ
    • nodeId
    • 無線モジュールのノードID。nodeIdは同じnetGroup内においてユニークにする必要がある。IDの範囲は0〜31だが通常は0〜30を使用する。nodeIdの1〜26に対応する大文字のA〜Zを利用することもできる(しかし今後は推奨しない)。数字の0はOOK(On-Off-Keying/オンオフ変調)のために予約されている。31は特別で同一netGroup内の任意のnodeIdのパケットをピックアップできる。
    • freqBand
    • 無線モジュールで利用する周波数。RF12_433MHZ、RF12_868MHZ、RF12_915MHZが用意されていて、利用するモジュールの周波数に合ったものを使用する。
    • netGroup
    • ノードを区切る為に利用する。同じnetGroupのノードが通信できる。このパラメータはオプションであり、省略した場合はデフォルトの212 (0xD4)が利用される。これ(212)はRFM12で唯一利用できるIDであり、RFM12Bでは他の任意のIDを利用できる。

  • rf12_config()
  • rf12_initialize()とEEPROMの0x20〜0x3Fに書きこまれた設定を呼び出す。0x20〜0x3Fに含まれるチェックサムが正しくない場合、rf12_initialize()は呼び出されない。実行結果としてnodeIdを返す。(なければ0を返す)
    #include <rf12.h>
    #include <ports.h>
    byte rf12_config();
    
    パラメータ
    なし。

  • rf12_easyInit()
  • 簡単な送信手法設定。
    この関数はドライバが初期化された後、rf12 initialize() または rf12 config()を利用して呼び出す必要がある。
    #include <rf12.h>
    #include <ports.h>
    void rf12_easyInit(byte seconds);
    
    パラメータ
    • seconds
    • 新しいデータパケットまでの最小値(1〜255秒)を設定する。0を使用すると最短で送信される。
      ・433および915 MHzの周波数帯では、100ミリ秒(10パケット/秒)に固定。
      ・866 MHz帯では、送信されるバイト数に依存。

以下、和訳途中...
基本関数
  • rf12_recvDone()
  • rf12_canSend()
  • rf12_sendStart()
  • rf12_sendWait()

簡易送信関数
  • rf12_easyPoll()
  • rf12_easySend()

その他
  • rf12_control()
  • rf12_encrypt()
  • rf12_lowbat()
  • rf12_onOff()
  • rf12_sleep()

2011年10月27日

RFM12B + Arduino

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

Hope Microelectronics社製の微弱無線モジュール
日本では日昇テクノロジー通販(http://www.csun.co.jp/SHOP/200712022.html)で買える。
お値段は1200円 880円(2012/4現在)ですが、SparkfunでSMDタイプが6.95ドルから売ってる模様。

周波数帯は315/434/868/915MHzの4種。(国によって使用できない周波数帯が有り)
定格電圧は2.2V〜3.8Vらしいけど、Arduino UNOからの5Vでも特に問題なく動作するっぽい。
(というより、5VのArduinoでRFM12Bを使う場合はVCCを3Vから取ると動作不安定になりました。)

参考資料
微弱無線モジュールのテスト (CPUを作ろう)
RFM12B wireless FSK transceiver module (Hope Microelectronics)
RF12B programming guide - RF12B_code.pdf (上記製造元のWebより)
RFM12B library for Arduino (JeeLabs)
→2013.2.14追記:ライブラリが新しくなっている模様です。https://github.com/jcw/jeelib

とりあえず、Hope Microelectronics社のプログラミングガイドの通りに接続してみる。

接続
GND-----------GND
5V--------------VCC
pin D2---------IRQ (interrupt request out)
pin D10-------SEL (chip select in)
pin D11-------SDI (SPI data in)
pin D12-------SDO (SPI data out)
pin D13-------SCK (SPI clock in)

左の写真はpin D2が抜けてます(;・∀・)
送信と受信のサンプルプログラムをそれぞれ1台ずつ書き込んでテスト。
送信側のLEDは等間隔で点滅。
受信側のLEDは送信側からのデータを受信できたら受信の度に点滅。
(受信が継続して問題なければ送信側と同じ等間隔で点滅)

というわけで、しばらくはこの無線モジュールで遊んでみます。
XBeeと比較して安価なので、無線通信デバイスの量産とか色々出来るということです。
先人の知恵と産物を使いながら、まずは使いこなせるように色々やってみます。