夏休みらしく貯金箱を工作する

夏休みといえば工作の宿題を思い出します。
工作は好きだったんですが、持っていくのが面倒でとにかく嫌だった思い出。

そんな思い出を懐かしみつつ、夏休み工作の定番である貯金箱を作って遊びます。

仕様

貯金箱工作で大事なのはお金を入れた時にどんなアクションをさせるかです。
自動で小銭を分別する機能的なものやコインの重さを利用して仕掛けが動作するものなど、さまざまです。懐かしい・・

今回は貯金のモチベーションをアップするために、小銭を入れたら曲が流れる仕様で作りたいと思います。 ・・・ジュークボックスかな?

音楽再生

音楽のソースを準備するのが面倒なので、Youtubeを再生することにします。
Youtubeなんで折角だからMVを再生するといいですね。

ブラウザで動画を再生したいのでRaspberry piX Windowを使います。

最初はRaspberry Pi3で実験してましたが、動画再生においてパワー不足を感じたのでRaspberry Pi4を使うことにします。
手持ちの小さいLCDパネルがRaspberry pi3用しかないのでHDMIのコネクタが合わずケーブルを束ねて接続しました。これは工作する上で邪魔ですね・・

段ボールで外装作ってみましたが、ケーブルのせいで超でかい!でもお陰で夏休みの工作感は増した気がします。

ブラウザの表示と操作はpythonで行います。

import webbrowser
import pyautogui

webbrowser.open(URL)  # YouTubeの表示
# ここにウエイト入れないと!
pyautogui.press('f')  # フルスクリーンにするキー操作

webbrowser.openでブラウザを立ち上げてから再生が始まらないとキーを送出しても反応しないのでウエイトが必要です。

また、早々に気づいたんですがYoutubeはたまに広告が入ります。普段なら気にならないですが、小銭を入れて曲が流れるまで広告を待つのも変な感じです(シュールで面白いですが)。

対策として、再生したいURLを表示して広告を見た後で先頭にシークして待つ方法をとります。

アイドル時

小銭投入を待っている間、デスクトップが出てるのは変なのでLCDをオフにしたいところです。

ただ、HDMIの出力をオフすると私の持っているLCDは青一色の入力待ち状態になるのでどっちみち不具合感満載です。

何らかの画像を全画面表示して待ち受けることにします。
OpenCVのimshowで全画面表示します。

cv2.namedWindow('img', cv2.WINDOW_NORMAL)
cv2.setWindowProperty('img', cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN)

img = cv2.imread('表示したい画像ファイル')
cv2.imshow('img', img)
cv2.waitKey(0)

cv2.destroyAllWindows()

小銭投入のセンシング

小銭投入口にセンサを設置し、ポーリングしておけば投入を検出できます。GPIO1本でできるから余裕です。

・・と思ったらピンヘッダ埋まってるから5V取れない!

しょうがないのでArduinoを使いました。センサヒットしたらシリアルポートに文字を送信します。

void setup() {
  Serial.begin(115200);
  ::pinMode(10, INPUT_PULLUP);
}

void loop() {
  if (::digitalRead(10) == HIGH) {
    Serial.print("*");
    while (::digitalRead(10) == HIGH);
  }
}

小銭投入口がガイドになるので取り付けも適当で問題なさそうです。

完成!

全て組み込み、段ボール丸出しなので外装に手頃な包装紙を貼って完成です!

小銭投入の反応が良いので小気味いいですね。

金額によって再生する曲を変えたり、いろんな工夫をすると楽しそうです。あとは小型化とスタイリッシュさの向上が望まれます。

終わり

ところで今時の小学生も夏休みの工作するんでしょうか?
ひょっとしておじさんだけに通じるあるあるだったり・・?

それはさておきやっぱり工作は楽しいですね!

ソースコード

import cv2
import webbrowser
import pyautogui
import time

URL = 'https://再生するYoutubeのURL'
PIC = 'アイドル時に表示する画像'
# Arduinoのシリアルポート
UART = '/dev/ttyACM0'

# 映像を準備する
webbrowser.open(URL)
# 再生開始されないとキー操作効かないのでちょっと待つ
time.sleep(20)
# フルスクリーンにする
pyautogui.press('f')

# 広告入る場合もあるのでのんびり待つ
time.sleep(60)
# 再生を停止して先頭へシーク
pyautogui.press('k')
pyautogui.press('0')

while True:
  # ロゴ表示
  cv2.namedWindow('img', cv2.WINDOW_NORMAL)
  cv2.setWindowProperty('img', cv2.WND_PROP_FULLSCREEN, cv2.WINDOW_FULLSCREEN)
  img = cv2.imread(LOGO)
  cv2.imshow('img', img)
  cv2.waitKey(500)

  # シリアルポートからデータ待ち
  _ = ser.read()

  cv2.destroyAllWindows()

  # ウインドウの切り替えを失敗する時もあるのでちょっと待つ
  time.sleep(0.5)
  # 再生
  pyautogui.press('k')

  # 終わるちょっと前まで待つ
  time.sleep(1*60+23)
  # 停止して先頭へシーク
  pyautogui.press('k')
  pyautogui.press('0')