自宅IoTの実現へ第一歩!Raspberry Pi KitとAlibabaCloudのLogService活用


皆さんこんにちは、エンジニアのシャです。

以前弊社のエンジニアたちがLogServiceについてたくさんのブログを書きました。

過去参考記事:

 

本日は上記の内容を踏まえて、今回はもう少し実用的なところでLogServiceについてご紹介していきたいと思います。

 

 

いきなりですけど、Raspberry Piとセンサー群を利用し、集められたデータをLogServiceへ可視化できるDemoキットを作ってみましたw。こんな感じです〜

f:id:sbc_syayou:20200927163733p:plain

Raspberry Pi Kitの全体図

AlibabaCloudのLogService側のダッシュボードはこんな感じです〜

f:id:sbc_syayou:20200927174214p:plain

LogServiceダッシュボード

 唐突過ぎて、なんだかよくわからない方がたくさんいらしゃると思いますが、これからは上記のDemoを少しずつ紹介していきたいと思います。

 簡単に一言で言うと、これは「自作Raspberry Piセンサーキット」です。複数のセンサーキットから収集したデータをRaspberry Pi経由で、AlibabaCloudのLogServiceへ送信され、最終的に、ダッシュボード上にデータを可視化される。

基本構成

f:id:sbc_syayou:20200927174454p:plain

システム構成

きっかけ

 Raspberry Pi 4が2019年11月ごろ日本市場にリリースされ、低廉な価格と広い汎用性で高い注目を浴びました。そこで私もRaspberry Pi 4に興味を持ち始め、ちょっと触ってみたいという気持ちをきっかけで本工作を初めました。

 

目的

・Raspberry Piを触ってみる

・Pythonを実用的に勉強したい

・センサー側の知識を勉強したい

・LogServiceの実用的なシナリオを検討したい

・レゴ ブロックを楽しむ(一番楽しいかもw)

途中で色々試行錯誤があって、最終的にはRaspberry Pi+各種センサー+レゴ ブロック+AlibabaCloud LogServiceダッシュボード構成に落ち着きました。

 

まず本Demoキットの構成を紹介していきたいと思います。

f:id:sbc_syayou:20200927203147p:plain

Demoキットの全体図

 センサーキット構成

 Raspberry Pi4(①)


アマゾンにて約6000円で購入(日本技適対応正規品)

仕様

メモリ:4GB
OS:Raspbian

モニター(7インチモバイル式②)

f:id:sbc_syayou:20200927201352p:plain

7インチモニター

同じ店でセットで購入した。Raspberry Piへssh接続が可能ですが、今回はDemo展示用に特別購入した。

センサー類(③〜⑨)

中国のTAOBAOECサイトで購入したmakerobot社が開発したセンサー一式

f:id:sbc_syayou:20200927200044p:plain

CLB Raspbeery pi super kit一式

※本写真はTAOBAOの店サイトからの転載

上記写真掲載したようで、開発用の全ての道具が揃えて、とても便利です。
個人的な感想としては、全40種類のセンサーを一通りテストしてみた、不良品がなく、全部正常に稼働ができた。また、お店からの技術サポート(もちろん中国語ですが。。。)が意外にしっかりしていて、いい買い物経験でした。
そして、値段も手頃で(当時購入した金額は約日本円で2000円前後)。興味がある方は「AliExpress」などで検索してみてください。

※日本アマゾンでもにたようなキットがたくさん売られていると思います、値段は若干割高ですが、同じく実現できるはずです。

レゴブロック

一式をアマゾンで購入した。

クラシック アイデアボックス×2

www.amazon.co.jp
基礎板 4枚

www.amazon.co.jp   

 詳細構成〜セットアップ手順

 これからは本Demoの詳細構成について説明したいと思います。

Raspberry 4

Raspberryのセットアップ手順はここで割愛させて頂きます。

Googleなどすればたくさんの関連記事があると思います。

例えば、下記の参考記事には役に立つかもしれないです。

raspida.com

ブレードボード

今回はたくさんのセンサーを扱いたいので、Raspberry基盤本体のGPIOインタフェースが足りなくなる。拡張用にブレードボードを利用しました。 

f:id:sbc_syayou:20200927221831p:plain

ブレードボード配線

配線がちょっと汚くてすみません。。。

また、センサー側のインタフェース名称は型番によりブレードボードとあってないものがありまして、インタフェース名のマッピング表は下記に整理しました(ここ一番苦労しました〜w)。

f:id:sbc_syayou:20200927222226p:plain

ポート一覧表

興味がある方は参照して自分で動かしてみてください。

また、「超音波距離センサー」、「タッチセンサー」、「光感知センサー」は同じく「GPIO17」番を利用するので、母線でブレードボードのした空いているポート(25番、27番、29番)に延長しました。利用するとき手動で切り替える。

センサー側について

センサー側を制御するには基本Pythonを使っています。

実行環境

利用ライブラリー:RPi.GPIO

Python:3.7.2

処理流れ

1、各センサーを制御するライブラリーを利用し、センサーからデータを取得する(超ざっくり。。。)。

2、取得したデータをLogServiceのSDKを利用し、LogServiceへ送信する。

 ・送信間隔は1秒間ずつ。

 ・データ間でTopicを分けて識別する。

3、LogService側でデータを集計し、ダッシュボードへセット。

LogServiceのSDKは弊社過去の下記記事を参照すればできるはず!

www.sbcloud.co.jp

 ジャイロ加速センサー

f:id:sbc_syayou:20200927223110p:plain

ジャイロ加速センサー

本センサーの仕様は超音波を発射し、障害物までの距離を測れる

最大測量距離:9.9m

f:id:sbc_syayou:20200927230525p:plain

障害物があった場合

センサー制御用コード

#!/usr/bin/env python

import RPi.GPIO as GPIO
import time
from aliyun.log import *

TRIG = 11
ECHO = 12

def setup():
    GPIO.setmode(GPIO.BOARD)
    GPIO.setup(TRIG, GPIO.OUT)
    GPIO.setup(ECHO, GPIO.IN)

def distance():
    GPIO.output(TRIG, 0)
    time.sleep(0.000002)

    GPIO.output(TRIG, 1)
    time.sleep(0.00001)
    GPIO.output(TRIG, 0)


    while GPIO.input(ECHO) == 0:
        a = 0
    time1 = time.time()
    while GPIO.input(ECHO) == 1:
        a = 1
    time2 = time.time()

    during = time2 - time1
    return during * 340 / 2 * 100

 ※LogServiceへデータ送信部分コードは割愛致します。

タッチセンサー

f:id:sbc_syayou:20200927230647p:plain

タッチセンサー

仕様 

  • 円盤部に指をタッチすると感知されと、コンソール上に”ON”が表示され、LogServiceに”1”を送信する。
  • 指を離れると、コンソール上に”OFF”が表示され、LogServiceに”0”を送信する。

 

センサー制御用コード

 
#!/usr/bin/env python
import RPi.GPIO as GPIO
import time

TouchPin = 11
Gpin   = 12
Rpin   = 13

tmp = 0

def setup():
    GPIO.setmode(GPIO.BOARD)       # Numbers GPIOs by physical location
    GPIO.setup(Gpin, GPIO.OUT)     # Set Green Led Pin mode to output
    GPIO.setup(Rpin, GPIO.OUT)     # Set Red Led Pin mode to output
    GPIO.setup(TouchPin, GPIO.IN, pull_up_down=GPIO.PUD_UP)    # Set BtnPin's mode is input, and pull up to high level(3.3V)

def Led(x):
    if x == 0:
        GPIO.output(Rpin, 1)
        GPIO.output(Gpin, 0)
    if x == 1:
        GPIO.output(Rpin, 0)
        GPIO.output(Gpin, 1)


def Print(x):
    global tmp
    if x != tmp:
        if x == 0:
            print ('    **********')
            print ('    *     ON *')
            print ('    **********')
        if x == 1:
            print ('    **********')
            print ('    * OFF    *')
            print ('    **********')
        tmp = x

def loop():
    while True:
        Led(GPIO.input(TouchPin))
        Print(GPIO.input(TouchPin))

def destroy():
    GPIO.output(Gpin, GPIO.HIGH)       # Green led off
    GPIO.output(Rpin, GPIO.HIGH)       # Red led off
    GPIO.cleanup()                     # Release resource

if __name__ == '__main__':     # Program start from here
    setup()
    try:
        loop()
    except KeyboardInterrupt:  # When 'Ctrl+C' is pressed, the child program destroy() will be  executed.
        destroy()
   

  ※LogServiceへデータ送信部分コードは割愛致します。

気圧センサー

仕様

  • 現在の気温を感知する。
  • 現在の気圧を感知する。

f:id:sbc_syayou:20200927231648p:plain

