これは何?
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ファイルを作ります。
この記事が参考になりました。
qiita.com
雑ですがコードはこんな感じ。
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
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)
GPIO.setup(B_pin, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(C_pin, GPIO.IN, pull_up_down=GPIO.PUD_UP)
RST = 24
DC = 23
SPI_PORT = 0
SPI_DEVICE = 0
disp = Adafruit_SSD1306.SSD1306_128_64(rst=RST)
disp.begin()
disp.clear()
disp.display()
font = ImageFont.load_default()
width = disp.width
height = disp.height
image = Image.new('1', (width, height))
draw = ImageDraw.Draw(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
except KeyboardInterrupt:
GPIO.cleanup()
肝心のArduboyにhexをアップロードする部分は
github.com
このソフトウェアを使いました。
起動時にプログラムを実行するために、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ホストになれるマイコンを使うことで解決できそうです。