リモコンで操作する プラレール はメーカーから製品として発売されていて、初期はハードウェアマスコンを使い、赤外線リモコンで操作するしくみでしたが、今ではWiFi接続してスマホアプリから操作したり、デュアルカメラ搭載と飽くなき進化を続け、さすがに値が張ります。これを Raspberry Pi Zero で実現してしまう記事をちらほら見てるうちに、自分でも作りたくなった製作記シリーズの第1回です。
当初、先頭制御&電源車にモーター車が連結する、次のような構成を考えました。
このとき必要な部品を列記すると、こんな感じに。
- プラレール機関車(試作中は適当なDCモータで代用)
- Raspberry Pi Zero W
- 同カメラモジュール
- モータドライバ L9110S
- 電源18650
- DC-DCコンバータ
しかし、プラレールの機関車タイプへの移植を考えると、先頭車をモータ&制御とする次のような構成を採用することにしました(実は、いくつか試したDC-DCコンバータがいずれも不安定で使用に耐えず、よくあるUSBモバイルチャージャーが良かったのでこれを採用したのも大きい)。
早速、Raspberry Pi Zero WにRaspbianを入れたSDカード挿して起動。初めてのPWM制御に挑戦します。モータを電圧ではなく、周波数・力率で調整出来るのはとても楽ちん。一応USBテスターで電流値を確認しながら周波数値を決めます。
電流値1.75Aに仰天。PWM周波数を調整してだいぶ落とせましたが、DCモータがこんなに電力消費するものとは知りませんでした。ここでモータドライバへの電源もRaspberry Piからぶら下がりで得る回路図になっていたのを思い出し、慌ててバッテリから直接得る形へと変更した次第です。PWMテストプログラムはこんな感じ。周波数で全体的な傾きを、Duty Cycleで出力度合いを制御し、最後は必ずGPIOをcleanup()するのが礼儀。ほぼほぼ小学生並のプログラミング基礎。
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 31 32 33 34 35 36 37 38 39 40 41 42 |
import RPi.GPIO as GPIO from time import sleep GPIO.setmode(GPIO.BCM) pinFwd = 23 pinRev = 24 pwmFrq = 100 GPIO.setup(pinFwd, GPIO.OUT) GPIO.setup(pinRev, GPIO.OUT) p = GPIO.PWM(pinFwd, pwmFrq) q = GPIO.PWM(pinRev, pwmFrq) p.start(0) p.ChangeDutyCycle(50) for x in range (50): p.ChangeDutyCycle(x) sleep(0.1) for x in range (50): p.ChangeDutyCycle(50-x) sleep(0.1) sleep(1) p.stop() q.start(0) q.ChangeDutyCycle(50) for x in range (50): q.ChangeDutyCycle(x) sleep(0.1) for x in range (50): q.ChangeDutyCycle(50-x) sleep(0.1) sleep(1) q.stop() GPIO.cleanup() |
開発中、Raspberry Pi Zeroへは母艦からsshで繋いでいるのですが、DHCPで一体今日はIPいくつなんだろ、が地味に面倒。ジャンク箱にI2C接続のLCDがあったので、IPアドレス表示させるようにしています。
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 31 32 33 34 35 36 37 38 39 |
# -*- coding: utf-8 -*- # RPLCD IP ADDR INDICTOR # http://rplcd.readthedocs.io/ # from RPLCD import i2c from time import sleep import time import socket import fcntl import struct # LCD PARAMETERS lcdmode = 'i2c' cols = 16 rows = 2 charmap = 'A00' i2c_expander = 'PCF8574' address = 0x27 port = 1 # GET IP ADDR def get_ip_address(ifname): s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) return socket.inet_ntoa(fcntl.ioctl( s.fileno(), 0x8915, struct.pack('256s', ifname[:15]) )[20:24]) # INIT LCD lcd = i2c.CharLCD(i2c_expander, address, port=port, charmap=charmap, cols=cols, rows=rows) # DRAWING PANEL lcd.clear() lcd.write_string(time.strftime('%H:%M:%S') + '\r\n' + get_ip_address('wlan0')) sleep(300) lcd.backlight_enabled = False lcd.close(clear=True) |
これをcronで定期的に実行します。併せて、過去の経験からRaspberry PiのWiFi系がいまいち信用出来ないので、外向きにひたすらpingして応答無き時はインターフェースのリセットを試みる仕組みも定期運用。
次回は、制御とカメラ受像のためのWeb UI構築について記したいと思います。
参考と鳴謝)