YU2TA7KA's BLOG ~take one step at a time~

派生開発、組み込み開発周りのこと。

もう布巾を頭に乗せないぞ! おうちハックNo.1

はじめに

最近Raspberry Pi3 B+ と参考書としてRaspberry Piで学ぶ電子工作を購入しました。その参考書にあるサンプルを組み合わせて、初めてのおうちハックをしました。今後の課題も多々ありますが、ひとまずやりたいことはできたかなぁと。


課題

f:id:yuji-tanaak:20181228113601j:plain
おうちの布巾ハンガー

キッチンで私が料理をしていると、上図の布巾が頭に当たってハンガーから布巾が落ちるという課題がありました。

解決策

ハンガーを奥に押しやって、頭に当たらないようにする。具体的には、フォトレジスタで明るさ判別し、その値によってサーボモーターでハンガーを移動させる。ムービングハンガー!

実装

実装結果

f:id:yuji-tanaak:20181228115501p:plain
f:id:yuji-tanaak:20181228115536p:plain
動作例はトップのツイートの動画になります。良い感じでハンガーを奥に押しやってくれています。

回路図

フォトレジスタの入力側を参考書の図6-9から、サーボモーターの出力側を図8-13のもので構成しています。参考書の回路図はラズベリーパイやブレッドボードの絵に記載されておりわかりやすいです。

ソースコード

# -*- coding: utf-8 -*-
import RPi.GPIO as GPIO
from time import sleep
import wiringpi as wiringpi

# MCP3208からSPI通信で12ビットのデジタル値を取得。0から7の8チャンネル使用可
def readadc(adcnum, clockpin, mosipin, misopin, cspin):
    if adcnum > 7 or adcnum < 0:
        return -1
    GPIO.output(cspin, GPIO.HIGH)
    GPIO.output(clockpin, GPIO.LOW)
    GPIO.output(cspin, GPIO.LOW)

    commandout = adcnum
    commandout |= 0x18  # スタートビット+シングルエンドビット
    commandout <<= 3    # LSBから8ビット目を送信するようにする
    for i in range(5):
        # LSBから数えて8ビット目から4ビット目までを送信
        if commandout & 0x80:
            GPIO.output(mosipin, GPIO.HIGH)
        else:
            GPIO.output(mosipin, GPIO.LOW)
        commandout <<= 1
        GPIO.output(clockpin, GPIO.HIGH)
        GPIO.output(clockpin, GPIO.LOW)
    adcout = 0
    # 13ビット読む(ヌルビット+12ビットデータ)
    for i in range(13):
        GPIO.output(clockpin, GPIO.HIGH)
        GPIO.output(clockpin, GPIO.LOW)
        adcout <<= 1
        if i>0 and GPIO.input(misopin)==GPIO.HIGH:
            adcout |= 0x1
    GPIO.output(cspin, GPIO.HIGH)
    return adcout

#servo_min = 36   # 50Hz(周期20ms)、デューティ比3.5%: 3.5*1024/100=約36
#servo_max = 102  # 50Hz(周期20ms)、デューティ比10%: 10*1024/100=約102

#GPIO初期化 
#役割ピン番号で設定する https://qiita.com/msrks/items/7de29c4294ce677e05a0
GPIO.setmode(GPIO.BCM)
# ピンの名前を変数として定義
SPICLK = 11
SPIMOSI = 10
SPIMISO = 9
SPICS = 8
# SPI通信用の入出力を定義
GPIO.setup(SPICLK, GPIO.OUT)
GPIO.setup(SPIMOSI, GPIO.OUT)
GPIO.setup(SPIMISO, GPIO.IN)
GPIO.setup(SPICS, GPIO.OUT)

wiringpi.wiringPiSetupGpio() # GPIO名で番号を指定する
wiringpi.pinMode(18, wiringpi.GPIO.PWM_OUTPUT) # PWM出力を指定
wiringpi.pwmSetMode(wiringpi.GPIO.PWM_MODE_MS) # 周波数を固定するための設定
wiringpi.pwmSetClock(375) # 50 Hz。ここには 18750/(周波数) の計算値に近い整数を入れる
# PWMのピン番号18とデフォルトのパルス幅をデューティ100%を1024として指定。
# ここでは6.75%に対応する69を指定
wiringpi.pwmWrite(18, 69) 

adc_pin0 = 0
light_count = 0

try:
    while True:
        inputVal0 = readadc(adc_pin0, SPICLK, SPIMOSI, SPIMISO, SPICS)
        print(inputVal0)
        print(light_count)
        #明るいが5回になったら動く
        if inputVal0 > 2100:
            light_count += 1
        #暗いが5回になったら動く
        else:
            light_count -= 1

        if light_count > 5:
            #ハンガーを押す
            wiringpi.pwmWrite(18, 69)
            light_count = 0
        elif light_count < -5:
            #初期位置に戻る
            wiringpi.pwmWrite(18, 85)
            light_count = 0

        sleep(0.2)

except KeyboardInterrupt:
    pass

GPIO.cleanup()

こちらのソースコードも参考書のものをほぼコピーして利用しています。フォトレジスタの入力値からサーボモーターの動作の制御が若干変わっているくらいです。ベースは下記ダウンロード項目の06-02-led.pyと08-04-servo.pyです。
 Raspberry Piで学ぶ電子工作 超小型コンピュータで電子回路を制御する - ブルーバックスシリーズの特設ページ

今後の展望

  1. マイコンを使い小型基板化させる。現状のラズベリーパイは完全にオーバースペック。
  2. 電源周りをなんとかする。省電力化して電池のみで長期間動かせるようにしたい。
  3. 制御アルゴリズムを改良する。明るくなったら奥に押しやる、という単純制御ですが、もうちょい細かく制御しないと運用に耐えられれない気がする。

まとめ

何か作りたいなぁという気持ちが最近また湧いてきて、勢いのままラズベリーパイと参考書を購入しました。そして、適当な課題と解決策が思いついたので、エイヤでやってみました。やっぱり思ったとおりにモノが動くと面白いです。参考書が本当に丁寧にいろいろ書かれており、その紹介されたものを組み合わせるだけでかなりいろいろできるようになる気がします。勢いの続く限り、おうちハック続けたいと思います。