ArduinoでIIDXコントローラを自作
きっかけ
※この記事は本家4級、BMS2段の初心者が書いています。
キーボードでBMSするの楽しいんですけど、やっぱり専用コントローラでゲームしたいわけです。ばちばち鳴らして音ゲーしたいですよね?
しかしながら専コンは売ってないし、本家に1000円も投入してないのに海外コンに3万も払うのはばかばかしく感じます。あとMacなので動くか不安。
じゃあ自作しかないので自作しましょう。
コンセプト
形は公式に準拠させる
金をかけない
見た目にはこだわらない
プレイ出来ればいい
がんばらない
材料選定
基板
自作キーボードについてのネットの記事を探してみると、だいたいASCII製5鍵コンの基板を乗っ取って作るのが主流のように思います。しかしながらそもそも売ってなかったりPSのコネクタからUSBに変換しなければならなかったり難しいはんだ付けが要求されたりなのでコンセプトに合いません。今時のマイコンは簡単に入手できてファームも簡単に書けるのでArduinoを使用することにします。しかしながら純正は高いですね。安くあげるといえば中華製。AliExplessで互換品のProMicroを調達します。小さいので組み込み向けですし、とくに複雑な手順を踏まなくてもキーボードとして動作できるのが決め手でした。
ボタン
三和ボタンとか芝ボタンとかで盛り上がるところでしょうが、前者はひとつ1000円、後者はひとつ500円と高いわけです。 安物といえば中華製。そこでまたもやAliExplessで調達します。 ja.aliexpress.com
マイクロスイッチ
調達したボタンに付いてきたマイクロスイッチは固すぎて腱鞘炎不可避なのでなくなくオムロンのVX-5-1A2を調達してきました。押圧0.25Nでここだけゲーセン仕様になりました。
スプリング
調達したボタンに付いてきたスプリング、黒鍵と白鍵で押圧が異なることに気がついてしまいました。見なかったことにしました。(いずれ交換するかもしれません)
皿
適当にロータリーエンコーダ買うかと思ってたら5鍵コン見つけてしまったのでこれを使うことにします。
外装
アクリルとか加工頼むと高いし自分で穴開けるのは面倒なのでALL木材。塗装とか何か貼ったりとかも面倒なのでパスします。
その他
リード線とかユニバーサル基板とかは適当に調達します。仮組用のブレッドボードとかも調達します。
かかった金額まとめ
1$ = 120円としてます。
調達先は上の2つ以外梅澤無線電気です。
材料名 | 単価 | 個数 | 価格 |
---|---|---|---|
ProMicro | $ 3.53 | 1 | 424円 |
ボタンセット | $ 21.66 | 1 | 2600円 |
マイクロスイッチ | 172円 | 7 | 1204円 |
抵抗100本入り(220オーム) | 154円 | 1 | 154円 |
抵抗10本入り(4.7kオーム) | 64円 | 1 | 64円 |
ブレッドボード | 108円 | 3 | 324円 |
リード線 | 194円 | 2 | 388円 |
ユニバーサル基板 | 86円 | 1 | 86円 |
ジャンパワイヤ | 162円 | 2 | 324円 |
みのむしケーブル | 162円 | 1 | 162円 |
1x4材 | 198円 | 1 | 198円 |
5鍵コン | 324円 | 1 | 324円 |
合計 | 6252円 |
リストに載ってない天板は家に転がっていたベニヤです。
5000円くらいに収めたかったですがブレッドボードとかはまた使えるのでよしとします。
安いメカニカルキーボード買えたなあと少し思います。
製作
天板製作
適当に図面書いてその通りにベニヤを切ります。 寸法は
を参考にさせて頂きました。
皿部分について
自分が解説するよりわかりやすいと思うので参考にしたサイトを貼って終わりにします。 mell0w-5phere.net 多分ここがわかりやすいかなあって思います。フォトインタラプタ、とか ロータリーエンコーダ、とかで検索すると詳しくわかると思います。
無残に解体された5鍵コン
基板製作
ProMicroのデジタルピンに鍵盤のマイクロスイッチ 、アナログピンにフォトインタラプタの出力を繋ぎます。
完成した基盤は天板の裏に端材を貼り付けてネジで留めておきます。
素人なので適当です。
ファームウェア
Arduinoに書き込むソフトウェアです。 Arduino LeonardoでINFINITAS用の変換器を作る | darekasannetのブログ これを参考に書きました。githubに置いてあります。 github.com
外観、皿
1x4材で枠を作って天板を乗っけて釘で留めます。
皿は用意できなかったので段ボール工作になりました。
裏蓋は無しです。
以上。完成です。おめでとう
感想
- 見た目がクソダサい。 凝ると無限に金がかかるので、我慢できない人は海外コンを買うべき
- 黒鍵と白鍵の重さが違うのと、たまに皿が変な反応する(触ってないのに連打される)意外は良好
- 段ボール皿、プレイ感は違うけどめちゃくちゃ軽いので楽しい
- というかこれ作ってから1週間くらいたつけど忙しくて全然プレイできない
結論
どうしても皿をうまく作るのは(見た目、感触)キツいと思います。専コン欲しい人で
- どうしてもゲーセンに近づけたい人 -> 買った方がいい
- 金が無限にある人 -> 買った方がいい
- 見た目にこだわりたい人 -> 買うか無限の金をかけて自作
- 金が無いけど知識がない人 -> 全然作れるから作れ
- DP環境欲しいけど10万も出せない人 -> このクオリティなら1万かからないで作れる
レッツ自作ライフ
pythonで二次元ガウス分布を得る
結論
インパルス画像にガウシアンフィルタを適用させることで得られる
まえがき
中央に重み付けして加算したい*1ことがあったので, 二次元ガウス分布が欲しかったのですが, ライブラリにはなさそうだし式から起こすのも面倒なのでいい方法を探しました.
そこで, 簡単に得る方法を見つけたのでまとめておきます.
コード
import scipy.ndimage.filters as fi import numpy as np def gkern(kernlen=21, nsig=3): # kernlen x kernlen のゼロ行列を作成 inp = np.zeros((kernlen, kernlen)) # 中央の要素を1にする inp[kernlen // 2, kernlen // 2] = 1 # ガウシアンフィルタを適用し, 結果を返す return fi.gaussian_filter(inp, nsig)
解説
kernlenは得られるガウス分布のサイズ, nsigはガウス分布の広がりです. 大きい方がよりとんがってない分布になります. 1のときにいわゆる標準正規分布となります.
ためしてないですが, 中央の要素ではなく好きな場所を指定すればカーネルがずれてくれると思います
*1:普通にガウシアンフィルタを適用して総和を取れば良いことにあとから気づきました
OpenCV(python)で外接長方形にそって画像を切り出す
調べるより書いたほうが速いコードですけどブログのネタがないんですね.
対象画像
ここから赤丸の外接長方形にそって画像を切り出します.
コード
def bounding_rect_img(img): """ 外接長方形を切り出して画像として返す :param img: 入力画像 :return: 出力画像 """ img_g = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # boundingRectが1チャンネルしか対応してないため変換する x, y, w, h = cv2.boundingRect(img_g) crop = img[y:y+h, x:x+w] return crop def main2(): img = cv2.imread("image_path") crop = bounding_rect_img(img) cv2.imwrite("save_path", crop) if __name__ == '__main__': main2()
結果
コメント
白背景の場合はcv2.bitwise_not()とか使ってください.
JavaFXで時間管理タイマーを作る [メモリリーク編]
(上から2つ目のプロセスです)
しばらく使ってたんですけど、なんか妙にメモリ食うんですよねこれ。起動時から100MBくらい使うし3時間位でこうなるし。
というわけで原因を探してたんですけど、こんな記事を見つけました。
ドキュメントにもしっかりその旨が書いてあるらしく
警告: 実行中のTimelineはFXランタイムから参照されます。Timelineを無限にした場合、適切に停止しないと、メモリー・リークが発生する可能性があります。アニメーション化されるプロパティを持つすべてのオブジェクトがガベージ・コレクションの対象となるわけではありません。
だそうです。
コード
追加部分を抜粋すると
public class Controller implements Initializable { private int c = 0; private Timeline timeline = new Timeline(new KeyFrame(Duration.seconds(1), //時間経過をトリガにするのはTimelineクラスを使う new EventHandler<ActionEvent>() { public void handle(ActionEvent actionEvent) { //ここに書いた処理がDuration.seconds(1)で示した感覚で実行される c++; if (c > 60){ c = 0; timeline.stop(); timeline.play(); } } } ) ); public void mainButtonClick(ActionEvent actionEvent) { if (mainTimer.getStatus()){ //タイマーが動作中のクリック }else { //タイマーが動作していない timeline.setCycleCount(100); //何回繰り返すか指定する } }
何回呼ばれたか数えるカウンタを用意して、一定回数(60回)呼ばれたら停止して再開すると言った形にしました。
非常に頭の悪い感じになりましたが、これで治るのか楽しみですね
JavaFXで時間管理タイマーを作る [fxml & css編]
見た目があまりにもダサくて使いたくなかったため、fxmlとcssを用いて見た目をいい感じにします。
ネットにある情報がfxmlじゃなくてjavaコードで構造を定義してるものが多くて正直わかりませんでした。英語で探せばよかったかな。
コード
<BorderPane fx:controller="Controller" xmlns:fx="http://javafx.com/fxml"> <stylesheets> <URL value="@labTimer.css"/> </stylesheets> <top> <VBox alignment="CENTER"> <HBox> <Label text="らぼいん"/> <Region HBox.hgrow="ALWAYS"/> <Label fx:id="nowTimeLabel"/> </HBox> <HBox> <Label fx:id="inDate" text="00/00 00:00:00"/> <Region HBox.hgrow="ALWAYS"/> <Label fx:id="nowTime" text="00/00 00:00:00"/> </HBox> <Label text=" "/> <Label text="らぼ時間"/> <Label fx:id="allTimerLabel"/> </VBox> </top> <center> <GridPane alignment="center" hgap="10" vgap="10"> <Label text="研究時間: " GridPane.rowIndex="0" GridPane.columnIndex="0"/> <Label fx:id="childTimerLabel1" GridPane.rowIndex="0" GridPane.columnIndex="1"/> <Label text="休憩時間: " GridPane.rowIndex="1" GridPane.columnIndex="0"/> <Label fx:id="childTimerLabel2" GridPane.rowIndex="1" GridPane.columnIndex="1"/> <Label text="その他時間: " GridPane.rowIndex="2" GridPane.columnIndex="0"/> <Label fx:id="childTimerLabel3" GridPane.rowIndex="2" GridPane.columnIndex="1"/> </GridPane> </center> <bottom> <VBox alignment="CENTER"> <Label fx:id="statusLabel" /> <Label fx:id="mainTimerLabel" /> <HBox> <Region HBox.hgrow="ALWAYS"/> <Button fx:id="mainButton" onAction="#mainButtonClick"/> <Region HBox.hgrow="ALWAYS"/> <Button fx:id="childButton1" text="研究" onAction="#button1Click"/> <Region HBox.hgrow="ALWAYS"/> <Button fx:id="childButton2" text="休憩" onAction="#button2Click"/> <Region HBox.hgrow="ALWAYS"/> <Button fx:id="childButton3" text="その他" onAction="#button3Click"/> <Region HBox.hgrow="ALWAYS"/> </HBox> </VBox> </bottom> </BorderPane>
Label#mainTimerLabel{ -fx-font-size:28pt; } Label#allTimerLabel{ -fx-font-size:28pt; }
解説
BorderPone
top, left, center, right, bottomの5つの構造をもち、それぞれに配置できる
stylesheets
URLタグでスタイルシートの場所を指定できる。Pone要素の中に書かないとダメっぽい?直書きもだめでした。
HBox, VBox
それぞれ要素を横に並べる、縦に並べるときに使う
Region HBox.hgrow="ALWAYS"
空白の指定。左右均等配置になる。ウィンドウ自体を拡大したらこの部分が伸びる
GridPone
GridPane.hogeIndexに従って格子状に配置できる
CSS
クラス#fx:id{CSSのタグに-fx-をつけたもの}で修飾できる
結果
参考
JavaFXで時間管理タイマーを作る [まとめ]
JavaFXで時間管理タイマーを作る [時刻編]
Java日付時刻APIメモ(Hishidama's Java8 Date and Time API Memo)
このサイトを参考に時刻関連の実装を行う
仕様変更
- らぼりだ時刻は普段使われないので現在時刻を表示する。
コード(追加部分)
private LocalDateTime dt; private DateTimeFormatter dtf = DateTimeFormatter.ofPattern("MM/dd HH:mm:ss"); private Timeline timeline = new Timeline(new KeyFrame(Duration.seconds(1), //時間経過をトリガにするのはTimelineクラスを使う new EventHandler<ActionEvent>() { public void handle(ActionEvent actionEvent) { //ここに書いた処理がDuration.seconds(1)で示した感覚で実行される dt = LocalDateTime.now(); nowTime.setText(dt.format(dtf)); } } ) ); public void mainButtonClick(ActionEvent actionEvent) { if (mainTimer.getStatus()){ //タイマーが動作中のクリック nowTimeLabel.setText("らぼりだ: "); dt = LocalDateTime.now(); nowTime.setText(dt.format(dtf)); }else { //タイマーが動作していない dt = LocalDateTime.now(); inDate.setText(dt.format(dtf)); nowTimeLabel.setText("現在時刻: "); } }
成果物
一応完成ということにします