フォト
サイト内検索
ココログ最強検索 by 暴想
2026年6月
  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        
無料ブログはココログ

最近のトラックバック

にほんブログ村

  • にほんブログ村

« 「日本の武器で滅びる中華人民共和国」兵頭 二十八著を読んで | トップページ | 北朝鮮のミサイル発射に全漁連が陳情したことに思う »

2017年3月 7日 (火)

Raspberry Pi2を使って温度、湿度についてDHT11センサーによりpython3でグラフ化しモニタ

 この記事は少し古いので、ソースコードにあるplt.draw()をplt.pause(.01)に変更する必要があります。詳細は「GrovePi+の温湿度センサー(DHT22)からのデータをmatplotlibでリアルタイムグラフ化」を見てください。


 題名のとおりで結構簡単そうに思えますが、これがなかなかに難しかったのです。

 一応、備忘録として書いておこうと思います。
 まず、DHT11センサーをWebページ「簡単にRaspberryPi+DHT11で気温と湿度を通知するTweetBotを作る。」によりRaspberry Piに繋げます。写真を載せておきます。中央下水色がDHT11です。ソースを読めば解りますが4番ピンに繋げています。
Dscn0323
 まず、DHT11センサーの読み取りは同WebページにPython2.7.3のソースが紹介されています。当方はdht11.pyを、Python3.4.2で動作させました。Python3としてソフト上のエラーは出ませんが、dht11.pyは多分タイミングの関係でエラーが多くて0表示になり実用には耐えません。出来ればC言語でRaspberry Piにデーター化してPythonでグラフ化してモニタしたかったのですが当方の腕ではWebに紹介されている組み込み手法も理解できず、今のところこの方法は放置しています。
20170312173237_654x554_scrot
 以下、dht11.pyのソースです。dht11.pyは次に示すdht11_monitor3.pyと同じフォルダー(ディレクトリ)に入れれば作動するようです。

import time
import RPi

class DHT11Result:
    'DHT11 sensor result returned by DHT11.read() method'

    ERR_NO_ERROR = 0
    ERR_MISSING_DATA = 1
    ERR_CRC = 2

    error_code = ERR_NO_ERROR
    temperature = -1
    humidity = -1

    def __init__(self, error_code, temperature, humidity):
        self.error_code = error_code
        self.temperature = temperature
        self.humidity = humidity

    def is_valid(self):
        return self.error_code == DHT11Result.ERR_NO_ERROR

