Improve tracking significantly
This commit is contained in:
parent
2544de6857
commit
d7f71a41fb
3
dance.py
3
dance.py
|
@ -165,9 +165,6 @@ async def connect_joycon(app, ws, data):
|
|||
host_ip_addr=host_ip_addr,
|
||||
console_ip_addr=console_ip_addr,
|
||||
on_state_changed=on_joydance_state_changed,
|
||||
accel_acquisition_freq_hz=config['accel_acquisition_freq_hz'],
|
||||
accel_acquisition_latency=config['accel_acquisition_latency'],
|
||||
accel_max_range=config['accel_max_range'],
|
||||
)
|
||||
app['joydance_connections'][serial] = joydance
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import random
|
|||
import socket
|
||||
import ssl
|
||||
import time
|
||||
import traceback
|
||||
from enum import Enum
|
||||
from urllib.parse import urlparse
|
||||
|
||||
|
@ -11,10 +12,9 @@ import aiohttp
|
|||
import websockets
|
||||
|
||||
from .constants import (ACCEL_ACQUISITION_FREQ_HZ, ACCEL_ACQUISITION_LATENCY,
|
||||
ACCEL_MAX_RANGE, ACCEL_SEND_RATE, JOYCON_UPDATE_RATE,
|
||||
SHORTCUT_MAPPING, UBI_APP_ID, UBI_SKU_ID,
|
||||
WS_SUBPROTOCOLS, Command, JoyConButton,
|
||||
WsSubprotocolVersion)
|
||||
ACCEL_MAX_RANGE, FRAME_DURATION, SHORTCUT_MAPPING,
|
||||
UBI_APP_ID, UBI_SKU_ID, WS_SUBPROTOCOLS, Command,
|
||||
JoyConButton, WsSubprotocolVersion)
|
||||
|
||||
|
||||
class PairingState(Enum):
|
||||
|
@ -68,6 +68,8 @@ class JoyDance:
|
|||
self.is_input_allowed = False
|
||||
self.available_shortcuts = set()
|
||||
|
||||
self.accel_data = []
|
||||
|
||||
self.ws = None
|
||||
self.disconnected = False
|
||||
|
||||
|
@ -239,52 +241,81 @@ class JoyDance:
|
|||
async for message in self.ws:
|
||||
await self.on_message(message)
|
||||
|
||||
async def send_accelerometer_data(self):
|
||||
accel_data = []
|
||||
delta_time = 0
|
||||
|
||||
end = time.time()
|
||||
async def tick(self):
|
||||
sleep_duration = FRAME_DURATION * 0.75
|
||||
last_time = time.time()
|
||||
frames = 0
|
||||
|
||||
while True:
|
||||
if self.disconnected:
|
||||
break
|
||||
|
||||
# Make sure it runs at exactly 60 FPS
|
||||
while True:
|
||||
time_now = time.time()
|
||||
dt = time_now - last_time
|
||||
if dt >= FRAME_DURATION:
|
||||
break
|
||||
last_time = time_now
|
||||
frames = frames + 1 if frames < 5 else 1
|
||||
|
||||
if not self.should_start_accelerometer:
|
||||
await asyncio.sleep(0.5)
|
||||
await asyncio.sleep(sleep_duration),
|
||||
continue
|
||||
|
||||
start = time.time()
|
||||
if delta_time > ACCEL_SEND_RATE:
|
||||
delta_time = 0
|
||||
while len(accel_data) > 0:
|
||||
accels_num = min(len(accel_data), 10)
|
||||
await asyncio.gather(
|
||||
asyncio.sleep(sleep_duration),
|
||||
self.collect_accelerometer_data(),
|
||||
self.send_accelerometer_data(frames),
|
||||
)
|
||||
|
||||
await self.send_message('JD_PhoneScoringData', {
|
||||
'accelData': accel_data[:accels_num],
|
||||
'timeStamp': self.number_of_accels_sent,
|
||||
})
|
||||
async def collect_accelerometer_data(self):
|
||||
if self.disconnected:
|
||||
return
|
||||
|
||||
self.number_of_accels_sent += accels_num
|
||||
accel_data = accel_data[accels_num:]
|
||||
if not self.should_start_accelerometer:
|
||||
self.accel_data = []
|
||||
return
|
||||
|
||||
try:
|
||||
await asyncio.sleep(JOYCON_UPDATE_RATE)
|
||||
joycon_status = self.joycon.get_status()
|
||||
except OSError:
|
||||
self.disconnect()
|
||||
return
|
||||
try:
|
||||
accel = {
|
||||
'x': self.joycon.get_accel_x(),
|
||||
'y': self.joycon.get_accel_y(),
|
||||
'z': self.joycon.get_accel_z(),
|
||||
}
|
||||
|
||||
# Accelerator axes on phone & Joy-Con are different so we need to swap some axes
|
||||
# https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering/blob/master/imu_sensor_notes.md
|
||||
accel = joycon_status['accel']
|
||||
x = accel['y'] * -1
|
||||
y = accel['x']
|
||||
z = accel['z']
|
||||
|
||||
accel_data.append([x, y, z])
|
||||
self.accel_data.append([x, y, z])
|
||||
except OSError:
|
||||
self.disconnect()
|
||||
return
|
||||
|
||||
end = time.time()
|
||||
delta_time += (end - start) * 1000
|
||||
async def send_accelerometer_data(self, frames):
|
||||
if not self.should_start_accelerometer:
|
||||
return
|
||||
|
||||
if frames < 5:
|
||||
return
|
||||
|
||||
tmp_accel_data = []
|
||||
while len(self.accel_data):
|
||||
tmp_accel_data.append(self.accel_data.pop(0))
|
||||
|
||||
while len(tmp_accel_data) > 0:
|
||||
accels_num = min(len(tmp_accel_data), 10)
|
||||
|
||||
await self.send_message('JD_PhoneScoringData', {
|
||||
'accelData': tmp_accel_data[:accels_num],
|
||||
'timeStamp': self.number_of_accels_sent,
|
||||
})
|
||||
|
||||
self.number_of_accels_sent += accels_num
|
||||
tmp_accel_data = tmp_accel_data[accels_num:]
|
||||
|
||||
async def send_command(self):
|
||||
''' Capture Joycon's input and send to console. Only works on protocol v2 '''
|
||||
|
@ -292,16 +323,14 @@ class JoyDance:
|
|||
return
|
||||
|
||||
while True:
|
||||
if self.disconnected:
|
||||
return
|
||||
|
||||
try:
|
||||
if self.disconnected:
|
||||
return
|
||||
|
||||
await asyncio.sleep(FRAME_DURATION)
|
||||
if not self.is_input_allowed and not self.should_start_accelerometer:
|
||||
await asyncio.sleep(JOYCON_UPDATE_RATE * 5)
|
||||
continue
|
||||
|
||||
await asyncio.sleep(JOYCON_UPDATE_RATE * 5)
|
||||
|
||||
cmd = None
|
||||
# Get pressed button
|
||||
for event_type, status in self.joycon.events():
|
||||
|
@ -309,7 +338,7 @@ class JoyDance:
|
|||
continue
|
||||
|
||||
joycon_button = JoyConButton(event_type)
|
||||
if self.should_start_accelerometer: # Can only send Pause command while playing
|
||||
if self.should_start_accelerometer: # Only allow to send Pause command while playing
|
||||
if joycon_button == JoyConButton.PLUS or joycon_button == JoyConButton.MINUS:
|
||||
cmd = Command.PAUSE
|
||||
else:
|
||||
|
@ -318,7 +347,7 @@ class JoyDance:
|
|||
elif joycon_button == JoyConButton.B or joycon_button == JoyConButton.DOWN:
|
||||
cmd = Command.BACK
|
||||
elif joycon_button in SHORTCUT_MAPPING:
|
||||
# Get command depends on which button was pressed & which shortcuts are available
|
||||
# Get command depends on which button is being pressed & which shortcuts are available
|
||||
for shortcut in SHORTCUT_MAPPING[joycon_button]:
|
||||
if shortcut in self.available_shortcuts:
|
||||
cmd = shortcut
|
||||
|
@ -344,27 +373,21 @@ class JoyDance:
|
|||
|
||||
# Send command to server
|
||||
if cmd:
|
||||
data = {}
|
||||
if cmd == Command.PAUSE:
|
||||
__class = 'JD_Pause_PhoneCommandData'
|
||||
data = {}
|
||||
elif type(cmd.value) == str:
|
||||
__class = 'JD_Custom_PhoneCommandData'
|
||||
data = {
|
||||
'identifier': cmd.value,
|
||||
}
|
||||
data['identifier'] = cmd.value
|
||||
else:
|
||||
__class = 'JD_Input_PhoneCommandData'
|
||||
data = {
|
||||
'input': cmd.value,
|
||||
}
|
||||
data['input'] = cmd.value
|
||||
|
||||
# Only send input when it's allowed to, otherwise we might get a disconnection
|
||||
if self.is_input_allowed:
|
||||
await self.send_message(__class, data)
|
||||
await asyncio.sleep(0.01)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
import traceback
|
||||
await asyncio.sleep(FRAME_DURATION * 5)
|
||||
except Exception:
|
||||
traceback.print_exc()
|
||||
await self.disconnect()
|
||||
|
||||
|
@ -403,17 +426,18 @@ class JoyDance:
|
|||
) as websocket:
|
||||
try:
|
||||
self.ws = websocket
|
||||
|
||||
await asyncio.gather(
|
||||
self.send_hello(),
|
||||
self.send_accelerometer_data(),
|
||||
self.tick(),
|
||||
self.send_command(),
|
||||
)
|
||||
|
||||
except websockets.ConnectionClosed:
|
||||
await self.on_state_changed(self.joycon.serial, PairingState.ERROR_CONSOLE_CONNECTION)
|
||||
await self.disconnect(close_ws=False)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
except Exception:
|
||||
traceback.print_exc()
|
||||
await self.on_state_changed(self.joycon.serial, PairingState.ERROR_CONSOLE_CONNECTION)
|
||||
await self.disconnect(close_ws=False)
|
||||
|
||||
|
@ -449,6 +473,6 @@ class JoyDance:
|
|||
await self.hole_punching()
|
||||
|
||||
await self.connect_ws()
|
||||
except Exception as e:
|
||||
except Exception:
|
||||
await self.disconnect()
|
||||
print(e)
|
||||
traceback.print_exc()
|
||||
|
|
|
@ -14,10 +14,9 @@ WS_SUBPROTOCOLS = {}
|
|||
WS_SUBPROTOCOLS[WsSubprotocolVersion.V1.value] = 'v1.phonescoring.jd.ubisoft.com'
|
||||
WS_SUBPROTOCOLS[WsSubprotocolVersion.V2.value] = 'v2.phonescoring.jd.ubisoft.com'
|
||||
|
||||
JOYCON_UPDATE_RATE = 0.02 # 50Hz
|
||||
ACCEL_SEND_RATE = 40 # ms
|
||||
ACCEL_ACQUISITION_FREQ_HZ = 50 # Hz
|
||||
ACCEL_ACQUISITION_LATENCY = 20 # ms
|
||||
FRAME_DURATION = 1 / 60
|
||||
ACCEL_ACQUISITION_FREQ_HZ = 60 # Hz
|
||||
ACCEL_ACQUISITION_LATENCY = 40 # ms
|
||||
ACCEL_MAX_RANGE = 8 # ±G
|
||||
|
||||
DEFAULT_CONFIG = {
|
||||
|
@ -25,9 +24,6 @@ DEFAULT_CONFIG = {
|
|||
'host_ip_addr': '',
|
||||
'console_ip_addr': '',
|
||||
'pairing_code': '',
|
||||
'accel_acquisition_freq_hz': ACCEL_ACQUISITION_FREQ_HZ,
|
||||
'accel_acquisition_latency': ACCEL_ACQUISITION_LATENCY,
|
||||
'accel_max_range': ACCEL_MAX_RANGE,
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue