LEGO x M5Stack x Node.js x Web UIでつくるルービックキューブ自動崩しロボの技術スタック紹介

# はじめに
今年[Cube Scrambler](https://protopedia.net/prototype/4244)という作品を作ったのですが、LEGO x M5Stack x Node.js x Web UIで作ってみたら個人的にとても作りやすくしっくりきました。
本記事では実装にあたり使用した技術スタックを紹介したいと思います。



# [Cube Scrambler](https://protopedia.net/prototype/4244)とは
ルービックキューブを自動で崩したり揃えたりする、レゴとM5Stackで作れるロボットです。
このロボットを実際に作るにあたって使った技術を紹介していきます。

![GIF動画読み込み中…](https://user-images.githubusercontent.com/22117028/262297192-1c5727ee-eac5-48f8-9f05-78393aee8d66.gif)

https://protopedia.net/prototype/4244

https://github.com/miso-develop/cube-scrambler



# システム構成

![image](https://user-images.githubusercontent.com/22117028/290484317-09cde26c-2acd-447f-8a5a-4defa646d25e.png)

図のように以下の3つのカテゴリーに分けて紹介していきます。

* ハードウェア
* ソフトウェア（バックエンド）
* ソフトウェア（フロントエンド）





# ハードウェア

## ルービックキューブの回転機構
2つのサーボモーターの組み合わせでルービックキューブ全面の回転を行っています。
1つは土台部でルービックキューブの横回転を、もう1つはアーム部でルービックキューブの縦回転を担当しています。

このしくみは[ルービックキューブソルバーロボ](https://www.toysrus.co.jp/s/dsg-739421700)という既製品を参考にさせていただきました。

https://www.toysrus.co.jp/s/dsg-739421700

## LEGO

![image](https://gist.github.com/assets/22117028/fb6969a3-5fde-49f5-af4a-d03c2a179299)

筐体はLEGOで作っています。
3Dプリンタを持っていればそれ用のものを作りたかったのですが、持っていないため先述のルービックキューブソルバーロボを参考にLEGOで作りました。
結果としてとてもポップな見た目と、誰でも作れるオープンソース性があってとても良かったと思います。

またオープンソース性というところでGitHubにて組立説明書を公開しています。

[**➡ 組立説明書**](https://drive.google.com/file/d/1LfaUZmzZbCQRWulfV_bqecyGe_8wCMht/view)

![.](https://user-images.githubusercontent.com/22117028/263433813-eee6a7b1-f17d-4ff5-a04a-4e80cd8f1318.png)

まるで本物のLEGOの説明書のような出来ではないでしょうか。
これは[Studio 2.0](https://www.bricklink.com/v3/studio/download.page)というソフトを使って作っています。

Studio 2.0は[BrickLink](https://www.bricklink.com/v2/main.page)というLEGOパーツ売買サイトが作ったLEGO専用3D CADみたいなソフトで、PC上でLEGOの設計やレンダリング、組立説明書の作成ができます。
また使用するブロック一式を直接BrickLinkから購入したりもできます。

https://www.bricklink.com/v3/studio/download.page

https://www.bricklink.com/v2/main.page

## M5Stackデバイス

![image](https://gist.github.com/assets/22117028/02484d88-4f26-4342-afbc-b80d40b7274c)

サーボモーターを制御するマイコンにはM5Stackデバイスを使っています。
開発時は[Atom Lite](https://www.switch-science.com/products/6262)で実装していましたが、最終的にどのM5Stackデバイスでも使えるようになりました。
特に画面付きデバイスでは某ｽﾀｯｸﾁｬﾝらしき顔がディスプレイに表示されます。

![GIF動画読み込み中…](https://user-images.githubusercontent.com/22117028/268170653-b6dda61b-b5c6-4422-9fea-07ec170be564.gif)

オススメはバッテリーや画面も付いている[M5Stack Core2](https://www.switch-science.com/products/9349)ですが、安価に作りたい場合は[ATOMS3 Lite](https://www.switch-science.com/products/8778)がオススメです。

https://www.switch-science.com/products/9349

https://www.switch-science.com/products/8778

M5Stackデバイスの制御には後述するopnizを使用しており、デバイス自体に書き込むコードは1行も書いておらず[opniz CLI](https://github.com/miso-develop/opniz-cli)を使ってopnizデバイス化しただけです。
opnizデバイスの内部では[M5Unified](https://github.com/m5stack/M5Unified)が使われています。

https://github.com/miso-develop/opniz-cli

https://github.com/m5stack/M5Unified

## [GeekServo](https://www.switch-science.com/products/6811)

![image](https://gist.github.com/assets/22117028/0d2639ae-6755-48ed-ab71-872e1e90ab06)

レゴとくっつくサーボモーターです。
グレーの270度タイプのものを2つ使っています。

https://www.switch-science.com/products/6811

これをM5Stackデバイスへつないで制御します。
M5Stackデバイスとの接続は[Grove サーボ用2分岐ケーブル](https://www.switch-science.com/products/1250)を使っています。
配線がすっきりして便利です。

https://www.switch-science.com/products/1250



# ソフトウェア（バックエンド）

## Node.js & TypeScript

![image](https://user-images.githubusercontent.com/22117028/290505008-7571dd32-8072-4190-b8e5-778179d0e719.png)

バックエンド環境はNode.jsにて実行され、コードはTypeScriptで書きました。
Node.jsではM5Stackデバイスの制御用にopnizと、フロントエンド用にExpressを起動しています。

## [opniz](https://github.com/miso-develop/opniz-sdk-nodejs)

![image](https://gist.github.com/assets/22117028/28893f26-00bc-42a2-a6b8-16f4b8464a32)

M5Stackデバイスの制御にはopnizを使用しています。
opnizはM5StackデバイスをNode.jsから遠隔制御するオープンソースのIoTフレームワークです。
M5Stackデバイスを一度opnizデバイス化してしまえば、以降デバイスへの再書込不要でNode.js上から自由に制御できます。

https://github.com/miso-develop/opniz-sdk-nodejs

## Express

![image](https://gist.github.com/assets/22117028/ec15ab67-1de9-480e-99b1-3340df3d13e6)

後述するフロントエンドを提供しているWebサーバーにExpressを使用しています。
UIのHTMLの静的配信と、UIから呼び出されるAPIを提供するAPIゲートウェイとして使用しています。

## ルービックキューブのロジック

### 揃えるロジック
ルービックキューブを揃える（解く）アルゴリズムとしては「[Two-Phase-Algorithm](http://kociemba.org/twophase.htm)」というアルゴリズムが一般的です。
このTwo-Phase-AlgorithmのJavaScript実装である「[min2phase.js](https://github.com/cs0x7f/min2phase.js/)」というライブラリを使いました。

https://github.com/cs0x7f/min2phase.js/

### 崩すロジック
ランダムだったり、ある特定の状態に崩すアルゴリズムというのが見当たらなかったため、こちらは自分で考えました。
と言ってもしくみは単純で、まずランダムにキューブの状態を生成します。
しかしランダムなキューブ状態だとそもそも揃えることが可能な状態ではない可能性があるため、先述のmin2phase.jsを通して揃えることができるかチェックします。
この「ランダム生成→min2phase.jsチェック」をひたすら繰り返し、揃えることのできる崩れた状態を引き当てる、というしくみで実装しました。



# ソフトウェア（フロントエンド）

## Web UI
フロントエンドはWeb UIで提供しています。
また一応インターフェースという意味ではCLIとM5Stackデバイスのボタンもインターフェースとして機能提供しています。

<div style="display: flex; justify-content: space-between;">
	<img src="https://user-images.githubusercontent.com/22117028/263659725-6e6f6cd5-cea7-4629-ba0a-662ed955a02c.png" alt="Scramble View" width="160" style="border: solid 1px #bbb" />
	<img src="https://user-images.githubusercontent.com/22117028/263655815-e07282b3-cc23-4e87-8fc7-ea9e40f1d863.gif" alt="Solve View" width="160" style="border: solid 1px #bbb" />
	<img src="https://user-images.githubusercontent.com/22117028/263659860-5524fe7c-0ab7-4d0b-ab5e-76ce0994cf4e.png" alt="Sequence View" width="160" style="border: solid 1px #bbb" />
	<img src="https://user-images.githubusercontent.com/22117028/263659958-84a703b9-3985-432b-bebd-af919df81cbf.png" alt="Step View" width="160" style="border: solid 1px #bbb" />
</div>

## [Alpine.js](https://alpinejs.dev/)

![image](https://gist.github.com/assets/22117028/eafff0c7-3b4a-46a5-a99d-d3346d5a0d35)

シンプルなUIだったため、フロントエンドフレームワークとしては軽量フレームワークであるAlpine.jsを使いました。
はじめて使ってみたのですが軽量ゆえにTypeScriptではなくJavaScriptでそのまま書くコンセプトであり、書いている途中でバックエンド同様TypeScriptで書きたくなってきたりと辛みがでてきました。

https://alpinejs.dev/

ただ後述するTailwind CSSとの組み合わせで作られたUIライブラリ等の情報が多く公開されており、コピペしていじくるだけでAlpine.jsの学習と実装を賄えられて便利でした。

https://devdojo.com/pines

https://windstatic.com/

## [Tailwind CSS](https://tailwindcss.com/)

![image](https://gist.github.com/assets/22117028/44c2ca04-f6ef-4438-b558-005e083fb089)

これもはじめて使いましたが、UIパーツを適切にコンポーネント化する場合はTailwind CSSがいい感じだと思いました。
CSS用クラスのグローバルな名付けに脳リソースを割かなくてよくなるので。

https://tailwindcss.com/



# おわりに
以上「LEGO x M5Stack x Node.js x Web UI」な技術スタック構成の紹介でした。
この構成なら3Dプリンタを持っていなかったり、電子工作よく分からないWeb系な方でも気軽にものづくりできる構成なんじゃないかと思います。