[PYTHON] Reliez la souris au gyroscope du Nintendo Switch Procon

en premier

Je voulais utiliser Splatoon 2 de Nintendo Switch avec une souris. Dans les rues, des convertisseurs capables de déplacer des commutateurs Nintendo avec une souris sont déjà sur le marché. Cependant, les convertisseurs commerciaux ne remplaçaient le mouvement du bâton du contrôleur de jeu que par le mouvement de la souris (pour autant que je puisse voir). Je pensais que cela ne fonctionnerait pas bien avec cette méthode. Par conséquent, j'ai créé un appareil qui remplace le mouvement du gyroscope du contrôleur professionnel par le mouvement de la souris.

Cependant, c'est devenu quelque chose que je ne pouvais pas bien utiliser avec mes compétences techniques. Je pense que la méthode consistant à remplacer le mouvement du gyroscope par le mouvement de la souris sera pratique si elle est bien faite. Je vais publier ce que j'ai fait jusqu'ici ici.

C'est fait

La vidéo ne peut pas être ouverte

Comment utiliser

Article très utile

Choses à préparer

La souris que j'utilise https://www.elecom.co.jp/products/M-Y8UBXBK.html Je pense que c'est probablement le cas. Si le format de données envoyé par la souris est le même que celui de ma souris, je pense que cela réduira le problème de réécriture du code python qui sera posté plus tard.

procédure

Veuillez configurer Rasppie (cette fois, j'ai choisi Raspbian comme système d'exploitation). Activez la connexion filaire dans les paramètres de la manette Nintendo Switch. Allumez le gyroscope dans les paramètres du Splatoon 2. Découvrez le fournisseur ID (VID) de votre souris. Le VID de ma souris ELECOM était 04F3 Connectez votre souris, clavier et contrôleur Pro au port USB Type-A du Raspeye. Connectez le port HDMI 0 de Raspeye à l'écran. L'écran connecté sert à afficher l'écran de Raspeye. L'écran qui affiche l'écran de jeu se connecte au port HDMI sur la station d'accueil de la Nintendo Switch. Après avoir confirmé que le commutateur Nintendo est activé, Connectez le commutateur Nintendo au port Type-C (je l'ai connecté au port USB de la station d'accueil du commutateur Nintendo). Ensuite, Razzpie commencera. Dans Raspbian, ajoutez dtoverlay = dwc2 à /boot/config.txt et dwc2 et libcomposite à / etc / modules pour charger le module dwc2.

Être capable de devenir un super utilisateur avec su sur la ligne de commande Créez un fichier appelé add_procon_gadget.sh illustré ci-dessous Tapez source add_procon_gadget.sh sur la ligne de commande

add_procon_gadget.sh


#!/bin/bash

cd /sys/kernel/config/usb_gadget/
mkdir -p procon
cd procon
echo 0x057e > idVendor
echo 0x2009 > idProduct
echo 0x0200 > bcdDevice
echo 0x0200 > bcdUSB
echo 0x00 > bDeviceClass
echo 0x00 > bDeviceSubClass
echo 0x00 > bDeviceProtocol

mkdir -p strings/0x409
echo "000000000001" > strings/0x409/serialnumber
echo "Nintendo Co., Ltd." > strings/0x409/manufacturer
echo "Pro Controller" > strings/0x409/product

mkdir -p configs/c.1/strings/0x409
echo "Nintendo Switch Pro Controller" > configs/c.1/strings/0x409/configuration
echo 500 > configs/c.1/MaxPower
echo 0xa0 > configs/c.1/bmAttributes

mkdir -p functions/hid.usb0
echo 0 > functions/hid.usb0/protocol
echo 0 > functions/hid.usb0/subclass
echo 64 > functions/hid.usb0/report_length
echo 050115000904A1018530050105091901290A150025017501950A5500650081020509190B290E150025017501950481027501950281030B01000100A1000B300001000B310001000B320001000B35000100150027FFFF0000751095048102C00B39000100150025073500463B0165147504950181020509190F2912150025017501950481027508953481030600FF852109017508953F8103858109027508953F8103850109037508953F9183851009047508953F9183858009057508953F9183858209067508953F9183C0 | xxd -r -ps > functions/hid.usb0/report_desc

ln -s functions/hid.usb0 configs/c.1/

ls /sys/class/udc > UDC

