球体POV neon final

はじめに

 

2015年から球体デバイスを作成しています.

もともとのアイデアは2015年のハッカソンから始まって,MakerFaireTokyo(以下MFT)でも展示させていただいています.

初代は


www.youtube.com

 

下はそこからパターンをきれいに表示させることができるようにLEDの数を増やしたもの


www.youtube.com

 

と,ここまで来るとLEDの消費電力など限界が見えてきたにも関わらず,ある欲求が首をもたげてきます.

これで絵を表示したい!

 

 

 

 

....という話は

tajmahal0707.hatenablog.com

 こちらで語っていますので,こちらではPOVに移行してからのお話を... 

今回の球体POV

 

2018年から球体デバイスをPOV化した取り組みを行ってきており,現在第3世代が進行中です.

今年はfinalの年と位置づけて,完結を目指しています.

 

POV=バーサライタとは一列に並べたLEDを高速に移動させ,残像現象を利用して映像を表示するディスプレイです.映像を呈示するのに大量のLEDを用意する必要がなく小型・低消費電力化できる点や,回転体(今回の球もそう)であれば立体的な映像表現が可能になる点が利点となります.

 

第2世代(2019)では


www.youtube.com

 

ここまでできていましたが,いくつかの問題点が未解決なのでした.

特に重要なのが次の2点.

  • LEDがフルカラーで表示することができなかった
  • 姿勢センサが機能していなかった

