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

2020年8月5日水曜日

無駄にpython側でもダイレクトにdataformatへ格納する処理を作ってみた

スクリプト的に流れが気に入らなかったので、結局pythonでもドライバで実装したサンプリング配列を作らないで直接dataformatを作成する処理を実装することに。

ついでに異常値に色付けなども行ってみました。
ドライバを介さないと途端に割り込み処理による取りこぼしが発生していました。
pi@rasp4b4g:~/gpioread $ python3 ./dht.py --debug --nodriver
Output for debugging.
gpio_no : 5
No driver is used.
OSError : 1 IsNoDriver
Sampling is performed without using a driver.
respons low  : 82
respons high : 87
data low     : 51 ~ 55
data high '0': 23 ~ 26
data high '1': 69 ~ 72
data format : 3F 00 23 06 68
2nd read.
OSError : 1 IsNoDriver
Sampling is performed without using a driver.
respons low  : 85
respons high : 89
data low     : 43113
data high '0': 21 ~ 29
data high '1': 66 ~ 73
data format : 2F 00 23 06 68
CRC Error.
ErrorCode :  2  retry.
OSError : 1 IsNoDriver
Sampling is performed without using a driver.
respons low  : 82
respons high : 87
data low     : 48 ~ 133
data high '0': 21 ~ 29
data high '1': 65 ~ 72
data format : 3F 00 23 06 D0
CRC Error.
ErrorCode :  2  retry.
OSError : 1 IsNoDriver
Sampling is performed without using a driver.
respons low  : 88
respons high : 87
data low     : 48 ~ 58
data high '0': 21 ~ 29
data high '1': 65 ~ 72
data format : 3F 00 23 06 68
DHT results.
Retry count : 2 time(s)
Conversion  : DHT11V1.3
Temperature : 35.6 C
Humidity    : 63.0 %

不完全とはいえ、こうなると割り込み停止させるためにメモリマップドレジスタに展開されている割り込み停止処理も入れておきたくはなります。個人的にはそれよりドライバをちゃんと登録して、再起動時にも読み込まれるようにするのが先の様な気がしますw

サンプリングせずにダイレクトにビットを格納してみると…

作業としてはあまり大変そうではなかったので、コピペして切り張りして試してみました。
最初、ちょっと間違えてLOW信号の長さを見てしまったため、FFFFFFFFFFになってしまいましたが、見直してすぐに正しい処理が流れてよかったw
インターバルのデバッグもそのままコピーしたのでログから実行時間を比べてみました。

2020年8月4日火曜日

サイクルカウントのウェイトを作成してGPIOのPull Up/Downを実装してみました。

150Cycleのウェイトループが作れるようになったのでドライバ側でpull up/downの実装も行ってみました。これで一歩踏み込んだ形になります。
ただし、データシート上に記載してありましたが、pull up/downの設定値はcpuから見えなくなるため、設定値はソフト側で管理する必要があるとのこと。なので、これを行うとRpi.gpioの内部バッファと実際値のズレが生じてRpi.gpoiでうまく機能しなくなる可能性があります。

実装中に色々と新たな発見というか記載を見かけて色々な部分を書き換えながら実装していましたが、一番気になったのがioremapでアクセスできるようになったメモリーに対してアクセスするためにioread/iowriteといった関数を通す必要があるらしいという点。

2020年7月31日金曜日

一回りしてpythonに戻って

一通り手直しを終え、ドライバが無かったらそれなりに動く形のものに落ち着きました。

各変数の位置がいい加減だったり、配列は相変わらずどんぶりだったりと突っ込み所も多いですが、参考になれば

2020年7月15日水曜日

結構な頻度で取りこぼすのですが?

色々と試行している最中ですが、そろそろ万策尽きそうです。

DHT11の古い方のデータシートに注意書きとして
Note: The host reads the temperature and humidity data from DHT11 always the last measured value, such as twice the measured interval of time is very long, continuous read twice to the second value of real-time temperature and humidity values.
とデータタイミングダイアグラムの図の下に書いてありました。しかも赤い色の文字で。
英語力が無いのでよくわかりませんが、グーグル翻訳に通すと
注:ホストは、DHT11から温度と湿度のデータを常に読み取ります。たとえば、測定間隔の2倍は非常に長く、リアルタイムの温度と湿度の値の2番目の値を2回連続して読み取るなどです。
一時期のグーグル翻訳はかなりすごい感じで訳されてた気がするのですが、最近なんかパッとしませんね…
とにかく2連続で値を取得して後から取得した値がその時の気温、湿度だよと言ってるのだと思うのですがどうでしょうw

