はじめに
Arduino Leonardo(またはArduino Micro)を使ったら簡単にできたと思うが、使っていないArduino Nano Everyがあったので今回はそちらを使用した。
PyQt5を使ったシリアル通信でつまづいた。原因不明のエラーに悩まされたが以下を追加したら解決した。
import serial with serial.Serial('COM5', 9600) as ser: time.sleep(2)
なぜかいったんpyserialを使って接続を確立させるとうまくいった。
バージョン確認(pip freeze)
PyQt5==5.15.0 PyQt5-sip==12.8.0 pyserial==3.4 python-vlc==3.0.11115
Pythonスクリプト
import os import glob import random import time import sys from PyQt5 import QtCore, QtSerialPort from PyQt5.QtWidgets import QLabel, QApplication, QWidget, QFrame from PyQt5.QtGui import QImage, QPixmap, QFont import vlc import serial with serial.Serial('COM5', 9600) as ser: time.sleep(2) with open('kana.txt', encoding='utf-8') as f: all_kanas = set(f.read().replace('\n','')) for i in range(4): button_image = [QImage('button/%d.png'%i) for i in range(4)] ok_sound = vlc.Media('sound_kana/ok.wav') boo_sound = vlc.Media('sound_kana/boo.wav') player = vlc.MediaPlayer() dummy_sound = vlc.Media('sound_kana/dummy.wav') player.set_media(dummy_sound) player.play() os.chdir(os.path.join(os.getcwd(), 'character')) all_character = [os.path.splitext(i)[0] for i in glob.glob('*.png')] class Window(QWidget): def __init__(self): super().__init__() self.answer_position = 0 self.button_ready = False self.serial = QtSerialPort.QSerialPort( 'COM5', baudRate=QtSerialPort.QSerialPort.Baud9600, readyRead = self.receive) self.serial.open(QtCore.QIODevice.ReadWrite) self.initUI() def initUI(self): self.kana_label = [QLabel(self) for i in range(10)] for i in range(10): self.kana_label[i].setGeometry(600+i*100, 200, 100, 100) self.kana_label[i].setFont(QFont("Times", 72, QFont.Bold)) self.kana_label[i].setAlignment(QtCore.Qt.AlignCenter) self.kana_label[i].setLineWidth(3) self.button_label = [QLabel(self) for i in range(4)] self.choice_label = [QLabel(self) for i in range(4)] for i in range(4): self.button_label[i].setGeometry(184 + 434 * i, 900, 250, 50) self.button_label[i].setPixmap(QPixmap.fromImage(button_image[i])) self.choice_label[i].setGeometry(184 + 434 * i, 650, 250, 250) self.choice_label[i].setFont(QFont("Times", 120, QFont.Bold)) self.choice_label[i].setAlignment(QtCore.Qt.AlignCenter) self.pic_label = QLabel(self) self.pic_label.setGeometry(50, 50, 500, 500) self.make_question() def receive(self): #ボタンが無効なら何もしない if self.button_ready == False: dummy = self.serial.readAll() else: self.button_ready = False my_message = self.serial.readAll().data()[0] if ['A', 'S', 'D', 'F'].index(chr(my_message)) == self.answer_position: player.set_media(ok_sound) player.play() loop = QtCore.QEventLoop() QtCore.QTimer.singleShot(1000, loop.quit) loop.exec_() self.make_question() else: player.set_media(boo_sound) player.play() loop = QtCore.QEventLoop() QtCore.QTimer.singleShot(1000, loop.quit) loop.exec_() self.button_ready = True def make_question(self): #画面のリセット for i in range(10): self.kana_label[i].setFrameStyle(QFrame.NoFrame) self.kana_label[i].setText('') character_name = random.choice(all_character) star_image = QImage(character_name + '.png') self.pic_label.setPixmap(QPixmap.fromImage(star_image)) kanas = list(character_name) kana_len = len(kanas) question_position = random.randint(0, kana_len-1) question_kana = character_name[question_position] kanas[question_position] = '' for i in range(kana_len): self.kana_label[i].setText(kanas[i]) self.kana_label[question_position].setFrameStyle(QFrame.Box | QFrame.Plain) others = list(all_kanas - set([question_kana])) choices = random.sample(others, 3) choices.append(question_kana) random.shuffle(choices) self.answer_position = choices.index(question_kana) for i in range(4): self.choice_label[i].setText(choices[i]) self.button_ready = True def keyPressEvent(self, e): # エスケープキーを押すと画面が閉じる if e.key() == QtCore.Qt.Key_Escape: self.close() app = QApplication(sys.argv) ex =Window() p = ex.palette() p.setColor(ex.backgroundRole(), QtCore.Qt.white) ex.setPalette(p) ex.showFullScreen() sys.exit(app.exec_())
Arduinoスケッチ
const int buttonON = LOW; // ボタンが押されているとピンの値はLOW const int buttonOFF = HIGH; // ボタンが押されていないとピンの値はHIGH const int buttonPin1 = 2; const int buttonPin2 = 3; const int buttonPin3 = 4; const int buttonPin4 = 5; int buttonState1; void setup() { Serial.begin(9600); pinMode(buttonPin1, INPUT_PULLUP); pinMode(buttonPin2, INPUT_PULLUP); pinMode(buttonPin3, INPUT_PULLUP); pinMode(buttonPin4, INPUT_PULLUP); } void loop() { if (digitalRead(buttonPin1) == buttonON) { Serial.write('A'); delay(300); } if (digitalRead(buttonPin2) == buttonON) { Serial.write('S'); delay(300); } if (digitalRead(buttonPin3) == buttonON) { Serial.write('D'); delay(300); } if (digitalRead(buttonPin4) == buttonON) { Serial.write('F'); delay(300); } }
使用したもの
Arduino Nano Every ブレッドボード Cherry MXキースイッチ(青軸) キーキャップ( 「遊舎工房」の通販で購入) タミヤ PLA PLATE 1.0mm厚 タミヤ プラ材 5mm角棒 タミヤ 1.5A 平行コード (5m) DAISO カラーボード(白)450×300×厚さ5mm DAISO PETIT BLOCK(ウェディングケーキ)