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

まずデモ

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

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

 魚などの生物の群れの動きをシミューレーションするアルゴリズムでは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まで。