そのためにどうしても2連続でDHTからデータを読み込みさせようとしています。昔の記憶をたどると、DHT11では連続してデータを読み取ろうとするとエラーが頻発してしまうことがありました。これがDHT22も同様に発生しています。
原因を調べるために結構突っ込んで調べたのが昨日で、今日はそれなりに改善策を講じたりしていますが、結果としてこれといったインパクトはありませんでした。
面白かった?ポイントとしては、python3でarray.array('B', [0 for i in range(100)])とかで一気に領域確保を行うと、予想以上に時間がかかってしまい、センサーに送信要求を出すと、受信準備が整う前にデータが送信され始めてしまい、開始部分を思いっきり取りこぼすという事態に陥りました。
安易な逃げ方としてクラス変数にして、領域確保はインスタンス作成時に逃がして、使いまわすためにバッファの長さも変数として追加しました。
そのおかげで、サンプリング時のループがかなり安定したのですが、問題は結構な頻度で取りこぼしてしまう状態に。
過去の経験から、GPIO.inputを短時間に呼び出している部分を1μsとか10μs以下では呼ばないようにしたり、軽くなりすぎたループにあえてウェイトをかけたりと、やってみましたがこれといったインパクトもなく、悪影響しか出なかったので最終的にバッファの確保以外はそのままとなりました。
別の角度から取りこぼしてしまうのならデータから救えそうな状態なら救ってしまえということで、信号を取りこぼしてバースト状態になっている部分を補正する処理も実装してみたものの、予想以上に取りこぼしが発生していて多少は救えましたが決定打にはなりませんでした。
DHT22はDHT11と比べてデータシート上のタイミングが結構違っていて、推奨値なども結構異なっています。実際はDHT11と同様の手順でデータは送られてくるのですが、推奨値にしたり、記載通りの手順に則ると素早く受信開始できるようになりました。けども…どうしても2連続の呼出しを行うためには間に0.5~2秒程度時間を置かないとデータが送られてこないのであまり違いは無いかもw
データシートにはセンサー自体のレスポンスタイムが、条件付きの数字ですが、湿度は6s未満、温度は10s未満とそれなりにかかるので、下手をすると10s程度待たないとだめかもしれません。2sでスリープするっていうのが個人的には引っかかりますが、きっとデータ送受信部分だけなんだよね?と考えてます。
センサーのハード的な問題もありそうなのですが、一番の問題はやはりデータの取りこぼし問題なのは変わらず、ps -aFでプロセス番号を拾って、taskset -cp 0 14437でプロセッサー固定させて実行しても状況は変わらず仕舞い。
プロファイラなどでどこでウェイトがかかっているのか調べてもよさそうなんですが…ここで他の言語の力を借りることを考え始めました。pythonはその辺がメインの使用用途だと思うんですが、正直面倒くさそうwとはいえ、実際にどのくらいの実行時間がかかるのかちょっと様子を見てみたいということで、時間取得から様子を見てみました。
検索すると超単純な時間取得のソース(https://www.mm2d.net/main/prog/c/time-04.html)があったのでそれをコピペして実行時間を見てみることに。
pi@rasp3bprs:~ $ gcc test.c
pi@rasp3bprs:~ $ ./a.out
1594811448 557473
1594811448 557880

これはgettimeofday()で取得した値を表示させることを2回行っただけの物なのですが、これで結構参考になる数字が。秒数はさすがにカウントアップされないものの、μ秒の単位では
407μ秒「も」かかってしまっていて正直ダメかとも思ったのですが、よくよく考えればこれはprintfの処理も含まれているので、gettimeofday()の応答時間をざっくりと様子を見てみたいのであれば、連続して呼び出した後で表示させるしかないわけで…変えて実行してみました。
pi@rasp3bprs:~ $ gcc test.c
pi@rasp3bprs:~ $ ./a.out
1594811575 025131
1594811575 025132

勘違いでなければ1μ秒で変数に格納されているのでいい感じです。(すべてraspberry pi 3b+で実行)
実際に必要な解像度としては安定していれば20μ秒程度になってしまっても行けるとは思うので、とりあえずcで作って、pythonへの組み込みはそのあと考えようかなとか。

2020年7月14日火曜日

DHT22のCRCエラーが発生した様子

いろいろとグダりながらもざっくりと変更していて少しだけ見えてきた部分があります。
現時点での結論を言ってしまえば、原因は実行時の何らかのウェイトによってうまく信号を拾えていない感じ。

そもそもpythonでリアルタイムっぽい処理が書けててすごいなぁと感心してただけなんですが、DHT11で使用していたライブラリっぽい物も大雑把にしか見ていなく細かく追って行ってようやくつかめた感じです。
肝心のデータ信号の受信部分がループを使ったソフト的なカウントのサンプリングを行ってそこからビットを起こすということをやっているのですが、そのサンプリング処理はループに依存してました。時間軸とは異なっているために、ループ自体のサイクルが一定ではない場合データ受信で失敗するということです。
しかも、時間を無視しているために、エラー原因もいくらバッファを見ても原因の究明ができません。
良くも悪くも現状1ループ10μs以下では動いているので、サンプリングレートは10μs程度はあるようです。(Raspberry pi 3b+)処理時間がどの程度変わってしまうか正直わからないままごりっと書き換えてみました。
まずはデータフォーマットも単なるサンプリングから信号が切り替わるまでのループ回数を記録するように変更。これだけで配列への格納タイミングがざっと10分の1程度にはなるはずです。
実測値は 1508個から82個へ処理速度が上がれば上がるほど元々の方はデータが増えますが、変更後はバーストや取りこぼしなどで変動することはあっても極端に巨大化することは無いはずです。(変更後のバージョンは初期の信号状態を保持する必要があると思ったので、本来は81個のはず)

続いてループカウントになっている部分を時間へ変更します。
μ秒単位の時間操作がまともにできるか不安を抱えつつ、time.time()でμ秒を扱うことに。さらに、配列をarray.array('B')で1byteのデータとしてみました。(python3ではint扱いになっているので、1データあたりの消費量は4バイトだとは思います。('B')を指定したため、オーバーフローや範囲エラーが出るので想定外の事態になるとエラーで落ちるというおまけつきです(笑)
データーフローを見ると時間は最大でも80μ秒程度なので255μ秒以上は格納することが無いという前提です。
その結果がこちら
array('B', [1, 29, 81, 54, 52, 26, 52, 26, 54, 24, 53, 26, 54, 26, 51, 26, 54, 73, 53, 26, 66, 74, 52, 26, 54, 73, 52, 74, 52, 75, 52, 73, 54, 73, 54, 71, 68, 26, 54, 24, 54, 26, 56, 23, 53, 26, 51, 26, 54, 26, 52, 73, 66, 26, 54, 24, 55, 24, 55, 73, 54, 72, 53, 73, 55, 73, 52, 25, 64, 73, 54, 73, 54, 74, 52, 26, 54, 24, 54, 25, 54, 26, 52, 26, 45])
最初の1個目の1は信号線が初期状態でHIGH状態だったことを示し、その後からは切り替わるまでのμ秒時間となっています。数字を見る限りそんなに悪くない感じで入っていて、3B+のpython3でもそれなりに処理が行える感じがしました。
このサンプリング結果からビットパターンの信号のみを抜き出している部分があるのですが、もともとトリッキーな部分があったのですが、格納データを変えたのですこしすっきりしました。
データ開始の信号を除去してHIGH状態のビット情報だけのサンプリングデータは
[26, 26, 24, 26, 26, 26, 73, 26, 74, 26, 73, 74, 75, 73, 73, 71, 26, 24, 26, 23, 26, 26, 26, 73, 26, 24, 24, 73, 72, 73, 73, 25, 73, 73, 74, 26, 24, 25, 26, 26]
となります。基本的にはLOWデータは50μs前後の数値を取り除いた部分となります。
逆に取り除いた数字を並べてみましょう…手作業ですがw
52, 52, 54, 53, 54, 51, 54, 53, 66, 52, 54, 52, 52, 52, 54, 54, 68, 54, 54, 56, 53, 51, 54, 52, 66, 54, 55, 55, 54, 53, 55, 52, 64, 54, 54, 52, 54, 54, 54, 52, 45
結構疲れましたが、こんな感じ
最低は最後の45ですが、これはデータが終了した後のLOW信号なので正直関係ありません。
そうすると、範囲は51~66μsで、サンプリングサイクルが数μsということを考えれば悪くない範囲だと思います。
ここの処理以降はまた手を入れていませんが、データビットの0か1かを判断するためにサンプリングデータの最小値と最大値から閾値を決めてビット列を作成し、5byteのデータを組み立てていました。もともとはループカウントなのでこのようなことをやっていますが、サンプリング単位がμsになっているので、もうすこし決め打ちしても大丈夫なような気はします。ただスループットが低いRaspberry pi zeroとか2bとかを考えるともう少し様子を見ないとダメですね。zeroは欲しいと思いつつ、結局まだ買っていない…。

ここまできてようやくCRCエラーやビット落ちの様子が判断できるようになります。

何度かコンソールから連続してセンサー値を拾っていると、結構な確率でエラーが発生するようになります。
その時に発生したCRCエラーの様子。
pi@rasp3bprs:~ $ python3 ./setup/sbin/dht22.py --pin 6 --debug
pin : 6
Output for debugging.
array('B', [0, 74, 79, 55, 24, 55, 23, 54, 28, 52, 24, 54, 27, 54, 23, 53, 76, 51, 28, 67, 71, 54, 71, 54, 28, 54, 23, 54, 76, 50, 28, 54, 72, 54, 72, 67, 28, 54, 23, 54, 28, 54, 23, 54, 24, 56, 24, 54, 28, 54, 71, 67, 28, 50, 28, 51, 28, 51, 77, 50, 28, 54, 72, 54, 23, 54, 25, 63, 76, 54, 71, 54, 71, 54, 27, 54, 23, 54, 28, 54, 71, 54, 23, 49])
[24, 23, 28, 24, 27, 23, 76, 28, 71, 71, 28, 23, 76, 28, 72, 72, 28, 23, 28, 23, 24, 24, 28, 71, 28, 28, 28, 77, 28, 72, 23, 25, 76, 71, 71, 27, 23, 28, 71, 23]
the_bytes
02 cb 01 14 e2 ← これは正常なデータですが、初回なので破棄されますw
array('B', [0, 58, 88, 48, 25, 59, 25, 56, 25, 49, 25, 56, 25, 56, 24, 55, 76, 49, 24, 100, 39, 56, 77, 46, 24, 56, 32, 45, 77, 55, 24, 56, 65, 56, 77, 66, 24, 56, 24, 56, 25, 56, 24, 56, 24, 49, 25, 56, 24, 56, 66, 76, 24, 56, 24, 48, 24, 56, 77, 55, 24, 56, 66, 56, 24, 56, 28, 56, 76, 55, 76, 45, 75, 56, 24, 56, 24, 55, 25, 56, 66, 56, 24, 46])
[25, 25, 25, 25, 25, 24, 76, 24, 39, 77, 24, 32, 77, 24, 65, 77, 24, 24, 25, 24, 24, 25, 24, 66, 24, 24, 24, 77, 24, 66, 24, 28, 76, 76, 75, 24, 24, 25, 66, 24]
the_bytes
02 4b 01 14 e2 ← CRCエラーが発生しているデータ
CRC Error.
2nd. retry. 2
array('B', [0, 50, 76, 48, 36, 49, 25, 56, 25, 49, 25, 56, 24, 56, 24, 56, 76, 48, 25, 67, 77, 56, 66, 56, 24, 57, 32, 46, 77, 45, 35, 45, 76, 56, 66, 66, 35, 45, 35, 46, 24, 55, 24, 55, 24, 58, 24, 55, 24, 55, 76, 65, 24, 55, 24, 48, 35, 45, 76, 55, 24, 56, 66, 55, 24, 55, 28, 115, 31, 46, 66, 55, 76, 56, 24, 55, 24, 55, 26, 56, 65, 56, 24, 45])
[36, 25, 25, 25, 24, 24, 76, 25, 77, 66, 24, 32, 77, 35, 76, 66, 35, 35, 24, 24, 24, 24, 24, 76, 24, 24, 35, 76, 24, 66, 24, 28, 31, 66, 76, 24, 24, 26, 65, 24]
the_bytes
02 cb 01 14 62
CRC Error.
2nd. retry. 2
array('B', [0, 62, 85, 57, 24, 57, 24, 45, 35, 48, 25, 55, 25, 55, 24, 56, 76, 47, 24, 65, 75, 55, 76, 55, 24, 55, 30, 46, 76, 55, 65, 54, 24, 55, 24, 66, 35, 44, 34, 45, 34, 45, 35, 45, 34, 48, 24, 56, 24, 55, 76, 65, 24, 55, 24, 58, 24, 55, 66, 56, 24, 56, 75, 55, 24, 55, 27, 56, 76, 55, 75, 45, 76, 55, 24, 55, 24, 55, 25, 55, 76, 45, 76, 46])
[24, 24, 35, 25, 25, 24, 76, 24, 75, 76, 24, 30, 76, 65, 24, 24, 35, 34, 34, 35, 34, 24, 24, 76, 24, 24, 24, 66, 24, 75, 24, 27, 76, 75, 76, 24, 24, 25, 76, 76]
the_bytes
02 cc 01 14 e3
DHT22 results.
Retry count : 2 time(s)
Error code  : 0
Temperature : 276 C
Humidity    : 716 %
なんのこっちゃというような結果ですが、気温と湿度が10倍されたままというのは置いておいて、最初に正常にデータを得られているのですが、どこかに「センサー値の現時点での値を取得するためには複数回データを取得する必要がある」と書いてあった記憶があり、破棄しています。記述された資料が見当たらないので昨日この部分を外して様子を見ていたら、しばらく放置して2回センサー値を表示させたら1回目と2回目で気温が1℃以上変わったので、スリープ直後はスリープ前のセンサー値を返す感じなのだと思います。
で、問題なのが、DHTが悪いのか、Raspberry piが悪いのかわからない部分で、連続でデータを取得するとエラーが発生しやすい。でも連続で値を取得しないと現時点でのセンサー値が分からないというジレンマに陥ります。
ま、どうでもいいんですがw

で、本題の異常値を探ってみると、2つ目のサンプリングデータで100μsとかある部分があります。3つ目では115μsとなっている部分があり、おそらくこの時に何らかの原因で処理が止まってしまったのだと思われます。
今回は運良く?LOW信号がバーストしたような感じになっていてHIGH信号のビットが1になるべきものが0になっただけと考えられます。(気色塗り部分)

もう一つのデータ落ちに見えてしまったパターンはおそらくHIGH信号がバーストしてしまったようになってしまい、結果としてLOW信号への切り替わりのタイミングを取りこぼした結果だと推測しています。
さてどうでしょうか…

array('B', [0, 70, 76, 56, 27, 54, 21, 54, 26, 54, 29, 49, 26, 54, 26, 54, 73, 54, 22, 71, 70, 54, 75, 54, 25, 49, 25, 57, 27, 54, 26, 49, 77, 54, 26, 65, 24, 55, 26, 54, 26, 53, 26, 49, 26, 54, 29, 48, 26, 53, 76, 65, 26, 54, 25, 55, 24, 54, 72, 54, 26, 49, 76, 54, 26, 54, 71, 61, 77, 54, 71, 183, 30, 49, 72, 55, 26, 49, 78, 52, 27, 43])
[27, 21, 26, 29, 26, 26, 73, 22, 70, 75, 25, 25, 27, 26, 77, 26, 24, 26, 26, 26, 26, 29, 26, 76, 26, 25, 24, 72, 26, 76, 26, 71, 77, 71, 30, 72, 26, 78, 27]
pull up lengths Error. len : 39
ログから漁ってみましたが、こんなデータです。
パット見あまり変なところはありませんでしたが、赤塗したところが怪しそうな気がします。信号的には60μsを超える波形はデータ開始時のみでデータ中には現れることはありません。なのでここの間にHIGH信号を完全に取りこぼしているのかな?と推測しました。
とおもったらもっと怪しいのが183とかトンでも数字がありましたwよって正解は、HIGH信号のバーストではなく、LOW信号バースト、正確には単なる「HIGH信号の取りこぼし」でした(笑)

といった具合に、悪者がはっきりしました。Raspberry pi で動いている環境でした(´-ω-`)

Raspberry pi 4bでDHT11を動かしたときにエラーが発生しにくい気がするというのは気のせいではなく、処理速度が上がってスクリプトの実行が安定した結果だった様です。

あと気づいたのは、正常時はビット信号が綺麗にサンプリングできている感じなのに対して、エラー時は全体的にサンプリングにばらつきがあるように思えます。70μsを越えているデータが頻発している。



データシートに詳しくはホームページ見てね的なことが書かれていたので見てみると、センサーの一押しが、DHT10とか外見はあまり変わらずI2C仕様のDHTが…マジかw早速アマゾンで見てみると、3個セットで2400円ぐらいだったかな…微妙な値段だけど、悪くなさそう?

2020年7月13日月曜日

DHT11とDHT22

色々と思うところがあってセンサーの選定をしていましたが、安価で簡単に手に入りそうなDHT22をポチって見ました。2個セットで1400円。一個700円とか3個セットのBME280より高価ですね…。

で早速手持ちのソースをデータシートをみつつ変更したところ、いきなりうまく行かず…すこし試行錯誤した結果、開始時の手順はDHT11の時と同じにするのが安定しました。データシート上だと細かく記載されていて手順が増えているようにも思えたのですが、結果としてpull upされた状態からダウン状態にした後、アップして待機するだけでデータが送られてきました。

それなりにDHTの共通ライブラリっぽいソースも見てみましたが、DHT11とDHT22とではデータの加工方法が違うだけのようでした。

今回DHT22を選んだ理由として、小数点以下の数字が取得できるっていうのがポイントだったのですが、これは今日発覚したDHT11でも温度の小数点が取得できたということで半減してしまいました…。(解像度が16bitで温度が整数のみってどう考えてもおかしいだろという突っ込みはさておきw)

気を取り直してスペックを見てみましょう。

DHT11DHT22
温度範囲0~50℃
-20~60℃
-40~80℃
温度解像度16bit16bit
温度レスポンス10s10s未満
湿度範囲20~90%RH
5~95%RH
0~99.9%RH
湿度解像度16bit0.1
湿度レスポンス6s5s未満
電源電圧3.5~5.5V3.5~5.5V
消費電力0.3mA8mA
サスペンド時60μA10~20μA
スリープまでの時間2s2s
上記は各データシートからの抜粋値で、レスポンスに関してはデータシート上に前提条件として1/e(63%)とか25℃でとか書いてあるので、センサー素子から値を得るのに何度も試行する必要があるもののようです。範囲が広がっているDHT22の方が消費電力が上がっているのもこの辺が影響してそうです。

正直、アップデート後のDHT11なら一般使用は問題ないんじゃというのはさておき、気になる違いはとしてDHT22の優れている点は温度、湿度の範囲が少し広いところでしょうか。DHTの仕様特性として、ほとんどの時間をサスペンド状態で放置されるはずなので、サスペンド時の消費電力が低くなっているのもいい感じです。
デメリットとして消費電力が数字上結構上がっているところ。データシート上はturn onと書いてありましたが、絶えず値をとり続けるのであれば、DHT11は結構優位ですね。

見直せば見直すほど、DHT22を買った利点がないわけですがw



関係ないところで、Raspberry piの放熱やセンサー自体の放熱もあるようで、DHTシリーズはエラー時のリトライで取得できる温度が少し上ってしまう感じがします。手で連続で値を取得すると温度がすこし上がることが多いのもおそらくセンサー自体の発熱があるためのような。

DHT11の温度は小数点まで持っていたw

錯乱状態が少し解消され様子を見たところ、
16時過ぎぐらいからグラフの形が矩形からいい感じになりました。
今までは小数点以下は無いと思っていたので、ここで100均の基準温度計に表示を合わせてみます。
小数以下がカットされていたという感じの重なり具合に。

すでにDHT22を買ってしまったんですが、温度の小数部があるなら、基準センサーはDHT11でもよかったかも…(==;

仕様を呑み込めなく錯乱へ…

昨日電車の中で、スマホでデータシートやソースを見ながら頭の中を整理してかなりの部分がすっきりしたのですが、困ったことにDHT11の仕様で勘違いしていた部分があったようで…

そもそもの起点に戻って整理してみようかと。

まず元となったpythonのソースがどこだったのか謎だったのですが、おそらく
ここだったと思われ。再度アクセスしたらgitサーバーが落ちたのかアクセスがエラーに。
で、経緯としてはその後、修正が加わって大きな違いは
「温度と湿度ともに小数部を加味するようになった。」
という点。
で、DHT11自体は仕様がアップグレードされセンサーの感度範囲が広がったこと。
湿度は 20-90%RHから5-95%RH
温度は 0 to 50 ℃ to - 20 to 60 ℃

大きな違いは温度がマイナス温度から検知できるということ。

で、アップデート後のドキュメントで温度に関しての説明で
The temperature is high as part of the data of the temperature.
The temperature is low as part of the data of the temperature, and the temperature low bit 8 is the negative temperature, otherwise the temperature is positive
と書かれていて、あんまり意識していなかったのですが、これをグーグル翻訳にかけてみると…
気温のデータとして気温が高い。
温度データの一部として温度が低く、温度の低いビット8が負の温度で、それ以外の場合は温度が正
意味不明すぎなのですが、原文を見直せば見直すほど意味が理解できなくなりました(*´Д`)
もともと英語力なんて無いのであれなんですけどw
英語圏の人はこれで理解できるのかな?

で、色々と考えた結果、アップデート後のv1.3では「温度がマイナスの場合は、温度の下位バイトの8ビット目が1になる」というとらえ方でいいのかな?どのタイプのDHT11を手にしているのかもわからないのであれなんですが、、、現状の上記のgitのソースを見ると、
humidity = the_bytes[0] + float(the_bytes[1]) / 10
となっていて、pythonで 0b10000000ってなっててもマイナスの扱いなんてしないし、そもそも足しこんでいるのですっげーやばいと思うんですよね。
そもそも「/10」っていう部分が気になる人には気になるかもw
pi@rasp4b4g:~ $ python3
Python 3.7.3 (default, Dec 20 2019, 18:57:59)
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> 0b10000000
128
>>> float(0b10000000)
128.0

こんな感じでfloatしても、こんなことに。 仕様上は下位バイトは0~9までしか格納されないのですが、マイナスの場合は符号ビットを取り外さないとイケないわけで。
humidity = (the_bytes[0] + (the_bytes[1] & 0x7F)*0.1)*(-1if(the_bytes[1] & 0x80)else(1))
とか、そんな感じにする必要があるような?

v1.3のセンサーも無いし、データシートのデータサンプルに気温4024℃とパリティーエラーしか載ってないので正確なことは言えませんが。

他にもなんか色々といままで見かけた仕様も矛盾してしまってたりしてほんとに錯乱状態だったので綺麗さっぱりと忘れることにしよう。

この辺が気になりだした原因は、そもそもDHT11の仕様で湿度、温度ともに整数値しかないと思っていたところ、受け取った4バイトのデータを実際に表示して気づいたという。
しかも、decimalを10進と翻訳されて、データフォーマットが回路用に設計されてるのかな?とか勘違いしてたのが原因でした。実際のデータを表示させてその勘違いに気付いた次第です。




そもそもなところで、センサー誤差を拾うために結局DHT22も入手して只今思案中w

2020年7月6日月曜日

グラフのセンスが無さすぎる

センサーごとのアジャストを行ったり、色の調整を少ししたら、

そういえば温度のメモリも1℃刻みでほしいよなとか、
温度、湿度、気圧と表示は気温しか出していなかったので、温度と湿度の軸を揃えてみようかなとか、

まずは温度の刻みを直してみると、グレーの濃さが微妙だなとか、、、きりがないw

私以外見ることが無いマイグラフなのでとにかく把握しやすいものということであえてy軸は温度、湿度、気圧と分けていたわけですが、phpのスクリプトは単純にそれぞれ独立して上限下限を決めてプロットしているだけなので、軸を揃えたければ単純に一致させてあげるだけでグラフも簡単にそろう作りになっていたので試しにやってみたところ
高湿度のこの時期はこんな感じに。温度の波が今までの半分程度になってしまうので結構寂しい感じに。
元々、温度を中心に考えて、湿度と気圧はおまけ的に表示させていたのですが、改めて見てみると、やっぱり軸を揃える意味は少ないようです。
温度に関しては、気温は0℃~40℃、Raspberry pi の温度が~60℃として考えても、20目盛ぐらい助長になっています。
軸の状態を元に戻してみると、、
高湿度なのでRaspberry piの温度と重なってしまう感じになっていますが、数字の重なりさえなければ実用的に問題ないかなぁ…グラフとしては上下に踊ってくれた方が楽しいし。
やはりほとんど波が無いグラフは面白くない。

正直、グラフなんてこだわったことがことがほとんどないのでセンスも何もないのが一番悲しいw





DHT11とBME280の差異は上下に数値を補正しただけで波形はほぼ一致しました。試しに湿度や温度をエアコンで変えてみましたが振れ幅も一緒なのでこの温度、湿度下ではいい感じです。冬場までこのままセンサーをつなげたままの状態を維持すれば少し違った結果が得られそうな感じはします。
ただ、驚くべきことに、安価なDHT11の湿度の方が反応が良いようです。温度の反応速度はどちらも一緒のような雰囲気です。

2020年7月4日土曜日

気になりだすと止まらないセンサーの精度

使っているスクリプトを色々な角度から確認してみたところこれ以上おかしな点はなさそうなので、さらに別の角度から考えてみようかと。
極論は温度、湿度、気圧計を横に並べて比べてみるしかないとおもいます。
ですが、手持ちに無いので、既に使わなくなってしまったDHT11を発掘してつなげてみました。
個人的には、DHT11は温度、湿度センサーで、精度も整数値しか取得できない上、センサー値を取得するときにどうしてもエラーが発生してしまうことからあまり信用していませんでした。
エラーに関しては仕様上の問題もありますが、レスポンスが確実に悪くなるのと、リトライが発生するので時間上不安定になりがちになります。いままで10分間隔にロギングしていた理由の一つとして当初はDHT11も使用していて分刻みだと1分以内に処理が終わらなくなるかも?と考えていたからです。もうすこしエラー率が低くて、リトライもあまり発生していなければよかったのですが。あとは、分刻みだとログデータの発生量が結構インパクトありそうな気がしていたところです。ざっくりと計算すると、固定長のバイナリファイルに収めると1年間で10Mbyte程度になりました。これが大きいか小さいかというのは考え方次第です(が、他に本体の電源電圧やCPUクロックなどのログも取り入れていけばそれだけ大きくなってしまいます)。現状はいろいろ便利そうという理由だけでSQLite3を使ってデータを記録しているので、だいたい1日80Kbyte程度。これが365日なので約26Mbyte程度となります。(ざっくり昼間計算したら1年間で30Mbyteという数字が出てきたきがしますw)
まぁその他もろもろの事情で10分間隔だったわけでが。

さて、少しロギングできたので様子を見てみると…

DATE TIMEBoardTempHumiPressTemp3Humi3error3Temp1-3Humi1-3B - T
2020-07-04 23:07452772877066309100405429000780000-230-1169116507
2020-07-04 23:06452772882066196100414029000770000-180-1080416457
2020-07-04 23:05447902883066111100419329000770000-170-1088915960
2020-07-04 23:04452772888065887100418130000770000-1120-1111316397
2020-07-04 23:03457642892065794100422330000770000-1080-1120616844
2020-07-04 23:02452772884066079100417430000770000-1160-1092116437

データは1000倍して整数値で格納しているので、温度のBME280とDHT11の差は1℃程度でしたが、気になっている湿度は10%以上の差が発生していました。同じBME280の別の個体との差が7%程度あったので、気になっていましたが、まさかの10%以上の差がでているとは…。

昨日の夜に天気HPの地点情報の湿度を比べてもBME280の湿度の数値はかなり低く、室内とはいえ窓を開けた状態で30%程度低かった記憶があります。
現時点でDHT11と比べると…HPでは89%、78%、BME280の湿度は…66%となってます。同じ部屋にあるもう一つのBME280は、73%と出ています。

結構な期間温度センサーを動かしていましたが、あまり細かいところは気にしていなかったとはいえ、BME280は気圧センサー以外はあまり正確な値ではないようです。ただ、センサー感度は悪くないので、ちょっとした変化はすぐに掴める気はします。

結構気に入ってBME280を買いそろえてしまいましたが、別の気温センサー探そうかな?