4月24日のブログで書いているように、超音波式の風向風速計のキットを組み立てて、一応動作するようになりました。この風向風速計からは、次のような形式で3秒に一度の割合で風向と風速のデータがシリアルポート経由で送られてきます。
#-0.0,0.1,-0.0,0.0
$WIMTA,20.7,C*1E
$WIMWV,155,R,0.0,M,A*3F
#0.0,0.0,-0.0,0.0
$WIMTA,20.7,C*1E
$WIMWV,170,R,0.0,M,A*38
風向は$WINWV,の次の値(上の例では155と170)、風速は$WINWV,???,Rの次の値(上の例では0.0と0.0)です。受信したデータから風向と風速を解読するのは比較的簡単なのですが、これらの値(瞬時値)から平均値を求めるにはどうすれば良いのでしょうか?データの総和をデータ数で割るという一般的な平均値の求め方を適用するのはいささか無理があります。風向と風速は2つの組み合わせで意味のあるデータなので、ベクトルとして扱う必要があります。
HackRF Oneのチュートリアル(動画)に風向と風速を例にしたPythonプログラミングに関するものがあったので、これを流用させてもらいました。(この動画の18:00分あたり)
風向・風速は2次元のベクトルであり・・・それも、角度と絶対値という極座標表現そのものです。それを複素数として扱い、pythonの複素数ライブラリ(cmath)を使って簡単に処理しちゃうという手品のような技です。
風向・風速データのリストから平均値を得る関数averageを含むモジュールvector.pyを次のように定義しました。
import math
import cmath
tau = 2*math.pi
e = math.e
def average(readings):
base = e**(1j * tau/360)
total = 0
for r in readings:
total += r[1]*base**r[0]
result = total /len(readings)
angle = cmath.log(result, base).real
if angle < 0:
angle += 360
return(angle, abs(result))
これを使って、シリアルポートからデータを連続的に受信し、300回分のデータ(15分間)の平均値を求めて、RAMディスクに格納するプログラム(windVector.py)を以下に示します。
import serial
import time
import vector
import os
COM="/dev/ttyUSB0"
bitRate=9600
ser = serial.Serial(COM, bitRate, timeout=10)
cnt = 0
readings = []
while True:
line = ser.readline()
line_disp = line.strip().decode('UTF-8')
if ("$WIMWV" in line_disp):
#print(line_disp)
seg = line_disp.split(',')
#print('cnt %d, angle %d, velocity %f' % (cnt, int(seg[1]), float(seg[3])))
last_readings = [int(seg[1]), float(seg[3])]
readings.append(last_readings)
cnt+=1
if (cnt >= 300):
path = '/home/pi/ramdisk/windData.txt'
if os.path.isfile(path):
os.remove(path) #remove it
f= open(path, 'w')
angle_velocity = vector.average(readings)
line = 'direction %f speed %f \n' % (angle_velocity[0], angle_velocity[1])
f.write(line)
f.close()
cnt = 0
readings = []
#print('program end')
ser.close()
RAMディスクのファイルに書き込まれた値は15分に一度更新されるので、温度や湿度などを15分毎に読み出す時に、風向・風速データ(平均値)をRAMディスクから読み出して、データベースに一緒に書き込むようにする予定です。
ちなみに、RAMディスクは、「Raspberry Pi ファイルをRAMに保存」という記事を参考にして、次の手順で作成しました。
1)ディレクトリを作る
mkdir ~/ramdisk
2)/etc/fstabを編集する
sudo nano /etc/fstab
pi@raspberrypi:~ $ cat /etc/fstab
proc /proc proc defaults 0 0
PARTUUID=4c0ebe06-01 /boot vfat defaults 0 2
PARTUUID=4c0ebe06-02 / ext4 defaults,noatime 0 1
# a swapfile is not a swap partition, no line here
# use dphys-swapfile swap[on|off] for that
tmpfs /home/pi/ramdisk tmpfs defaults,size=2m 0 0
pi@raspberrypi:~ $
3)再起動する
4)dfコマンドで確認する
pi@raspberrypi:~ $ df -h
Filesystem Size Used Avail Use% Mounted on
/dev/root 14G 2.3G 12G 17% /
devtmpfs 87M 0 87M 0% /dev
tmpfs 215M 0 215M 0% /dev/shm
tmpfs 86M 636K 86M 1% /run
tmpfs 5.0M 4.0K 5.0M 1% /run/lock
tmpfs 2.0M 0 2.0M 0% /home/pi/ramdisk
/dev/mmcblk0p1 253M 49M 204M 20% /boot
tmpfs 43M 0 43M 0% /run/user/1000
pi@raspberrypi:~ $