Macbook Pro 13にAkitio NodeでRX580を繋げて3Dゲームを遊びたい開発したい!(使用レビュー編)

blog.takumus.com 先日こんな記事を書きました。
GTX970をegpuで繋いでいろいろする!というものでした。今回の記事のタイトルでおかしいなと思う方いらっしゃると思います🤔
なぜGTX970がRX580になってるの!?はい。今回の記事は、どうしてグラフィックボードを変更したのかと、RX580に変えてみてどうなったかを書きたいと思います。

GTX970をなぜ辞めた?

Appleが公式に対応していないグラボだからか、MacOSにて多くの問題が出てきてしまったからです。

問題1. Chromium系が全滅

Google Chromeをはじめ、SlackやDiscord、また僕の大好きなVSCodeのパフォーマンスが著しく低下しました。GPUを上手に使えていないようで、まともに使えません。

問題2. スリープ復帰時等にカーネルパニック

これも困りました。スリープをオフにすれば対応できますがグラボのファンも回りっ放しなので問題です。

問題3. OSのアップデートのたびにフォーラムを確認するのは面倒くさい

OSが新しくなると、当てるべきパッチも変更しなければならないと予測されます。これは面倒です。

問題4. 不安定

ランダムにカーネルパニックします。これは最悪です!

問題5. 起動後の抜き差しは、だめ!

10.13.4からは、起動後でも抜き差し出来て、グラフィックの切り替えをサポートしているのですが、非公式のGTX970ではそれが出来ません。カーネルがパニクります。

なぜRadeon RX580にした?

support.apple.com Apple公式ページにあるように、High Sierra 10.13.4よりegpuとして正式にサポートされているグラフィックボードだからです。
海外のフォーラムでAkitio Node + RX580をMacOS 10.13.4と繋ぐだけで使用できた!という報告もあります。

Macの情報サイトとしてはトップクラスの9to5Macが動画付きで上げていたので決めました。

jp.msi.com

Akitio Node + RX580にしてみてどうなった?

MacOSでの使用感

上で挙げたGTX970で見られた問題はほぼ全て解決しました。全くストレスなく使用できます。 ただし、問題が全くないわけではありません。

Chromium系はやはりグラフィックが怪しい。

Chromeでブラウジングしていてストレスを感じることは全くありませんが、WebGLなどを描画させるとRX580とは思えないFPSの低下が見られます。 調べてみると、ChromiumはRX580ではなく、内蔵グラフィックスを使っていました。
Chromeのアクセラレーションの設定を片っ端から試しても解決せず、結局クラムシェルモードにすることでRX580を使ってくれるということを発見しました
この問題の対応はAppleが行うのかGoogleが行うのかわかりませんが、将来的には治ってほしいです。
今のところ、家では外付けのキーボートとマウスで使っています。そのためMacを開く必要が無いので、これで解決するのであれば問題にはなりません。

Unityでのパフォーマンスは微妙

SceneやGameの単体表示ではヌルヌル動きますが両方表示すると30fps位に落ちてしまいます。しかしステータスでは100fpsほど出ているのです。VSyncのように上限fpsが制限されているような感じです。クオリティ設定で最低にしても最高にしても変わりませんでした。
海外フォーラムでは、windowsで同じような症状の人が数名確認できました。やはりグラフィックドライバのVSync設定をどうにかすることで対応しているようです。
MacにはAMDのドライバが内蔵されていますが、ドライバのコントロールパネルは現在は触れない状態ですので、対応の手段は無さそうです。
そもそもgpu内蔵のiMacでも同じ症状が確認できたので、egpuの問題ですら無いかもしれません。

Bootcampでの使用感

全く問題ありません。完璧に動きます。
前回の記事でも触れたように、Bootcampでは起動後の抜き差しは不可能です。起動前にタイミングよくakitio nodeの電源を入れるか、refindでうまいことするしかありません。僕はうまいことしました。

ゲームとかはどう?

RX580はGTX1060程らしいです。そこそこ最近のゲームが普通に遊べるレベルではありますが、egpu化すると本来のグラボ性能の70%-80%の性能しか出ないと言われているのであまり期待はしませんでした。
とりあえず、Steamで2つ程購入しましたのでレビューします。
※僕がプレイしてみて、ストレスを感じないくらいのギリギリの設定で検証しています。

1. Getting Over It

まずは元々持っていたこのゲームを試しました。
4K + 極限設定 = 50 - 60fps

2. Nier Automata (Steam版)

前から憧れていたゲームです。偶然にもセールで半額だったのでDLCと合わせてSteamで購入しました。
WQHD + アンチエイリアスオフ、それ以外最高設定 = 50 - 60fps

撮影に使ってるiphone xのホワイトバランスがおかしくて映像汚いです。

予想以上に普通にゲームできた

