見出し画像

ESP32-C3 その4 簡易データーグローブソフトウェア部門(アナログスティック)


簡易データグローブとは

精度はそんなに高くなく、指の曲がりは曲げ伸ばし、指同士の間隔は測れず、ただただ安価を目指します。

の続き
そのままコード載せようかと思ったけど整理しきれないので掻い摘んで

ESP32C3側のプログラム

ADCの値を読み取ってOSCでUnityに送信
platformIOを使います。OSCの送信にはArduinoOSCを使うのでライブラリを追加する。analogReadでセンサー値読み込んで、OscWiFi.sendでUnityに送る。とってもシンプル。ssidとpassは環境に合わせてください。

#include <Arduino.h>
#include <ArduinoOSCWiFi.h>

#define LEFT_LITTLE 0
#define LEFT_RING 1
#define LEFT_MIDDLE 2
#define LEFT_INDEX 3
#define LEFT_THUMB 4

// WiFi stuff
const char ssid[] = "OninNoLAN";
const char pass[] = "14671477";

// for ArduinoOSC
const char osc_host[] = "192.168.100.105";
const int osc_send_port = 3333;
const int osc_recv_port = 3334;

void setup() {
	Serial.begin(115200);

	WiFi.disconnect(true, true);  // disable wifi, erase ap info
	delay(1000);
	WiFi.mode(WIFI_STA);
	WiFi.begin(ssid, pass);

	while (WiFi.status() != WL_CONNECTED) {
		Serial.print(".");
		delay(500);
	}

	pinMode(LEFT_LITTLE, INPUT);
	pinMode(LEFT_RING, INPUT);
	pinMode(LEFT_MIDDLE, INPUT);
	pinMode(LEFT_INDEX, INPUT);
	pinMode(LEFT_THUMB, INPUT);
}

void loop() {
	float lit = analogRead(LEFT_LITTLE);
	float rng = analogRead(LEFT_RING);
	float mid = analogRead(LEFT_MIDDLE);
	float idx = analogRead(LEFT_INDEX);
	float tmb = analogRead(LEFT_THUMB);

	OscWiFi.send(osc_host, osc_send_port, "/Left/Hand/Little", (float)lit);
	OscWiFi.send(osc_host, osc_send_port, "/Left/Hand/Ring", (float)rng);
	OscWiFi.send(osc_host, osc_send_port, "/Left/Hand/Middle", (float)mid);
	OscWiFi.send(osc_host, osc_send_port, "/Left/Hand/Index", (float)idx);
	OscWiFi.send(osc_host, osc_send_port, "/Left/Hand/Thumb", (float)tmb);

	delay(50);
}

Unty側のプログラム

OSCを受け取ってアバターのMUSCLEを操作してボーンを動かす。
OnDataReceivedで変数に保存updateで定期的にアバターに反映です

Start()

muscles使うのでアニメーターと必要なものを保存

    void Start()
    {
        if (_animator != null) {
            _animator = VRMObject.transform.GetComponent<Animator>();
        }
        _handler = new HumanPoseHandler(_animator.avatar, _animator.transform);
        _humanpose = new HumanPose();
    }

Update()

そのまま代入知るとガクガクするのでClampでぬるっと動かす

	void Update()
	{
		_handler.GetHumanPose(ref _humanpose);

		float _val = 0.0f;

		_val = _humanpose.muscles[71];
		_val = Mathf.Lerp(_val, Mathf.Clamp(left_little, -1.0f, 1.0f), 0.2f);
		_humanpose.muscles[71] = _val;
		_humanpose.muscles[73] = _val;
		_humanpose.muscles[74] = _val;

		_val = _humanpose.muscles[67];
		_val = Mathf.Lerp(_val, Mathf.Clamp(left_ring, -1.0f, 1.0f), 0.2f);
		_humanpose.muscles[67] = _val;
		_humanpose.muscles[69] = _val;
		_humanpose.muscles[70] = _val;

		_val = _humanpose.muscles[63];
		_val = Mathf.Lerp(_val, Mathf.Clamp(left_middle, -1.0f, 1.0f), 0.2f);
		_humanpose.muscles[63] = _val;
		_humanpose.muscles[65] = _val;
		_humanpose.muscles[66] = _val;

		_val = _humanpose.muscles[59];
		_val = Mathf.Lerp(_val, Mathf.Clamp(left_index, -1.0f, 1.0f), 0.2f);
		_humanpose.muscles[59] = _val;
		_humanpose.muscles[61] = _val;
		_humanpose.muscles[62] = _val;

		_val = _humanpose.muscles[55];
		_val = Mathf.Lerp(_val, Mathf.Clamp(left_thumb, -1.0f, 1.0f), 0.2f);
		_humanpose.muscles[55] = _val;
		_humanpose.muscles[57] = _val;
		_humanpose.muscles[58] = _val;

		_handler.SetHumanPose(ref _humanpose);
	}

OSCを受信した際の処理

    public void OnDataReceived(Message message)
    {
        if (message.address == "/Left/Hand/Little")
        {
            float _val = (float)message.values[0];
            _val = (_val - adc_max / 2.0f) / (adc_max / 2.0f);
            left_little = -_val ;
        }

        if (message.address == "/Left/Hand/Ring")
        {
            float _val = (float)message.values[0];
            _val = (_val - adc_max / 2.0f) / (adc_max / 2.0f);
            left_ring = -_val;
        }

        if (message.address == "/Left/Hand/Middle")
        {
            float _val = (float)message.values[0];
            _val = (_val - adc_max / 2.0f) / (adc_max / 2.0f);
            left_middle = -_val;
        }

        if (message.address == "/Left/Hand/Index")
        {
            float _val = (float)message.values[0];
            _val = (_val - adc_max / 2.0f) / (adc_max / 2.0f);
            left_index = -_val;
        }

        if (message.address == "/Left/Hand/Thumb")
        {
            float _val = (float)message.values[0];
            _val = (_val - adc_max / 2.0f) / (adc_max / 2.0f);
            left_thumb = -_val;
        }

    }

アナログセンサーの入力がニュートラルで4095/2になります。
0で指を反る。4095で指を握る。

MUSCLEの-1.0f ~ 1.0fへ変換してあげないといけない。
この部分で合わせてキャリブレートもできるかも。

アナログスティックを使ってみた感想

パーツ自体が大きいので手の甲に5つ装備するのはちょっと無理かな。めちゃ手の大きい人なら可能ではあるけど現実的ではない。Switchの修理パーツとして売られてるものはもっと小型なのでそれを使えば・・・

ニュートラルにもどる性質があるので握りからニュートラルの状態への動きは良好。反りはちょっと使いにくいです。

指輪型のスティック引っ張りパーツを3Dプリンタで作ったけどそこそこ指輪型の部分が擦れるので皮膚に負担がある。続けて使うのはちょっとねぇ。

次回からは曲げセンサー編へ

1000円もしない値段で買えるなら曲げセンサーでいいじゃん、です。

この記事が気に入ったらサポートをしてみませんか?