いくつかの場所に分散したArduino機から、各種の情報(センサー情報とか)を送信して、一台の受信機(ホスト)でそれらをまとめて受信し、PCと接続し、PCで処理したりサーバーに上げたり・・という事を実現したので、そのまとめ。
いろんなWEBからの情報を集めながら、複数台の通信が出来るようになったので、まとめておくことにした。
何台も同じような配線をするのは面倒だし、nRF24L01モジュールの性能が配線に敏感・・という書き込みがあちこちにあったので、基板を起こすことにした。→基板製作の詳細はこちらへ
搭載出来る部品は下記のとおり。
- Arduino Nano (5V) x 1
- 16×2 LCD module (4bit interface) (5V)
- nRF24L01 (3.3V)
- MAX6675 module (5V)
nRF24L01用の3.3Vレギュレーターやパスコンを基板上にマウントすることにより、安定した3.3Vを供給出来るようにしてある。他には、MAX6675モジュールの端子配列が商品によって異なる順番になっているのに対応しており、いくつかのユニバーサル部分を設けてある。実際のアプリケーションでは、このユニバーサル部分に、PhotoCouplerを載せて、外部からの24Vパルスを検出するようにした。
【RF通信の試行錯誤】
nRF24L01の仕様書によると、”Multiceiver”という使い方があるようなので、これを使うことにした。
この使い方ならば、最大6台の送信ユニットから一台の受信ユニットへデータを送ることが出来る。各パイプの設定がミソのようだが、仕様書を参考にしてマネてみた。
パイプ(アドレス)を設定するレジスタは全部で6個。送信側が6台で、受信側が一台だとアドレスが足りないんじゃ?と思ったが、よく見てみたら、このモードの時には、基本的にはRX側からはデータを送ることが出来ないようなので、これで良いのかも。
実際のコードでは設定は次のようにした。(「RF24.ino」をダウンロード )
ライブラリは、Githubから”RF24”をダウンロードして利用した。また、送信側と受信側で同じソースコード上で開発を行いつつ、切り替えを単純にするために、コンパイルオプションで、送信側と受信側(HOST)を切り替えるようにした。(#define HOSTが受信側)
[送信側、受信側の共通定義]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
// pipe address definition #include <spi.h> #include "RF24.h" #define N_PIPES 6 // total number of pipe = 6; const uint64_t pipes[N_PIPES] = { 0xF0F0F0F0D2LL, 0xF0F0F0F0E1LL, 0xF0F0F0F0E2LL, 0xF0F0F0F0E3LL, 0xF0F0F0F0E4LL, 0xF0F0F0F0E5LL }; //pipes[0] -- pipes[5] RF24 radio(9, 10); // (CE, CS) uint8_t len; uint8_t pipe; uint16_t got_temp10; //temperature * 10 value uint16_t got_width_H, got_width_L, got_count; uint8_t RF_channel; uint8_t error_cnt = 0; extern uint8_t wdt_counter[]; bool r_blink[N_PIPES] = {true, true, true, true, true, true}; // // initialize RF module // void begin_RF() { // RF24 setting radio.begin(); RF_channel = 100; radio.setChannel(RF_channel); radio.setRetries(1, 1); //(n, m) = 250us + (n x 250us) interval, m times retries radio.setPayloadSize(8); // maybe better stability radio.setPALevel(RF24_PA_HIGH); // RF power set as HIGH radio.setDataRate(RF24_250KBPS); // data rate = 250kBPS (nRF24L01+ only) |
パイプは全部で6本とし、それぞれに仕様書の例を参考にしてアドレスを振った。アドレスの振り方に色々が制約があるようなので、あまり冒険はせずに従った。
初期化としては、RFのチャンネルを100, Payloadは8バイト、信号強度は強、スピードは250kbpsとして、より信頼性の高い、通信距離の稼げる設定を採用した。
[ホスト(受信側)定義]
1 2 3 4 5 6 7 8 |
radio.openReadingPipe(0, pipes[0]); //read pipe #0 from Remote-0, pipes[0] radio.openReadingPipe(1, pipes[1]); //read pipe #1 from Remote-1, pipes[1] radio.openReadingPipe(2, pipes[2]); //read pipe #2 from Remote-2, pipes[2] radio.openReadingPipe(3, pipes[3]); //read pipe #3 from Remote-3, pipes[3] radio.openReadingPipe(4, pipes[4]); //read pipe #4 from Remote-4, pipes[4] radio.openReadingPipe(5, pipes[5]); //read pipe #5 from Remote-5, pipes[5] |
[センサー(送信側)定義】
1 2 3 |
radio.openWritingPipe(pipes[tx_pipe]); //pipe for writing data, only one for one remote |
それぞれの送信機(最大6台)が 0 から 5までの、tx_pipe番号を取ることにより、ホスト側で設定したパイプと一致する。
[ホスト側受信処理]
ホスト側(受信側)では、受信した際のパイプ番号から、どの送信機からの信号なのかを判別できる。おまけとして、どの送信機からのデータが届いて、届いていないかを判定できるように、watch dogもどきのカウンターを設けて、一定時間データが届いていない送信機がわかるようにした。
1 2 3 4 |
if (radio.available(&pipe)) { wdt_counter[pipe] = 0; //reset the WDT for the recieved pipe len = radio.getDynamicPayloadSize(); // 8byte as setup radio.read(&rxd8, len); |