日別アーカイブ: 2026/01/12

フルトラ#260111

自作フルトラッキングは、XIAOESP32C3+LSM6DSVでトラッカーを作成し、SlimeVRに認識させることができたので、手順をまとめておこう。
開発環境の準備
VisualStudioCodeでPlatformIO使う。インストールしたら、SmileVRのファームウェアをGitでローカルフォルダにクローンする。これらの手順はこのページにまとめられている。
ファームウェアの準備
プロジェクトのplatformio.iniファイルから、ファームウェアの設定(使うマイコンやセンサーの種類)を行う。ここに手順が記載されている。ここには、SlimeVRで使用される主要なマイコン用の設定が、あらかじめ何種類も記載されている。ESP8266、ESP32系が多いが、ここではXIAOESP32C3を想定する。冒頭default_envsで指定した設定でプログラムのビルドが行われる。ここではseeed_XIAO_ESP32C3という設定を新たに追加して使用している。「WifiのSSIDとパスワードをハードコードするばあいはここに書け」とあるが、ここのSSIDとPWは機能しない。これに長時間悩まされることとなる。

[platformio]
build_cache_dir = cache
;default_envs = seeed_xiao_esp32s3
default_envs = seeed_XIAO_ESP32C3

(中略)

;If you want to set hardcoded WiFi SSID and password, uncomment and edit the lines below
;To uncomment, only remove ";" and leave the two spaces in front of the tags
; '" - quotes are necessary!'
  -DWIFI_CREDS_SSID='"HELL"'
  -DWIFI_CREDS_PASSWD='"koda・・・・"'

(中略)

[env:seeed_XIAO_ESP32C3]
platform = espressif32 @ 6.7.0
platform_packages =
  framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#3.0.1
  framework-arduinoespressif32-libs @ https://github.com/espressif/arduino-esp32/releases/download/3.0.1/esp32-arduino-libs-3.0.1.zip

board = seeed_xiao_esp32c3

build_flags =
  ${env.build_flags}
  -DESP32C3
  -DARDUINO_USB_MODE=1
  -DARDUINO_USB_CDC_ON_BOOT=1

monitor_filters = colorize, esp32_exception_decoder
board_build.filesystem = littlefs

センサーの準備
センサーの設定はdefines.hから行う。解説ページで作ることもできるが、XIAOESP32C3の作成事例を参考に手動で作るのが良い。
①IMUをLSM6DSVに指定
②IMUの回転角度を指定(サンプルは解説ページにあるがよくわからない)
③セカンドIMUのあるなしを指定。
④LSM6DSVとのI2C接続(SCLとSDA)に使う端子を指定。SeeedのXIAOESP32C3マニュアルを見ながら指定する。ここでは作成事例に倣いD1とD2に指定。
⑤LSM6DSVの割り込み端子を指定する。IMUが測定完了をマイコンに知らせる端子(INT1)があり、これをつなぐと処理がスムースになるので必ずつなぐ。INT2はなくても良いらしいのでダミーとなっている。
⑥PIN_BATTERY_LEVELは電池電圧を調べる端子を指定する。ここではD0。Battry関連の設定を適切に行うと、適度な電圧低下でマイコンをスリープさせて電池を破損から守ってくれる機能があるらしい。
 上記設定にしたがって組み上がったトラッカーが、以下のブレッドボードとなる。どうにか動いているがD0未接続ですね。電池駆動にした際、電池の出力を分圧した値をD0に入れると思われる。センサーの設定は重要で、接続に失敗するとトラッカーが起動しなくなり、シリアル・ポートにログが出なくなるので注意。

#define IMU IMU_LSM6DSV
#define SECOND_IMU IMU
#define BOARD BOARD_CUSTOM
#define IMU_ROTATION DEG_180
#define SECOND_IMU_ROTATION DEG_180
 
#define PRIMARY_IMU_OPTIONAL false
#define SECONDARY_IMU_OPTIONAL true
 
#define MAX_IMU_COUNT 1
 
