airpocket が 2024年01月29日22時40分20秒 に編集
コメント無し
本文の変更
# はじめに SORA-Q(LEV-2)によるSLIM撮影ミッションの大成功、おめでとうございます! このプロジェクトはSORA-Qと同じく「世界初」を目指して立ち上げました。 SPRESENSEを使って(たぶん)世界初のたまごの分類専用AI(役には立たない)の開発記録です。 この装置が実現するのは、生たまごとゆでたまごの2クラス分類です。エクストラサクセスとして、生たまご、ゆでたまご、温泉たまごの3クラス分類にも挑戦します。 # 実現のための手法 テーブルの上でたまごに回転運動を与えるとゆでたまごは回り続け、生たまごはすぐに停止します。 これは、ゆでたまごは白身や黄身に運動エネルギーが伝わりやすく大きなエネルギーを受け取ってまわり続けるのに対し、生たまごは中身が流動してエネルギーが伝わらず損失も大きいためです。 この現象を利用し、モーターを使ってたまごに回転加速度を与えた際の消費電力を測定することで、たまごの内部状態を推定することを狙いました。 閾値を使った判定も可能ですが、「自分だけしか持っていないAIモデルを作ってみたかった!」ため、Neural Network Consoleをつかって[生たまご][ゆてたまご]のクラス分類を行うモデルを制作しました。 判定用のデータには、回転時のモーター電流を測定して用いています。ステッピングモータでたまごを加減速しながら回転させた際の電流値を1024回サンプリングしてFFTし、512次元のベクトルデータとしてクラス分類を試みました。 # いきなり完成 学習済みのモデルを使用して10個の生たまごと10個のゆでたまごの分類を行ったところ正答率は100%でした。 @[twitter](https://twitter.com/AirpocketRobot/status/1751607371452010956) エクストラサクセスとして温泉たまごの検出をこころみましたが、これには失敗しています。 採取したデータを見ると分類可能な情報は内包しているように見えるため、AIの学習を工夫すれば分類できる可能性も十分あるのではないかと考えています。 また冒頭に書いた通りたまごに加速度を与えた際の回転トルクの減衰や位相のずれを見る予定でしたが、実査にはたまご内部の硬さ変化による固有振動数のシフトを観測しているように見受けられます。(もう少しデータを精査して考察が必要です) 最後の「おまけ」に詳述しますが、たまごの内部状態を把握するにはたまごとモーターをリジットに固定しS/N比の高い信号伝達ルートを確保することがもっとも大切なポイントでした。 開発の過程においては、モーターとたまごホルダー間、たまごホルダーとたまご間のそれぞれの固定が甘く、情報の多くが失われているという問題に気付くのが遅れて大いに悩まされました。 IoTシステムへのAIの実装にも同様の課題は重要なポイントであると思われ、今回の開発はとても良い経験になりました。 ## 構成 装置の構成は下図の通りです。  ステッピングモーターで卵を回し、その際の電流変化を読み取っています。 タイマーを使用せずそれなりに一定タイミングで測定するため、メインコアでセンシング、サブ1コアでモーター制御しています。 装置はディスプレイを含む本体の上にたまごホルダーが載っている構造です。  たまごホルダーはNema17 ステッピングモーターに直結して回転させています。 自作基板は、市販のDC-DCコンバータ、モータードライバ、電流センサを載せ、ディスプレイやSPRESENSEと接続するだけのシンプルな構成です。  電源は12V ACアダプタから供給し、モータードライバへ供給。SPRESENSEへはDC-DCコンバータで5Vに降圧して供給しました。 ## 動作している様子 @[twitter](https://twitter.com/AirpocketRobot/status/1751951371992256551) ディスプレイには、測定した電流値をFFT解析したグラフを表示しています。 # 学習用データ データ採取時は規定の周波数でモーターを回転させつつ電流値を測定し、得られた電流データはFFT処理を行いmicroSDに保存します。 測定はゆでたまご10個、生卵10個、温泉たまご10個を用い、それぞれ100回ずつ合計3000回行いました。 次の図は、実際に測定した電流の変化の例です。電流値を正規化してグラフ表示しています。  加速度が任意の周期の正弦波に一致する様、モーターを速度制御しています。また、ステッピングモーターはその構造上、1stepごとに短周期の加減速を繰り返しています。 大きな周期の正弦波にステッピングモータのステップ動作に由来する小さな周期の波が重畳しています。 ゆでたまご、生たまご、温泉たまごそれぞれについて同様の測定を行いFFT処理して周波数特性を比較したところ、小さな周期の波がたまごの状態に伴う特長を多く保持していました。  生たまごには120Hz付近に特徴的なピークがありますが、ゆでたまごでは100Hz付近にシフトし、温泉たまごでは100~120Hzに幅広く存在しつつ全体的にピークが低くなっています。 詳しく調査できていませんが、生たまごは液状の白身が内部の運動状態との絶縁層となり、リジットに締結された「卵殻+たまごホルダー+モーターのローター」の一体物が120Hz付近に固有振動数を保有し共鳴、ゆで卵は固まった白身の弾性により低周波側にシフト、温泉たまごはゲル状の白身が緩衝材となって共鳴振動自体を緩和させた、、、のかもしれません。 # 学習について 得られたデータは512次元のベクトルデータとして扱い、Sony Neural Network Consoleで学習させました。初期のモデルは下図左の構造でしたが、自動探索機能を使用して精度の高い下図右のモデルへ変更しています。  データの6割を学習用、残りをバリデーション用に用いています。 データサイズが小さいため、200世代の学習に必要な時間はCPUで10秒以下でした。 # 部品とコード 詳細は[Git hub](https://github.com/airpocket-soundman/egg-analyzer)に(まだ整理できてませんが)公開しています。 ## 部品表 |名前|数量|備考| |-|-|-| |SPRESENSE メインボード|1|(switch science)[https://www.switch-science.com/products/3900]| |SPRESENSE 拡張ボード|1|(switch science)[https://www.switch-science.com/products/3901]| |ILI9341 2.2" TFT LCD|1|amazonなどから| |A4988 ドライバボード|1|amazonなどから| |Nema17 HS4023|1|[秋月電子](https://akizukidenshi.com/catalog/g/g105372/)| |M5Stack用電流計ユニット|1|(switch science)[https://www.switch-science.com/products/6739]| |60mmx80mm ユニバーサル基板|1|| |M2x10 ボルト|8|基板固定用| |M3x5 皿ボルト|4|ステッピングモーター固定用| |M3x10 ボルト|6|トップパネル固定用| |タクトスイッチ|1|[秋月電子](https://akizukidenshi.com/catalog/g/g115660/)| |φ2.1×φ5.5電源ジャック|1|[秋月電子](https://akizukidenshi.com/catalog/g/g106568/)| |XHコネクタメス|適量|ケーブル側| |XHコネクタオス|適量|ユニバーサル基板側| |QIコネクタオス|適量|SPRESENSE接続用|
|CASING BASE|1|3Dプリンタ出力| |CASING TOP MOTOR|1|3Dプリンタ出力| |CASING TOP DISPLAY|1|3Dプリンタ出力| |EGG HOLDER BASE|1|3Dプリンタ出力| |EGG HOLDER TOP|1|3Dプリンタ出力|
|CASING BASE|1|3Dプリンタ出力※| |CASING TOP MOTOR|1|3Dプリンタ出力※| |CASING TOP DISPLAY|1|3Dプリンタ出力※| |EGG HOLDER BASE|1|3Dプリンタ出力※| |EGG HOLDER TOP|1|3Dプリンタ出力※| ※[3Dプリント用データ](https://github.com/airpocket-soundman/egg-analyzer/tree/main/stls)はGit hubにて公開しています。
## コード 長いので割愛します。必要な方は[Git Hub](https://github.com/airpocket-soundman/egg-analyzer)をご覧ください。
[subcore1用コード]()では、maincoreからのパケットを待ってモーターを制御します。
[subcore1用コード](https://github.com/airpocket-soundman/egg-analyzer/tree/main/src/egg_AI_sub)では、maincoreからのパケットを待ってモーターを制御します。
maincore用コードは、[学習データ採取用]()と[推論用]()があります。subcoreコードは共通です。
maincore用コードは、[学習データ採取用](https://github.com/airpocket-soundman/egg-analyzer/tree/main/src/egg_AI_data_collector_main)と[推論用](https://github.com/airpocket-soundman/egg-analyzer/tree/main/src/egg_AI_main)があります。subcoreコードは共通です。
学習データ採取用コードでは、指定した回数の測定を繰り返し、rawデータとFFTデータをmicroSDに保存します。 推論用は測定後FFT解析して推論を実行、測定データをmicroSDに保存します。 # 最後に 生たまごとゆでたまごの分類は成功しましたが、エクストラサクセスとした温泉たまごの分類には成功していません。可能であれば温泉たまごの硬さをポイント評価できる温泉たまごスケールの開発まで進めたいと考えています。 データ採取の過程でモーターの回転数を高くした方が内部の情報が多く抽出できている様に見受けられたのですが、温泉卵を高速回転すると半生状態の白身構造が破壊されてしまい生たまごとの差が見えなくなってしまうという現象も発生しました。 データ採取行為自体が測定対象の状態を変化させてしまうというのはありがちなことでもあり、面白く感じました。 世界にただ一つの自分オリジナルAIを作ってみたくて立ち上げたプロジェクトですが、基本機能は満足できました。生たまごとゆでたまごを判別するAIを持っているのは世界でも私ひとりだけかもしれないと思うと愉快な気分です。 # おまけ 開発余話 今回の開発では、たまごの内部情報を含んだ学習用データを採取するのにもっとも苦労しました。テスト装置を作成し、データ測定を開始したところ ①再現性のあるデータが得られない ②得られたデータに含まれる特徴が少ない(S/N比が低い) ③テスト測定では良好なデータが得られるが、数百~数千の本測定時に特徴が消える などの事象に悩まされました。 開発が進むに従い断片的に集まった情報をもとに原因をつぶしていったところ、ここに挙げた問題はすべてたまごホルダーに起因する問題であり、ホルダーの進化に開発の歴史を見ることが出来ます。  上写真は左の第一世代から右端の第五世代までの進化の様子です。 理想的なデータを取得できるまで、仮説を重ねてたまごホルダーの改良を続けました。 ## 第一世代  たまごの保護を念頭に置き、硬めのゴムフォームにたまごを圧入して固定。 一見多くの特長を抽出できたように見えたが、ゴムフォームが振動を吸収/発振してしまい一体何の情報が見えているのか判らないゴミデータばかり。 ## 第二世代  たまごをベースの上に直接置き、ソケットをネジ締めして固定。たまごの固定、芯出しを同時に行える基本設計が決定。ホルダーの重量が重すぎるとたまごの特長が埋没する可能性を考慮し、軽量化した第三世代を開発。 ## 第三世代  ネジピッチを小さくしつつ、ぎりぎりまでソケットの肉厚を削減。たまごホルダーの軽量化/回転トルク低減を狙った。 当初良好かと思われたが繰り返し測定するとS/N比が不足する事例が発生。 ## 第四世代  S/N比向上をねらい、ベース部品を剛性の許す限り肉抜きして軽量化。 とても良好なS/N比を得られたが、繰り返し測定すると急速にS/N比が悪化。よく観察すると圧入固定していたモーター軸とホルダーの締結部にガタが発生。繰り返し応力により樹脂がへたり、モーターとホルダーの締結が甘くなっていることが確認できた。 ## 第五世代  モーター軸に対してネジ締めできる構造を追加して、 「モーター」⇔「ホルダー」⇔「たまご」 間の締結をすべて確実に固定することで十分な情報を得られる様になった。