Yakatano が 2024年01月29日23時32分48秒 に編集
コメント無し
本文の変更
# はじめに 2023年のMaker Faire Tokyo 2023やNT東京にIsolation Cubeというガジェットを展示しました. @[youtube](https://www.youtube.com/watch?v=w3pRgsE_wJo) Isolation Cubeは,1面8x8=64 LEDの正方形マトリクスを6枚用いて正6面体( 合計384LED)のCubeディスプレイに9軸のIMUセンサを用いてセンサの角度に合わせてディスプレイ表示を更新することで,いつも同じ向きに画像を呈示することができるデバイスです. 今回はより球体に近づけるべく新規に基板を起こして一枚50LEDの正五角形基板から成る正12面体(600LED)に拡張してみました. 今まではマイコンにESP32を使用していましたが,LED数が増えてきたのでマルチコアで画面を分割して高速化を図るアイデアです. ESP32だと2コアなので1コア300LEDとなりますが,SPRESENSEは6コアあるので,メインUIコア+4コア(1コアで150LEDを担当)する実装を目指します. ### モチベーション 球体ディスプレイを作るモチベーションについては以前にオープンエッジデバイス研究会で話しているので、そちらを。。 [slideshare](https://www.slideshare.net/KatanoYasuo/5pptx#2) ### 完成イメージ # 部品 ## SPRESENSE 今回はSpresenseさんから以下の製品をお借りして実装しました. ### メインボード ![メインボード](https://camo.elchika.com/c1749f7085fdd70e94af192cc82b99188729f401/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f64633031346230652d313132332d343630632d396265662d3032343133653864363133302f63656639343838362d366333372d343230622d383264622d326233393863323832666263/) [製品情報](https://elchika.com/promotion/spresense2023/#:~:text=Spresense%20%E3%83%A1%E3%82%A4%E3%83%B3%E3%83%9C%E3%83%BC%E3%83%89-,%E8%A3%BD%E5%93%81%E6%83%85%E5%A0%B1,-%E6%8B%A1%E5%BC%B5%E3%83%87%E3%83%90%E3%82%A4%E3%82%B9) ここは説明不要だと思います. コアが6つもあるので,600個のLEDを分散して制御することができれば速度的にも有利です.IMUの回転角度情報から全てのLEDの仮想座標の3次元回転を個別に計算しなければならないのでかなりの計算量となるため,分散処理は必須と言っても良いものです. また,メインボードにLiPo用のDCDCを備えるため,DCDC用の基板を用意する必要がなく,LEDへの電力共有もEXT_VDD経由で大きい電流も出力できそうです. ### LTE拡張デバイス ![LTE拡張デバイス](https://camo.elchika.com/0f312611fba0e070ceea0af680fba3f29f899062/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f64633031346230652d313132332d343630632d396265662d3032343133653864363133302f62313561373330352d313562302d343161392d383434612d386535343733633038373333/) サンプル提供いただいたものは拡張ボードだったのですが,Isolation Sphereに格納するには大きすぎたので,手持ちのLTE拡張ボードを使用しました. Isolation sphereの正12面体部分の内部にちょうど収まるサイズなので,そのまま収納します. 要求する機能としては表示する画像を格納するためのSDカードが欲しかったのと,UIやデータ転送のためにSIMが使えるならワンチャン....と思ったためです.欲しかった機能はSDカードのみなので,SPI接続で...とも思ったのですが,ボール内に収まりそうなのでそのまま行きます. ### SPRESENSE用Qwiic接続基板 ![SPRESENSE用Qwiic接続基板](https://camo.elchika.com/120147603e5b0bc33fa3e9d578cdde396d8b0f44/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f64633031346230652d313132332d343630632d396265662d3032343133653864363133302f64316262333664362d396638392d346333662d386266312d663035643431613562333266/) [製品情報](https://www.switch-science.com/products/6318) これと[BMI270](https://nextstep.official.ec/items/66165488)の両方をサンプル提供いただいたのですが,どちらが使えるかわからず,現時点ではIsolation Cubeで使い慣れているBNO055が接続可能なQwiic接続基板を採用しています.Qwiicだとケーブルが邪魔になるので,どこかの機会でBMI270も試してみたいと思います. ### BLE1507(BLE serialization firmware) ![BLE1507](https://camo.elchika.com/d1ed1a7c85ff045043cd6bea1796b9b3c0306a3c/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f64633031346230652d313132332d343630632d396265662d3032343133653864363133302f37303466653661622d613262372d346566312d613334372d323338623039303966633330/) [製品情報](https://elchika.com/promotion/spresense2023/#:~:text=BLE%20serialization%20firmware)-,%E8%A3%BD%E5%93%81%E6%83%85%E5%A0%B1,-BLE1507(NUS%20firmware) こちらもサンプル提供いただきました. もともとESP32を採用していた理由がBLEもしくはWiFiが使える(ボールとして完全に閉じた形状&全面ディスプレイになるため,電源ONなどUI操作をボタンとして配置できないため無線機能が必須)こと,だったのでこのデバイスを見つけた時に「おお,これならSPRESENSE使えるやん,しかもマルチコア数多い!」となって採用を決定したのでした. ## 表示用LED ### WS2812C-2020 ![WS2812C-2020](https://camo.elchika.com/73af12d51272eba13650a79c0f2453470ca79769/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f64633031346230652d313132332d343630632d396265662d3032343133653864363133302f30326663336231642d646133312d346661322d623839392d366631626464656161616337/) [秋月電子でも販売している](https://akizukidenshi.com/catalog/g/gI-15068/)Neopixelベースのマイコン内蔵RGB LEDです.2020の名の通り2mm角という非常に小さなLEDです. WS2812-2020のシリーズには二種類(他方はWS2812B-2020)あり,その差は消費電力です.WS2812C-2020は5mAとWS2812B-2020の12mAと比較して小さい電流量なので,大量のLEDをLiPoなどの限られた電源で駆動させるのに向いています(当然暗くなりますが..) このLEDを50個直列で配置するための正五角形基板を起こしました. ![正五角形基板](https://camo.elchika.com/183a3907f8ce7880bc4d125d7d0f619381e2a95b/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f64633031346230652d313132332d343630632d396265662d3032343133653864363133302f31336562643839612d313432332d343935652d623234632d633730633338316135373364/) 中心から螺旋状にシリアル配線してあります.所々にある穴は熱対策&ネジ穴として外骨格を固定することを想定していましたが,現時点ではただの穴です. ![裏側](https://camo.elchika.com/877c631370445cc1d3ab06f92154179da91bdac3/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f64633031346230652d313132332d343630632d396265662d3032343133653864363133302f64326639656564392d323131662d346565372d613762362d363035653837326563396464/) 裏側には配線およびコンデンサが配置されています. 接続して表示してみるとこんな感じ. @[twitter](https://twitter.com/Yakatano/status/1686709358540046336?s=20) (リンクされないようなのでこちらに[別リンク](https://twitter.com/Yakatano/status/1686709358540046336?s=20)を。。) ## IMU ### BNO055 ![Adafruit_BNO055](https://camo.elchika.com/ddb82c00abde0dac25e29d60f969536ded535868/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f64633031346230652d313132332d343630632d396265662d3032343133653864363133302f30393535353734632d393931392d346335332d383035382d316666313837666137373065/) 現状で個人的には一番信頼できるIMUです.BNO085という後継もあるのですが一部使いにくいところがありこちらを愛用しています. 3次元回転にQuaternionを使っておりリソースが有限な中で直接Qaternionが関数から取得できるのは助かります. BNO055はキャリブレーションが不要かつドリフトもかなり抑えられており,Isolation Sphereのような完全封じ込め型のデバイスには助かります. ## 電源 ![Aliexpress](https://camo.elchika.com/18592b0936527b57faa6a2d86e5bbbb868c35dfb/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f64633031346230652d313132332d343630632d396265662d3032343133653864363133302f36383330613462342d373462312d346333362d383435612d373633313564333231386139/) 3.7v 2000mahの充電式リチウムポリマー電池, 104040 LiPo電池になります。 40mmx40mmのサイズで、正12面体に内接する最大立方体の1辺が約40mmなのでこのサイズをチョイス。メインボードに接続して使用します。 # 設計 ## 正12面体 ### 基本設計思想 Isolation Sphereを作成するにあたって、重要な正12面体の諸元とそれらを作成するための基本設計を行います。 実はMaker Faire Tokyo 2023においてすでに一度正12面体のバージョンを作成していました。 ![内骨格バージョン](https://camo.elchika.com/13b3b47d6553d8e94c09dbf7a52c09e46561745d/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f64633031346230652d313132332d343630632d396265662d3032343133653864363133302f39653965393533632d623234342d343730322d616664322d303035356366646534623664/) このときには次のような内骨格構造をしていました(若干5角形のサイズも小さかったのですが。。)構造的には内部のマイコンやバッテリー配置が安定していたのですが、内部の容量が小さくなり(さらに配線の余裕を考えていなかったので)配線がギッチギチになってしまい「組み立てるとどこかが断線する」状態になっておりあえなくお蔵入りとなってしまいました。 そこで今回は最終目標である球体に近づけるため、球体の外殻(内側が正12面体)を作成し、その外殻パネルにLED基板を貼り付ける外骨格構造を採用しました。 ![外骨格構造](https://camo.elchika.com/3c6aa95ef5850f0fb12c81e8d10ed1761fc0ca93/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f64633031346230652d313132332d343630632d396265662d3032343133653864363133302f33336134373739342d636164332d343035362d383539342d643732386563303932643265/) 外骨格には内側の基板に配置されたLEDから外側の球まで穴を開け、球表面をボロノイ分割で600分割することで全面をディスプレイにすることができています。 これが外骨格の1基板分。 @[twitter](https://twitter.com/Yakatano/status/1739655883725140466?s=20) (リンクされないようなのでこちらに[別リンク](https://twitter.com/Yakatano/status/1739655883725140466?s=20)を。。) (黒レジンで作成したら光の拡散量が少なくなってしまったので、後に白レジンに変更) これをパネルとして組み合わせて球体にします。そうすると内部に骨格を配置する必要がないので内部の容積が十分確保できるようになり、SpresenseもLTE拡張ボードまで収納することができるようになりました。 3Dプリンタで出力するときには3パネルを1セット(150LED)として4セット用意してこれを組み合わせて球体を形成します。SPRESENSEの場合はこの1セットを1コアが担当することを想定しています。 @[twitter](https://twitter.com/Yakatano/status/1740968387570978861?s=20) (リンクされないようなのでこちらに[別リンク](https://twitter.com/Yakatano/status/1740968387570978861?s=20)を。。) 基板は平面・外殻は球体となっているので基板の周辺は球表面までの距離が近く歪が増え、基板重心付近では遠くなるため、若干視野角が異なることがどの程度画像に影響するか、はひとつ大きな課題になります。 ## 600LEDの配置 さて、球表面をn個に均等分割する方法というのはかなり難しく、理論的な方法はなかなか見つかりません。 今回設計した外殻球はφ100mm、内部の正12面体の外接球がφ80mmとなっています。この外殻球表面に600LED(600LED÷12面体=50LED/基板)を均等に配置する、という問題を考えます。 ### 一般化螺旋集合 解析的に解く方法はないだろうか?といろいろと探してみたのですが、私の要求に合うものがなかなか見つかりません。 一つ「[一般化螺旋集合](https://blog.panicblanket.com/archives/3778)」というものがあるのですが、この方法で600LEDを配置してみるとこのようになります。 @[youtube](https://youtu.be/0GsdxohajtE?si=YKieayR3R3wrCN-E) わかるでしょうか?この方法だと一様分布ではありますが螺旋方向の「スジ」ができてしまうのです。 Isolation Sphereのコンセプトは「回転させても絵が変わらない」というものです。しかしこのLEDの配置パターンだと上下に「極」ができてしまい、これを回転させるとどうしてもパターンが回転していることがわかってしまう。 球を回転させてもどこが「極」かわからない、となる必要があるのです。 ### Icosphere IcosphereというのはBlenderなどのCGソフトで球を表現するための方法の一つです。 球の表現の代表的な方法は、上のIcosphereとUV sphereというものです。 UV Sphereというのは、 ![UV sphere](https://camo.elchika.com/116e7894ef36a33d5d4a29b77606bc766734d552/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f64633031346230652d313132332d343630632d396265662d3032343133653864363133302f64656564363735302d323465632d346436302d393034642d386161616639353039663265/) このように、緯度と経度で構成される球です。そのためテクスチャマッピングの貼り付けなどには非常にやりやすいメリットがありますが、北極・南極に点が集中するため、その部分が歪みやすいデメリットがあります。 対して、Icosphereというのは、 ![Icosphere](https://camo.elchika.com/ae69e5909413d3caeda3d6958254da218f0cae73/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f64633031346230652d313132332d343630632d396265662d3032343133653864363133302f39363134373230382d313766612d343030372d383730662d613737366462656637356638/) 正多面体をsubdivide分割して細かくしていく球の表現方法です。正多面体の性質として極性を持たないため、回転してもどこが極かはわからないのです。 理想的ではあるのですが、図に示すように複雑性の上がり方が極端で自分で個数を制御できないのです(左からsubdivide=2→3→4)。 任意の数(Isolation Sphereの場合は600)の配置を行うことができないため、今回も採用は見送りました。 ### 逐次的な方法 最終的に採用した方法がこちら @[youtube](https://youtu.be/Au8QosJG8wA?si=FrItu_LpA4WdDRp-) UNITYを用いて、内部球(動画中の青い球)に重力を設定し、大気圏のようなもの(動画中の半透明の白い球)を設定し、このこの球の内側に衝突判定を設定することでボールがはみ出すことを防ぎます。 そこに任意数(ここでは600)のボール(動画中の緑球)を配置してお互いが衝突しながら最適配置を探す。。。という方法です。 詳細は以前に書いた[ブログ](https://tajmahal0707.hatenablog.com/entry/2023/06/08/074602)があるのでそちらを・・・ ## LED球体の設計 これまででLED 600個を球体表面に配置することができました。これを基板上では50x12の配置に、球表面では均等部分布にする必要があります。また、外殻球表面の穴を円筒にしてしまうと円筒間に隙間ができてしまい球表面全体をディスプレイにする際に問題になります。 そこで、基板と接する部分は円筒で、球表面上ではボロノイ分割にすることにします。こんな感じ。 ![円筒→voronoi分割](https://camo.elchika.com/6126b279c81befc7371e54c5f360d76b4acaef04/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f64633031346230652d313132332d343630632d396265662d3032343133653864363133302f37316162653361312d663736382d343037322d393539352d636335653631336562663965/) ### voronoi分割 うまくいったら絶対エモいので、頑張りましたw [【Blender】有機的なオブジェクトを作る方法 Geometry Nodes編](https://styly.cc/ja/tips/blender-geometrynodes-nyu/) [【Blender】ボロノイ構造のオブジェクトを作る方法](https://styly.cc/ja/tips/blender/nimi-blender-voronoi/) いろいろvoronoiを作る方法は紹介されています。しかし球表面に対して適用しているものがなかなか見つからず、苦労しました。 Isolation Sphereでは使用しませんでしたがこんなサイトもあります。 [voronator](https://www.voronator.com/) [github:py_sphere_Voronoi](https://github.com/tylerjereddy/py_sphere_Voronoi) このようなライブラリも存在するのですが、自分の望んだ動作にならないため、オリジナルで作ることにしました。 #### Delaunay多角形 上で配置した600点の3次元位置はすでに計算できています。しかしこの点群から辺・面を繋いでポリゴンを生成するのはちょっと面倒です。 この点群は定義から全て球表面上にあり、均等に近ければ近いほど各点を繋いだポリゴンは正三角形に近くなることがわかります。正三角形に近くなればなるほどこのDelaunay多角形から作るvoronoi多角形は6角形になります。 また、同時にすべての点が球表面上にあるためこの点の集合は凸多面体であることもわかります。 そこでpythonで凸包を生成するプログラムを作成しました。 ライブラリにはopen3dを使います。 ソースコードの一部。(このままコピペでは動きませんがエッセンスはこんな感じ) ``` python:点群→凸包の生成 import open3d as o3d import pandas as pd import plotly as py import plotly.express as px import numpy as np from stl import mesh points = [] for i, d in df.iterrows(): p = d[['x', 'y', 'z']].values points.append(list(p)) pointcloud = o3d.geometry.PointCloud() # pointcloud.points = o3d.utility.Vector3dVector(df[['x', 'y', 'z']].values) pointcloud.points = o3d.utility.Vector3dVector(points) hull, _ = pointcloud.compute_convex_hull() hull_ls = o3d.geometry.LineSet.create_from_triangle_mesh(hull) hull_ls.paint_uniform_color((0, 1, 0)) hull.compute_vertex_normals() o3d.io.write_triangle_mesh(stl_filename, hull) o3d.visualization.draw_plotly([pointcloud, hull_ls]) ``` 出力結果はこんな感じ。 ![Delaunay多角形](https://camo.elchika.com/7b1941dd6ace25f124714613677157c921f9e649/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f64633031346230652d313132332d343630632d396265662d3032343133653864363133302f30313966643331322d663536362d343337302d626665632d653039653537316462346262/) これをstl形式でファイル出力します。 ![stl](https://camo.elchika.com/3b194fee6aa9620ccf1ba78556c4533bc5d33bb6/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f64633031346230652d313132332d343630632d396265662d3032343133653864363133302f32306336633733382d316137632d343639662d626334392d313538326362346433633831/) stlファイルで出力することで、各3角形の3次元位置を個別に取得することができるため、後のvoronoi計算処理が楽になります。 ### voronoi多角形の作成 Delaunay多面体ができたのであれば、そこからvoronoi多角形に拡張します。 @[wikipedia](https://ja.wikipedia.org/wiki/%E3%83%9C%E3%83%AD%E3%83%8E%E3%82%A4%E5%9B%B3) Delaunay多角形をstlで出力したのは、stlの出力フォーマットが3角形を形成する頂点座標を3角形ごとに出力されるためです。 ```python:stl読み込み from stl import mesh stl_data = mesh.Mesh.from_file(filename ) print(stl_data.points) ``` これを実行すると > [[-49.31912 7.78104 2.6608098 ... -49.956623 1.3397751 -1.5939546] [-48.49622 6.584802 10.235096 ... -44.360455 9.363192 21.082712 ] [ 47.784668 -9.589299 -11.165614 ... 45.983433 -17.109419 -9.632838 ] ... [ 47.255344 -12.76661 10.195397 ... 45.92527 -19.05439 5.272538 ] [ 45.92527 -19.05439 5.272538 ... 42.422623 -25.259659 7.891177 ] [ 44.41393 -19.146568 12.681166 ... 42.422623 -25.259659 7.891177 ]] となり、stl.pointsは配列として9x「面の数」となっており、この9はDelaunay三角形の3頂点の3次元座標を表しています。 voronoiの定義から各Delaunay三角形の座標&辺情報が必要で、voronoiはdelaunay三角形の頂点を母点とし、母点でつくる辺の垂直二等分線によって分割される面をvoronoi多角形として、voronoi面を形成する頂点をvoronoi頂点と定義されます。 @[twitter](https://twitter.com/clintfulkerson/status/1748766259682967974?s=20) (リンクされないようなのでこちらに[別リンク](https://twitter.com/clintfulkerson/status/1748766259682967974?s=20)を。。) このように黄線で定義されるDelaunay三角形に対して水色線のvoronoi多角形を定義する。 ここでvoronoi頂点も外殻球表面上の点となるため、頂点で構成される点群も凸包であることがわかります。 そこで先程の凸包プログラムを適用することでvoronoi多角形の形状も取得することができます。 その結果がこちら ![voronoi多角形](https://camo.elchika.com/a768d36a2945fa965b5cb1b843bfd335d0fdaae4/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f64633031346230652d313132332d343630632d396265662d3032343133653864363133302f39333337373336342d626239392d343661302d383238322d383835393735396662336664/) ![stl](https://camo.elchika.com/164ce25f0b61d4a88056b6635495440c15a5388d/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f64633031346230652d313132332d343630632d396265662d3032343133653864363133302f30373336623337642d616361662d343639622d393265612d333738356463346439303864/) ### LEDからの円筒穴の作成 基板上のLEDの位置と、対応する外殻球上の点を結んだパイプ形状(以後ミミズ)を作成する。 こんな感じ。 @[twitter](https://twitter.com/Yakatano/status/1733491717066924194?s=20) (リンクされないようなのでこちらに[別リンク](https://twitter.com/Yakatano/status/1733491717066924194?s=20)を。。) この大量のミミズを外角球からboolean演算でくり抜くことでLEDからの導光路を確保する。 ```python:blender_booleans import bpy boolean_type = 'DIFFERENCE' root_object = bpy.data.objects['shell-05'] selected_objects = bpy.context.selected_objects for obj in selected_objects: print('boolean', obj.name) name = 'bool-' + obj.name.split('-')[1] + '-' + obj.name.split('-')[2] bool01 = root_object.modifiers.new(type="BOOLEAN", name=name) bool01.object = obj bool01.operation = boolean_type bpy.context.view_layer.objects.active = obj bpy.ops.object.modifier_apply(modifier=name, report=True) ``` これはコード内でroot_object名を指定して、booleanしたいオブジェクトを選択した状態でこのpythonを実行すると、root_objectに対して選択したオブジェクトをすべてboolean演算するマクロです。 これを使い各パネルごとに各色のミミズをboolean演算する。 大量のmodifierが生成されてかなり重くなるが、これを一括で適用する裏技を紹介しておく。 modifierがあるオブジェクトを選択して、 ![modifier一括適用](https://camo.elchika.com/957e9123b557552668e10f316761719042d84232/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f64633031346230652d313132332d343630632d396265662d3032343133653864363133302f38393238356663372d383639322d343634302d383663392d333339626234373939636363/) meshを選択することで、このオブジェクトに付いているmodifierが一括適用される。 覚えておくと良い。 ### voronoi 穴の作成 voronoi多角形の頂点(多くは6点、たまに5点や7点)とLEDの中心(正12面体の五角形上の点)をまとめて点群にすると、この点群は凸包となる。 この凸包をポリゴン化するとvoronoi多角形を底面とする多角錐(voronoi錐)ができます。 作成したvoronoi錐がこんな感じ。 | ![表](https://camo.elchika.com/c67ff09de8e3dc7e99ae0df5f2f36abaa9c8d1f7/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f64633031346230652d313132332d343630632d396265662d3032343133653864363133302f66656232326232392d386637332d346630632d623733382d343133393462626565623838/) |![裏](https://camo.elchika.com/784f1843552c3f71f0b1feec75fa008ef51314ee/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f64633031346230652d313132332d343630632d396265662d3032343133653864363133302f64646332656365642d613561632d346133362d626162382d313837303961356265663030/) | |:---:|:---| これを外殻からbooleanで削除することで外殻にvoronoiの穴があきます。 ただ、その前にvoronoi錐にBevelを適用することでvoronoi錐の角が丸くなりより滑らかな穴が開けられます。 ![bevel適用](https://camo.elchika.com/b620af23f68752fa9925745e6b3306ca3e14a9ca/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f64633031346230652d313132332d343630632d396265662d3032343133653864363133302f65333736386236312d663562392d343439382d393933392d653064623661626464646366/) これで外殻球の完成。 @[youtube](https://youtu.be/4m_QSiS4KtM?si=UaREAnfV81zA0ORN) 中にはこのようにspresenseを格納 ![黒いテープに包まれているのがSPRESENSE](https://camo.elchika.com/895d61a9a7539a5f76fc2588778c5312399c206b/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f64633031346230652d313132332d343630632d396265662d3032343133653864363133302f62656237366165642d313863632d346634622d623836342d353265663032303333636262/) ![閉じているところ](https://camo.elchika.com/589fad6d18427a1b8186635b28da029a3890acd2/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f64633031346230652d313132332d343630632d396265662d3032343133653864363133302f35333963343031352d613234342d343664312d396361322d633338343761303432323237/) ### 葬送のフリーレン でこのような球体配置が話題になっていたようです。 @[youtube](https://www.youtube.com/watch?v=odP8k8_zrlc) 私はここで見たのですが @[twitter](https://twitter.com/motcho_tw/status/1741337056067096609?s=20) その時にはフリーレンのことを知らずにマジレスしてしまいました。私の回答も一部を5角形(もしくは7角形)に置換することで球体表面の6角形分割を行うことができるようになる派でしたw ちょうどこのようなガジェットを作っていた最中だったので、タイムリーすぎて思わず反応してしまいました。 # 動作 基本的な動作・アルゴリズムは、Isolation Cubeと同じものなので、それを踏襲します。
Isolation Cubeの動作アルゴリズムについては「[ブログ](https://tajmahal0707.hatenablog.com/entry/2023/06/08/074346)」に記載してあります。 [slideshare](https://www.slideshare.net/KatanoYasuo/5pptx#2) ←こちらにも原理的な説明が載っています。
Isolation Cubeの動作アルゴリズムについては「[ブログ](https://tajmahal0707.hatenablog.com/entry/2023/06/08/074346)」に記載してあります。[slideshare](https://www.slideshare.net/KatanoYasuo/5pptx#2) ←こちらにも原理的な説明が載っていますが、内容について改めて説明します。
## 原理
簡単に映像を呈示する原理についてIsolation Cubeを例に説明します。 [
簡単に映像を呈示する原理についてIsolation Cubeを例に説明します。Isolation SphereはCubeのLED配置を変えただけのものなので。 行っていることを概観すると、CGの世界で行われているテクスチャマッピングを現実の世界で実装している感じです。 ### 最初に用意するもの #### LEDの3次元位置 各LEDパネルのLEDの三次元位置を計算し、記録しておきます。 Isolation Cubeの場合には、[aliexpress](https://ja.aliexpress.com/item/1005005994450466.html?spm=a2g0o.order_list.order_list_main.66.21ef585aZRepwj&gatewayAdapt=glo2jpn) このパネル(8x8 WS2812-5050)を使用しています。LEDパネルのサイズは64x64mm。LEDは8x8なので、8mm間隔で並んでいるものと考えると
![キャプションを入力できます](https://camo.elchika.com/919c4059f199be0741bb5c0ae9a59ca488a52972/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f64633031346230652d313132332d343630632d396265662d3032343133653864363133302f61366665643536372d646432352d346166342d393261352d366337623161613630336264/)
](tajmahal.mond.jp/neon-on/images/cube-graph.html)
このようなLEDパネルの配置になるのです。([リンク先](tajmahal.mond.jp/neon-on/images/cube-graph.html)にグリグリ回せるグラフをおいておきます。)
このLEDの3次元位置をIMUの値を用いて回転することで自己位置を把握するのです。
#### Isolation SphereのLED3次元配置 Isolation SphereのLEDの配置は、前述のDelaunay多角形のVertex位置がLEDの配置と対応しています。 このLED配置は、基板とは関係なく外側で均等になるように600個のLEDを配置したものです。これらがどのような順番でシリアル接続されているのか、は基板(パネルあたり50LED)の配置によって決まります。そこで600 LEDをそれぞれの基板に割り当てる処理を行いました。
#### テクスチャマッピングデータ Isolation Cubeに貼り付けるテクスチャを用意します。汎用的に画像を貼り付けられるように一般的なパノラマ画像を使います。 パノラマ画像は[正距円筒投影図法](https://ja.wikipedia.org/wiki/%E6%AD%A3%E8%B7%9D%E5%86%86%E7%AD%92%E5%9B%B3%E6%B3%95#:~:text=%E6%AD%A3%E8%B7%9D%E5%86%86%E7%AD%92%E5%9B%B3%E6%B3%95%EF%BC%88%E3%81%9B,%E3%81%A8%E5%91%BC%E3%81%B0%E3%82%8C%E3%82%8B%E3%81%93%E3%81%A8%E3%81%8C%E3%81%82%E3%82%8B%E3%80%82)とも呼ばれ、画像のx軸、y軸がそのまま経度・緯度に対応するような画像で、 ![地球のパノラマ画像](https://camo.elchika.com/54b204e6cac2d9735e6e21864e37ad2e1584676d/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f64633031346230652d313132332d343630632d396265662d3032343133653864363133302f64326366646261352d323834372d343863622d383361312d373032333631623438616231/) そのため、球体にこのテクスチャ画像を貼り付けるには緯度と経度がわかればその場所の色を抽出することが可能になる利点がある反面、北極・南極付近が大きく歪むという欠点があります。 しかしパノラマ画像はVRやCGとも相性がよく、無料で入手可能なサイトも多い([たとえば](https://www.easypano.com/jp/panorama-gallery.html))ので入手も容易と考え、採用しています。 ## IMUによるLEDの仮想回転 IMU(ここではBNO055)を内蔵することで、Isolation Cube(Sphere)自身が回転するとその回転角度をquaternionで返してきます。 その回転情報に対してLED座標に同じ回転を加えると、現実世界の回転と同じ回転状態を得ることができます。 今回はそうではなく、LED座標に逆の回転を加えると、仮想的なLEDの座標は全く回転していない状態を作ることができるのです。 細かい計算式は[こちらのブログ](https://tajmahal0707.hatenablog.com/)で書いているので説明はしませんが、 ![youtube short](https://camo.elchika.com/9efe00e7bf8c40acdd26a612d308a81a39539116/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f64633031346230652d313132332d343630632d396265662d3032343133653864363133302f65653936346663392d653838622d343262332d616265652d306139343162376134383539/) ショート動画が貼り付けられないので、[youtube](https://www.youtube.com/shorts/FoM4IvFu58s)←こちらから。 上のリンクのようにセンサ(ここではM5stack)を回転させると画面下の球体(たくさんのLEDに相当するボールで構成されている)に地球のテクスチャが配置されています。 この地球は画面上のパノラマ画像からサンプリングしており、センサの値を相殺するような回転を仮想的なLEDに与えているため、動画のようにセンサが回転しても球体に貼り付けられている地球は回転してない(いつも右下あたりにオーストラリアがある)ことがわかります。 動画の後半、拡大していくとパノラマ画像上にLED位置が表示され、センサに合わせて移動していることがわかると思います。 この動きは非線形(特に極付近で顕著)なので、結構計算が大変なのです。 ## テクスチャ値をLEDに反映 各LEDに表示するべき色がわかれば、これらの色をLEDに与えて光らせます。Isolation Cubeでは、テクスチャマップにRGB値を格納するのではなく、マスクデータとしてバイナリデータを格納しています。 マスクデータにすることで、表示するパターンを切り替えます。 マスクによって定義された表示領域にはいろいろなカラーパターンを表示するモードを作って表示しています。 | ![キャプションを入力できます](https://camo.elchika.com/8665c04323d76edaf46c07b53dffd5a95aaed070/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f64633031346230652d313132332d343630632d396265662d3032343133653864363133302f65363461303132312d336664622d346534382d383863372d316536303661356630653630/) | ![キャプションを入力できます](https://camo.elchika.com/39fa33902c4b333e941fc06acb8c62579025203c/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f64633031346230652d313132332d343630632d396265662d3032343133653864363133302f30646364323134612d333066332d343939622d383432322d336438373738396633646135/) | ![キャプションを入力できます](https://camo.elchika.com/82f057eff6aa6302b4c75abc622ec358ef66ae1d/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f64633031346230652d313132332d343630632d396265662d3032343133653864363133302f31653230333061332d633530662d346438362d613430302d336133656537623138616637/) | |:---:|:---|:---| 上はIsolation Cubeではこの3つのマスクファイルを読み込んでパターンを表示していました。 @[youtube](https://youtu.be/w3pRgsE_wJo?si=4yHgm0cZ4j1_FOTC) Isolation Sphereでも同様のマスクファイルを読み込むことを目標とします。 # 実装 今回の実装は、基本構造はIsolation Cubeと同一です。 異なる点は、 ・BLE実装 ・マルチコア、共有メモリ関連 ・ファイル読み込み となります。 特にマルチコアはSPERSENSE導入の決め手なので、頑張って実装したいと思います。 ## BLE実装 実装の現状です。 結論から言うと、ちょっと上手く行っていません。