Skip to content

Instantly share code, notes, and snippets.

@spiralray
Forked from ompugao/README.md
Last active February 9, 2019 09:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save spiralray/0dcf5006038449a622ae2e381b2c0d33 to your computer and use it in GitHub Desktop.
Save spiralray/0dcf5006038449a622ae2e381b2c0d33 to your computer and use it in GitHub Desktop.
scramble joycon standalone

installation

  1. connect ps3 controller to your machine, and install ps3 controller driver for windows from here

    https://digiful.net/88/#i-8

  2. install miniconda (for python 3.7) https://conda.io/en/master/miniconda.html

  3. start anaconda prompt

  4. create virtualenv

conda create joycon_standalone
activate joycon_standalone
  1. install dependencies
pip install pygame
pip install click

usage

python joycon_standalone.py [id]

from io import StringIO
from time import sleep
import click
import logging
import numpy as np
import multiprocessing as mp
import pygame
import queue
import socket
import struct
import sys
logger = logging.getLogger(__name__)
handler = logging.StreamHandler()
handler.setLevel(logging.DEBUG)
logger.setLevel(logging.DEBUG)
logger.addHandler(handler)
logger.propagate = False
PROC_COMMAND_SETUP = 0
PROC_COMMAND_RUN = 1
PROC_COMMAND_STOP = 2
class Command():
def __init__(self, ):
self.id = 0
self.vel_surge = 0
self.vel_sway = 0
self.omega = 0
self.kick_speed_x = 0
self.kick_speed_z = 0
self.dribble_power = 0
def communicate(in_queue, out_queue):
proc_command, data = in_queue.get()
if proc_command == PROC_COMMAND_SETUP:
host = data[0]
port = data[1]
else:
print('invalid command')
sys.exit()
inputdata = None
b_stop = False
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
while True:
is_empty = False
try:
proc_command, data = in_queue.get(False)
except queue.Empty as e:
is_empty = True
if proc_command == PROC_COMMAND_STOP:
break
if is_empty == True:
continue
kick_power = np.int(np.clip(data.kick_speed_x * 2, 0, 15))
dribble_power = np.int(np.clip(data.dribble_power, 0.0, 15.0))
d = 0x53.to_bytes(1, 'little')
d += data.id.to_bytes(1, 'little')
d += ((0x10 if kick_power > 0 else 0x00) | (0x08 if data.kick_speed_z > 0 else 0)).to_bytes(1, 'little')
d += (dribble_power *16 + kick_power).to_bytes(1, 'little')
d += struct.pack('fff', data.vel_surge, data.vel_sway, data.omega)
checksum = 0
for i, c in enumerate(d):
if i == 0:
continue
checksum ^= c
d = d + checksum.to_bytes(1, 'little') + (checksum ^ 0xff).to_bytes(1, 'little')
#print(d.hex())
s.sendto(d, (host, port))
# axes = joystick.get_numaxes()
# buttons = joystick.get_numbuttons()
# hats = joystick.get_numhats()
#
# logger.info("There is " + str(axes) + " axes")
# logger.info("There is " + str(buttons) + " button/s")
# logger.info("There is " + str(hats) + " hat/s")
# def getHat(number):
# if joystick.get_hat(number) != (0,0):
# # returns tuple with values either 1, 0 or -1
# logger.info( "Hat value is %s, %s" %(joystick.get_hat(number)[0],joystick.get_hat(number)[1]))
# logger.info( "Hat ID is %s" %(number))
@click.command()
@click.argument('id', type=int)
@click.option('--port', '-p', type=int, default=12345)
def main(id, port):
if not (0 <= id <= 12):
logger.info('id should be between 0 and 12')
sys.exit(1)
# setup the pygame window
pygame.init()
screen = pygame.display.set_mode((200, 200), 0, 32)
pygame.display.set_caption("joycon standalone")
clock = pygame.time.Clock()
myfont = pygame.font.SysFont("monospace", 15)
# how many joysticks connected to computer?
joystick_count = pygame.joystick.get_count()
logger.info("There is " + str(joystick_count) + " joystick/s")
if joystick_count == 0:
# if no joysticks, quit program safely
logger.info ("Error, I did not find any joysticks")
pygame.quit()
sys.exit()
else:
# initialise joystick
joystick = pygame.joystick.Joystick(0)
joystick.init()
host = '192.168.15.%2d'%(id+10)
port = port
in_queue = mp.Queue()
out_queue = mp.Queue()
p = mp.Process(target=communicate, args=(in_queue, out_queue))
p.start()
in_queue.put([PROC_COMMAND_SETUP, (host, port)])
L1 = 6
L2 = 4
R2 = 5
R1 = 7
TRIANGLE = 0
CIRCLE = 1
CROSS = 2
RECTANGLE = 3
SELECT = 8
START = 9
L3 = 10
R3 = 11
LEFT_JOY_X = 0
LEFT_JOY_Y = 1
RIGHT_JOY_X = 2
RIGHT_JOY_Y = 3
b_holonomic_mode = False
b_boost_mode = False
last_select_button = False
command = Command()
command.id = id
while True:
loop_exit = False
for event in pygame.event.get():
# loop through events, if window shut down, quit program
if event.type == pygame.QUIT:
loop_exit = True
if loop_exit:
break
# holonomic
current_select_button = joystick.get_button(SELECT)
if last_select_button != current_select_button and current_select_button == True:
b_holonomic_mode = not b_holonomic_mode
last_select_button = current_select_button
# turbo
vel_scale = 1
b_boost_mode = False
if joystick.get_button(R1):
b_boost_mode = True
vel_scale = 3
if b_holonomic_mode:
command.vel_surge = - joystick.get_axis(LEFT_JOY_Y) * vel_scale
command.vel_sway = 0
command.omega = - joystick.get_axis(LEFT_JOY_X) * 1.57 * vel_scale
else:
command.vel_surge = - joystick.get_axis(LEFT_JOY_Y) * vel_scale
command.vel_sway = - joystick.get_axis(LEFT_JOY_X) * vel_scale
#WARN なぜかR2がとれないので右stickで回転
command.omega = - joystick.get_axis(RIGHT_JOY_X) * 1.57 * vel_scale
kick_mode = ''
if joystick.get_button(CROSS):
command.kick_speed_x = 3
command.kick_speed_z = 0
kick_mode = 'Normal'
elif joystick.get_button(CIRCLE):
command.kick_speed_x = 3
command.kick_speed_z = 3
kick_mode = 'Chip'
else:
command.kick_speed_x = 0
command.kick_speed_z = 0
kick_mode = 'Off'
b_dribble = False
command.dribble_power = 0
if joystick.get_button(L1):
command.dribble_power = 8
b_dribble = True
# ss = StringIO()
# if axes != 0:
# for i in range(axes):
# #getAxis(i)
# ss.write("%lf "%(joystick.get_axis(i)))
# logger.info(ss.getvalue())
# ss.close()
screen.fill((0,0,0))
label = myfont.render("Turbo: %s"%('On' if b_boost_mode else 'Off'), 1, (255,255,255))
screen.blit(label, (30, 70))
label2 = myfont.render("Holonomic: %s"%('On' if b_holonomic_mode else 'Off'), 1, (255,255,255))
screen.blit(label2, (30, 85))
label3 = myfont.render("Kick: %s"%kick_mode, 1, (255,255,255))
screen.blit(label3, (30, 100))
label4 = myfont.render("Dribble: %s"%('On' if b_dribble else 'Off'), 1, (255,255,255))
screen.blit(label4, (30, 115))
pygame.display.update()
in_queue.put([PROC_COMMAND_RUN, command])
clock.tick(30)
in_queue.put([PROC_COMMAND_STOP, None])
p.join()
pygame.quit()
sys.exit()
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment