Contrôleur Groove Coaster

Il y a quelques années, j'avais acheté une contrôleur GENBU Groove Coaster sur Yahoo!オークション (via Buyee).
Celui-ci comporte d'une prise USB-B (relié au PC, il alimente les switchs et LEDS des boutons droite, gauche et start) et une entrée 5V CC (pour l'alimentation et de l'anneau de LEDS autour des joysticks).
Par ma faute, et problème de conception ou manque d'informations étiquetée, j'avais oublié qu'il s'agissait d'une entrée 5V. La prise étant celle utilisée de manière standard pour le 12V... ça a fait pouf 💥!

La partie USB-B fonctionne toujours, car les deux prisent sont sur des PCB distinctes.

J'ai donc cassé la PCB de gestion de couleurs de LED (couleurs arc-en-ciel non programmable) et les deux PCB de bande LED.
De plus, d'origine, il n'y a aucun effet ou interaction entre les boutons appuyés et les cercles de LED comme sur la borne originale.

Par conséquent, les missions sont :

  • Refaire une PCB de gestion des touches + LED
  • Refaire les PCB de strip LED
  • Faire le code python pour gérer tout ça

Gestion des touches

Anneaux de LED

Code CircuitPython

import board
import pwmio
import digitalio
import time
import neopixel
import math
import usb_hid
from adafruit_hid.keyboard import Keyboard
from adafruit_hid.keycode import Keycode

kbd = Keyboard(usb_hid.devices)

R_LED = pwmio.PWMOut(board.GP3, frequency=5000, duty_cycle=0)
L_LED = pwmio.PWMOut(board.GP26, frequency=5000, duty_cycle=0)
S_LED = pwmio.PWMOut(board.GP16, frequency=5000, duty_cycle=0)

NUM_PIXELS = 18
R_STRIP = neopixel.NeoPixel(board.GP1, NUM_PIXELS, brightness=0.2, auto_write=True)
L_STRIP = neopixel.NeoPixel(board.GP28, NUM_PIXELS, brightness=0.2, auto_write=True)

R_PUSH = digitalio.DigitalInOut(board.GP4)
R_PUSH.direction = digitalio.Direction.INPUT
R_PUSH.pull = digitalio.Pull.UP

R_UP = digitalio.DigitalInOut(board.GP6)
R_UP.direction = digitalio.Direction.INPUT
R_UP.pull = digitalio.Pull.UP

R_DOWN = digitalio.DigitalInOut(board.GP9)
R_DOWN.direction = digitalio.Direction.INPUT
R_DOWN.pull = digitalio.Pull.UP

R_RIGHT = digitalio.DigitalInOut(board.GP11)
R_RIGHT.direction = digitalio.Direction.INPUT
R_RIGHT.pull = digitalio.Pull.UP

R_LEFT = digitalio.DigitalInOut(board.GP14)
R_LEFT.direction = digitalio.Direction.INPUT
R_LEFT.pull = digitalio.Pull.UP

L_PUSH = digitalio.DigitalInOut(board.GP27)
L_PUSH.direction = digitalio.Direction.INPUT
L_PUSH.pull = digitalio.Pull.UP

L_UP = digitalio.DigitalInOut(board.GP22)
L_UP.direction = digitalio.Direction.INPUT
L_UP.pull = digitalio.Pull.UP

L_DOWN = digitalio.DigitalInOut(board.GP21)
L_DOWN.direction = digitalio.Direction.INPUT
L_DOWN.pull = digitalio.Pull.UP

L_RIGHT = digitalio.DigitalInOut(board.GP19)
L_RIGHT.direction = digitalio.Direction.INPUT
L_RIGHT.pull = digitalio.Pull.UP

L_LEFT = digitalio.DigitalInOut(board.GP18)
L_LEFT.direction = digitalio.Direction.INPUT
L_LEFT.pull = digitalio.Pull.UP

S_PUSH = digitalio.DigitalInOut(board.GP17)
S_PUSH.direction = digitalio.Direction.INPUT
S_PUSH.pull = digitalio.Pull.UP

LUMINOSITE_FAIBLE = int(65535 * 0.20)
LUMINOSITE_FORTE = 65535

BLUE = (0, 0, 255)
WHITE = (255, 255, 255)

FLASH_LEDS = [1, 4, 7, 10, 13, 16]

flash_time_left = 0
flash_time_right = 0
FLASH_DURATION = 0.05
FLASH_BRIGHTNESS = 1.0

previous_states = {
    'R_PUSH':   True,
    'R_UP':     True,
    'R_DOWN':   True,
    'R_LEFT':   True,
    'R_RIGHT':  True,
    'L_PUSH':   True,
    'L_UP':     True,
    'L_DOWN':   True,
    'L_LEFT':   True,
    'L_RIGHT':  True,
    'S_PUSH':   True
}

key_mapping = {
    'R_PUSH':   Keycode.I,
    'R_UP':     Keycode.O,
    'R_DOWN':   Keycode.L,
    'R_LEFT':   Keycode.K,
    'R_RIGHT':  Keycode.M,
    'L_PUSH':   Keycode.E,
    'L_UP':     Keycode.Z,
    'L_DOWN':   Keycode.S,
    'L_LEFT':   Keycode.Q,
    'L_RIGHT':  Keycode.D,
    'S_PUSH':   Keycode.ENTER
}

while True:
    current_time = time.monotonic()

    for button_name, key in key_mapping.items():
        current_state = not globals()[button_name].value
        if current_state and not previous_states[button_name]:
            kbd.press(key)
            if button_name == 'R_PUSH':
                flash_time_right = current_time + FLASH_DURATION
            elif button_name == 'L_PUSH':
                flash_time_left = current_time + FLASH_DURATION
        elif not current_state and previous_states[button_name]:
            kbd.release(key)
        previous_states[button_name] = current_state
    
    if not R_PUSH.value:
        R_LED.duty_cycle = LUMINOSITE_FORTE
    else:
        R_LED.duty_cycle = LUMINOSITE_FAIBLE
    
    if not L_PUSH.value:
        L_LED.duty_cycle = LUMINOSITE_FORTE
    else:
        L_LED.duty_cycle = LUMINOSITE_FAIBLE
        
    if not S_PUSH.value:
        S_LED.duty_cycle = LUMINOSITE_FORTE
    else:
        S_LED.duty_cycle = LUMINOSITE_FAIBLE
    
    t = time.monotonic() * 10
    brightness_right = 0.20 + 0.05 * math.sin(t)
    brightness_left = 0.20 + 0.05 * math.sin(t)
    
    R_STRIP.brightness = brightness_right
    L_STRIP.brightness = brightness_left
    
    R_STRIP.fill(BLUE)
    L_STRIP.fill(BLUE)
    
    if current_time < flash_time_right:
        R_STRIP.brightness = FLASH_BRIGHTNESS
        for led_index in FLASH_LEDS:
            R_STRIP[led_index] = WHITE
        R_STRIP.brightness = brightness_right
            
    if current_time < flash_time_left:
        L_STRIP.brightness = FLASH_BRIGHTNESS
        for led_index in FLASH_LEDS:
            L_STRIP[led_index] = WHITE
        L_STRIP.brightness = brightness_left
    
    time.sleep(0.02)

Résultat