Tapez ʻexitsur la ligne de commande pour revenir à un utilisateur normal. Tapezsudo dmesg | grep -A7 057e` sur la ligne de commande.

pi@raspberrypi:~ $ sudo dmesg | grep -A7 057e
[ 7201.091044] usb 1-1.3: New USB device found, idVendor=057e, idProduct=2009, bcdDevice= 2.00
[ 7201.091060] usb 1-1.3: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[ 7201.091074] usb 1-1.3: Product: Pro Controller
[ 7201.091087] usb 1-1.3: Manufacturer: Nintendo Co., Ltd.
[ 7201.091099] usb 1-1.3: SerialNumber: 000000000001
[ 7201.112454] input: Nintendo Co., Ltd. Pro Controller as /devices/platform/scb/fd500000.pcie/pci0000:00/0000:00:00.0/0000:01:00.0/usb1/1-1/1-1.3/1-1.3:1.0/0003:057E:2009.0002/input/input1
[ 7201.114447] hid-generic 0003:057E:2009.0002: input,hidraw0: USB HID v1.11 Joystick [Nintendo Co., Ltd. Pro Controller] on usb-0000:01:00.0-1.3/input0

Il y a un endroit où il est dit hidraw0. C'est comme un fichier qui représente un contrôleur Pro, et les nombres ci-dessous hidraw peuvent varier en fonction de votre environnement, alors vérifiez quel est le nombre hidraw.

Ensuite, la souris trouvera le numéro de hidraw, donc sur la ligne de commande sudo dmesg | grep -A7 Remplacez la partie" mouse VID "du mouse VID par le mouse VID et appuyez sur. Le VID de ma souris ELECOM était «04F3». Vérifiez quel numéro la souris est cachée.

Créez un programme qui interrompt les données de fonctionnement de la souris entre la communication entre le commutateur Nintendo et le contrôleur Pro. Créez le fichier de code python ci-dessous. (Désolé pour le code très sale).

mouse_gyro.py


#!/usr/bin/env python3

import os
import threading
import time
import random

# Re-connect USB Gadget device
os.system('echo > /sys/kernel/config/usb_gadget/procon/UDC')
os.system('ls /sys/class/udc > /sys/kernel/config/usb_gadget/procon/UDC')

time.sleep(0.5)

gadget = os.open('/dev/hidg0', os.O_RDWR | os.O_NONBLOCK)
procon = os.open('/dev/hidraw3', os.O_RDWR | os.O_NONBLOCK)
mouse  = os.open('/dev/hidraw2', os.O_RDWR | os.O_NONBLOCK)
mouse_int = bytes([0,0,0,0])
def mouse_input():
    global mouse_int
    while True:
        try:
            mouse_int = os.read(mouse, 128)
            #print('<<<', output_data.hex())
            #print(output_mouse.hex())
            #os.write(gadget, output_mouse)
        except BlockingIOError:
            pass
        except:
            os._exit(1)



def procon_input():
    while True:
        try:
            input_data = os.read(gadget, 128)
            #print('>>>', input_data.hex())
            os.write(procon, input_data)
        except BlockingIOError:
            pass
        except:
            os._exit(1)

def convert(ou_dt_i, mo_in_i, weight, reflect):
    mo_in_i = int.from_bytes(mo_in_i, byteorder='little', signed=True)
    ou_dt_i = int.from_bytes(ou_dt_i, byteorder='little', signed=True)
    if reflect == True:
        mo_in_i = mo_in_i * -1
        ou_dt_i = ou_dt_i * -1
    merged_gy = ou_dt_i + mo_in_i * weight
    if merged_gy > 32767:
        merged_gy = 32767
    elif merged_gy < -32768:
        merged_gy = -32768
    else:
        pass
    merged_gy = merged_gy.to_bytes(2, byteorder='little', signed=True)

    return merged_gy

def replace_mouse(output_data, mouse_int):
    #a = output_data[0:13]

    #mouse no click wo migi no button ni henkan
    ri_btn = 0
    if mouse_int[0] == 1:#hidari click
        ri_btn = 0x80#ZR button
    elif mouse_int[0] == 2:#migi click
        ri_btn = 0x40#R button
    elif mouse_int[0] == 4:#chuu click
        ri_btn = 0x08#A button
    ri_btn = (output_data[3] + ri_btn).to_bytes(1, byteorder='little')
    a = output_data[0:3] + ri_btn + output_data[4:13]

    #kasokudo sensor ni tekitou ni atai wo ire naito setsuzoku ga kireru
    if mouse_int[1] != 0:
        b = 127
    else:
        b=0
    if mouse_int[2] != 0:
        b = 127
    else:
        b = 0
    d = bytes([0,0,0,0,0,0,0,0,0,0,0,0,0,0,0])
    ac0 = bytes([255]) if output_data[14] + b > 255 else bytes([output_data[14] + b])
    ac1 = bytes([255]) if output_data[16] + b > 255 else bytes([output_data[16] + b])
    ac2 = bytes([255]) if output_data[18] + b > 255 else bytes([output_data[18] + b])
    ac0_1 = bytes([255]) if output_data[26] + b > 255 else bytes([output_data[26] + b])
    ac1_1 = bytes([255]) if output_data[28] + b > 255 else bytes([output_data[28] + b])
    ac2_1 = bytes([255]) if output_data[30] + b > 255 else bytes([output_data[30] + b])
    ac0_2 = bytes([255]) if output_data[38] + b > 255 else bytes([output_data[38] + b])
    ac1_2 = bytes([255]) if output_data[40] + b > 255 else bytes([output_data[40] + b])
    ac2_2 = bytes([255]) if output_data[42] + b > 255 else bytes([output_data[42] + b])

    #mouse no ugoki wo gyro no ugoki ni henkan
    gy0_0 = convert(output_data[19:21], mouse_int[1:2], 250, False)#
    gy1_0 = convert(output_data[21:23], mouse_int[2:3], 250, False)#
    gy2_0 = convert(output_data[23:25], mouse_int[2:3], 0, False)#

    gy0_1 = convert(output_data[31:33], mouse_int[1:2], 250, False)#
    gy1_1 = convert(output_data[33:35], mouse_int[2:3], 250, False)#
    gy2_1 = convert(output_data[35:37], mouse_int[2:3], 0, False)#

    gy0_2 = convert(output_data[43:45], mouse_int[1:2], 250, False)#
    gy1_2 = convert(output_data[45:47], mouse_int[2:3], 250, False)#
    gy2_2 = convert(output_data[47:49], mouse_int[2:3], 0, False)#

    e = a+output_data[13:14]+ac0+output_data[15:16]+ac1+output_data[17:18]+ac2 \
        +gy0_0+gy1_0+gy2_0 \
        +output_data[25:26]+ac0_1+output_data[27:28]+ac1_1+output_data[29:30]+ac2_1 \
        +gy0_1+gy1_1+gy2_1 \
        +output_data[37:38]+ac0_2+output_data[39:40]+ac1_2+output_data[41:42]+ac2_2 \
        +gy0_2+gy1_2+gy2_2 \
        +d

    print(int.from_bytes(gy1_0, byteorder='little'))
    #print(mouse_int[1])
    return e

def procon_output():
    global mouse_int
    while True:
        try:
            output_data = os.read(procon, 128)
            #output_mouse = os.read(mouse, 128)
            #print('<<<', output_data.hex())
            #print(output_data)
            e = replace_mouse(output_data, mouse_int)
            #print(e.hex())
            os.write(gadget, e)#output_data
            mouse_int = bytes([0,0,0,0])
        except BlockingIOError:
            pass
        except Exception as g:
            print(type(g))
            print(g)
            os._exit(1)

threading.Thread(target=procon_input).start()
threading.Thread(target=procon_output).start()
threading.Thread(target=mouse_input).start()

Réécrivez le nombre suivant de hidraw assigné aux variables procon et mouse par le nombre que vous avez confirmé plus tôt. Ensuite, je réécris le code python pour faire correspondre le code python avec le signal envoyé par la souris. La souris que j'utilise https://www.elecom.co.jp/products/M-Y8UBXBK.html Je pense que c'est probablement le cas, mais avec cela, vous n'aurez peut-être pas besoin de réécrire votre code. Pour savoir quelles données votre souris envoie, décommentez #print (output_mouse.hex ()) dans la fonction mouse_input (). Au lieu de cela, il est plus facile de voir si vous commentez la partie print () ailleurs. Pour exécuter ce code python, tapez sudo python3 mouse_gyro.py sur la ligne de commande.

Si tout se passe bien, vous pourrez déplacer le gyroscope maladroitement avec votre souris, comme dans la vidéo ci-dessus.

Il arrive souvent que le contrôleur Pro soit déconnecté au milieu. Suivez les instructions sur l'écran du commutateur ou appuyez et maintenez le petit bouton rond sur le côté du contrôleur pour réenregistrer le contrôleur. À ce moment-là, le prochain nombre de hidraw peut changer. Dans ce cas, réécrivez la partie affectation de la variable procon du code python en appuyant sur la commande pour vérifier à nouveau le numéro hidraw écrit ci-dessus.

À la fin

Si vous avez regardé la vidéo ci-dessus ou essayé l'opération, vous comprendrez. Même si je déplace la souris, le gyroscope ne bouge pas correctement. Je voudrais demander votre aide. Le code Python est disponible sur GitHub et il n'y a pas de licence, alors n'hésitez pas à le modifier. Je vous serais très reconnaissant de bien vouloir coopérer.

Merci pour la lecture.

https://github.com/Bokuchin/SwitchProconGyroMouse

Lien d'article auquel j'ai été autorisé à me référer

Recommended Posts

Reliez la souris au gyroscope du Nintendo Switch Procon
Changer la valeur de paramètre de setting.py en fonction de l'environnement de développement
Supplément à l'explication de vscode
L'histoire d'essayer de reconnecter le client
Script pour changer la description de fasta
10 méthodes pour améliorer la précision de BERT
Comment vérifier la version de Django
L'histoire de la mise en place de MeCab dans Ubuntu 16.04
L'histoire du changement de pep8 en pycodestyle
Lien vers les points de données du graphe créé par jupyterlab & matplotlib
Lorsque vous passez la souris sur Matplotlib, l'image correspondante s'affiche.
Comment trouver la zone du diagramme de Boronoi
Trouver la main de "Millijan" par l'optimisation des combinaisons
L'inexactitude de Tensorflow était due à log (0)
J'ai essayé de corriger la forme trapézoïdale de l'image
Modifiez le point décimal de la journalisation de, à.
Je souhaite personnaliser l'apparence de zabbix
De l'introduction de pyethapp à l'exécution du contrat
Essayez de simuler le mouvement du système solaire
[Java] Comment basculer entre plusieurs versions de Java
Histoire de passer de Pipenv à la poésie
J'ai essayé de vectoriser les paroles de Hinatazaka 46!