すごいですegpu。夢が広がりますね!Macbook Pro 13で普通にゲームできるとは思わなかったです。 今回ディスプレイが4Kだったため、fullHDよりは高い解像度で検証しましたが、fullHDであれば上記のゲームは最高設定でも平均60fps程出ています。

egpuは、どういう人におすすめ?

  • AKitio Node(44,000円)
  • MSI RX580 8GB中古(36,000円)

合わせて80,000円です。
この費用だと、上手くパーツを選べば普通にゲームが出来るパソコンは組めます。
よって、ゲームしたいだけ!の方にはこの構成はおすすめしません。

  • Macbook Pro (Thunderbolt 3対応)を持っている。
  • MacOSでそこそこgpuが必要な作業をしたい。
  • ゲームもしたい。

これらの全てに当てはまれば、僕はegpuをおすすめしたいです。

実は...

  • ゲームコントローラ Xbox one のマインクラフトの豚バージョン(8,000円)
  • Steamのゲームを入れるための外付けSSD transcend 480GB(18,000円)
  • ゲームコントローラや外付けSSDなどを繋ぐためのoricoのUSBハブ(5,000円)
  • Windows 10 Home(14,000円)

合わせて41,000円です。
と言った具合でなんやかんやお金がかかっています...

Macbook Pro 13にAkitio NodeでGTX 970を繋げて3Dゲームを遊びたい開発したい!(セットアップ編)

最近Unity(3D,2Dゲームを開発するソフトウェア)に興味を持ち、自分のMacbook Proを使って勉強しているのですが、スペック不足なのかスムーズに開発ができず悩んでおりました。

僕の環境

Mac
  • High Sierra 10.13.4
  • MacBook Pro (13-inch, 2017, Two Thunderbolt 3 ports)
  • 2.5 GHz Intel Core i7
  • 16 GB 2133 MHz LPDDR3
  • Intel Iris Plus Graphics 640 1536MB
外付けディスプレイ
  • EIZO EV2736W 2560x1440 (置いてあるだけ)
  • LG 27UK650-W 3840 x 2160 (HDMIで接続)

f:id:takumus:20180418161130p:plain いつもは4Kの方をMacbook Proに接続して使ってます。EIZOは昔使っていたのですが、macの端子が足りなくて使えていません
グラボ無しのMacbook Proを、4Kディスプレイに接続して3Dヌルヌル動かすのは無理がありますよね。そんな僕を救ってくれる何かが

ありました!

www.akitio.jp これはThunderbolt 3という規格を使い、主にノートパソコン等にグラフィックボードを増設できるマシンです。
外付けGPU、外部のGPUという意味からEGPU(External GPU)と呼ばれています。AKiTiO Node以外にも様々な製品が出ておりますがAmazonにこれしか無かったので買うことにしました。

意外と高い

AKiTiO Node意外と高いです。更にグラフィックボードも必要になるのでこちらも買わなければなりません。それらを合わせて、

  • AKiTiO Node : 44,000円
  • MSI Gaming GTX 970 : 20,000円(友人から中古で購入)

合計 : 64,000円

結構高いです。普通に悪くないデスクトップパソコンは組めそうですが、僕は外でも家でも同じパソコンを使いたいのです。また、Mac OSが好きなため、新たにパソコンを組むという選択肢はありませんでした。

AKiTiO Nodeを使うための環境

AKiTiO NodeをはじめとするEGPUを使うには、Thunderbolt 3による高速な転送が求められます。自分のMacがThunderbolt 3に対応しているかを確認しましょう↓ support.apple.com ※Thunderbolt 2を3に変換するアダプタを使って、Thunderbolt 3に対応していないMacでも使用できるそうです。(AKiTiO Nodeでは未確認)

AKiTiO Nodeの外観

でか過ぎです! f:id:takumus:20180418172626p:plain

MSI GTX 970を挿入してみた

2スロット消費する大型のグラフィックボードも入ります。 f:id:takumus:20180418172724p:plain

背面

f:id:takumus:20180418172918p:plain

ケーブルを差すとこんな感じ

f:id:takumus:20180418173630p:plain

セットアップ(僕はこれで成功しましたが、自己責任でお願いします)

1. まずはBOOTCAMPのWindows 10にてAKiTiO Nodeのファームウェアアップデートとグラフィックボードの動作確認

※グラフィックボードは抜いておきます。
1-1. BOOTCAMPでWindows 10を起動。

1-2. Thunderbolt 3のドライバをインストール。

downloadcenter.intel.com NUC専用となっていますが、これで良いみたいです。

1-3. Windowsの電源を切る。

1-4. AKiTiO Nodeを接続しAKiTiO Nodeの電源を入れ、Windowsを起動。

1-5. デバイスマネージャでThunderboltが認識されているか確認。

1-6. ファームウェアをインストール www.akitio.com

1-7. ついでにグラフィックボードのドライバもインストール。

1-8. Windowsの電源を切る。

1-9. AKiTiO Nodeにグラフィックボードを挿入。

