Tundra TrackerとRP2040でオリジナルのコントローラーをつくる
更新日:2023-03-31
/blog/2023/03/diy-controller-with-tundra-tracker-and-rp2040blogTundra TrackerとRP2040で通信する方法を備忘録を兼ねて書いてみようと思います
GitHub – tundra-labs/rp2040_examples
Tundra Tracker
TundraLabsが開発しているVRトラッカーでSteamVRのLighthouseに対応しています
このトラッカー小型だったり稼働時間が長かったりと色々な特徴がありますが個人的に一番だと思っているのが拡張性です
vive trackerにも外部との接続端子がありましたがそれぞれの端子は1bitの情報しか扱えず、アナログスティックなどを搭載することはできませんでした
しかしTundra Trackerは底面のフラットケーブルを介してマイコンなどとSPI通信を行うことができるのでアナログスティックを搭載したりすることが出来ます
ドライバー
まず新しいドライバを作成する必要があります
{
"alwaysActivate": true,
"name" : "driver_name",
"directory" : "",
"resourceOnly" : false,
"hmd_presence" : []
}
DriverManifest · ValveSoftware/openvr Wiki · GitHub
"input_source": {
"/input/stick": {
"type": "joystick",
"binding_image_point": [
0,
0
],
"order": 1
},
"/output/haptic": {
"type": "vibration",
"binding_image_point": [
5,
35
]
}
},
"input_components": {
"/input/stick/x": {
"bit_offset": 0,
"bit_width": 10,
"type": "scalar",
"min": 0,
"max": 1024,
"unit": "twosided",
"special_value_zero":0
},
"/input/stick/y": {
"bit_offset": 10,
"bit_width": 10,
"type": "scalar",
"min": 0,
"max": 1024,
"unit": "twosided",
"special_value_zero":0
}
}
input_componentsでオフセット、幅(大きさ)、種類などを指定することでSPIで送られてくるビット列を各入力に割り当てることが出来ます(Tundra Trackerオリジナル要素っぽい?)
この例だとビット列の0番目から9番目までの10ビットをスティックのx軸に、10番目から19番目までの10ビットをy軸に割り当てています
ドライバの登録
作成したドライバーを使うにはSteamVRのドライバーフォルダの中に直接ぶち込むかSteamvrに登録する必要があります
今回はSteamvrにドライバを登録する方法で行きます
これならコマンドひとつで解除できますし
ドライバの登録/解除は
<Steamのフォルダ>/steamapps/common/SteamVR/bin/win64/
にあるvrpathreg.exeから行います
ドライバを登録するには引数にadddriver <ドライバのパス>を指定します
> vrpathreg.exe adddriver <driver_path>
これでvrdrivermanifestのnameで設定した名前でドライバが登録されます
JSON File
SteamVRデバイスには種類(コントローラーなのかトラッカーなのか)や製造元、読み込むInputプロファイルのパスなどが記述されているjsonファイルが書き込まれています
これを書き換える必要があるのでデフォルトのものをデバイスからダウンロードします
パソコンにデバイスをUSB接続した状態で
<Steamのフォルダ>/steamapps/common/SteamVR/tools/lighthouse/bin/win64/lighthouse_console.exe
を実行しコンソールが開いたらdownloadconfigを実行
lh> downloadconfig
LHR-<Serialnumber>: Read config of 1261 bytes from [vid:28de, pid:2300] (LHR-<Serialnumber>) and inflated to 3567 bytes
Wrote 3567 bytes to LHR-<Serialnumber>.json
lh>
これでLHR-{シリアルナンバー}.jsonという名前でファイルが保存されます
このファイルは書き換えるので元に戻すためにバックアップを取っていてください
書き換えるのは2か所だけでまずfirmware_configに”mapped_input” : trueを追記
"firmware_config" : {
"mapped_input" : true,
}
そしてinput_profileの値を新しく作成したinput_profileのパスに変更
"input_profile" : "{tundra_labs}/input/tundra_tracker_profile.json" -> "input_profile" : "{driver_name}/input/input_profile.json"
出来たらuploadconfigで書き換え後のファイルをデバイス内に書き込みます
lh> uploadconfig "LHR-{Serialnumber}.json"
Compressed config size is 1262
LHR-1076335E: Triggered keepalive (succeeded)
LHR-1076335E: Packet received after 0.032s, keepalive (0/1)
Wrote the contents of LHR-{Serialnumber}.json as the config on the device
lh>
SteamVRの設定からコントローラのテストを開きデフォルトから変わっていれば成功です!!
RP2040
Tundra Trackerとマイコン(RP2040)はSPIで通信を行います
トラッカー側がマスターでマイコンがスレーブです
公式サンプルがあるのでそれを使います
typedef struct __attribute__( ( packed, aligned( 1 ) ) )
{
uint8_t system : 1; //0
uint8_t a : 1; //1
uint8_t b : 1; //2
uint8_t trigger_btn : 1; //3
uint8_t grip : 1; //4
uint8_t thumbstick : 1; //5
uint8_t menu : 1; //6
uint8_t thumbstick_en : 1; //7
uint16_t thumbstick_x : 10; //8
uint16_t thumbstick_y : 10; //18
uint16_t trigger : 10; //28
uint16_t index : 10; //38
uint16_t middle : 10; //48
uint16_t ring : 10; //58
uint16_t pinky : 10; //68
}
controller_data_t;
このコードでは専用の構造体を宣言することで分かりやすくビット配列を表現できるようにしています コロン以降はそれぞれの変数に割り当てられるビット数です
typedef struct __attribute__( ( packed, aligned( 1 ) ) )
{
unsigned int x:10;
unsigned int y:10;
}
controller_data_t;
アナログスティックを搭載する場合の例です
作ってみました(色々雑ですが)