気圧センサー

センサー制御用コード

import Adafruit_BMP.BMP085 as BMP085
import time
from aliyun.log import *

def setup():
    print  ('\n Barometer begins...')

def loop():
    while True:
        sensor = BMP085.BMP085()
        temp = sensor.read_temperature()    # Read temperature to veriable temp
        pressure = sensor.read_pressure()   # Read pressure to veriable pressure
        print ('')
        print ('      Temperature = {0:0.2f} C'.format(temp))     # Print temperature
        print ('      Pressure = {0:0.2f} Pa'.format(pressure))   # Print pressure
        time.sleep(1)
        print ('')

def destory():
    GPIO.cleanup()              # Release resource

if __name__ == '__main__':      # Program start from here
    setup()
    try:
        loop()
    except KeyboardInterrupt:   # When 'Ctrl+C' is pressed, the child program destroy() will be  executed.
        destory()

 

 ※本プログラムは別途Adafruit_BMPライブラリが必要になります。

 ※LogServiceへデータ送信部分コードは割愛致します。

液晶モニター

f:id:sbc_syayou:20200927232459p:plain

液晶モニター

仕様

  • 上下二段英文字が表示されることが可能
  • 「This is LogService Demo ! Thankyou for watching ^_^」が表示される
  • 文字移動速度調整可能

 

センサー制御用コード

 
#!/usr/bin/env python
import LCD1602
import time

def setup():
    LCD1602.init(0x27, 1)   # init(slave address, background light)
    LCD1602.write(0, 0, 'Hello~~~!!')
    LCD1602.write(1, 1, 'WWW.ALIBABACLOUD.COM')
    time.sleep(2)

def loop():
    space = '                '
    greetings = 'This is LogService Demo ! Thankyou for watching ^_^'
    greetings = space + greetings
    while True:
        tmp = greetings
        for i in range(0, len(greetings)):
            LCD1602.write(0, 0, tmp)
            tmp = tmp[1:]
            time.sleep(0.8)
            LCD1602.clear()

def destroy():
    pass

if __name__ == "__main__":
    try:
        setup()
        loop()
        while True:
            pass
    except KeyboardInterrupt:
        destroy()
         
 ジャイロ加速センサー

f:id:sbc_syayou:20200927233026p:plain

ジャイロ加速センサー

仕様

  • 三軸センサー
  • 加速度を感知することが可能

 センサー制御用コード

 

#!/usr/bin/python

import smbus
import math
import time
from aliyun.log import *

power_mgmt_1 = 0x6b
power_mgmt_2 = 0x6c

def read_byte(adr):
    return bus.read_byte_data(address, adr)

def read_word(adr):
    high = bus.read_byte_data(address, adr)
    low = bus.read_byte_data(address, adr+1)
    val = (high << 8) + low
    return val

def read_word_2c(adr):
    val = read_word(adr)
    if (val >= 0x8000):
        return -((65535 - val) + 1)
    else:
        return val

def dist(a,b):
    return math.sqrt((a*a)+(b*b))

def get_y_rotation(x,y,z):
    radians = math.atan2(x, dist(y,z))
    return -math.degrees(radians)

def get_x_rotation(x,y,z):
    radians = math.atan2(y, dist(x,z))
    return math.degrees(radians)


bus = smbus.SMBus(1) # or bus = smbus.SMBus(1) for Revision 2 boards
address = 0x68       # This is the address value read via the i2cdetect command

bus.write_byte_data(address, power_mgmt_1, 0)

while True:
    time.sleep(0.1)
    gyro_xout = read_word_2c(0x43)
    gyro_yout = read_word_2c(0x45)
    gyro_zout = read_word_2c(0x47)

    print ("gyro_xout : ", gyro_xout, " scaled: ", (gyro_xout / 131))
    print ("gyro_yout : ", gyro_yout, " scaled: ", (gyro_yout / 131))
    print ("gyro_zout : ", gyro_zout, " scaled: ", (gyro_zout / 131))

    accel_xout = read_word_2c(0x3b)
    accel_yout = read_word_2c(0x3d)
    accel_zout = read_word_2c(0x3f)

    accel_xout_scaled = accel_xout / 16384.0
    accel_yout_scaled = accel_yout / 16384.0
    accel_zout_scaled = accel_zout / 16384.0

    print ("accel_xout: ", accel_xout, " scaled: ", accel_xout_scaled)
    print ("accel_yout: ", accel_yout, " scaled: ", accel_yout_scaled)
    print ("accel_zout: ", accel_zout, " scaled: ", accel_zout_scaled)

    print ("x rotation: " , get_x_rotation(accel_xout_scaled, accel_yout_scaled, accel_zout_scaled))
    print ("y rotation: " , get_y_rotation(accel_xout_scaled, accel_yout_scaled, accel_zout_scaled))
    print ("")

    time.sleep(0.5)