1-10. Macbook ProにAKiTiO Nodeを接続(必ずAKiTiO Nodeの電源は切る

1-11. Windowsで起動。
ここが一番ミソです。海外フォーラムで現在も様々な議論がされていますが、色々読んだ結果、環境によるということがわかりました。
私の環境ではWindowsで起動しWindowsのロゴが出て0.5秒後くらいにAKiTiO Nodeの電源を入れると上手くいきます。

電源を入れるタイミングが、↓

バッチリの場合

→いつもより起動に時間(2,3分ほど)がかかります。起動後グラフィックボードを認識します。
ディスプレイが接続されていた場合、ディスプレイにも画面が出力されます。

遅すぎた場合

→Windowsが通常に起動しグラフィックボードが認識されません。

早すぎた場合

→Macbook ProのディスプレイにWindowsロゴ出て、少しすると高速に点滅し画面が乱れます。
音が出ることから、起動はしているようなので、パスワードログインを一旦オフにして、シャットダウンのショートカットを覚えておくと良いでしょう。

1-11. BOOTCAMPで、グラフィックボードの正常動作を確認。
ベンチマークなどしてみてください。

2. 本命のMac OS High Sierra 10.13.4で動くように

ここからはカーネルをいじったり、SIPを無効化したり、失敗すると面倒な事になりうる領域に入ります。そのためバックアップをしておきましょう。

2-1. MacとAKiTiO Nodeの電源を切る。

2-2. Cmd + Rを押しながらリカバリモードで起動。

2-3. 上のメニューバーよりターミナルを起動しcsrutil disableを実行。
これによりSIPを無効化します。SIPを無効化しないとNVIDIAのGPUをMacに認識させるためのドライバやツールが動きません。

2-4. Macで起動。

2-5. ターミナルを起動し、下記のシェルを実行。

sudo su
curl -s "https://raw.githubusercontent.com/learex/macOS-eGPU/macOS10134/experimental/nvidia10134Install.sh" | bash

このシェルは、中身を見たところ、

  • NvidiaのQuadro向けドライバをダウンロード&インストール。
  • MacOSにNVIDIAグラフィックボードを認識させるためのpkgを適用。
  • AppleGraphicsのkextを書き換え?(復元用に元のkextのバックアップは取っているっぽです)

下手なことは言えないですが、すごいことをやっています。
uninstallerもあるようなので、一応引用元の掲示板を見てください。
↓引用元 egpu.io

すべての処理が終わると自動で再起動します。

2-6. Macの電源を切る。

2-7. AKiTiO Nodeの電源を入れる。

2-8. Macの電源を入れる。

2-9. グラフィックボードを認識するか確認。
Windowsと違ってタイミングなどは必要ありません。
グラフィックボードにディスプレイが接続されていた場合はすでにもう映るはずです。
f:id:takumus:20180418185715p:plain
認識すると、Macbook ProなのにGraphicsがGTX 970のような面白い状況になります。

お疲れ様でした

セットアップはひとまずこれで終わりです。 僕はと言いますと、ケーブル一本で、WQHDと4KとMac本体のトリプルディスプレイが実現しました! f:id:takumus:20180418191825p:plain f:id:takumus:20180418192654p:plain

常用する上での注意

Thunderboltは基本的に電源を切った状態での抜き差しをすること。

MacやWindowsで、OSが立ち上がった後にケーブルを抜くとMacbook Proの電源が落ちます。
Macはカーネルパニック、Windowsは再起動します。

OSのアップデートに注意

まずフォーラムで動作確認をしてからアップデートしましょう。
最近では、10.13.3から10.13.4にアップデートしたときにたくさんのEGPUユーザーがトラブルに巻き込まれたそうです。

そもそもAppleが公式で使えると言っていないから、

何が起きるかわかりません。覚悟は必要です。

終わりに

日本でMacとEGPUの記事をかかれている方は少なく、特に今回のようなMac OS High Sierra 10.13.4 + AKiTiO Node + NVIDIAについては見つけられませんでした。
この記事は海外のフォーラムから手探りで集めた情報だということをご理解いただけたらと思います。
もしもやってみたいという方がいらっしゃいましたら、この記事を参考にしていただくのも良いのですが、海外のフォーラムがとてもスピーディーなのでそちらを優先して読んでいただければと思います。 egpu.io

生物っぽいルート計算をするライブラリを作りたい

まずデモ

 デモを用意しました。マウスクリックで餌がおけます。ドラッグすることで餌の方向を指定できます。

生物っぽいルート計算とは🤔?

 魚などの生物の群れの動きをシミューレーションするアルゴリズムではBoidsと言うものが有名ですね。お互いの位置関係のみで動く単純なアルゴリズムで非常に面白い動きをします。以下の動画がわかりやすいです。
www.youtube.com  しかし今回私が作りたいものは、これらとは違います。スタートゴール位置と向きを設定し、そのルートを生物っぽくなるように計算するというものです。

f:id:takumus:20180131150434p:plain

 上の図は、私の思う、生物っぽいルートの手書きのイメージ図です、P1がスタート、P2がゴールです。この図を見て「その場で回転して方向を合わせてから進めば効率よくない?」「大回りしすぎじゃない?」「なんか、うねうねしてない?」と思う方がいると思います。
 しかし、魚等の生物の場合その場で回転できないので、大回りをする必要があります。ただし、大型の魚の場合小回りがききません。また、生物は直線移動はしません。これらを踏まえて、ここで言う生物っぽさを定義します。

・その場で回転しない。

 出来る生物もいるが、今回は無しとする。

・大回りしたりしなかったりする。

 どれだけ小回りがきくかは生物の種による。

・完全な直線は描かない。

 ちょっとうねうねしたりする。

 私が勝手に超単純な条件を定義してしまいましたが、定義を複雑化するとアルゴリズムも大変になり、またそのライブラリを使うのも大変になります🤔 今回はこの条件で生物っぽさを表現したいと思います。

アルゴリズムの説明

小回り度

 まず小回り度と言うものを定義しました。これは、その生物がどれだけ小回りがきくか?を示す値です。

f:id:takumus:20180131141448p:plain:w300

 上の図は小回り度がRの魚の例です。この魚はターンで描ける最小の円の半径がRです。このRが小回り度です。この小回り度という概念がルート計算のミソです。

スタートとゴールに向きがある

 はじめにも書きましたが、今回はスタートとゴールが位置のみではありません。位置と向きです。っぽさのの条件の1つとして、その場で回転できないと定義したので、スタートとゴールにも向きがなければなりません。

とりあえずスタートからゴールに移動するには

 一旦、完全な直線を描かないという条件を捨てて、スタートからゴールへの、小回り度を満たすルート計算方法を考えてみます。

f:id:takumus:20180131143217p:plain:w300

 スタート(P1)とゴール(P2)、それぞれの位置からベクトルに対して±90度になる位置に円(半径は小回り度)を書きます。その円と円の必要な分の共通接線を書くと、上の図のようになります。更に、円の孤と接線をたどれば、小回り度を満たしつつP1P2へたどり着くためのルートが見えてきます。

f:id:takumus:20180131144255p:plain:w300

 その方法で、実際にルートを書いてみました。重なってしまうので、ルートの線を少しずらしています。(見にくくてすみません)今回、ルートは全部で4つあるようです。共通接線の方法だと、ルートは最大で4つ、最低でも1つ生成されます。

わざとうねうねさせてみる

 生物っぽい条件の中でまだ満たしていないのは、残りの完全な直線を描かないだけですね。
 小回り度を満たすルートは生成できましたが、もちろんまだ生物っぽさが足りません。直線と正円の孤で生成されたルートは綺麗すぎます。強いて言うなら車っぽいでしょうか?
 うねうねといえばsin、cosですね🤔。私は高校3年の最後の数学のテストを0点取るくらいには数学が苦手で、大学に入ってからちょっと手を出したくらいです。そんな私が「うねうねといえばsin、cosですね🤔」などと語る事をどうか許してください。誰でも最近知った言葉とか使いたくなりますよね?今私はそれです。

とりあえずまず直線に対してsinを適用してみる
f:id:takumus:20180131153936p:plain:w500

 まずP1からP2に移動するだけの直線ルートを用意しました。これをsinでうねうねにしてゆきます。

f:id:takumus:20180131154156p:plain:w500

 まず単純にベクトルに対し直角の方向へsinを適用しウェーブしました。しかし、うねうねのせいでP1のベクトルとずれてしまいました。また、P2に至ってはゴールがずれています。sinも使い方を気をつけないと、このように暴れてしまいます。
 これらの2つの問題を同時に解決する方法を考えました。単純な方法です。これにさらに上から大きなcos(-π ≦ θ ≦ π)を掛けます。

f:id:takumus:20180131154847p:plain:w500

 するとこうなります。sinでうねうねさせ、ルートの中間で遊びつつ、ちゃんとゴールへたどりつきます。

ついに完成...!

 一言で言えば、小回り度によって書かれる円との共通接線と孤を利用したルートにsinとcosを与えただけです。以下の図は、こののアルゴリズムで生成したルートでのす。

虫っぽいルート
f:id:takumus:20180131155503p:plain:w250 f:id:takumus:20180131155536p:plain:w250
魚の泳ぐ感じのルート
f:id:takumus:20180131155657p:plain:w250
中間点を設けたルート(補助線あり)
f:id:takumus:20180131155731p:plain:w250f:id:takumus:20180131155812p:plain:w250

 こんな感じです。どうでしょうか!生物っぽさを感じますでしょうか?

ライブラリ

 このライブラリはTypeScript製です。JavaScriptかTypeScriptで使えます。次回の記事で、ライブラリの使い方とサンプルについて説明します。まだドキュメントもないので全く使い物になりませんが、一応おいておきます。 github.com

インストール

npm install routes @types/routes --save --registry http://npm.takumus.com

3Dプリンタでニンテンドースイッチのスタンドを作った!

久々の更新です。

大学四年になりました。就活の時期ですが、最近、ニンテンドースイッチでゼルダをするのにハマっています…!
スイッチはテレビでも遊べますし、ポータブルにもなります。もう本当に素晴らしいゲーム機です。充電しながら立てられないこと以外は!

スイッチをお持ちの方はわかると思いますが、本体から生えているスタンドは充電しながら立てることができません。

ライセンス商品として、プレイスタンドがあるのは知っていますが、僕の持っているキャリングケースには収まらない気がして買うのを控えていました。(収まったよ!と言う方コメントお願いします。買います)

そんなわけで、3Dプリンターでスタンドを作ってみようと調べていたら、海外の方が超画期的なスタンドを自作しているのを見つけました。

紹介動画

※動画投稿者と3Dデータの製作者は異なるっぽいです。 www.youtube.com

ジョイコンを差し込むところに付けられる分割型のスタンドです。薄いのでキャリングケースにも余裕で入ります。本当に天才的な発想です。
早速プリントして使ってみたのですが、いくつか問題がありました。

問題点

3Dプリンターの設定が難しい。

動画の通り、スタンドは上から差し込みます。なので、スイッチ本体の重さで落ちてしまうのです。
f:id:takumus:20170416113513g:plain
素材を厚めにプリントすれば摩擦も大きくなるので落ちる心配は無くなります。ただ、本体の重さを支えるほどの摩擦なので、装着時にレールに大きめの負荷がかかると思います。

長く使えない。

初めは固定されたとしても、何度も使うことで素材が削れて滑るようになるかもしれません。

純正の充電ケーブルを使うと足が浮いてしまう。

海外の方も動画内で、純正のケーブルだと使いにくいから別のなら使えると紹介しています。
足が短いので端子が地面についてしまいます。

これらの問題を解決するため、基本構造をパクリつつ、俺バージョンを作ってみました!

パクって作った俺バージョン

※カチッと言う音が鳴るので音あり推奨です。 www.youtube.com Fusion 360で作成しました。 f:id:takumus:20170415133038p:plain スライド用のT時の部分は海外の方のものとほぼ同じです。それに加えて先端にロックをつけました。つまんでいる間はロックが外れるようになっています。ジョイコンの仕組みと同じです。
f:id:takumus:20170415133140p:plain f:id:takumus:20170415171653p:plain CAD初心者が頑張って作るとこんなスケッチになるので本当にすみません。
f:id:takumus:20170415140343p:plain

改善点

プリンターの設定や精度に依存しにくくなった気がする。

あそびを多く取って設計しました。そのためスムーズにスライドします。でも滑り落ちることはありません。ロックがついているのでカチッと止めることができます。

長持ちすると思う。

遊びが多いので、スライドをしても負荷がかかりにくいと思います。ジョイコンよりも緩く設計したつもりです。そのためスライドによってパーツが削れることも少なくなったのではないでしょうか。

純正ケーブルでも大丈夫でしょう。

長めに取ったので問題はなさそうです。 f:id:takumus:20170415134049p:plain

純正キャリングケースに入った。

これは改善点ではなく、長くはなりましたが一応入りますという報告です。

3Dデータ

こちらからダウンロードできます。
www.thingiverse.com 現状、ノーマル版とミニ版があります。
※ノーマル版を推奨しますが、もしもお持ちのプリンターに入りきらない場合はミニ版を使用してください。
ミニ版は少し短いため充電ケーブルがやや干渉します。そのためノーマル版よりも傾斜があります。

これから

もう少し機能追加版を作ってみたい。

角度が変えられたり、ケーブルをまとめられたり等。色々思いつきますが、 高品質なプリンターでしかプリントできないような細かいギミックはもう少し検討しようと思います。
そういうバージョンとして別に出すと言うのもアリですね。
※私はGenkei社のLepton 2を使用しています。

Fusion 360

装着部分だけ3Dモデルを切り離すことに成功しました。Fusion 360難しいです。
ですがこれでスタンドのバリエーションを増やすのも楽になりそうです。
f:id:takumus:20170415170603p:plain

自転車のホイールにお絵描きした

まえがき

なぜ作ったか

 私の通う大学には1年間かけてグループで何かを作る「プロジェクト」というものがあり、私は「自転車をスマートに!」というテーマのプロジェクトに参加しました。
 他のメンバーは、自転車にウインカーを付けたり、自動変速機(開発担当の記事へのリンク)を付けたり。私もそれらを手伝う予定だったのですが、急に思いついてしまったので残像ディスプレイというものを考案しました。残像ディスプレイと言うのは私が名付けたのですが、簡単に言うと、数十個のledの列が回転しながら点滅して残像で絵や文字を表示するものです。既にそのような製品は割とあるので、ご存知の方は多いかもしれません。

f:id:takumus:20161223234036j:plain

既にあるのになぜ作ったか

 既にある製品は、自転車のタイヤに絵を描画するためにsdカードなどのメディアを経由するものが多く、車輪を一時的に停止する必要があります。(後日調べたらbluetoothで転送するタイプの物がありました。まじで悔しいです)
 そこで、スマートフォンなどで描いた絵や文字をリアルタイムで転送する仕組みを取り入れたらもっと面白くなるのでは!と思い制作しました。

プロジェクト発表会での展示

お絵描き体験

www.youtube.com スローはこちら
 PCに表示したQRコードを読み取り、スマートフォンで描いた絵がタイヤに反映されているのがわかります。プロジェクト発表会は、それぞれのブースに見学者が見にくる形式なので、自分のスマホで描いた絵をタイヤに送信できるという体験をして貰うことにしました。

具体的な説明

写真

全体像です。 f:id:takumus:20161221142546p:plain ラズベリーパイとモバイルバッテリーが積んであります。 f:id:takumus:20161221142923j:plain シフトレジスタとLEDを付けた基板です。 f:id:takumus:20161221142910j:plain 半田頑張りました。 f:id:takumus:20161221142935j:plain 基板からのケーブルはラズベリーパイに刺せるようにしています。 f:id:takumus:20161223112515j:plain タイヤから外した全体像です。 f:id:takumus:20161223112600j:plain ※ケーブルの色が違いますが、写真を撮った時期が違うのです。

ハード面

 LED表示部分の基盤はシフトレジスタを大量に使用し、5本位の線で制御しています。またリードスイッチと磁石を組み合わせる事で回転数を取得し、LED点灯のタイミングを制御しているので、低速でも高速でも乱れる事なく表示ができます。
 ラズベリーパイにつながっているケーブルはリードスイッチとLED制御線のみで、開発においてはハード面よりもソフトウェア面の方が大変でした。

ソフトウェア面

 今回、展示用にQRコードを読み取ってもらい、ブラウザから絵が描けるという体験を実現させました。ブラウザからタイヤにデータを送るのに、そこそこ多くのレイヤーを挟んでいます。

お絵描きツールと、お絵かきサーバー

f:id:takumus:20161221154608p:plain  見学者にすぐ絵を描いてもらうためには、ブラウザという選択肢一択でした。canvasは直接触るのは大変なので、PIXI.jsを使ってお絵描きツールを作りました。このお絵かきツールは描いた線の座標情報をサーバーに送信する機能しかありません。座標情報は、node.jsで立てたhttpサーバーに送られ、そこから動画右下に置かれたPCに送られます。
 線を描くごとに(タッチリリース時に)データ送信をしているのですが、時々失敗するので一応送信ボタンもあります。ちなみにこのお絵かきツールの自転車のホイールイラストはスクリプトで描いています笑

 今回展示用という事でたくさんの人がQRコードを読み取り絵を描きます。しかしこの仕様だと、例えば体験を終えて部屋の外に出た後もそのURLから絵を送信する事ができてしまうので、いろいろと問題になります。 今回それらを徹底的に対策しました。
 QRコードで取得できるURLを、http://~~.com/?hogehogeこうしました。最後にハッシュ値を加えています。そして見学者が入れ替わるごとにハッシュ値を更新し、QRコードを再生成します。クライアントは送信時にこのハッシュ値をサーバーに送り照合します。サーバーはそのハッシュ値が最新のものでないと絵の受信を拒否する仕組みにしました。これで問題は解決です。 f:id:takumus:20161221155141p:plain

お絵かきデータの変換

 お絵描きサーバーから送られた座標データは動画右下に置かれたPCで残像ディスプレイ用データに変換されます。この変換ソフトはAS3で書き、AIRアプリケーションとして動作しています。変換には、やや重い処理が必要になるのでWorker(スレッド)を立てて処理しています。
 変換自体もサーバーでやりたかったのですが、時間がなかったので自分が得意なAS3で実装することになりました。それ以外にも色々な理由はありますが!
 変換されたデータはいよいよラズベリーパイへ送ります。ラズベリーパイはPCと同じネットワークにつながっているのでローカルネットワーク上でデータをやり取りしています。

LED制御

 PCが送信したデータはラズベリーパイ上で走るnode.jsサーバーが受信します。サーバーはchildprocessとしてC++で書いたled制御プログラムを走らせていて、受信したデータをchildprocessへ標準入力で渡します。
 C++で書いたled制御プログラムは、複数スレッドで構成されています。データ受信スレッド、回転数検知用スレッド、led点灯用スレッドが主なスレッドです。なので回転しながらスムーズにデータを受信したり、回転数にあわせてledを点灯する事ができます。回転数に合わせてledを制御する細かいロジックについて解説すると、とても長くなってしまうので省略させていただきます。最後に貼ったソースをご覧ください。

さいごに

ソース

github.com 終盤追い込みで開発したので、ソースや設計が汚いのと、階層がぐだぐだなので許してください。
一応少し大まかに階層を分けておくので、興味のある方はご覧ください。

ラズベリーパイ側のC++とnode.js部分

/server/src

PCで絵を変換する部分

/client

お絵描き用のWebページ部分

/web_client

お絵描き用のサーバー部分

/web_server

お礼

 ここまでお読みいただきありがとうございました。質問などございましたら、me(あっ)takumus.comまたは@takumusまで。

ListUI for as3を作った。

FLASHer その2 Advent Calendar 2016の20日目の記事です。

github.com

どんなライブラリなの!

 タッチでスクロールが出来てドラッグで並べ替えが出来る気持ちの良いListUIライブラリです。リストのセルや右側に出るスクロールバー等、すべてが拡張(自作)することを想定して作られているため、使用のハードルがやや高いかもしれません。デフォルトスキンなどが存在しません。作ってください!
 最近は特にflashはオワコン!とか言われてはいますが、AIR等を使ったアプリやソフト。そういったものは意外と世の中で生きています。(展示物系等でも多いです。)そういった部分で必要になったので作りました。
 as3がある程度分かる人に向けた解説になります。分かる人はgithubのサンプルのソース読んでください笑。

サンプルを用いて解説

サンプルを用意しました。
サンプルの機能:
・セルをタッチすると、そのデータがログに出る。
・右の方をドラッグで並べ替え。
・左の方クリックで削除。
・ドラッグや削除でデータに変更があるとログに出る。

f:id:takumus:20161219182319p:plain

demo : http://takumus.com/labs/list-ui-for-as3/samples/demo/
demoのソース : github.com

Listクラス

demoのメインクラスである、Demo.asから重要な部分を切り出しました。
gist.github.com  Listクラスは、初期化時にセルクラス、セルの高さ、セル同士の間隔、スクロールバークラスを要求します。 必須なのはセルクラス、セルの高さだけです。セルクラスについての説明は下で行います。
 Listにデータをセットするにはlist.setDataを呼びます。Arrayを渡すだけです。demoでは、A~Uまでを渡しています。
 セルから送られてくるメッセージを受け取るには、ListEvent.MESSAGEを追加します。メッセージについても下で解説します。
 Listのデータに変更があった場合、ListEvent.UPDATEが発火されます。この時、変更後のデータはlist.getData()で取得できます。

ListCellクラス

 demoのSimpleCell.asを見てみましょう。これはDemoのセルクラスです。削除ボタンや、ソートボタン、そしてラベルなどが配置されているのが分かります。List初期化時に渡していたセルクラスとはこれの事です。ListCellを継承して作ったオリジナルのセルです。このように渡すことで、Listはこれを生成し画面に配置してくれます。

resizeメソッド

 ListCellにはresizeというメソッドがあります。これはCellがレスポンシブであるために用意されたもので、Listのresize時に呼ばれます。SimpleCellでもresizeをオーバーライドして、テキストやボタンの位置、背景の再描画を行っています。基本的にはresizeはオーバーライドしてください。

setDataメソッド

 ListCellにはsetDataというメソッドがあります。これはセルのデータが更新された時に呼ばれます。今回、ListにsetData("ABCDEFGH...".split(""))という具合でStringの配列を渡したので、setData(data:CellData)のdata.dataはStringになります。(ジェネリクス使った方が良かったですね。今度直します。)
 例えば今回のSimpleCell.asで、setDataメソッドは
_label.text = data.data.toString();
と実装されています。dataはCellDataなのでdata.dataとしなければいけない事に注意してください。

クリック、タッチ、そしてmessage、remove、sort...

 細かい解説の前に、注意点があります。タッチイベント、マウスイベントはどちらも必ずListCellMouseEventを使います。bodyに対して通常のマウスイベントやタッチイベントを追加してはいけません
 その理由として、例えばスクロールのためにセルをドラッグしてリリースする過程で、通常のイベントは、タッチもしくはクリックを発行します。スクロールしたときはイベントが出ないようにしたり、その他おかしな挙動が起こらないようなListCellMouseEventを定義してあります。なのでこちらを使いましょう。  SimpleCell.asに、このような記述があります。これはCellがマウスや指によって押された時の処理です。 gist.github.com  まずListCellMouseEvent.MOUSE_DOWN時に、マウスが右の方(ドラッグアイコンの位置)だったら、beginSort()を呼んでいます。これはListCellのメソッドで、as3で言うstartDrag()のようなもので、ドラッグアンドドロップによるソートを開始するというものです。マウスやタッチが解除され次第、勝手に終了するので、ソートを開始させたいボタン等がListCellMouseEvent.MOUSE_DOWNされた時にbeginSort()を呼べばdemoのような挙動をします。ソート完了時、ListEvent.UPDATEを発火します。
 次に、ListCellMouseEvent.CLICK時に、マウスが左の方(削除アイコンの位置)だったらremove()が呼ばれています。これもListCellのメソッドで、このセルを削除するという命令を出すものになっています。これが呼ばれた瞬間削除されます。削除確認ボタンを点けたい場合は、自前で実装してください。※削除完了時に、ListEvent.REMOVEを発火します。
 また、マウスがセル自体をクリックした場合にmessage()が呼ばれています。これは、ListCellからListへメッセージを渡すことが出来るListCellのメソッドです。引数に何らかのデータを入れることも出来ます。
 今回、message("Hi. My data is [" + data.data + "]")となっていますので、demoではセルタッチ時にログにこのようなメッセージが出ると思います。これは、Listクラスのインスタンスに対し、ListEvent.MESSAGEでハンドル出来ます。Demo.asを見ていただければ分かると思います。

スクロールバーのカスタマイズ

 正確にはバー自体をドラッグでスクロールする事はできないので、ただのスクロール(する位置を示す)バーですが!
 これについては、SimpleScrollBar.asを見ていただきたいと思います。
 resize時にレンダリングするようにresizeをオーバーライドするだけで完了です。new List()するときに4番目にそのインスタンスを渡せばよいです。

ListCellのインスタンス生成数とデータ数の関係について(割と重要)

 今回のUIは、ListCellのインスタンス数を極力減らすように心がけています。画面内に収まる最低の個数だけ生成し、データ数が1万件あろうが画面に5セルしか表示できないのであれば5つのインスタンスしか生成しません。
 これにより、パフォーマンスの向上を実現しています。一つのセルインスタンスとデータは対になっている訳ではないので、設計時は注意が必要です。setDataが全てです。

謝罪

 ライブラリの開発経験も浅く、自分のライブラリの説明などしたことが無いので随分とごちゃごちゃしてしまいました。それでも使用してくださる方がおりましたら、長い時間をかけてサンプルを見て解読していただくか、私に連絡していただけると幸いです! → me(あっ)takumus.com

ArduinoでDVDドライブのステッピングモーターを回す(スイッチでキャリブレーションする)

DVDドライブのモーターの回路は↓で紹介しています。 blog.takumus.com ステッピングモーター制御ライブラリSuteppaについては↓です。 blog.takumus.com

 DVDドライブのモーターがSuteppaを使って回せる!という事は紹介しました。そこで今回はもっと実用的なデモを行います。

私が手に入れたDVDドライブの仕様

 キャリブレーションの前に、まず私の手元にあるDVDドライブの仕様を調べましょう。以下のようになっています。
f:id:takumus:20161016124250p:plain  センサー部分が上下に動くように、軸がネジ状になっています。また、一番下に一番端に来たことを調べるためのスイッチが付いていました。
 一番下から上まで大体488ステップ(1-2相励磁で)必要なことも分かりました。ではこの仕組みをそのまま利用してセンサーを上下させてみたいと思います。

キャリブレーションする

 ステッピングモーターが現在の角度を把握できない(ロータリーエンコーダーなしで)という事はご存知だと思います。そんなステッピングモーターを制御するにはまず初期角度を設定する必要があります。こういった処理をキャリブレーションと言います
 今回は、とりあえず最大まで回してスイッチに触れたらそこをhomeとする。みたいなキャリブレーションを行いたいと思います。

スイッチへの食い込み?

 注意しなければならないことがあります。既にスイッチに深く食い込んでしまった状態でキャリブレーションを行うと、キャリブレーション開始と同時にその地点がhomeになります。モーターの力とスピードでスイッチを押した時と、元々押されたスイッチとで、homeにずれが生じます。

スイッチへの食い込み対策

 それを解決する方法として思いついたのが、まずスイッチ方向へゆっくり近づくのは同じですが、スイッチを押したら少し逆回転させ、再びスイッチを探す。というものです。確実にスイッチをモーターの力とスピードで押す。こうすることで正確なキャリブレーションが行えます。

スイッチへの食い込み対策の利点

 この方法を取る利点はもう一つあります。キャリブレーションは正確に行うため、基本低速で行うべきなのです。しかし、バーがスイッチから遠かった場合、スイッチに到達するまでとても時間がかかります。そこで今回の方法のように2度スイッチを押すことで、1度目のキャリブレーションを高速化し、スイッチを押したら2度目はその場所から少し戻り、ゆっくりキャリブレーションをするという事が出来ます。

ソース

gist.github.com

動画

 右側にスイッチがあります。一度右端に行って、ちょこっと戻る動作が確認できると思います。これがキャリブレーションです。その後は、紙で作った矢印とマーカーの位置から、正確に動いていることが分かると思います。
 Arduinoをリセットしてキャリブレーションからやり直させる。というのを何度か行っています。 www.youtube.com