This is a collaborative space. In order to contribute, send an email to maximilien.chaumon@icm-institute.org
On any page, type the letter L on your keyboard to add a "Label" to the page, which will make search easier.

Joystick curdes

Utilisation du Joystick Current Design au CENIR

Prise en main par le sujet

Le joystick peut être utilisé de deux manières différentes :

  1. Avec le manche, il se tient dans toute la paume de la main. Il est plus facile d'effectuer de grands déplacements dans une direction donnée.
  2. Sans le manche, il est utilisé à la manière d'un fingerstick, entre le pouce et l'index. Il est plus aisé de suivre des courbes avec précisions.

Installation du joystick dans l'IRM

Confort d'utilisation

Le CENIR possède un support joystick qui se visse au lit de l'IRM. Il assure la stabilité et une bonne prise en main, le manche est disposé horizontalement dans la continuation du bras du sujet. Cette configuration est très conseillée pour l'utilisation du joystick avec manche.

Le joystick peut également être posé sur le ventre du sujet. Cette disposition est viable sans le manche.

Branchements

Le CENIR dispose actuellement de deux fORP, de deux faisceau de fibres optiques ainsi que de deux joystick amagnétiques.
Le faisceau de fibres optiques fait, comme pour les boîtiers réponse, le lien entre le fORP (boîtier électronique) et le joystick. Cependant, il faut bien veiller à toujours utiliser le joystick avec le même faisceau de fibres optiques, car le joystick a été calibré sur un faisceau donné. Si on en change entre deux sujets, on obtiendra une différence de sensibilité des déplacements en X et Y du manche du joystick.

Modes du fORP associés au Joystick

Du point de vue de l'ordinateur de stimulation, le joystick Current Design peut être utilisé de deux manières différentes :

  1. Il peut émuler un dispositif HID USB géré automatiquement par DirectX (sous Windows). Dans ce cas, il faut tourner la fléche du sélecteur de mode du fORP en mode 5.
  2. Il peut être utilisé via le port série avec une plus grande précision temporelle : plus de 1000 points par seconde (débit de 57600 bauds). Dans ce cas, il faut configurer le fORP en mode 7.

Utilisation du joystick en mode 7

Pour obtenir plus de points sur le décours temporel du déplacement du manche selon les deux axes, il convient d'utiliser le mode 7 et de se brancher en série sur l'ordinateur de stimulation. Les données provenant du joystick passent par le fORP qui les transforme en un train de quatre octets. Ceci présuppose un peu de programmation.

Format des trains d'octets

En mode 7, des trains de quatre octets sont envoyés en continu sur le port série selon le modèle suivant :

n° d'octet

d7

d6

d5

d4

d3

d2

d1

d0

1

1

gch

trg

dte

y10

y9

y8

y7

2

0

x6

x5

x4

x3

x2

x1

x0

3

0

y6

y5

y4

y3

y2

y1

y0

4

0

0

0

0

x10

x9

x8

x7

Le premier bit du premier octet est le bit de synchronisation. Il sert à repérer le début d'un train d'octet.
gch et dte représentent respectivement les boutons gauche et droite du joystick. Ils valent 1 si le bouton correspondant a été appuyé, 0 sinon.
trg est le trigger provenant de l'entrée BNC du [fORP]. Il vaut 1 si un trigger a été reçu.
x10 -> x0 définit le déplacement en X codé sur 11 bits : les valeurs s'échelonnent donc de -2||10|| à +2||10||-1. ([-1024; 1023])
y10 -> y0 définit le déplacement en Y codé sur 11 bits.

Code source en Matlab

Voila le code Matlab, utilisant la librairie port série de Cogent afin de faire fonctionner le joystick en série :

  • Initialisation du port série
Error rendering macro 'code': Invalid value specified for parameter 'lang'
global cogent

... % initializations

% Cogent configuration
config_serial(serport, 57600); % serport is the serial port number
... % the rest of cogent configuration

start_cogent
porthandle = cogent.serial{serport}.hPort;

... % initialization after Cogent start

while time < 60*1000 % loop example
    [X, Y] = fORP7_getdata (porthandle);

    ... % block of instructions using X and Y variables

end
  • Code source de la fonction qui récupère et décode les données
Error rendering macro 'code': Invalid value specified for parameter 'lang'
function [ X, Y, LB, RB, trigger, Time ] = fORP7_getdata (porthandle)

% -------------------------------------------------------------------------
% fORP7_getdata :
%
% This function translates the bytes coming through a serial port from
% Current Design fORP with switch position 7: "programmer's joystick" into
% unscrambled variables : X and Y moves, left and right buttons, trigger.
%
% The serial port must have been opened with the following arguments :
% 57600 bauds, 8 data bits, no parity, 1 stop bit.
%
%
% Syntax :
% [ X, Y, LB, RB, trigger, Time ] = fORP7_getdata ( porthandle )
%
% Input :
% - porthandle : handle to the serial (COM) port onto which the fORP is
% plugged.
%
% Outputs :
% - X : vector of X since last translation [-1024;1024].
% - Y : vector of Y since last translation [-1024;1024].
% - LB : vector of left button status, '1' means the button is pressed.
% - RB : vector of right button status, '1' means the button is pressed.
% - trigger : vector of TTL synchronization with the MRI trigger,
%             '1' means the fORP has been triggered.
% - Time : the absolute time vector of each point in the Cogent time basis.
% -------------------------------------------------------------------------

persistent residu;

if isempty(residu)
    residu = {[], []};
end

mask.SyncBit = 128; % Bit de reperage dans les trains d'octets
mask.LB = 64; % Bouton de gauche
mask.trigger = 32; % Bouton du milieu emule : trigger provenant de l'entree BNC du fORP
mask.RB = 16; % Bouton de droite
mask.low = 127; % Bits de poids faible des deplacements en X ou Y
mask.high = 15; % Bits de poids fort des deplacements en X ou Y

ind = 1;
X = []; Y = []; LB = []; trigger = []; RB = []; Time = [];

[ vector, time_v ] = CogSerial( 'GetEvents', porthandle );
vector = [residu{1} vector'];
time_v = [residu{2} time_v'];

lgvect = length(vector);

if ~lgvect
    time_v = [];
end

while ( ind < lgvect-2 )

    if ( bitand(vector(ind), mask.SyncBit) == mask.SyncBit )
        LB = [LB, bitand(vector(ind), mask.LB)/mask.LB];
        RB = [RB, bitand(vector(ind), mask.RB)/mask.RB];

        trig_temp = bitand(vector(ind), mask.trigger);
        if trig_temp
            trigger = [trigger, time_v(ind)*1000];
        end

        Xw = 128*bitand(vector(ind+3), mask.high) + bitand(vector(ind+1), mask.low);
        if Xw > 1023
            Xw = Xw - 2047;
        end

        Yw = 128*bitand(vector(ind), mask.high) + bitand(vector(ind+2), mask.low);
        if Yw > 1023
            Yw = Yw - 2047;
        end

        X = [X, Xw];
        Y = [Y, Yw];
        Time = [Time, time_v(ind)];

        ind = ind+4;

    else
        ind = ind+1;
    end
end

if (ind < lgvect)
    residu = {vector(ind:lgvect), time_v(ind:lgvect)};
else
    residu = {[], []};
end