はじめに
OBのUMEです。
部活公式Vtuberができたりランダムのサイトがいつのまにやら新しくなったりブログリレーをやったりとアクティブに活動しているのを見てすげーという気持ちになっていたところ、 活発な部員のペンギンから
老害OB枠として新歓ブログリレー参加して貰えません?(原文ママ)
というメッセージを受け取ったので、適当に何か記事を書いてみます。
新入生を意識してかふわっとした楽しげな記事が多いですが、自分は少しお堅い記事を書いてみます。
記事の内容に直接関係ないですが、ブログ執筆用のページ普通に高機能ですごい。
やること
この3Dジェスチャーを認識するモジュールを使ってみます。電子工作のモジュールを扱うスイッチサイエンスというところに新商品として並んでいたものです。
(良い感じの短い名前が付いていなさそうなので、この記事内では Seeed_mgc3130 と呼ぶことにします)
磁場の変化をもとに手の動きを読み取るモジュールのようです。
関連商品として Skywriter HAT というものも並んでいます。
これもSeeed_mgc3130と似たようなモジュールで、こちら の記事でラズパイ版Minecraftを指で動かすところまで行われています。
Seeed_mgc3130はまだそのような使用体験を書いたものが無さそうだったので、上記記事と同様にMinecraftの操作ができるところまでやってみます。
電子工作は1年もやってない初心者ですががんばります。
マイコンの話
おそらくマイコンのことをあまり知らない人が多いと思うので、ざっくりと説明しておきます。
ArduinoやRaspberryPiなどのマイコンは、基板上のピンに電圧をかけたり、かかっている電圧を読み取ったりできます。
基本的に機能はこれだけですが、これができるといろんなことができます。
例えば、気温によって出力電圧が変わる温度センサーをアナログピンにつないで、電圧を読み取ることで温度を得ることができます。
もっと汎用的な使い方として、電圧のHIGH/LOWの高速な切り替えでデジタルな信号を表現することで、異なるマイコンやモジュール間で通信ができます。 小型液晶のモジュールなどはこういった通信で受け取った値を元にして表示するようになっています。
今回はRaspberryPiというマイコンを使います。このマイコンは上記のようなマイコンとしての基本機能に加えてLinuxというOSが動くという特徴があります。
その特徴を生かすことで、センサモジュールで読み取った値を元にtwitterとかslackとかに投稿するbotなんかも作れたりします。
ただ、高機能な分だけ値段も高めで、別途microSDカードやminiHDMI⇔HDMIケーブルも必要です。
熱も出るので放熱用のケースやファン、ヒートシンクなども必要です。
操作もLinuxなので初めて触る人には少し敷居が高いかもしれません。
今回は使いませんが、ArduinoというマイコンだとTypeBやmicroUSBケーブル一本でPCと接続して操作でき、プログラムを書く環境もソフト一個インストールするだけで終わるので非常にらくちんです。
最近だと無線や小型液晶モジュールなどが標準搭載されたM5stackという種類もあり、Arduinoの開発環境を使えたりします。
使うもの
- Raspberry Pi 4 スターターキット(4GB RAM版)
セットのやつを持っておくとトラブルに逢いにくい。お値段高め - Seeed_mgc3130
本命。壊した時の予備含めて2つ買っておいた - ヒートシンク
Seeed_mgc3130を取り付けるので放熱関係は高さ10mmくらいまでのものしか取り付けられず、取り付けてもたぶんほとんど効果はない
セットアップ
ラズパイのセットアップはこの記事のメインテーマではないので、詳細な操作は省きます。 Linuxの操作や設定について何か分からないことがあれば活発な部員のペンギンを頼りにしましょう。
基本的なセットアップが終わったら、I2C通信を有効にしておきます。
Seeed_mgc3130を使えるようにする
まずはモジュールをラズパイに接続します。
今回使うSeeed_mgc3130はHATやシールドと呼ばれるタイプで、ピンが並んだところに差し込むだけでOKです。
次に公式ページやライブラリのReadmeに書かれている通りに設定します。
(記述を省いていますが、一通りコマンドを打ち込むごとに cd
でhomeに戻るようにしましょう)
# ncursesのインストール
wget https://invisible-mirror.net/archives/ncurses/ncurses-6.1.tar.gz
tar -xvf ncurses-6.1.tar.gz
cd ncurses-6.1/
./configure
make
sudo make install
ncurses6-config --version
# WiringPiのインストール
git clone https://github.com/WiringPi/WiringPi.git
cd wiringPi
./build
一通り設定が済んで、サンプルプログラムを動かすと以下のような感じで読み取った値が表示されます。
# Seeed_mgc3x30のサンプルプログラム
git clone https://github.com/Seeed-Studio/Seeed_mgc3x30.git
cd Seeed_mgc3x30
make clean && make
./mgc3130
************************************************************
* *
* Position X : 28306 *
* Position Y : 0 *
* Position Z : 34198 *
* *
* Gesture : North to South *
* *
* Airwheel angle : 2272 *
* *
* Touch electrode : Center
* Tap electrode : *
* Double Tap electrode : * *
* *
* *
* *
* *
* *
************************************************************
モジュールの上10cmくらいで指を動かすとxyzが変化します。
また、タッチすると大まかなタッチ位置(中心と東西南北)、ダブルタップかどうか等が表示されます。
ボード上を良い感じの速度で横切った時は(South To North)みたいに出ます。判定されるにはちょっとコツが要ります。
ボード上でボードと平行な面上で指を良い感じの速度で回すと回転角が変化します。これも判定されるにはちょっとコツが要ります。
Seeed_mgc3130をPythonで使う
Python用のライブラリをgithubからcloneしてきて、説明の通りにインストールします。
git clone https://github.com/open-electronics/GestIC.git
cd GestIC/AppRaspberry/Librerie/MGC3130_Lib/V1_1_0_0/MGC3130
sudo python setup.py install
このライブラリをimportして使うのですが、 getX()
みたいな値を取得する関数は用意されていないみたいなので、
モジュールから読み取ったbyte列から良い感じでxyzの値を取ってくるようにします。
ライブラリの実装を雰囲気で見た感じ、以下のような感じで値が取れるみたいです。
import sys
sys.path.insert(0, "/usr/local/lib/python2.7/dist-packages/MGC3130")
import MGC3130
from MGC3130 import *
import RPi.GPIO as GPIO
import time
# 初期設定
# なくてもいけるっぽい
MGC3130_SetAdd("/dev/i2c-1")
GPIO.setmode(GPIO.BCM)
MGC3130_Begin(GPIO, 8, 11)
# 礼儀正しく終わるときは呼び出す
# GPIO.cleanup()
while(True):
# 読み取り
MGC3130_GetEvent()
# 生データから2byteずつ読み出し
x = MGC3130._xyz.xyzArray[1] * 256 + MGC3130._xyz.xyzArray[0]
y = MGC3130._xyz.xyzArray[3] * 256 + MGC3130._xyz.xyzArray[2]
z = MGC3130._xyz.xyzArray[5] * 256 + MGC3130._xyz.xyzArray[4]
print("{:>5},{:>5},{:>5}".format(x,y,z))
time.sleep(0.01)
最初にSeeed_mgc3130との通信に使うピンの指定などをします。引数は回路図を見たりしつつ雰囲気で入れておきます。
GetEvent
を呼び出すとモジュールからbyte列を読みだしてなんやかんやしているようですが、このあたりに書いてあるように、取得した生のbyte列の20~25番目に(x,y,z)が2byteずつ入っているようです。
この6byte分は別途 MGC3130._xyz.xyzArray
に格納されているのでそれを参照しています。
GetEventの実装上、検出した動きがないときはTelegram not managed
がコンソールに出力されます。
このあたりは適宜ライブラリの該当箇所をコメントアウトするなどした方がよさそうです。
Seeed_mgc3130をMinecraftで使う
x,y,zの値が取れたので、この値をMinecraftの主人公の位置として反映させるようにします。
import sys
sys.path.insert(0, "/usr/local/lib/python2.7/dist-packages/MGC3130")
import MGC3130
from MGC3130 import *
import time
from mcpi.minecraft import Minecraft
mc = Minecraft.create()
while(True):
MGC3130_GetEvent()
x = MGC3130._xyz.xyzArray[1] * 256 + MGC3130._xyz.xyzArray[0]
y = MGC3130._xyz.xyzArray[3] * 256 + MGC3130._xyz.xyzArray[2]
z = MGC3130._xyz.xyzArray[5] * 256 + MGC3130._xyz.xyzArray[4]
x = int(x/1024) - 32.5
y = int(y/1024) - 32.5
z = int(z/1024) + 0.5
mc.camera.setPos(y,z,x)
print("{:>5},{:>5},{:>5}".format(x,y,z))
time.sleep(0.01)
Minecraftを起動してワールドに入った状態でこれを呼び出すと、指の動きに合わせて動くようになります。
(スペースキー2回押しで空中浮遊モードになっておかないと、位置更新の間に重力で下に移動してしまうので上下にガタガタ動いてしまいます)
反応が遅延しているような気がしますが、シビアな入力を要求されるものを操作してみないとどの程度遅延しているか判断しにくいです。
多少の遅延を誤魔化せるように慣性で移動するようにしてみたら、ちょっとは遊べそうな操作感になりました。
今後の予定
RaspberryPiでとりあえず使えることは分かったので、今度はArduinoでやってみたい。
ArduinoのLeonardoという種類を使えばマウスになりきることができるので、擬似トラックパッドみたいなデバイスを作れそうな気がしている。
(実用性があるかどうかは一旦おいといて)
さいごに
プログラムが書けるとゲームやら解の探索やらbotの稼働やら何でもできるように思えますが、現実世界の物に干渉するためには電子工作は必須です。
今回のようにモジュールを繋ぐだけでも現実世界の情報を読み取れるようになります。モーターの制御とかやれば物を動かすこともできます。
電子工作は基本パーツ・ケーブル・マイコン・モジュール・用具といろいろ揃える必要があってお金がかかりがちなので、部活などでシェアできるとらくちんです。
部活内の競プロ熱がここ数年で盛り上がったように、電子工作も盛り上がったりしないかな...とこっそり思っています。