光感知センサー

f:id:sbc_syayou:20200927233527p:plain

光感知センサー

仕様

  • 真ん中U字部分にものを通過すると、信号が発する

f:id:sbc_syayou:20200927233713p:plain

ものが通過すると信号が発信される

 センサー制御用コード

 

#!/usr/bin/env python
import RPi.GPIO as GPIO
import time
from aliyun.log import *

PIPin  = 11
Gpin   = 12
Rpin   = 13

def setup():
    GPIO.setmode(GPIO.BOARD)       # Numbers GPIOs by physical location
    GPIO.setup(Gpin, GPIO.OUT)     # Set Green Led Pin mode to output
    GPIO.setup(Rpin, GPIO.OUT)     # Set Red Led Pin mode to output
    GPIO.setup(PIPin, GPIO.IN, pull_up_down=GPIO.PUD_UP)    # Set BtnPin's mode is input, and pull up to high level(3.3V)
    GPIO.add_event_detect(PIPin, GPIO.BOTH, callback=detect, bouncetime=200)

def Led(x):
    if x == 0:
        GPIO.output(Rpin, 1)
        GPIO.output(Gpin, 0)
    if x == 1:
        GPIO.output(Rpin, 0)
        GPIO.output(Gpin, 1)

def Print(x):
    if x == 1:
        print ('    *************************')
        print ('    *   Light was blocked   *')
        print ('    *************************')

def detect(chn):
    Led(GPIO.input(PIPin))
    Print(GPIO.input(PIPin))

def loop():
    while True:
        pass

def destroy():
    GPIO.output(Gpin, GPIO.HIGH)       # Green led off
    GPIO.output(Rpin, GPIO.HIGH)       # Red led off
    GPIO.cleanup()                     # Release resource

if __name__ == '__main__':     # Program start from here
    setup()
    try:
        loop()
    except KeyboardInterrupt:  # When 'Ctrl+C' is pressed, the child program destroy() will be  executed.
        destroy()

 

 

LogServiceのダッシュボード側 

続いてはLogServiceのダッシュボード側についてご紹介させて頂きます。

ダッシュボード説明エリア

f:id:sbc_syayou:20200927234301p:plain

紹介部分

ダッシュボードの概要を紹介する部分になります。

位置情報エリア

f:id:sbc_syayou:20200927234411p:plain

位置情報

端末側(Raspberry Pi)のIPアドレスも送信されるため、リアルタイム的に端末の現在位置を確認することができます。

今回は一台のみ利用するため、位置情報がひとつだけ

情報展示エリア

f:id:sbc_syayou:20200927234643p:plain

センサー情報展示エリア

Raspberry Pi経由で収集されたデータ展示エリアとなります。

  • 温度
  • 気圧
  • タッチ情報
  • 距離情報
  • 通過回数
  • 水平角度情報

ダッシュボードの更新間隔は15秒となりますので、準リアルタイムに情報を展示することができます。

予測エリア

f:id:sbc_syayou:20200927235023p:plain

予測エリア

気温、気圧データに対して、教師なし機械学習を利用し、予測してみました。

まとめ

長文になってしまい、恐縮です。。。

 

全体的にとても楽しかったです。

一通り手を動かしてみて、

センサー側の仕組みが理解でき、
Pythonのプログラム能力も上がってきた気がするw〜

まだまだ紹介できていないセンサーたちがたくさんあります

全部で40個があります。。。

これから引き続き紹介していきたいと思います。

 

また、このDemoキットの作成はあくまで第一歩となりまして、

次はセンサー類の連動の仕組みも考えてみたいと思います。

例えば、

  • 距離センサーとジャイロ加速センサーとミニスピーカと連動し、もの落とす防止の仕組みを考えられる。
  • 水滴感知センサーとLineAPI連動し、雨が降ったらLineに通知を送る仕組みなど
  • 気温気圧センサーとアレクサ連動し、暑くなったら・寒くなったらエアコンをいれる仕組み

などなど

それでは〜〜また次回へ