Skip to content

Instantly share code, notes, and snippets.

@ompugao
Last active February 9, 2019 09:14
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save ompugao/6f88db7574fb0e581f367ba316cd7e69 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
def int2chr(i):
return chr(i).encode('ascii')
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
try:
s.connect((host, port))
except socket.timeout as e:
logger.error('socket timeout!!!')
sys.exit(1)
except TimeoutError as e:
logger.error('socket timeout!!!')
sys.exit(1)
while True:
try:
proc_command, data = in_queue.get(False)
except queue.Empty as e:
pass
if proc_command == PROC_COMMAND_STOP:
break
kick_power = np.int(np.clip(data.kick_speed_x * 2, 0, 15))
dribble_power = np.int(np.clip(data.dribble_power / 50.0, 0.0, 15.0))
d = struct.pack('ccccfff', int2chr(0x53),
int2chr(data.id), int2chr((0x10 if kick_power > 0 else 0x00) & (0x08 if data.kick_speed_z > 0 else 0)),
int2chr(dribble_power << 4 + kick_power),
data.vel_surge, data.vel_sway, data.omega)#, int2chr(0x0), int2chr(0x0))
checksum = 0
for c in d:
checksum ^= c
d = d + int2chr(checksum & 0xff) + int2chr((checksum ^ 0xff) & 0xff)
s.sendall(d)
# 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 = 1
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(60)
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