class DHT11:
    'DHT11 sensor reader class for Raspberry'

    __pin = 0

    def __init__(self, pin):
        self.__pin = pin

    def read(self):
        RPi.GPIO.setup(self.__pin, RPi.GPIO.OUT)

        # send initial high
        self.__send_and_sleep(RPi.GPIO.HIGH, 0.05)

        # pull down to low
        self.__send_and_sleep(RPi.GPIO.LOW, 0.02)

        # change to input using pull up
        RPi.GPIO.setup(self.__pin, RPi.GPIO.IN, RPi.GPIO.PUD_UP)

        # collect data into an array
        data = self.__collect_input()

        # parse lengths of all data pull up periods
        pull_up_lengths = self.__parse_data_pull_up_lengths(data)

        # if bit count mismatch, return error (4 byte data + 1 byte checksum)
        if len(pull_up_lengths) != 40:
            return DHT11Result(DHT11Result.ERR_MISSING_DATA, 0, 0)

        # calculate bits from lengths of the pull up periods
        bits = self.__calculate_bits(pull_up_lengths)

        # we have the bits, calculate bytes
        the_bytes = self.__bits_to_bytes(bits)

        # calculate checksum and check
        checksum = self.__calculate_checksum(the_bytes)
        if the_bytes[4] != checksum:
            return DHT11Result(DHT11Result.ERR_CRC, 0, 0)

        # ok, we have valid data, return it
        return DHT11Result(DHT11Result.ERR_NO_ERROR, the_bytes[2], the_bytes[0])

    def __send_and_sleep(self, output, sleep):
        RPi.GPIO.output(self.__pin, output)
        time.sleep(sleep)

    def __collect_input(self):
        # collect the data while unchanged found
        unchanged_count = 0

        # this is used to determine where is the end of the data
        max_unchanged_count = 100

        last = -1
        data = []
        while True:
            current = RPi.GPIO.input(self.__pin)
            data.append(current)
            if last != current:
                unchanged_count = 0
                last = current
            else:
                unchanged_count += 1
                if unchanged_count > max_unchanged_count:
                    break

        return data

    def __parse_data_pull_up_lengths(self, data):
        STATE_INIT_PULL_DOWN = 1
        STATE_INIT_PULL_UP = 2
        STATE_DATA_FIRST_PULL_DOWN = 3
        STATE_DATA_PULL_UP = 4
        STATE_DATA_PULL_DOWN = 5

        state = STATE_INIT_PULL_DOWN

        lengths = [] # will contain the lengths of data pull up periods
        current_length = 0 # will contain the length of the previous period

        for i in range(len(data)):

            current = data[i]
            current_length += 1

            if state == STATE_INIT_PULL_DOWN:
                if current == RPi.GPIO.LOW:
                    # ok, we got the initial pull down
                    state = STATE_INIT_PULL_UP
                    continue
                else:
                    continue
            if state == STATE_INIT_PULL_UP:
                if current == RPi.GPIO.HIGH:
                    # ok, we got the initial pull up
                    state = STATE_DATA_FIRST_PULL_DOWN
                    continue
                else:
                    continue
            if state == STATE_DATA_FIRST_PULL_DOWN:
                if current == RPi.GPIO.LOW:
                    # we have the initial pull down, the next will be the data pull up
                    state = STATE_DATA_PULL_UP
                    continue
                else:
                    continue
            if state == STATE_DATA_PULL_UP:
                if current == RPi.GPIO.HIGH:
                    # data pulled up, the length of this pull up will determine whether it is 0 or 1
                    current_length = 0
                    state = STATE_DATA_PULL_DOWN
                    continue
                else:
                    continue
            if state == STATE_DATA_PULL_DOWN:
                if current == RPi.GPIO.LOW:
                    # pulled down, we store the length of the previous pull up period
                    lengths.append(current_length)
                    state = STATE_DATA_PULL_UP
                    continue
                else:
                    continue

        return lengths

    def __calculate_bits(self, pull_up_lengths):
        # find shortest and longest period
        shortest_pull_up = 1000
        longest_pull_up = 0

        for i in range(0, len(pull_up_lengths)):
            length = pull_up_lengths[i]
            if length < shortest_pull_up:
                shortest_pull_up = length
            if length > longest_pull_up:
                longest_pull_up = length

        # use the halfway to determine whether the period it is long or short
        halfway = shortest_pull_up + (longest_pull_up - shortest_pull_up) / 2
        bits = []

        for i in range(0, len(pull_up_lengths)):
            bit = False
            if pull_up_lengths[i] > halfway:
                bit = True
            bits.append(bit)

        return bits

    def __bits_to_bytes(self, bits):
        the_bytes = []
        byte = 0

        for i in range(0, len(bits)):
            byte = byte << 1
            if (bits[i]):
                byte = byte | 1
            else:
                byte = byte | 0
            if ((i + 1) % 8 == 0):
                the_bytes.append(byte)
                byte = 0

        return the_bytes

    def __calculate_checksum(self, the_bytes):
        return the_bytes[0] + the_bytes[1] + the_bytes[2] + the_bytes[3] & 255

 あと、matplotlibはPythonでグラフを描画するときなどに使われる標準的なライブラリで「りんごがでている」に入門の説明が載っています。しかし、参考にしたのは「電子工作速報>Arduino>【Python】Arduinoで測定した温度をグラフ化」です。日本語化についてはURLをひかえていなかったので載せられません申し訳ないところです。「Add/Remove Software」からVL-Gothicを導入してmatplotlibには反映させています。
 最終的にはy軸を2軸化して読み取りをC言語化したいところですが、とりあえず気温と湿度が示せる形で備忘録としたいと思います。
 以下は、dht11_monitor3.pyのソースです。

