ワイヤレスで温度を計測する方法のソフト編です.
XBee の設定およびホスト側のソフトについて説明します.
流れとしては,次のようになります.
- XBee をパソコンに接続して設定 (ホスト側,センサ側).
- ホストのシリアル通信の準備.
- ホストで受信スクリプトを実行.
では,早速内容に入ります.
XBee の設定
まず,XBee の設定をする準備までを説明します.
- 販売元の Digi の WEB ページから Next Generation XCTU をダウンロードしインストール.
- XBee USB インターフェースボードキットに XBee モジュールを載せたあと,パソコンに接続.
- XCTU を起動.
- インターフェースボードに対応する USB Serial Port を選択.
-
左上の「+」ボタンをクリック.
-
XBee モジュールがパソコンに認識されると左側にデバイスが表示されます.そしてそれをクリック下あと,右上の歯車ボタンを押すと,右側にデバイスの情報およびデバイスを設定するためのボタンが現れます.
以降は,ホスト側とセンサ用で異なりますので,それぞれについて説明します.この設定を行うことで,センサ側の XBee は定期的に A/D 変換の結果や I/O の状態をホスト側の XBee に送信するようになります.
ホスト側 XBee の設定
まずファームを書き換えたあと,設定を行います.
続いて設定です.
- 次の3項目を指定します.
- ID PAN ID
- ネットワークを識別する ID の設定.なんでもかまいませんが,ネットワークで接続する XBee 全てで共通にする必要があります.
- NI Node Identifier
- デバイスを識別するための文字列の設定.指定しておくと,デバイスを識別しやすいです.
- AP API Enable
- 通信のモードの設定.2 を指定して通信時のエスケープをが有効化しておきます.これにより,ホスト側のソフトが作りやすくなります.
また,「SH Serial Number High」と「SL Serial Number Low」をメモしておきます.あとで,センサー側の XBee の設定をするときに使います.
- 設定が完了したら,上の鉛筆ボタンを押して,設定内容を XBee に書き込みます.
以上でホスト側の XBee の設定は完了です.
センサ側 XBee の設定
ホスト側と同じく,ファームを書き換えたあと,設定を行います.
ファームの書き換え手順はホスト側に記載したのと同じです.ファームは,「XB24-ZB」→「ZigBee End Device API」→「*** (Newest)」を選択します.End Device を選択することにより消費電力を大幅に節約できる Sleep 機能が使えるようになります.
続いて設定です.
- 次の10項目を指定します.
- ID PAN ID
- ネットワークを識別する ID の設定.ホスト側の XBee と同じものを指定します.
- DH Destination Address High
- 送信先のアドレスの設定.ホスト側の XBee の「SH Serial Number High」の内容を指定します.
- DL Destination Address Low
- 送信先のアドレスの設定.ホスト側の XBee の「SL Serial Number Low」の内容を指定します.
- NI Node Identifier
- デバイスを識別するための文字列の設定.指定しておくと,デバイスを識別しやすいです.
- PL Power Level
- 送信電力の大きさの設定.とりあえず Medium を指定しておきます.室内であれば問題無く通信できると思います.電池の持ちに影響しますので,慣れてきたら通信が成立する範囲でなるべく小さくするのがお勧めです.
- ST Time before Sleep
- スリープモードに入るまでの待ち時間の設定.0x3E8 (= 1000ms = 1秒) を指定します.これによって,センサの A/D 値を送信した後,1秒後にスリープモードに入るようになります.
- SP Cyclic Sleep Period
- スリープモードに入った後,起きるまでの時間の設定.0x7D0 (10ms * 2000 = 20秒) を指定します.これによって,20秒毎にセンサの A/D 値を送信するようになります.
- D3 AD3/DIO3 Configuration
- DIO3 端子の設定.ADC を指定します.
- D5 DIO5/Assoc Configuration
- DIO5 端子の設定.Digital Input を指定します.(低電圧検出機能を使わない場合不要です)
- IR IO Sampling Rate
- 端子のサンプリング周期の設定.0x3E8 (= 1000ms = 1秒) を指定します.これによって,1度サンプリングをしたらスリープに入るようになります.
- 設定が完了したら,上の鉛筆ボタンを押して,設定内容を XBee に書き込みます.
以上でセンサ側の XBee の設定は完了です.
ホスト側のシリアル通信の準備
デフォルトでは,BeagleBone Black の UART 機能は OFF になっているので,以下の作業で有効化してやります.
- ttyO4_armhf.com-00A0.dtbo [キャッシュ] を /lib/firmware に保存.
-
/etc/rc.local に以下の行を追加.
1echo ttyO4_armhf.com > /sys/devices/bone_capemgr.9/slots - 再起動.
- /dev/ttyO4 が存在していれば準備完了.
- XBee®/XBee-PRO® ZB RF Modules [キャッシュ]
- XBee モジュールのマニュアルです.各種設定や,API モードの通信フレームフォーマットを理解するのに参照しました.
ホスト側のソフトの実行
以下の内容を「xbee_lm60biz.rb」という名前で BeagleBone Black に保存します.
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 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 |
#!/usr/bin/env ruby # -*- coding: utf-8 -*- require 'serialport' STDOUT.sync = true def xbee_api_parse_data_sample(buffer) digital_sample = {} analog_sample = {} digital_index = [] analog_index = [] digital_channel_mask = buffer[0..1].pack("c*").unpack("n")[0] analog_channel_mask = buffer[2] buffer.slice!(0, 3) (0..12).each{|i| digital_index.push(i) if ((digital_channel_mask & 0x1) == 1) digital_channel_mask >>= 1 } (0..3).each{|i| analog_index.push(i) if ((analog_channel_mask & 0x1) == 1) analog_channel_mask >>= 1 } if (digital_index.size != 0) then digital_value = buffer[0..1].pack("c*").unpack("n")[0] digital_index.each{|i| digital_sample[i.to_s.to_i] = (digital_value >> i) & 0x1 } buffer.slice!(0, 2) end analog_index.each{|i| analog_sample[i.to_s.to_i] = buffer[0..1].pack("c*").unpack("n")[0] buffer.slice!(0, 2) } return { digital: digital_sample, analog: analog_sample, } end def xbee_api_parse_receive_packet(packet) frame = {} frame[:frame_type] = packet[0].to_s(16).upcase frame[:source_address] = packet[1..8].pack("C*").unpack("H*")[0].upcase frame[:network_address] = packet[9..10].pack("C*").unpack("H*")[0].upcase frame[:receive_options] = packet[11] frame[:number_of_samples] = packet[12] return frame end def xbee_api_parse_io_data_sample_rx_indicator(packet) frame = xbee_api_parse_receive_packet(packet) frame[:sample_data] = xbee_api_parse_data_sample(packet[13..(packet.size-1)]) return frame end class XBee def initialize(dev) @sp = SerialPort.new(dev, 9600, 8, 1,SerialPort::NONE) @sp.flow_control = SerialPort::NONE @sp.read_timeout = 1000 @buffer = [] end def unescape(payload) ret = [] escaped = false payload.each_with_index{|val, i| if (escaped) then ret.push(val ^ 0x20) escaped = false elsif (val == 0x7D) then escaped = true else ret.push(val) end } return ret end def check_checksum(buffer) sum = 0; buffer[0..(buffer.size-2)].each{|val| sum += val } sum = 0xFF - (sum & 0xFF) return buffer[-1] == sum end def receive while (true) data = @sp.read(30) if (data != nil) @buffer += data.unpack("C*") end start_i = @buffer.index(0x7E) next if start_i == nil @buffer.slice!(0, start_i) next if @buffer.size < 20 length = unescape(@buffer)[1..2].pack("c*").unpack("n")[0] next if @buffer.size < (3 + length + @buffer.count(0x7D)) @buffer.slice!(0, 3) start_i = @buffer.index(0x7E) start_i = @buffer.size if start_i == nil packet = unescape(@buffer.slice!(0, start_i)) if check_checksum(packet) yield packet end break end end end xbee = XBee.new('/dev/ttyO4') def calc_temp(ad_value) return (((ad_value * 1200) / 1023) - 424) / 6.25 end ################################################## data = {} while (true) xbee.receive{|packet| begin frame = xbee_api_parse_io_data_sample_rx_indicator(packet) printf("%s: temperature: %.2f℃ (battery: %s)\n", frame[:source_address], calc_temp(frame[:sample_data][:analog][3]), (frame[:sample_data][:digital][5] == 1) ? 'OK' : 'NG') rescue Exception => e p e end } end |
保存したスクリプトを実行してしばらく待つと,下記のように送信元の XBee アドレスと計測した温度が表示されます.
1 2 3 4 5 6 |
ubuntu@beaglebone:~$ ./xbee_lm60biz.rb 0013A20040AAE258: temperature: 27.84℃ (battery: OK) 0013A20040AC1F90: temperature: 19.52℃ (battery: OK) 0013A20040AAE258: temperature: 27.84℃ (battery: OK) 0013A20040AC1F90: temperature: 19.52℃ (battery: OK) [以下略] |
この例の場合,センサノードが 2つあるため,それらから交互にデータを受信できていることがわかります.
あとは,適宜スクリプトを改造してやれば色々なことができると思います.例えば,値を RRDtool に突っ込んでやれば下記のようなグラフが簡単に作れます.(私の場合,SNMP + Cacti の組み合わせで作っています)
応用編
電波が届きにくい場合,中継用の XBee モジュールを配置することで,センサ側の送信電力を抑えたまま通信距離を伸ばすことができます.この場合,中継用の XBee モジュールは,ホスト側の XBee モジュールと同じ設定を書き込んでやって,電源 ON してやれば必要に応じて勝手に使われるようになります.(A/C アダプタ等から電源を取るような回路にし,送信電力を大きめにしてやると良いです)
例えば,下の図は XCTU で表示したネットワークトポロジですが,ホストとセンサが直接通信を行わず中継用のノードを介して行っていることが分かります.中継用のノードを追加した後,ホストやセンサの設定を一切変えなくても,自然にこのようなトポロジに変化します.
センサノードや中継用のノードを手軽にどんどん増やしてネットワークを拡張できるのは XBee の強みの一つですね.
コメント
[…] これでハードは完成です.ソフト編に続く. […]