これは何?
Arduboy用の書き込み装置です。Arduboy( https://arduboy.com/ )とはパソコンを通じてゲームを書き換え、書き換えたのちは1種類のゲームだけが遊べるというArduinoベースの携帯ゲーム機です。
しかし、出先でもArduboyのゲームを切り替えたいと思い作ったのがこれです。
(ちなみにGamebuino ( Getting started - Gamebuino Wiki) という同じくArduinoベースの携帯ゲーム機はSDカードスロットを搭載しており、そこからゲームを切り替えることができます。)
構成
仕組みも何もRaspberryPi Zeroです。
去年スイッチサイエンスで購入したものですが、なんかもったいなくて道具箱にしまいっぱなしにしていました。このままだと積み基板になってしまうということで使いました。
そしてOLEDとタクトスイッチを3つ。最後に3Dプリンタで作ったケースにより構成されています。
回路
とても簡単ですが回路図です。スイッチのプルアップはRaspberryPi Zero内部で行うので直結です。
ソフトウェア
RaspberryPi Zeroといっても中身は普通のLinuxです。Pythonを使ってI2C経由でOLEDを操作します。また、ブート時に自動的に起動させるためにsystemdのserviceファイルを作ります。
この記事が参考になりました。
雑ですがコードはこんな感じ。
import RPi.GPIO as GPIO import time import os import subprocess import Adafruit_GPIO.SPI as SPI import Adafruit_SSD1306 from PIL import Image from PIL import ImageDraw from PIL import ImageFont # Input pins: A_pin = 17 B_pin = 27 C_pin = 22 GPIO.setmode(GPIO.BCM) GPIO.setup(A_pin, GPIO.IN, pull_up_down=GPIO.PUD_UP) # Input with pull-up GPIO.setup(B_pin, GPIO.IN, pull_up_down=GPIO.PUD_UP) # Input with pull-up GPIO.setup(C_pin, GPIO.IN, pull_up_down=GPIO.PUD_UP) # Input with pull-up # Raspberry Pi pin configuration: RST = 24 # Note the following are only used with SPI: DC = 23 SPI_PORT = 0 SPI_DEVICE = 0 # 128x64 display with hardware I2C: disp = Adafruit_SSD1306.SSD1306_128_64(rst=RST) # Initialize library. disp.begin() # Clear display. disp.clear() disp.display() # Load default font. font = ImageFont.load_default() # Create blank image for drawing. # Make sure to create image with mode '1' for 1-bit color. width = disp.width height = disp.height image = Image.new('1', (width, height)) # Get drawing object to draw on image. draw = ImageDraw.Draw(image) # Draw a black filled box to clear the image. draw.rectangle((0,0,width,height), outline=0, fill=0) buttons = [0,0,0]; hexes = os.listdir('./data') position = 0; def flashWrite(): draw.rectangle((0,0,width,height), outline=0, fill=0) draw.text((0,30), 'writing...', font=font, fill=255); disp.image(image) disp.display() result = subprocess.call(['./leonardoUploader', '/dev/ttyACM0', './data/'+hexes[position]]); if result == 0: draw.text((0,30), 'success', font=font, fill=255); else: draw.text((0,30), 'error', font=font, fill=255); disp.image(image) disp.display() time.sleep(1) def scan(): global position global mode if not GPIO.input(A_pin): if buttons[0] == 0: position = position + 1 if position >= len(hexes): position = 0; buttons[0] = 1 else: buttons[0] = 0 if not GPIO.input(B_pin): if buttons[1] == 0: position = position - 1 if position < 0: position = len(hexes) - 1; buttons[1] = 1 else: buttons[1] = 0 if not GPIO.input(C_pin): if buttons[2] == 0: flashWrite(); buttons[2] = 1 else: buttons[2] = 0 def repaint(): draw.rectangle((0,0,width,height), outline=0, fill=0) if buttons[0]: draw.rectangle((0,0,10,10), outline=255, fill=1); else: draw.rectangle((0,0,10,10), outline=255, fill=0); if buttons[1]: draw.rectangle((10,0,20,10), outline=255, fill=1); else: draw.rectangle((10,0,20,10), outline=255, fill=0); if buttons[2]: draw.rectangle((20,0,30,10), outline=255, fill=1); else: draw.rectangle((20,0,30,10), outline=255, fill=0); draw.text((0,30), hexes[position], font=font, fill=255); disp.image(image) disp.display() scan() repaint() dirty = False def sig(n): global dirty scan() dirty = True GPIO.add_event_detect(A_pin, GPIO.BOTH, callback=sig, bouncetime=20); GPIO.add_event_detect(B_pin, GPIO.BOTH, callback=sig, bouncetime=20); GPIO.add_event_detect(C_pin, GPIO.BOTH, callback=sig, bouncetime=20); try: while 1: if dirty: repaint() dirty = False #time.sleep(.01) except KeyboardInterrupt: GPIO.cleanup()
肝心のArduboyにhexをアップロードする部分は
このソフトウェアを使いました。
起動時にプログラムを実行するために、systemdのservice定義を書きました。
[Unit] Description=arduboyWriter After=syslog.target [Service] Type=simple WorkingDirectory=/home/pi/arduboyWriter ExecStart=/usr/bin/python main.py TimeoutStopSec=5 StandardOutput=null [Install] WantedBy = multi-user.target
これを/eyc/systemd/systemにコピーして systemctl enable arduboy-writerなどとして有効化できます。
ケース
Fusion360でモデリングして、3Dプリンタで出力しました。3層の構造を4本のねじとナットでサンドイッチすることで固定しています。
Raspberry Pi ZeroのGPIOにはメスのピンヘッダをつけたので、ちょうどこの2層目がかっちりはまって、安定します。
まとめ
RaspberryPi ZeroでArduboyのゲームを書き込むのは、冷静に考えるとちぐはぐな解決策です。RaspberryPi ZeroのほうがArduboyの何倍も高スペックだからです。しかし、Arduboyは軽量で、ゲーム機として非常によくできているため、多少ちぐはぐであってもかまわないかな、ということで作ってみました。
世の中にはUSBホストになれるマイコンもあるようなので、そういったもので同じようなものが作れればよりスマートだと思います。(PIC32でできる気がするが、まだ僕にはそのスキルがありません・・勉強せねば・・)
RaspberryPi Zeroを使ったプロダクトは初めて作りましたが、この小ささはとても魅力的だと実感しました。小さいと3Dプリンタでケースを作るのも楽だし、成果物も小さく収められます。
ただ、Linuxをブートするため、起動時間が数十秒かかるというのがネックです。これも前述したUSBホストになれるマイコンを使うことで解決できそうです。