Sampling force transducer higher than 60Hz

Hi,

I am using a force transducer and I was wondering if I could use a sampling frequency higher than 60 Hz? I am using the joystick component.

Thanks in advance.
José

Hi José
Doesn’t look like anyone got back on here, but I’m currently trying to run an experiment with analogue input from a force transducer. I didn’t realise that the joystick component could be used for this?
Was wondering where you found the info to get this working? (or if anyone else has any leads, that would be hugely appreciated)
Thanks in advance
Simon

Hey Simon,

I am using a fiber optic grip device that gets recognized as a joystick on Windows. So the left and right force bars move the x and y axes. The joystick component from Psychopy can sample this, but it is bound to the sampling rate of the monitor.

To sample at a higher sampling rate, I modified the code from this Stack Overflow question.

def get_joystick_state(subject, session, stop_condition, q, min_max):
    """
    Use the joystick class to poll the state and save values as csv.

    Parameters
    ----------
    subject : str
        Subject ID.
    session : str
        Session number.
    stop_condition : Event
        Event to stop the joystick polling. When the event is set in the main thread, the polling stops.
    q : Queue
        Queue to send the data to the main thread.
    min_max : dict
        Dictionary with the min and max values of the joystick.
    """
    joystick = Joystick()
    df = pd.DataFrame()
    start_time = datetime.datetime.now()

    min_value, max_value =  min_max['min'], min_max['max']
    while not stop_condition.is_set():
        while (datetime.datetime.now() - start_time).microseconds < 10000:
            time.sleep(0.00001)
        joystick.update()
        df = pd.concat(
            (
                df,
                pd.DataFrame(
                    [
                        [
                            joystick.axis.get(1, None),
                            joystick.axis.get(0, None),
                            datetime.datetime.now().isoformat(),
                        ]
                    ],
                    columns=["1", "0", "time"],
                ),
            ),
            ignore_index=True,
        )
        if joystick.axis.get(1, None) == None:
            pass
        else:
            q.put(
                normalize(
                    joystick.axis.get(1, None), min_value=min_value, max_value=max_value
                )
            )
        start_time += datetime.timedelta(microseconds=10000)

    df.to_csv(
        f"../data/gripper_output/sub-{subject}_session-{session}_gripper_data.csv",
        index=False,
    )

Before every session I make the participants press to the maximum to get the maximum value of that session (it is not always the same with the fiber optic cable). In my case, I only use the right force bar (the “1”). The Queue class polls data from the secondary thread into the main one and I use that to give a visual input of how much force they are applying. If you do not need this, you can leave it out. With that timer I sample at 100 Hz.

So I do something like this:

from threading import Thread, Event
from joystick_sampler import get_joystick_calibration, get_joystick_state
import queue

if __name__ == "__main__": # Wrap your Psychopy code in a main thread
    stop_condition = Event()
    q = queue.Queue()
    
    # When the trial or block is about to start I start the other thread. I previously calculate the min and max values during a calibration block.
    Thread(target=get_joystick_state, args=(subject, session, stop_condition, q, min_max), daemon=True).start()
    
    # To poll values: q.get()
    # When everything is done
    stop_condition.set()

    # You can use stop_condition.clear() to keep using it for other blocks/trials

The timing precision I get from this is enough for me, but you might need to check if it also suits you.

Cheers,
José

Hi José,
Ah, I see. Very cool. Thanks for the info on this!
Cheers,
Simon