#ifndef IMU_DESC_LIST
#define IMU_DESC_LIST \
    IMU_DESC_ENTRY(IMU,        PRIMARY_IMU_ADDRESS_ONE,   IMU_ROTATION,        PIN_IMU_SCL, PIN_IMU_SDA, PRIMARY_IMU_OPTIONAL,   PIN_IMU_INT) 
 
#endif
 
#define PIN_IMU_SCL D1 //D1
#define PIN_IMU_SDA D2 //D2
#define PIN_IMU_INT D3 //D3
#define PIN_IMU_INT_2 D4 //D4
#define LED_PIN LED_OFF //OFF
 
#define PIN_BATTERY_LEVEL D0 //D0/A0
#define BATTERY_MONITOR BAT_EXTERNAL
#define BATTERY_SHIELD_RESISTANCE 0 
#define BATTERY_SHIELD_R1 100
#define BATTERY_SHIELD_R2 100

ビルドして送信し動作チェック
platformio.iniとdefines.hの準備ができたら、ビルド(✓ボタン)して送信(→ボタン)する。キャッシュが悪さをすることもあるようなので、Clean(左の虫アイコン→ボード→Generalからアクセス)もたまにする。送信が終わったら、シリアル・ポートを開く(コンセントのボタン)。適切にできていると、トラッカーからシリアル・ポートに起動メッセージが出力される。センサー認識メッセージに感涙の涙・・・。
Wifiログインできない問題
しかし、ハードコードしたSSIDとパスでアクセスポイントが見つけられない問題に直面する。ルータ側もチェックするが問題はなさそうであり、結局ソースコード(wifihandler.cpp)に手をいれるはめに。具体的には、ESP8266じゃないとき(つまりESP32である今回のようなとき)if (phyModeG) {return false;}となり、問答無用で何もしない設定になっていた。ここに接続用のコードを追記することでサーバーへの接続が可能となり、スマホのSlimeVRアプリにトラッカーを出すことに成功した。同じソースコードでS3も試したが、こちらはどうも様子がおかしく信号が安定しない。今回はC3で行くか。

bool WiFiNetwork::tryConnecting(bool phyModeG, const char* SSID, const char* pass) {
#if ESP8266
	if (phyModeG) {
		WiFi.setPhyMode(WIFI_PHY_MODE_11G);
		if constexpr (USE_ATTENUATION) {
			WiFi.setOutputPower(20.0 - ATTENUATION_G);
		}
	} else {
		WiFi.setPhyMode(WIFI_PHY_MODE_11N);
		if constexpr (USE_ATTENUATION) {
			WiFi.setOutputPower(20.0 - ATTENUATION_N);
		}
	}
#else
	/*
	if (phyModeG) {
		return false;
	}
	*/
	///////////////////////////////
	wifiHandlerLogger.info("ESP32: resetting WiFi state before begin()");
	WiFi.disconnect(true);
	delay(200);
	WiFi.mode(WIFI_STA);
	delay(50);	
	////////////////////////////////


	if (phyModeG) {
		// ESP32: PHY mode cannot be changed like ESP8266.
		// Treat "G retry" as a normal retry.
		wifiHandlerLogger.warn(
			"ESP32: PHY Mode G requested but not supported. Falling back to normal connect. SSID='%s' passLen=%d",
			(SSID ? SSID : "<saved>"),
			(pass ? (int)strlen(pass) : -1)
		);
		Serial.println("###DBG### ESP32 phyModeG requested -> fallback to normal connect");
		phyModeG = false; // 以降は通常接続として進める
	}

#endif

	/////////////////////////////////////////////
	wifiHandlerLogger.info(
		"###DBG### WiFi.begin about to run: SSIDptr=%p SSID='%s' passLen=%d phyModeG=%d",
		SSID,
		(SSID ? SSID : "<saved>"),
		(pass ? (int)strlen(pass) : -1),
		(int)phyModeG
	);
	Serial.println("###DBG### tryConnecting entered");
	/////////////////////////////////////////////

	setStaticIPIfDefined();
	if (SSID == nullptr) {
		WiFi.begin();
	} else {
		WiFi.begin(SSID, pass);
	}
	wifiConnectionTimeout = millis();
	return true;
}