# -*- coding: utf-8 -*-
import numpy as np
import matplotlib.pyplot as plt
import pygame
from pygame.locals import *
import serial
import sys
import time
import datetime
import RPi.GPIO as GPIO
import dht11
from matplotlib.font_manager import FontProperties#日本語化に必要
# initialize GPIO
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
GPIO.cleanup()
# read data using pin 4
instance = dht11.DHT11(pin=4)

font_path = '/usr/share/fonts/truetype/vlgothic/VL-Gothic-Regular.ttf'#日本語化
font_prop = FontProperties(fname=font_path)
plt.rcParams['font.family'] = font_prop.get_name()

def main():
    temps = [0]*100              # 気温格納
    humis = [0]*100              # 湿度格納
    t = np.arange(0,100,1)
    plt.ion()
    pygame.init()                # Pygameを初期化
    screen = pygame.display.set_mode((300, 100))   # 画面作成(横300×100)
    pygame.display.set_caption("傾斜角度")         # タイトルバー
    font = pygame.font.Font(None, 50)              # 文字の設定

    while True:
        screen.fill((0,0,0))            # 画面のクリア
        result = instance.read()  # DHT11インスタンスの作成
        temp = str(result.temperature) # 気温を文字列にする
        humi = str(result.humidity) # 湿度を文字列にする
        text = font.render(temp + "[℃]" + humi+"[%]", False, (255,255,255))    # 表示する文字の設定
        screen.blit(text, (10, 10))     # レンダ,表示位置
        pygame.display.flip()           # 画面を更新して、変更を反映
        # 温度データのリスト更新
        temps.pop(99)
        humis.pop(99)
        temps.insert(0,float(temp)) # 文字列にしたデータを少数を含む数値に変換
        humis.insert(0,float(humi))
        # グラフ表示設定
        line1, = plt.plot(t*2.25+1.125, temps, 'r-',label="気温[℃]") # X軸を2秒になるように調整、Y軸更新
        line1.set_ydata(temps)
        line2, = plt.plot(t*2.25+1.125, humis, 'b-',label="湿度[%]") # X軸を2秒になるように調整、Y軸更新
        line2.set_ydata(humis)
        plt.title("Real-time 気温 湿度")
        plt.xlabel("Time [s]")
        plt.ylabel("気温 [℃] 湿度[%]")
        plt.legend()
        plt.grid()
        plt.xlim([1,200])
        plt.ylim([0,100])
        plt.draw()
        plt.clf()
        for event in pygame.event.get():
            # 終了ボタンが押されたら終了処理
            if event.type == QUIT:
                pygame.quit()
                plt.close()
                sys.exit()

if __name__ == '__main__':
    main()

 各ソースには必要のないimportも含まれているかもしれませんがそこはご勘弁を願います。


<当ブログの関係記事>
Raspberry Piを使って温度、湿度についてDHT11センサーによりリアルタイムグラフ化(三軸)(その2)
Raspberry Piを使ってMCP3208によりAD変換しリアルタイムグラフ化

« 「日本の武器で滅びる中華人民共和国」兵頭 二十八著を読んで | トップページ | 北朝鮮のミサイル発射に全漁連が陳情したことに思う »

パソコン・インターネット」カテゴリの記事

コメント

コメントを書く

(ウェブ上には掲載しません)

トラックバック

« 「日本の武器で滅びる中華人民共和国」兵頭 二十八著を読んで | トップページ | 北朝鮮のミサイル発射に全漁連が陳情したことに思う »