Use joystick controls#

This example demonstrates how to use a joystick as an input device using button presses and continuous analog movement to control the position of a circle on the screen.

joystick experiment
exp_name: joyExp
date: 2024-12-16 22_24_26.435070
file: /home/circleci/project/examples/experiments/joystick_experiment.py
participant: foo
session: 001
2024-12-16 22:24:26,435 - INFO    - Expyfun: Using version 2.0.0.dev0 (requested dev)
2024-12-16 22:24:26,436 - INFO    - Expyfun: Setting up sound card using pyglet backend with 2 playback channels
2024-12-16 22:24:26,655 - WARNING - Expyfun: Mismatch between reported stim sample rate (24414) and device sample rate (44100.0). Experiment Controller will resample for you, but this takes a non-trivial amount of processing time and may compromise your experimental timing and/or cause artifacts.
2024-12-16 22:24:26,655 - INFO    - Expyfun: Setting up screen
2024-12-16 22:24:26,691 - EXP     - Expyfun: Set screen visibility True
2024-12-16 22:24:26,708 - INFO    - Initialized [1400  900] window on screen XlibScreen(display=<pyglet.canvas.xlib.XlibDisplay object at 0x7440b856db40>, x=0, y=0, width=1400, height=900, xinerama=0) with DPI 69.73
2024-12-16 22:24:26,709 - INFO    - Expyfun: Initializing dummy triggering mode
2024-12-16 22:24:26,710 - INFO    - Expyfun: Initialization complete
2024-12-16 22:24:26,710 - EXP     - Expyfun: Participant: foo
2024-12-16 22:24:26,710 - EXP     - Expyfun: Session: 001
2024-12-16 22:24:26,802 - INFO    - Expyfun: Exiting
2024-12-16 22:24:26,808 - EXP     - Expyfun: Audio stopped and reset.

# Author: Eric Larson <larson.eric.d@gmail.com>
#
# License: BSD (3-clause)

from expyfun import ExperimentController, analyze, building_doc
from expyfun.visual import Circle, Text

print(__doc__)

joystick = not building_doc
move_rate = 0.05  # map -1<->1 stick range to something decent for 60Hz refresh
noise_thresh = 0.01  # permit slight miscalibration
# on a Logitech Cordless Rumblepad, the right stick is the analog one,
# and it has values stored in z and rz
joy_keys = ("z", "rz")
with ExperimentController(
    "joyExp",
    participant="foo",
    session="001",
    output_dir=None,
    version="dev",
    joystick=joystick,
) as ec:
    circles = [
        Circle(ec, 0.5, units="deg", fill_color=(1.0, 1.0, 1.0, 0.2), line_color="w")
    ]
    # We use normalized units for "pos" so we need to compensate in movement
    # so that X/Y movement is even
    ratios = [1.0, ec.window_size_pix[0] / float(ec.window_size_pix[1])]
    pressed = ""
    if not building_doc:
        ec.listen_joystick_button_presses()
    count = 0
    screenshot = None
    pos = [0.0, 0.0]
    while pressed != "2":  # enable a clean quit (button number 3)
        #######################################################################
        # Draw things
        Text(ec, str(count), pos=(1, -1), anchor_x="right", anchor_y="bottom").draw()
        for circle in circles[::-1]:
            circle.draw()
        screenshot = ec.screenshot() if screenshot is None else screenshot
        ec.flip()

        #######################################################################
        # Get presses
        if not building_doc:
            pressed = ec.get_joystick_button_presses()
            ec.listen_joystick_button_presses()  # clear events
        else:
            pressed = [("2",)]
        count += len(pressed)

        #######################################################################
        # Move the cursor
        for idx, (key, ratio) in enumerate(zip(joy_keys, ratios)):
            delta = 0.0 if building_doc else ec.get_joystick_value(key)
            if abs(delta) > noise_thresh:  # remove noise
                pos[idx] = max(min(pos[idx] + move_rate * ratio * delta, 1), -1)
        circles[0].set_pos(pos, units="norm")
        if pressed:
            circles.insert(
                1, Circle(ec, 1, units="deg", fill_color="r", line_color="w")
            )
            circles[1].set_pos(pos, units="norm")
            if len(circles) > 5:
                circles.pop(-1)
            pressed = pressed[0][0]  # for exit condition
        ec.check_force_quit()

analyze.plot_screen(screenshot)

Total running time of the script: (0 minutes 0.467 seconds)

Gallery generated by Sphinx-Gallery