俺,ここを解決して完結するんだ...(死亡フラグ

 

 

そしてこの課題解決に加えて,

  • M5Stack基板 → オリジナル基板への変更
  • それに伴う構造部分の再デザイン

という大きな設計変更を行っていきます.

全体デザイン

球体ディスプレイ「neon」は直径10cmとかなり小型のディスプレイです.

このサイズはこのプロジェクトの元々のモチベーション「映えるジャグリングデバイス」が出発点となっていることから由来しています.

私はジャグリングの中でも「コンタクトジャグリング」という種類のジャグリングを練習しており,このボールがディスプレイだったらステキだ,と思ったのが開発のきっかけです(このあとジャグリングよりも電子工作にのめり込んでいったのですが...)


www.youtube.com

 

このボールにいろいろな映像が表示され,なおかつ転がしても映像が回転しなかったらどうでしょう?

ステキだと思いませんか?

このボールの直径が基本10cmなのです(もちろんサイズ違いもあります).

 

そのため

  • 手の上に乗るサイズ(10cm)
  • ボールとして転がすことができる構造(ボールの外側には何も無い状態)
  • 回転しても全面がディスプレイになるレイアウト

が「neon」ではとても重要な要素となるのです.

そのために基板・バッテリー・モーター・センサなどのユニットはすべて回転するLEDよりも内側に収納する必要があります.

 

基本構造の模式図を以下に示します.

模式図

以後の用語は上の表記を用いて説明します.

この図で言うと,回転するのは,④ベアリング,⑥LED基板,⑦スリップリングが回転し,それ以外は静止しているレイアウトになります.

 

最終版「neon」のコア部分はこのようになっています.


www.youtube.com

いろいろ装飾が入っていますが,おいおい説明していきます.

 

回転部分の設計

回転部分 詳細図

回転部分は上のようになっており,

厚さ5mm(内径90mm)透明の外殻の内側にLEDが配置されるリング状の基板(外径84mm,内径77mm)があり,回転軸には上部にモーターモジュールが配置されてます.回転部分はモーターの回転を受けるギヤがついており,外殻とコアを繋ぐシャフト内には外部からの給電用電源線が通っています.

この部分が唯一映像が表示されない部分であり大きな欠点ではありますが,片持ち梁で回転体の根元を支えることで反対側では隙間なく映像を表示することができるようになっています.

 

下部にはスリップリングという部品が配置されています.

slipring-japan.com

今回のように回転体にLEDが配置されている場合,そちらへの給電・信号を伝達する必要があり,そのようなバーサライタの方式にはいろいろなタイプがあります.

prototype09.com

neon」はこのページいうところの3の手法を採用しています.

理由は,球体の中に閉じ込めて転がしたりすることの特性上,回転体の重量が大きくなるとジャイロ効果によって本体の転がり回転をバーサライタの回転が邪魔することで,まっすぐ転がらなくなってしまうためです.

実はそのために外殻の厚みをわざと厚く取っています.外殻とコアの重量を重くすることで全体に対する回転体の重量比を圧倒的に小さくします.そうすることで回転体のジャイロ効果を相対的に無視するような方針を取っているのです.

 

しかしこのスリップリングには欠点もあり,

  • 耐久性が低い
  • 回転に伴うノイズの発生
  • 高回転に使える製品が少ない,高価
  • すぐ欠品する...

私の採用しているスリップリングは下記のaliexpressで$15くらいで購入した製品ですがすでに欠品で画像のみ残っていました(もう購入履歴のリンクも無くなっていました...)

今回はこのスリップリングを採用しますが,今後のために代用品を探しておかないといけません.

現時点で1000rpmに耐えて,超小型のスリップリングには下記のものがあります.

ja.aliexpress.com

MMC118は250rpmまでですが,高耐久・軍用のMMC1189は1000rpmまで使えます.しかし値段が......

ということで引き続きwatchは続けます.

最近いろいろな方がスリップリング採用していて,普通のスリップリングを1000rpmあたりで使用してもノイズは出ないようです.

もちろん耐久性は下がってしまうのでしょうが...

 

シャフト

シャフトは強度に直結するので,3Dプリンタではなく金属(真鍮もしくはアルミ)で作成したくて旋盤で加工しています.

シャフト

個人での開発において,この真鍮やアルミの金属加工はとても敷居が高かったです.私自身は機械工学科出身なので授業で旋盤を経験していたりしたのですが,そもそも旋盤を個人が扱える場所がほとんど無い状態です.

以前はTechShop Tokyoで旋盤が扱えたのですが,どんどん閉鎖していっています.

fabcross.jp

idarts.co.jp

今もまだ探しているので,良い場所があったらアドバイスいただけると嬉しいです.

 

外部との接続部分も難しいところで第一世代の当時からずっと悩み続けていました.

第一世代はオーディオ用の4極ジャックを使ってUSB microの配線をコアに導入してそのままM5stackに接続していました.

2.5mm4極ジャック

2.5mm4極ジャック

  • マル信無線電機
Amazon

これはこれでも良かった(4chなのでUSB2.0の信号がそのまま導入できるため,そのままarduinoIDEなどでコンパイルしたものをM5stackに転送できた)のですが,プラグがズレたり何よりシャフト径8mmに対してジャックの外径も8mmとなってしまい,うまく収まらないのが課題でした.シャフトに内ネジ切ってジャックのネジをはめ込んで固定しようと思ったのですが,そうすると外殻とのネジ深さが減ってしまい,強度的に問題があったのです.

 

そこで今回は外部との接続は電源2極のみのマグネット型にしました.

plug

今回採用したものはこちら

ja.aliexpress.com

調べた限り雌側コネクタの径が最も小さい(4.9mm)商品だと思います.上の2.5mmピンジャックがφ6だったので,8mmのシャフトを想定すると肉厚が1mm程度(そこからさらにネジ溝を切るのでもっと肉厚は薄くなる)

これがシャフト内にφ4.9のコネクタが設置できて内径に余裕ができたので,シャフト肉厚が増えることから強度も上げることができます.

なにより磁石で「パチン」と留まる感じがキモチイイw

 

コア

コアには,

  • メイン基板・モジュール基板
  • LiPoバッテリー,電源管理基板
  • モーター
  • 回転量を計測するホール素子

が収納され,シャフト・スリップリング同軸に配置する構造体の役割を持ちます.

コア概要図

各基板サイズが37x25mmとなっており,これを内部に収納できるようコアの直径を55mmに設定しました.

 

コアの内部にピッタリ

電池も中に収納します.

 

コア径は55mmですが,そこから回転体の回転量を計測するためのホール素子と磁石を設置します.

第2世代はコア部分が円筒で,端が回転体ギリギリのところにあったので,ホール素子を回転体ギリギリの位置に設置できたのですが,今回はかなり空間に余裕があり,ホール素子を取り付ける部分が課題になっています.

そのためにコアの外側に飾りを取り付けています.

 

コアと飾りを分けている理由は,バーサライタの重要な特徴の一つは透過性なのです.画像が生成される面の後ろが透けているのが映像の浮遊感を産むので,コアはより小さいほうが画像面の後ろ側が見えると考え,なるべく後ろの透過量を増やしているのです.

とはいえ,透過した先がテクスチャのある飾りであれば透過した感じを観察者は感じてもらえるのでは,ということでツルッとした面ではなく,凸凹のある飾りをいれてみました.

最終的にどちらが良いか判断して,形状を決めようと思っています.

 

これらの構造物は3Dプリンタで出力しています.

レジンはSK本舗さんの水洗いレジンの銀灰です.

今回の「neon」の構造には関係ありませんが,見る角度によって銀色になるお気に入りのレジンです.

プリンタはELEGOO Mars3です.造形精度はかなり良く気に入っていますが,購入してから立て続けに故障しまして,2度もELEGOO社からパーツを送ってもらった結果,現在快調に動くようになっています.

初回トラブルはタッチパネルが押せなくなり,2度目はCPUとZ軸センサが逝ってしまったらしく,ゼロ点まで下げたときに「メリメリ」とゼロ以下まで下げようとするので,慌てて電源OFFな感じでした.

それでも写真と状態を説明したらどちらも無償で速攻で代替パーツを送ってくれたので,サービスが良いのか故障慣れしてるのかわかりませんが,治ったので良しとします.

FDM方式も所有していますが,サイズと造形性能の関係でSLAの方を使っています.

外殻

さて実はSLA方式の3Dプリンタを導入した最大の動機は,この外殻の作成です.

第一世代,第二世代とも外殻の作成には本当に苦労しました.型をFDMで作りそこに透明レジンを流し込む方法やアクリルを削る方法も考えましたが,結局できてもかなりシンプルな形状になってしまうため諦めていましたし,Maker Faire に展示したときも外殻から出して展示していました.

いろいろ設計したものをDMM.makeに透明アクリルで3Dプリントを依頼しようとしましたが,そのときの見積もりで3Dプリンタが買えてしまうことが判明して,自分で作ろうと決意したのでした.

そのあたりの奮闘記は以下のリンクで

tajmahal0707.hatenablog.com

tajmahal0707.hatenablog.com

このときは実験用でFDMによる出力でした.

今回はついに本番です.

 

じゃーーーーん

印刷範囲ギリギリですがちゃんと出力できました.打ち出し直後はほんとにキレイ.

そうそう.実は以前AnycubicのPhoton-Sを所有していたのですが,そのときに印刷範囲がギリギリ足らずに設計そのものを100mm→90mmに変更して設計したのですが,よく考えてみたらmars3なら印刷範囲足りるし解像度も上がってキレイなんじゃね?  となって買い替えまでしたのでした.

 

両面打ち出したものがこちら

ところが,実はこれ嫁さんが落としてしまい,割れてしまいました.

使用したのはSK本舗の水洗い透明レジンでしたが,やっぱり高靱性かタフレジン使わなければいけなさそうです.

高靱性で透明なレジンとしてはこのへんかな〜〜

 

 

②に続く

 

 

第3世代 POV neon ③

はじめに

 前回の続き

tajmahal0707.hatenablog.com

今回はソフトウェアの話です.

 

第2世代では主にハードウェアの実装がメインで,ソフトウェアは必要最低限のものでした.

www.youtube.com

f:id:tajmahal0707:20210617145805j:plain

このように単色,単一画像を表示し続ける...

これはこれで良いのですが,最終目標は

スマホ側から信号(例えば音楽など)に合わせて画像・パターンを切替える

②できれば動画として表示したい

③ジャイロセンサを用いて,ボールが傾いても画像が傾かない

 

①②については,ハードウェア的にスマホと通信する機能は実装済み,動画として大量のデータを読み込むためにESP32ボードにはSDカードを実装しています.

 

そして,今までも構想にはあったけれど実装してこなかった③についての考察は,

tajmahal0707.hatenablog.com

ここで行いました.

 

 

www.youtube.com

processing上でのシミュレーション結果です.

ちなみに動画中の球体は,回転する120x45 dotsのLEDの位置に小さな球を配置し,それぞれのLEDの座標とジャイロセンサの情報を元に上記ブログのプログラムから地球儀のテクスチャを用いて各LEDの画素値を取得します.

動画中ちょっと見にくいのですが,世界地図の上に細かい線が引いてあり,ジャイロの動きに合わせて更新されているのがわかるかと思います.これはボールの経線を表しており,リアルタイムに更新されているのがわかります.

 

しかしいくらESP32がデュアルプロセッサとはいえ,これらの計算には大量のatan2とsqrt, sin, cosが登場します.ここを近似計算にすることによって計算負荷を下げ,他の通信系や画像処理にリソースを回したいところです.

 

ちなみにこの動画での結果が早いのは,これらの計算をPC(Macbook Pro)で行っているからです.ESP32ではまだ試していませんが,もっと遅くなってしまうことが当然予想されます.

逆にPCとwifi通信して角度情報を送っているため,タイムラグが発生しているのがわかります.

ESP32の浮動小数点処理

基本的には先人がいろいろ検討をしており,それを参考にしているので今更感はありますが,m5stack(ESP32)を使う人には参考になるのでは,と思います.

何より自分用のメモ.

 

ESP32はディアルコアで浮動小数点演算を行うコプロセッサがあり,floatの計算は速いようです...

といいつつ,探していたらこんな記事も見つけてしまいましたが.. 

 

しかし最近はこうゆうものも出たらしいので, 

inajob.github.io

浮動小数点演算の勢力図はまだ変わっていくのかもしれませんね.

期待したいです。

 

各処理の速度演算については, 

watako-lab.com

このサイトなど くわしく検証されています.

 

今回は標準関数によるatan2, sqrt, cosの3つの計算を近似計算に置き換えたものと置き換えなかったものとで比較しました.

計算に使用したソースコードは以下においてあります.

github.com

atan2

 まずはata2の計算をESP32上で比較します.

使用するマイコンはM5stack-grey.

Arduino IDE上でコーディングし,比較対象はmath.hのatan2と以下のサイトにあった近似計算です.

garchiving.com

 参考ページの手法は,およそ±0.01° 以内の誤差で収まるようなので,このアルゴリズムでも4次近似式を使用します.

 M5stackはマルチコアですが,片方はUIや通常のloop関数を扱っているので,計算部分は別スレッドで行いました.

標準関数であるatan2()と,近似計算を行う_atan2()とを交互に20万回計算し,かかった時間をμ秒で計測します.

atan2に入力するx, yはテキトーに決めて,値を放り込みました.

 

その結果

atan2()で2669332μ秒程度.1計算あたり約13.3μ秒.

近似式_atan2()は7.44μ秒以下...2倍行かないくらい.

上のブログは因数分解していたりなるべく整数になるような工夫が入っているので,まあ妥当な精度でしょうか...

sqrt

 つづいてsqrt計算.

www.finetune.co.jp

このブログを参考にニュートン法による漸化式を適用して,10万回計算したときのμ秒を計測します.

 

標準関数sqrtで412234μ秒.1回あたり4.1μ秒.

近似計算_sqrtで1420166μ秒.1回あたり14.2μ秒....

あれあれあれ...

標準関数は専用の計算プロセッサがあったりするのかな..これは標準関数を使った方が良さそうですね.

cos

 つづいて三角関数

近似方法としてはたとえば

知っ得! 軽量sin/cos 計算アルゴリズム

 などにテイラー展開ミニマックス近似などの方法が載っていますが,今回は参照テーブルを使うことにします.

360度を10,000分割し,その値をテーブルに格納します.

そのテーブルを使って,入力値となるcosの値を参照する近似方法です.同様に10万回計算したときにかかった時間をμ秒単位で計測.

 

標準関数cosでは131849μ秒.1回あたり1.3μ秒.

参照テーブルcosでは90135μ秒.1回あたり0.9μ秒.1.5倍くらい高速化しているか.

 

 

とまあ,こんな感じでESP32ベースでの計算高速化を検討してみました.

まとめ

 ジャイロ(IMU)による情報からテクスチャを回転させることでボールが回転しても画像は変化しないプログラムを書きました.

ESP32のようなマイコンでこのような重い処理を行うには,かなり処理を高速化しないといけないので,ESP32プロセッサで近似計算による高速化がどれくらい効果的かを検討しました.

 

結果的には,atan2,cosなどの三角関数計算においては,ある程度効果が見られそうで活用しようと思います.

しかし,sqrtの計算は標準関数の方が速いので無理せずおまかせしようと思いますw

 

 

現在はまだボールのハードウェアを作成している最中なので未検証ですが,はやくソフトウェアのフェーズに入って実装したいですね.

 

 

 

 

 

 


 


第3世代 POV neon ②

はじめに

前置きが長くなってしまったので分けました. 

①はこちら

tajmahal0707.hatenablog.com

第3世代POV neon

はじめに

第3世代POVは,精度,性能,機能と大幅に向上することにしました.

大きな変更点は,

  1. 第2世代で大きく問題となったフルカラーLED問題.
  2. 外装の再設計
  3. M5stack → ESP32独自基板
  4. ソフトウェア

MFT2021までにどこまで実現できるかな?? (審査受かってればだけれどなw)

 

フルカラーLED問題

第2世代POVで使用したLEDはAPA102-2020.

www.digikey.jp

フルカラーLEDの定番,DOTSTARの製品ですが,上で述べたようにPOVで使うにはリフレッシュレートが足りないことが確認されています.

では,他にリフレッシュレートを上げることができる超小型フルカラーLEDは存在するのか? 

 

いろいろ探した結果,見つけました.

Fast digital rgb pixel 2020 led chip HD107sroselighting.wordpress.com

 なんとPWM rate 27kHz!!,データ更新レートは40MHz!!

これならいけそうだ!

 

 しかも配置もNEOPIXELやDOTSTARと同じピンアサインなので,使い方も慣れていてGood.

ただしこの界隈,パチモノが多いというか...

 

 同じような見た目で性能が変わる,なんてのがザラ...

地獄のようなハンダゴテを超えた後に変なもの掴まされてただのゴミと化すのは流石に辛い...

Rose Lightingさんというところが元のようなのですが

 

 

1000個単位でしか売っていないようなのです....

 それでもなんとか手に入れて,現在実装待機中です.

 

外装の再設計

第3世代POVは,外装も大きく変えます.

f:id:tajmahal0707:20191031152237p:plain

とはいえ基本的な設計思想は第1世代から変わりませんが,ちょっとづつ改良を加えていきます.

f:id:tajmahal0707:20210616163104p:plain

 まだ,最終に向けてデザイン変更あるかもしれませんが,現状こんな感じ.

中央のキューブの中で回転軸の支柱を囲むように基板と電池が収まる予定です.

 

第2世代から変更した点

シャフト部分

第1世代は3Dプリンタ製 → 強度不足

第2世代は既製品(ステンレススペーサー)の流用

第3世代では専用に設計したシャフトを旋盤で削り出します.

f:id:tajmahal0707:20210616170351p:plain

素材は加工しやすい真鍮.両端にネジを切ることによって短い接合部でも強度と剛性を保つことができると考えました.
しかし,大きな問題が....そもそも旋盤加工を行う場所なんてあるのか? 設備は?

私自身,大学が機械工学科だったので旋盤作業自体は行ったことがありますが,個人で旋盤作業を行うことのできる施設が無い...

白羽の矢を立てたのはTechshopTokyo.

www.techshop.jp

残念ながら2020年2月に閉鎖してしまいました..

しかし,その直前に入会して講習受けて旋盤してきました.入会したのは2020年の12月くらい....

 

え? もちろんその時にはTechshopが閉鎖するなんて知りませんでしたよ.ええ.講習代? もちろん支払いましたよ.

 

今も設計変更が入って新しく作り直さないといけないのに,今後どこで作業すりゃあいいんだ....orz

f:id:tajmahal0707:20210616174820j:plain

外殻部分

いままでの外殻は半球状のものを組み合わせましたが,第3世代では野球のボールのような構造のデザインに変更予定.

tajmahal0707.hatenablog.com

今回のMFTに間に合うかはわかりませんが,このような構造の外殻を作っています.

ただ,私の持っているAnycubic Photon-Sではサイズがぎりぎり足りないため,どうしようかなあと悩み中.

基板収納部分

いままではM5Stackを流用していたので,中央の基板収納部分のサイズはm5stackの基板サイズ50x50mmを超えることはできませんでした.

しかし,第3世代は専用基板を設計することにしたために,サイズの自由度が増えます.専用基板を設計することにした理由は以下の3点

  1. M5stackのサイズ制限からの開放.
  2. 精度向上のために中央の回転軸を固定するため
  3. M5stackの不要な機能の除去とIMU(ジャイロセンサ)の性能向上

①については,ボールの直径がφ100mm確定であることからM5stackを採用することは中央部分の空間を圧迫し,設計の自由度を下げてしまうため

②については,中央にm5stackが収納されるため,回転軸が途中で途切れてしまい,3Dプリンタ程度の設計精度だとやはり軸にズレが生じてしまうことから回転精度が低くなってしまうことを懸念したため

 ③については,M5stackはライブラリも充実しているし,よくできている製品だと思っていますが,今回の目的に対していくつかの機能は不要でいくつかの機能は性能不足,という点もあり第3世代は頑張って基板を起こしてみることにしました.

具体的には,M5stack のIMUはMPU9250もしくはMPU6886+BMM150による9軸センサですが,boshのBNO055がかなり性能が良さげなのです.

www.switch-science.com

実際使ってみるとキャリブレーションもほとんど必要なく精度良く計測できているようで今回採用しています.

問題点としては,値段が高いことと,基板に実装しようとするとQFNでもない特殊な規格のようで一人でホットプレートリフローするにはかなり難しい点です.

 

今回はESP32をベースに,このIMUを組み込んだ基板を作成しよう,ということにしました.

基板設計

新しくM5stack相当の機能を持った基板を起こします.ピンアサインの基本的な構成はM5stackとなるべく共通になるように設定します

f:id:tajmahal0707:20210617010703p:plain

基板は設置スペースの都合で2枚に分離,さらに電源も別にしています.

 上図のESP32基板(上段)には,

・U1:ESP32本体

・J1:SDカード( SPI経由での読み書き,ピンアサインはM5stack準拠)

・J2:PCと通信を行うためのUARTシリアル通信

・J7:2枚めの拡張ボードとの接続を行うためのコネクタ

拡張ボード基板(下段)には,

U2:Motion Sensor(BNO055)

・U3:Motor Driver(DRV8355)

・U4:RTC(PCF8563TS)

・J5:フルカラーLED(HD107S-2020)とのSPI通信用コネクタ

・J6:4ch汎用GPIOコネクタ(うち一つは回転検出用ホール素子に使用)

・J8:3.3V,5V電源入力コネクタ

 

という構成です.

ESP32ボードは汎用性を持たせるために最低限の接続しかしておらず,拡張ボードとはJ7コネクタを介してI2C,HSPI,DACx2,GPIOx4の接続ができるように設計しました.

拡張ボート側を見ると分かる通りまだまだ余裕がありそうなので,今後他にもいろいろと積めると期待しています.

上のESP32ボード側は大したハンダ作業ではないので今回はホットプレートリフローを初体験してみました.

対して拡張ボードの方は,上述したとおりBNO055のピン配置は素人の私ではリフローする勇気はなく,こちらも初めて中国に実装も依頼しました.

www.digikey.jp

いままで基板の作成はFusionPCBを利用していましたが実装が高いと感じていたので,今回はPCBwayさんに基板作成と実装を依頼してみました.

www.pcbway.jp

基板サイズは40x26mm,基板は10枚作成しそのうち5枚に実装を依頼しました.

基板作成・実装合わせて$200くらい.ざっくり1枚$40くらいでしょうか.部品代込みなのでこんなものでしょうかね...(BNO055が2000円くらいするのでかなり安い方?)

依頼して一ヶ月かからなかったくらいでしょうか.無事に届きました.

f:id:tajmahal0707:20210617014336j:plain

 左がホットプレートリフローしたESP32基板(裏にSDカードスロット有り)

右が拡張ボードです.

ESP32ボード下側のコネクタにUARTシリアル変換を差し込んでPCからプログラムを書き込むことになります.

動作確認も無事に終わり,すべてのモジュールの動作を確認しました.

 

そして,分離した電源回路

f:id:tajmahal0707:20210617015202p:plain

左が電源回路で,

右が電源のオンオフを行うためのスイッチ回路です

電源回路は,

・U1:LiPo Battery Charger(MCP73831)

U2:3.3V DCDC(LT1615)

・U3:5V DCDC(LT1615)

・U4:電源IC(XC6192)

という構成になります.

U1はLiPoを充電しつつ電源を供給できる構成としてMCP73831を採用.ここからはLiPo出力の3.7Vが出力されるので,分岐して各DCDCへ.

U2はESP32を駆動するのに必要な3.3Vを安定供給できるようDCDCを,U3はモータやフルカラーLEDを駆動するための5Vを安定供給することを目的に配置.

今後も汎用性を持たせたいので各DCDCの入り口にはジャンパーを配置して5V出力のみ,3.3V出力のみと切り替えることも可能です.

そして電源IC. POV neonは最終的にボールの中に収まることを想定しているので,電源ON/OFFの操作を行うことが難しい.

ボールから外部へのアクセスはwifi,BLE以外(これは通電していることが前提なので電源ボタンには使えない)には4chのオーディオピンコネクタしか存在しないので.このオーディオピンから供給される電源線を使ってON/OFFしたいと考えて採用しました.

4chのうち,2ch分はUSBからの5V入力とGNDとなり,残りの2chのうち1本を使って電源の管理を行おうというものです.

電源ICというのは,ボタン長押しで電源ONなどいくつかの機能的な電源管理を行うICのようで,本当はbattery chargerのような機能を持ったものもあるのですが,今回はスイッチ機能のみ採用しました.

f:id:tajmahal0707:20210617092229j:plain

 奥にあるのがスイッチボックスとなります.向かって右側にUSB端子がありこちらから給電し,左側からケーブルが伸びて4chマイクロプラグを介してneonに接続されます.

第2世代ではここからそのままPCに接続してシリアル通信を行うことができましたが,今回はそれは廃止.

基板のシリアルコネクタからUSBシリアル通信を行うことで,基板の省スペース化を実現しています.

さいごに

現在は,これらすべてのパーツを組み合わせて最終工程に持っていくフェーズに入っています.

ソフトウェアの改良は③で紹介しようかなと思っていますが,現状の設計状況を3Dプリンタで出力した結果がこちら

f:id:tajmahal0707:20210617092921j:plain

モーターとスリップリングを仮組みして精度を確認しています.

シャフトもまだ金属ではなく3Dプリンタで打ち出したもので試し中

f:id:tajmahal0707:20210617093034j:plain

シャフト末端のマイクロプラグはなかなか小さいものが見つからず,最終的には自分で削ることになりそうです.
 

③のソフトウェア編に続く

tajmahal0707.hatenablog.com

 

第3世代 POV neon ①

はじめに

 

球体POV(Persistent Of Vision)というものを作成しています.

tajmahal0707.hatenablog.com

タイトルの通り,球体POVとしてはこれで3世代目に入っています.

もともとのアイデアは2015年のハッカソンから始まって,MakerFaireTokyo(以下MFT)でも展示させていただいています.

初代は


www.youtube.com

このようにPOVではなく,LEDを配置(右上のものはLED32個)してスマートフォンからの命令で複数のボールのパターンを制御するものでした.

 

下はそこからパターンをきれいに表示させることができるようにLEDの数を増やしたもの


www.youtube.com

 

と,ここまで来るとLEDの消費電力など限界が見えてきたにも関わらず,ある欲求が首をもたげてきます.

これで絵を表示したい!

 

 

 

 

....という話は

tajmahal0707.hatenablog.com

 こちらで語っていますので,こちらではPOVに移行してからのお話を... 

POV neonの歴史

 第1世代

第1世代は 2018年のMFTにてお披露目しました.


www.youtube.com

 この世代はLEDに入手しやすいNEOPIXEL(APA102-5050)を使用しています.LEDの大きさが5mm x 5mmなのでどうしても解像度が上げられず,LEDを数も17個に留まっています.

解像度を上げるために半ドットずらして反対側にも配置して33LEDにまで高解像度化していますが,せいぜい国旗あたりまでの解像力でした.

 第2世代

第2世代は 2019年のMFTにてお披露目しました.

tajmahal0707.hatenablog.com


www.youtube.com

MFTでは画像を表示するところまではいけませんでしたが,その後画像を表示できるように...


www.youtube.com

第2世代ではLEDをDOTSTAR(APA102-2020)という2mm x 2mmの超小型フルカラーLEDに交換し,片側45LEDという高精細を実現することができました.

この第2世代はMFTに来ていただいた方々にも興味を持っていただけて,モチベーションになっています.

 

MFTでは間に合いませんでしたが,動画の後半のように地球儀を表示できているところをお見せでき,画像を表示できる能力を手に入れることができました.

ただ,せっかくLEDがフルカラーなのに地球儀は赤一色であることにお気づきの方もいらっしゃるでしょう.

このあたりHomemadeGabageさんらと相談しながらいろいろと検証しています

homemadegarbage.com

そのため,上の動画の前半をご覧になっても分かる通りパターンが流れてしまっていることがわかります.

そう.DOTSTARでも2020のサイズではPOVとして動作するには遅いのです.そのあたりの詳細はここで議論しています

homemadegarbage.com

要するに,DOTSTARはLED自体の更新レートは19kHzあるのですが,それはLEDをが100%輝度(0xFF)の場合のみで,フルカラーでLEDををコントロールする場合,RGBの各値を0xFFより小さくしますよね.その明るさコントロールをPWMで行っているため,更新レートが400Hzに低下してしまうのです.

現在のPOV neonが一回転の速度が12Hz程度(1秒に12回転).一回転を分解能120(3度刻み)で表示しているので,更新レートは1.5kHz程度.当然間に合わないわけです.

このあたりの考察はHomeMadeGabageさんのここを参照

homemadegarbage.com

こんなわけで第2世代で画像を表示する場合には単色8色しか使えないのでした.

 

これを解決するために第3世代が爆誕することになります.

そしてこれを機に,今までマイコンはM5Stackを流用していましたがここも基板から起こすことにしました.

そのため2年がかりの更新となってしまいました(MFT2020は落選しちゃったんですけれどねえ)

 

第2世代のこのあたりまでの経緯については,Make:Japanさんに記事にもしてもらいました.嬉しい.

makezine.jp

 

②に続く
 

tajmahal0707.hatenablog.com

野球のシーム(縫い目)のようなボールを作る②

はじめに

球体POVというものを作成しています.

tajmahal0707.hatenablog.com

 その中で,今は外殻に相当するボール部分を制作しています.

tajmahal0707.hatenablog.com

なかなかいいところまでは行ったのですが,肉厚が足りないのか,くびれが強いためか,かなり無理矢理嵌めなければならなかったので緩んで隙間ができてしまいカタカタ鳴るくらいユルユルになってしまっていたのでした.


Printed seam ball

今回はこの問題を解決するために,接合部分に凸凹の嵌合部をblenderベースで作ってみたので紹介します.

 

blenderプログラマブルに任意の軌跡のパイプを作りたい人には参考になるのではないかな,と思っています.

やりたいこと

前回のブログではB値の設定を変更(B=0.5→B=0.35)してもうちょっと調整しようというところでおわっていたのですが,その調整して打ち出したものがこちらになります

f:id:tajmahal0707:20191224133410j:image

 途中から色が変わっているのはフィラメントがなくなって継ぎ足したからですw

でもこれだとかなりカチっと嵌ってくれます.

f:id:tajmahal0707:20191224133439j:image

前回はB値が大きかったためくびれが大きくて嵌めるときにかなり無理矢理行かないといけなかったのですが, 今回はザクッと差し込むことができました.

 

懸案だったボール内へのデバイス収納問題も,B=0.5のときは無理そうでしたが今回(B=0.35)では無事収納できました.

f:id:tajmahal0707:20191224133402j:image

 (とはいえ,実は対のパーツを組み込むことができないことが発覚して,未だ未解決になってしまっているのですが....)

 

 

 

しかーーーーーし

 

最初はしっかり嵌っていたのですが,しばらくすると緩んできてしまいます.

というより,印刷時に付いているサポート材(一番上の写真にボールの上下についている円柱のような部分)が付いているときはパーツを閉じる効果が強くて嵌め合い時の力も強かったのですが,このサポート材を取り外したら閉じる力が弱くなってしまったようなのです.

前回よりはマシなのですが,やっぱりこれじゃあ心配だ.

 

そこで嵌合部に凸凹を付けてしっかりと嵌るように作ることにします.

要するに作りたいものはこんなもの

f:id:tajmahal0707:20191224132311p:plain

 各パーツに対して,一方はUNIONで

f:id:tajmahal0707:20191224135555p:plain

他方はdifferenceで

f:id:tajmahal0707:20191224135657p:plain

このような凹凸をつけてあげれば重ねたときにパチっと嵌るのではないか,と期待したわけです.

Blenderでの作業

前のプログラムを変更して作ります.

Blender自由形状のパイプを作るにはパスを作って,そのパスに沿って形状をbevelする必要があります.前回のPolygonを作るコードは下にあります.

github.com

 参考にしたのはこのあたり

gist.github.com

使うのはcurve operatorです

shuvit.org

pythonプログラムで前回作ったpolygonのvertex値をつないでパスを作ります.

f:id:tajmahal0707:20191224132328p:plain

 まずは原点にbezierのオブジェクトを置きます.

bpy.ops.curve.primitive_bezier_circle_add(location=(0, 0, 0))

このときに作られるベジェのオブジェクトはedit modeにするとわかりますが,制御点が4つしかありません.これから軌跡に沿ってvertexを追加していくので今回は最初の4点は下のコマンドで消してしまいます.

bpy.ops.curve.delete(type='VERT')

それが終わると前回と同じ方法でちょうどパーツの中間になる値(今回は半径50mmで肉厚5mmの球のため,パスの半径(SEAM_RADIUS)は0.475ということになります)

角度に応じた軌跡上の点(x1, y1, z1)を計算したらその座標を追加してパスを伸ばしていきます.

bpy.ops.curve.vertex_add(location=(x1,y1,z1))

角度を0〜360まで回すとパスは一周して完了です.閉じる処理も必要ですがそれは手作業でやっちゃいました.

 

同時に角度が0のときの位置(開始点:xx1)にパイプの形状を決める円を配置します.

bpy.ops.curve.primitive_bezier_circle_add(location=xx1)

ちなみに開始点は,一度座標値をプリントしてそれをコピペしただけですw

配置した円は,向き・大きさを手動で整えておきます.

xx2まで出したのはxx2-xx1のベクトルがパイプ断面の法線になると思ったのですが,開始点はそのまま垂直なので使いませんでした.

 

 

えい,実行

f:id:tajmahal0707:20191224132259p:plain

パスを選択して,プロパティからcurveを選ぶと右のようなプロパティが出てきます.

bevel object」という項目に先程作った開始点にある断面形状(今回は円)を選んでやると上のようなパイプを作ることができるのでした.

 

これを前回作成したボールパーツに対してそれぞれboolean演算してやることで,各パーツに凹と凸を付けることができるのでした.

f:id:tajmahal0707:20200429134717p:plain

f:id:tajmahal0707:20200429134853p:plain
ただし,このままだとbezier curveがカーブオブジェクトのまま(図中の赤丸で囲った部分)なので,「object」「convert to」「Mesh from curve」を使ってカーブオブジェクトをメッシュに変換します.

f:id:tajmahal0707:20200429135037p:plain

こうすることでbooleanで凹凸をつけることができるようになります.

 

 

 

これを3Dプリンタにもっていき,印刷開始!

f:id:tajmahal0707:20191224133334j:image

じゃん.

上が凸で下が凹.

f:id:tajmahal0707:20191224133330j:image

ちゃんと凹みを表現できています.

 

 

実際に組んでみると 

f:id:tajmahal0707:20191224133322j:image

こんな感じ!!


piped seam ball

一部白いのは,今回もフィラメント不足で継ぎ足しましたw

左にあるボールはこのブログの最初に印刷した嵌合部なしのもの.右の透明が今回打ち出した嵌合部アリのボール.噛み合いが全然ちがいます.

これは流石にぴったり.ほとんどズレません.フィラメントの消費量は殆ど変わらないのにこれくらい造形がしっかりしてくるのは面白いですね.

工夫すればするほど良いものになっていく.

 

本番は光造形で打ち出すため素材が違うので嵌合部がどれくらい行くかはわかりませんが,なかなか満足の行くものができました.

 

 

 

 

でも,まあそれよりもこのボールの中にちゃんと本体が収納できるようにしないと光造形までたどり着くことはできないんですけれどね.....

 

 

 

野球のシーム(縫い目)のようなボールを作る

はじめに

球体POVというものを作成しています.

tajmahal0707.hatenablog.com

 

その中で,いままで外殻と呼んでいる透明のボール部分があります.

https://lh3.googleusercontent.com/Uf2_TV6jprZZVTuVSbxgeRL0vNsFn95X3MUV9Wa08J1xl1_c-qAbspuhumKkybLSZIZ4xBLRbBYu1Gy8jln22aXxjpmEYkqa_3-ShQ8ObiE1U5huTyuOVC01fRSakYqwwcUTtFmZae0nRjeTf6v0UkyWZDW-rHuXTz3wPjKMVpiRhKdudED66Yb8JuNazHngNGqZ8rEV9sK4Jm-mKIR0mt5Xf81PDUdTiBw7rCMkFMmIKO1Gmy9rx16Wd0e04U3GDmXPEx1a1DAJmLmB4hKoZIKOeUjiH3Tzy5zYqyCVUe2nx0pVXD5kF5SpQXZlC7hbgCY94tUBfBf1nGydwRJ_T6K9rWnaRCZny8kYR0elMC1F7OHvuleacaWqLAbP-Zyh_3h6siClshtX38seLanCWMfIqMxFFiqPpqtcYMM5LAG4zFynaDhhHNbybrjcD26BwFWgtkM57VChjDgxe_RtyPxu35sF-PNUggGmSILYXcejsTBfUXKWkgVxVpwnNceZFsK6hDXZ56kfIk1QnFP3wNr-u4TxIHRXxYVpIlTv2qZU1CAxpONusyAdGbF6u5k0bf1v5OIezSGpVGcy0W3tmNsSVMWHrqmySFgW5TAbbnRMe67rQ16Ui1WUknJ3fQ8EIQYc8_7xbMT2_cHL1T12jxoFTxwfQxBlzNtXMF7YREoqcCZgqsv6T4Kwh62u4Zuqc8pzQEn7AnWE6esOQhH72Inxbmqikm3aA1Dtz6XCR55fcaeg=w1266-h1686-no

これはAnyCubicのPhotn-Sという光造形型の3Dプリンタで出力しています.

 

打ち出し直後はこんな感じ

https://lh3.googleusercontent.com/X5V4x8wDwkXxCDzfNz9UnewOZU0IFIfbrusuBCgULUPnQ-R5Rm94iSvGxU6J-9eAWGGy30PP6t_znukoiBLrjU2awtBik16-xX91X8fIZs5zf2rLqh8eR0EKHR5pw7oBVgFpRCn_B0begpYbzJJjq7a2HzNqjrHgWxIuP4hH71KjctWmiQVcuf_suGU0j2z07zyLCFzGmX7jDQ9A42PI5bfba83RUpe501Jq_5OPm9P0ctHrriuX32ucM0wk8KtHfk2znusNU3lVH_5rvjfz3VASRdDVcWL9f8G-9Y3aUkRu6QYU70zozfsQ-oKIXX8wJid996jnzt1xMuwX7y-eEUEGnnd85xD6hmFgh7Fj4JdQZ-IvCcgbDfd-IFK0U86NJk45lSVzBdmLa--TKqgX4-_FlPJqWc1vAwpbVRU_OfsSGMBC5mwgoIdbxELF7PPVP6zT8oGVIJ6RfWP09q4gMNiXgVph8gVoRibcqeyTT1xQYY0pm7l7lrHi5VlvTUKAMi8E-G4fGWMkdGQxU_2Nu8ZLx8JEwFXeVK5XtjT7kI9Cqb-5HMb7-HUq0nvD6Aa29cQ6ZflBLRmSWAY1XUKtZpYs2hpUJN18yByc1LVJzS-5XegxtCk53e6EHvyk4uDmngWhwiL7dDSz5fBwGbqfXYe3SUdag2r3VRZITosNaWoz2E_4i_xWFw2-rHprF8H4_gyUdlb710nh3ZOEjM8FPNWl1fswHmAhK87tszkQuyRExFqh=w1266-h1686-no

ちなみにこれが 初めてphoton-sで打ち出したものだったりしますw  photon-sの印刷範囲が116×65×165mm のところに100×50×100mmのものを印刷したのでかなりギリギリだったのに,ちゃんと打ち出すことができました.

ほとんどデフォルトの設定のままでこれだけ出せるんだから大したものです.

打ち出し直後。

f:id:tajmahal0707:20191220155150j:image

これを磨いて、
f:id:tajmahal0707:20191220155146j:image

クリヤコートを吹きます。(UV硬化樹脂で、UVで変色しやすいのでUVカット付き)
f:id:tajmahal0707:20191220155141j:image

もうちょっと磨けばよかったな

 

これはこれで満足のいく出来ではあったのですが,今回さらに新しく球体ディスプレイを制作するにあたりボール部分もデザインを一新しようと考えたのでした.

元ネタはthingiverseのこれ.

www.thingiverse.com

見た瞬間「これだ!!」と思い,さっそくダウンロードしましたねw

ところが,中に入っていたのはscad拡張子.全く知らなかったのでしらべてみました.これらしい。。

qiita.com

早速ダウンロードして開いてみます。

f:id:tajmahal0707:20191219021047p:plain

 

 

なるほど.

関数を記述して形状を作るタイプのやつなんですね.これならボールサイズや肉厚もパラメータ変更できそう。POV-RAYなんかと似てますね。

でもそれなら今後使うことを考えて、いつも使っているBlender & pythonで作りたいなあ,ということで作りました.

原理

野球のボールの縫い目に沿ってボールを2分割します.

 

数式は探したら出てきました.あるもんですねーー。

www.darenscotwilson.com

これをblenderに移植します.

単位球表面における縫い目の位置は次式で表されます.

{displaystyle egin{eqnarray}left{egin{array}{l}x_alpha &=& cos(alpha) - B sin(3alpha) y_alpha &=& sin(alpha) + B sin(3alpha) z_alpha &=& F cos(2alpha)end{array} ight.end{eqnarray}}

ここで,(x_alpha, y_alpha, z_alpha)が alpha (0.0〜2pi)における 縫い目の単位球面上の座標値.このとき式にあるBとFは,

 B: 縫い目の隙間の幅を決める係数

 F: 縦横比を決める係数

となります.上のリンクにある図で引用すると,

http://www.darenscotwilson.com/spec/bbseam/bbseam-B0p6_F1p0.jpg

B=0.4
F=1.0
B=0.6
F=1.0
B=0.8
F=1.0

 今回はなんとなくB=0.5でやってみました.

ソースコードはこちら。

github.com

えい.実行!

f:id:tajmahal0707:20191220151055p:plain

こんなかんじに縫い目が出来上がりました.

あとは,これを繋いでポリゴン化(ここのソースコードは気が向いたら公開します)したあとで,ボールとbooleanかけると,,,,
 

f:id:tajmahal0707:20191220143456p:plain

こんな感じ.

これをstl化してFusion360に持ち込みます.

f:id:tajmahal0707:20191220151554p:plain

うっわ.Polygon量デカすぎ. 遅い! ボールのメッシュがすべてPolygonになってしまっているのですね.fusion360などのCAD系だと球は関数ですから, booleanの作業はfusion360で行うことにします.

f:id:tajmahal0707:20191220151823p:plain

先程の縫い目をPolygon化したもの(簡単のため半分(0~pi)だけ制作)をstlまたはobj形式で出力します.

この際に,Polygonの面の向きとか法線方向,重複点などの処理が必要なのですが今回は割愛.自分用のメモなので.

興味ある方からリクエストがあれば手順を書きます.

 

読み込んだstlFusion360上でメッシュとして読み込みます.

読み込んだあと,

f:id:tajmahal0707:20191220152826p:plain

「メッシュからBRep」に変換することで,メッシュをボディに変換することができ,その結果Fusion360上でオブジェクト同士のブーリアン演算などを行うことができるようになるのです.

半分のseamを鏡面コピーして準備完了。

f:id:tajmahal0707:20191220153215p:plain

さらにouter_shell(φ100mmのボール)からブーリアン演算で,inner_shellとseamを2つ抜きます.

f:id:tajmahal0707:20191220153508p:plain

えい,実行!

f:id:tajmahal0707:20191220153619p:plain

できましたw

これに,neon向けに穴あけ処理などを施して,photon-sで打ち出す前に確認としてAnycubic i3 Mega で打ち出してみます.


f:id:tajmahal0707:20191220084020j:imagef:id:tajmahal0707:20191220084023j:image

出ましたねえ。

嵌め込みが結構大変だけれど、なかなかいい感じ。なんだけれど気になる点が3つ

・嵌め込みがキツい。結構無理やり押し込んでる感じ。

・その割には嵌った後がユルい。カタカタいっちゃう感じ。この中にPOV入れて干渉しないかしらん

・この隙間にPOVを通せるのか? 

 

ユルさはこんな感じ.


Printed seam ball

 

今後はBの値を0.5→0.35にして隙間を開けてみようと思います。

 

球オブジェクトが回転しても天地が回転しないテクスチャをつくる

はじめに

球体POVというものを作成しています.

tajmahal0707.hatenablog.com

こんな感じで球体に映像を表示することができるガジェットで

このように完全にボールの中に収納してバッテリー動作することができます.


球体POV

このようなガジェットを制作してると,当然やりたくなることがあります.

そう

転がしても天地が同じ(画像は回転しない)になるボール

近いイメージはこんな感じ?


映画『ジュラシック・ワールド』ボーナスDVD特典映像

 縁日のおもちゃとかでボールの中に液体があり,中の物が浮いているので転がってもその向きが変わらないおもちゃとかありませんでした? 名前が理解らなくて検索できませんでした.

やってみたいと思いませんか?  私はそう思います..

 

 

そこでそんなこともあろうかと,このガジェットのマイコン部分には

を採用しています.

内部にMPU9250を搭載し,センサフュージョンから自己の姿勢quaternionやオイラー角を算出することができます.

これを使ってボールが回転しても,表示する映像は回転しない機能を実装しようと思います.

球体テクスチャの基本

この球体POVは,画像でテクスチャを与えるとそのLEDの位置に相当する色をテクスチャから取得して画像を表示します.

そのときのテクスチャを扱いやすい形式で与えることで正しい像を表示することができます.ここでは貼り付ける画像を「正距円筒図法」に基づいたものと定義しています.

ja.wikipedia.org

例えばこんな画像です.

f:id:tajmahal0707:20191126111738p:plain
これは,パノラマ画像とも呼ばれ,近年のCG分野で球体に貼るテクスチャとしては比較的一般的なもので、メルカトル図法とは縦の比が異なる親戚のような図法です.(地図の表現法について詳しくはこのへんあたりを参照)

この画像は基本的にはよくネットでも拾ってくることもできますし,thetaなどの360度カメラでも出力モードに設定されているので,入手することはそれほど苦労することは無いかと思います.

 

この図法の特徴は

  • 緯度と経度がそのまま画像上の座標値(uv座標)になっている
  • 緯度と経度で作る長方形が正方形になる

一方で北極・南極に向かうほど歪みが大きくなってしまうという欠点があります.

 

この画像テクスチャを球体にマッピングすることを考えます.

通常はこの処理はGPUで行ってしまうのですが,マイコンで処理を行うために一つ一つばらばらにしてみます.

上の地球の図面を例に考えると,テクスチャ座標を(u, v)(ここで画像サイズに依存しないように正規化して{0.0 ≦ u, v ≦ 1.0}とする)とします.

つまり,左上が(u, v)=(0.0, 0.0)で,右下が(u, v)=(1.0, 1.0)となります.(ただし実画像では緯線(±90度)と経線方向(360度)の長さ比は1:2で経線方向が長い)

赤道が北緯0度.北極は北緯90度(-{\pi}/2),南極が南緯90度({\pi}/2)となっています.東経は360度で地球一周(2{\pi})することとなり,u軸方向の画像中央は東経0度(グリニッジ)上で、画像中央(東経0度、北緯0度。アフリカの海のど真ん中)のuv座標は(0.5, 0.5)となる.

例えば東京を例(北緯36度,東経140度)に取ると

  • u=140/360+0.5=0.888    角度成分で正規化して,グリニッジ分(0.5)を足す
  • v=0.5-36/180=0.3          角度成分で正規化して,赤道分(0.5)から引く

となり,東京のuv座標(u, v)=(0.888, 0.3)は

f:id:tajmahal0707:20191118145553p:plain

だいたいこの辺になるということです. 

このように球面上の座標が判れば,換算したuv座標から対応する座標の色を算出できることになります。

球体POVの画像生成

さて、球面のテクスチャ座標が分かったところで、球体POVのLED各色を算出する方法について考えます。

球体POVは


球体POVデモ

最初の10秒くらいをみると分かるように円弧状に配置したLEDを回転させ、角度ごとに表示する色パターンを変えることで残像効果(Persistence of vision)によって映像を作る方法です。

そのため回転軸を北極南極と見なすと先のパノラマ画像のuv座標と相性の良い方法(LED配列方向がv軸方向、回転方向がu軸方向に対応)なのです。なぜならテクスチャから縦方向に順に色を読んで配置していくだけでLEDの色を決定することができるのですから。

 

  もちろん転がらない場合には...ね

 

この球体POVはLED配列方向に45個のLEDを、回転軸方向を120分割することによって120×45の分解能を持つディスプレイになります。

地球を表示するとこんな感じ(まだLEDの問題でフルカラーで出せていませんが)


球体POV

これを物体の回転に合わせてテクスチャ座標も回転させてみようというのが今回の試みです。ここからはまずprocessingを使ったシミュレーションで。

 

テクスチャ回転①

シンプルにテクスチャを横回転させてみましょう。

北極南極の軸は固定のままで、極軸周りに回転。オブジェクトは不動です.


longitude
スタートとなるuの座標が変化するだけなので簡単ですね。

f:id:tajmahal0707:20191119075538p:plain

青矢印のようにLEDスキャンを開始する位置をずらすことで,オブジェクトは動いていないのに映像が回転しているように見えることがわかります.
 

テクスチャ回転②

今度は縦回転。x軸周りに回転するので北極南極軸が回転します。

何も考えずに開始するvの座標値を変えてみましょう。


latitude

あれあれ、まあそうなりますよねえ。。。

極点周りで座標系が歪んでしまっているのにそれを考慮せずに回転させたらこうなります。

そこで天頂位置を変動させる方法を考えます。最初、この計算について1週間以上悩みました。。最初メルカトル図法のグーデルマン関数あたりの方に向かってしまい、相当ハマりました。

 

テクスチャ回転③

ポイントは「大円」です。

ja.m.wikipedia.org

大円とは球をその原点を通る平面で切った時にできる3次元円のことでその半径は球の半径に等しくなります.

f:id:tajmahal0707:20191119111806p:plain
球体POVの映像生成方法は,天頂軸の北極・南極を通る大円(以後LED大円,図中緑の円)に北極から南極に向けた半円上にLEDのを配置します.これがテクスチャuv座標系におけるv軸方向の座標を決定します.

u軸方向の座標は,LED大円を天頂軸回りの大円(以後回転軸大円,図中の青い円)に沿って回転させることでu軸をスキャンします.図からも分かる通り,回転軸大円とLED大円の法線ベクトルは直交します.

そのときの各LEDの座標値をuv座標に変換することで回転するテクスチャ値を得ることができると考えられます。

 

ここでもう一つのポイントはquaternion(四元数)です。

quaternionとはある回転軸ベクトル{v}周りに\thetaだけ回転させた量で回転を記述する方法です.

https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.amazonaws.com%2F0%2F51055%2F8aadab5a-9b24-c271-9384-9087c6fab19a.png?ixlib=rb-1.2.2&auto=compress%2Cformat&gif-q=60&s=5588c643a3fdca5ae491bb80d6fdd45c

まずベクトルvを {v'}=\dfrac{v}{\sqrt{v_x^ 2+v_y^ 2+v_z^ 2}}と単位ベクトル化します.

回転角をθ(rad)としたとき,この回転を表すquaternion:qは次式で表されます.

{q}=(q0, qx, qy, qz)=(cos(\dfrac{\theta}{2}), {v'} sin(\dfrac{\theta}{2}))

これをLED大円および回転軸大円の回転軸に対して適用します. 

LED大円におけるLEDの配置は,北極から南極まで -{\pi}/2〜{\pi}/2 の180度を45分割します.この座標値はquaternionを用いると簡単に記述できます.

これを大円周りの回転に適用すると,原点を通るLED大円の法線ベクトルを{n}_{LED}とすると,この法線ベクトル{n}_{LED}がquaternionの回転軸ベクトル成分となります.そして北極から南極に向かって 180/45=4 度間隔で回転させていくと45個のLEDの各座標値を得ることができるのです。これによってある経度におけるLED座標を求めることができ、それを天頂軸で回転させます。

天頂軸回転もquaternionで簡単に記述でき、天頂ベクトル{n}_{apex}を回転軸ベクトルにした回転を180/120=1.5度間隔で回転させていくことに相当します。 

天頂ベクトルのセンサによる回転

上記までである天頂ベクトルを与えた場合のLEDのuv座標を計算する準備ができました.

回転がない場合の天頂ベクトル{n}_{apex}は単位球のy軸上の天頂(北極に相当)に位置し,その座標値は{n}_{apex}=(0, 1, 0)となります.またLED大円の法線ベクトル{n}_{LED}{n}_{apex}と直行するx軸上と考えることができ,その座標値は{n}_{LED}=(1, 0, 0)とします. 

 

そこでMPU9250で取得した姿勢情報から天頂ベクトル{n}_{apex}を回転させることを考えます.

MPU9250でquaternionを求める方法はいくつかありますが,M5stackのサンプル例にある「MPU9250BasicAHRS」を用いるのが一番簡単です.

f:id:tajmahal0707:20191119123212p:plain

このサンプルの322~325行目にquaternionを取得する部分があります.

f:id:tajmahal0707:20191119123626p:plain

オイラー角(roll, pitch, yaw)も求められますが今回は使いません.

センサから取得したquatrenion をq_{sensor}=(q0,qx,qy,qz) とします.

(qx, qy, qz) が回転軸ベクトル.{q0} が回転量に相当し,回転軸ベクトル(qx, qy, qz) は単位ベクトルであるとします.

このquaternionq_{sensor}にもとづいて 2つのベクトル({n}_{apex}{n}_{LED})を回転させます.この2つのベクトルはそれぞれ軸方向の単位ベクトルなので0の項が多く計算を簡単にできそうですね.

通常のベクトル {v}=(v_x, v_y, v_z) をquaternion{q}_{sensor}=(q0, qx, qy, qz)で回転させる回転行列{R}_{sensor} を求めると

{R}_{sensor} = \begin{pmatrix} 1-2(q_y^ 2 + q_z^ 2)&2(q_x q_y - q_z q_0)&2(q_x q_z + q_y q_0) \\ 2(q_x q_y + q_z q_0)&1-2(q_x^ 2 + q_z^ 2)&2(q_y q_z - q_x q_0) \\ 2(q_x q_z - q_y q_0)&2(q_y q_z + q_x q_0)&1-2(q_x^ 2 + q_y^ 2) \end{pmatrix}

 

天頂ベクトル{n}_{apex}を回転{R}_{sensor}で移動させると

\begin{eqnarray}{n'}_{apex} &=& {R}_{sensor}\begin{pmatrix} 0 \\ 1 \\ 0 \end{pmatrix} \\ &=& (2(q_x q_y - q_z q_0), 1-2(q_x^ 2 + q_z^ 2), 2(q_y q_z + q_x q_0))\end{eqnarray}

と簡単な式になります.零があるのでたくさん消えますね.

 例えば天頂ベクトルをLED大円の法線ベクトル{n}_{LED}で90度({\pi}/2)回転させることを考えると,このときのquaternion {q}_{LED} = (cos(\pi/4), sin(\pi/4), 0, 0)から天頂ベクトル{n}_{apex}を回転させると,

{R}_{LED} = \begin{pmatrix} 1&0&0 \\ 0&1-2(sin(\pi/4)^ 2)&2( -cos(\pi/4) sin(\pi/4)) \\ 0&2 cos(\pi/4) sin(\pi/4)&1-2(sin(\pi/4)^ 2) \end{pmatrix}

\begin{eqnarray}{n'}_{apex} &=& {R}_{LED}\begin{pmatrix} 0 \\ 1 \\ 0 \end{pmatrix} \\ &=& (0, 1-2(sin(\pi/4)^ 2), 2 cos(\pi/4) sin(\pi/4)) \\ &=& (0, 0, 1)\end{eqnarray}

となり, 天頂ベクトル{n}_{apex} = (0,1,0)が90度回転して(0,0,1)へと変換され,x軸回りにy軸を90度回転させてz軸になったことがわかります.

 

同様にLED大円の法線ベクトル{n}_{LED}=(1,0,0)を回転{R}_{sensor}で移動させると

\begin{eqnarray}{n'}_{LED} &=& {R}_{sensor}\begin{pmatrix} 1 \\ 0 \\ 0 \end{pmatrix} \\ &=& (1-2(q_y^ 2 + q_z^ 2), 2(q_x q_y + q_z q_0), 2(q_x q_z - q_y q_0))\end{eqnarray} 

これも簡単な式にすることができました.

 それぞれ計算が簡単なので,別々の関数にしたほうが良さそうですね.

 

また,Quaternionには球面線形補間という性質があり,2つのベクトルを円弧状に補間することができます.

LED大円上の点p0とp1があるとき,パラメータt(0.0 ≦ t ≦ 1.0)を用いてその間を補間する中間のベクトルp(t)を求めることができ,その式は

p(t) = \dfrac{sin((1-t)\theta)}{sin(\theta)} p_0 + \dfrac{sin(t\theta)}{sin(\theta)} p_1

と表すことができます.

しかし,ここではこのあともセンサによる回転などが加わるのと,実装時にはこのあたりの計算はすべてすっ飛ばしてしまうことになるので,いろいろ検討したのですが今回は採用しないことにしました.

球上の座標の緯度経度計算

上記までセンサによって回転した天頂ベクトル{n'}_{apex} を求めることができました.この天頂ベクトルは単位ベクトルなのでそのまま球上の座標値として使うことができ,この座標値をもとに回転した天頂の緯度経度{n'}_{apex}(ひいてはテクスチャ上のuv座標)を算出します.

直交座標から極座標への変換公式を用います.単位球なので r=1 となり,

{\displaystyle \begin{eqnarray}\left\{\begin{array}{l}r &=& 1 \\ \theta &=& arccos({z}) \\ \phi &=& arccos(\dfrac{x}{\sqrt{x^2+y^2}})\end{array}\right.\end{eqnarray}}

で求めることができます.

 この極座標変換の結果から緯度:\thetaと経度:\phi が算出できます.この \theta\phi は単位がRadianなので,PIで割って正規化することでuv座標に変換することができるのです.

 

センサからオブジェクトの回転を踏まえたLEDの各点の球面上の座標を求め,その座標値の緯度経度ーひいてはテクスチャのuv座標を求めることで,各LEDのカラー値を求めることができます.

そこで,m5stackから取得したセンサ値をシリアル通信でprocessingに送り,その値をもとにテクスチャ値(というかLEDの位置にcubeを配置してそのcubeの色を指定)をシミュレーションしてみました.


Rotation test

画面の下がセンサ値に応じて回転している球体(正確には球表面上にcubeを配置したもの)で,その各LEDに相当するcubeの色を上のパノラマ画像のテクスチャ座標から得ています.(センサ値と実際の回転が一致していないのはご愛嬌.)

そして上のパノラマ画像上には,テクスチャ値を取得するために使用したuv座標の等緯線をマッピングしています.

動画を見るとわかりますが,オブジェクトの北極・南極が回転していろいろな位置に移動していることがわかります.そこを中心に新たにuv座標を取り直すことでパノラマ画像から回転に応じたテクスチャを作り直すことができるのです.

 

この処理の擬似コードはこちら

  // センサ値からquaternionを取得
  quat[4] = getQuaternionFromSensor();
  
  // 天頂軸回りに回転:モーターの回転方向
  for(int u = 0; u <= LONGITUDE; u ++){
        float uu = float(u) / float(LONGITUDE);

        // LED大円周りに回転:各LEDの色を求める
        for(int v = 0; v <= LATITUDE; v ++){
            float vv = float(v) / float(LATITUDE);

            // LED大円回転(vv*PI [rad]),結果をvec2に格納
            float[] vec2 = rotate(axisX, vv*PI, axisY);

            // vec2を回転軸大円で回転(uu*PI [rad]),結果をvec1に格納
            float[] vec1 = rotate(vec2, uu*PI*2.0 , axisX);

            // センサからの回転 quat でvec1を回転し,結果をvec0に格納
            float[] vec0 = rotateQuaternion(quat, vec1);
          
            float[] uv = pos2uv(vec0);            // vec0 のuv座標を変数uvに格納
            // uv 座標からテクスチャのカラーを取得
            color c = getColor(int(uv[0] * image_width), int(uv[1] * image_height));
        }        
    }

 quaternionは回転させる順番で結果が異なるので,順番に注意.

 

 

次回はこれを実際に球体に落としこむ作業に入ります.

大量の掛け算,三角関数計算があるので,ダイエットがんばらないと..