Beispiel #1
0
def test_already_closed():
    dev = MpDevice(Dummy())
    dev.start()
    res = dev.read()
    dev.stop()
    with raises(RuntimeError):
        dev.read()
Beispiel #2
0
def test_multi_devs():
    dev1 = MpDevice(Dummy())
    dev2 = MpDevice(Dummy())

    with dev1, dev2:
        sleep(0.2)
        time1, data1 = dev1.read()
        time2, data2 = dev2.read()

    print(time1[-5:], time2[-5:])
Beispiel #3
0
def test_views():
    dev = MpDevice(Dummy(), use_views=True)
    with dev:
        datas = []
        sleep(0.1)
        time, data = dev.read()
        datas.append(data)
        sleep(0.1)
        time, data = dev.read()
        datas.append(data)
    print(datas)
    assert (datas[0][2, 3] == datas[1][2, 3])
Beispiel #4
0
def test_restart():
    dev = MpDevice(Dummy())
    with dev:
        sleep(0.2)
        res = dev.read()
    with dev:
        sleep(0.2)
        res2 = dev.read()
    print(res[0])
    print(res2[0])
    assert (res[0].any() and res2[0].any())
    assert (res[0][-1] < res2[0][0])
Beispiel #5
0
def test_list():
    dev = MpDevice(DummyList())
    with dev:
        sleep(0.2)
        time, data = dev.read()
    assert (data.shape[0] > 10)
    assert (data.shape[0] == time.shape[0])
Beispiel #6
0
def test_none():
    dev = MpDevice(NoData())
    with dev:
        sleep(0.2)
        res = dev.read()

    assert (res is None)
Beispiel #7
0
def test_struct():
    dev = MpDevice(StructObs())
    with dev:
        sleep(0.2)
        time, data = dev.read()
    print(data)
    assert (data.shape[0] > 10)
    assert (data.shape[0] == time.shape[0])
Beispiel #8
0
def test_nones():
    dev = MpDevice(SometimesNot())
    with dev:
        sleep(0.2)
        time, data = dev.read()
    print(data.shape)
    assert (data.shape[0] > 10)
    assert (data.shape[0] == time.shape[0])
Beispiel #9
0
def test_mono():
    dev = MpDevice(Incrementing(), buffer_len=10)
    with dev:
        sleep(1)
        time, val = dev.read()

    print(time, val)
    assert (all(np.diff(time) > 0))
    assert (all(np.diff(val) > 0))
Beispiel #10
0
def test_remote_clock():
    dev = MpDevice(Dummy(clock=mono_clock.get_time))
    sleep(0.5)
    with dev:
        sleep(0.1)
        time, data = dev.read()
        tmp = mono_clock.get_time()
    print(tmp - time[-1])
    assert (tmp - time[-1] == approx(1.0 / Dummy.sampling_frequency, abs=3e-3))
Beispiel #11
0
def test_ringbuffer():
    dev = MpDevice(Dummy(), buffer_len=1)
    with dev:
        sleep(1)
        time, val = dev.read()

    assert (time.shape[0] == 1)
    assert (val.shape == (1, 5))
    print(time, val)
Beispiel #12
0
def test_device_single():
    dev = MpDevice(Dummy())
    dev.start()
    sleep(0.25)
    res = dev.read()
    dev.stop()
    assert (res is not None)
    time, data = res
    print(np.diff(time))
    print(data.shape)
    assert (data.shape[0] > 10)
    assert (data.shape[0] == time.shape[0])
Beispiel #13
0
def test_freq():
    original_fs = Dummy.sampling_frequency
    Dummy.sampling_frequency = 1

    dev = MpDevice(Dummy())
    with dev:
        sleep(4)
        time, val = dev.read()

    assert (time.shape[0] == 1)
    assert (val.shape == (1, 5))
    print(time, val)
    Dummy.sampling_frequency = original_fs
Beispiel #14
0
def test_read_multi():
    dev = MpDevice(Incrementing())
    with dev:
        times, dats = [], []
        for i in range(500):
            data = dev.read()
            if data:
                times.append(data.time)
                dats.append(data.data)
            sleep(0.016)
    times = np.hstack(times)
    vals = np.hstack(dats)
    print(times)
    print(vals)
    assert (all(np.diff(times)) > 0)
    assert (all(np.diff(vals)) > 0)
Beispiel #15
0
class LivePlot(pg.GraphicsLayoutWidget):
    def __init__(self, device):
        super(LivePlot, self).__init__()
        self.device = MpDevice(device, use_views=True)
        self.current_data = None
        self.lines = []
        dummy = np.ones(4)
        self.fig = self.addPlot(title='Foobar')
        self.fig.showGrid(x=True, y=True, alpha=0.4)
        self.fig.setClipToView(True)
        mi, ma = 0, 4000
        self.fig.setRange(yRange=[mi, ma])
        self.fig.setLimits(yMin=mi, yMax=ma)
        for j in range(3):
            pen = pg.mkPen(color=pg.intColor(j, hues=3, alpha=220), width=1)
            self.lines.append(self.fig.plot(dummy, dummy, pen=pen))
        self.timer = QtCore.QTimer()
        self.timer.timeout.connect(self.update)
        self.timer.start(0)
        self.playing = True

    def update(self):
        pos = self.device.read()
        if pos is None:
            return
        if self.current_data is None:
            self.current_data = pos.data
            self.current_time = pos.time
        elif self.current_data.shape[0] < self.device.device.sampling_frequency:
            self.current_data = np.hstack((self.current_data, pos.data))
            self.current_time = np.hstack((self.current_time, pos.time))
        else:
            ps0 = -pos.data.shape[0]
            self.current_data = np.roll(self.current_data, ps0, axis=0)
            self.current_data[ps0:] = pos.data
            self.current_time = np.roll(self.current_time, ps0)
            self.current_time[ps0:] = pos.time
        if self.playing:
            self.lines[0].setData(y=self.current_data[:]['digital'] * 2000)
            self.lines[1].setData(y=self.current_data[:]['a1'])
            self.lines[2].setData(y=self.current_data[:]['a2'])
        print(pos.data[-1])
Beispiel #16
0
if __name__ == '__main__':
    from toon.input import MpDevice
    from toon_rawinput.keyboard import Keyboard
    from toon_rawinput.mouse import Mouse

    print('sleeping-- plug in test device.')
    sleep(5)
    print('done sleeping-- good luck')
    mydev = MpDevice(Keyboard(clock=ptb.GetSecs))

    mytimes = []
    total_time = 60 * 2
    with mydev:
        t0 = time()
        while time() - t0 < total_time:
            res = mydev.read()
            if res:
                #print('mine: %s' % res.time)
                mytimes.append(res.time)
            sleep(0.02)

    import matplotlib.pyplot as plt
    import numpy as np

    mytimes = np.hstack(mytimes)
    mylen = len(mytimes)
    if mylen % 2 != 0:
        mytimes = mytimes[1:]
    mydff = np.diff(mytimes[::2])

    plt.plot(mydff)
Beispiel #17
0
class PinchTask(ShowBase, GripStateMachine):
    DATA_DIR = 'data'
    
    def __init__(self, id, session, hand, block, mode, wrist):
        ShowBase.__init__(self)
        GripStateMachine.__init__(self)
        base.disableMouse()
        wp = WindowProperties()
        wp.setSize(1920,1080)
        wp.setFullscreen(True)
        base.win.requestProperties(wp)

        self.sub_id = str(id)
        self.sess_id = str(session)
        self.hand = str(hand)
        self.block = str(block)
        self.mode = str(mode)
        self.wrist = str(wrist)
        
        self.prev_blk = os.path.join(self.DATA_DIR,'exp_1',self.sub_id,self.sess_id,self.wrist,self.hand,"B0")
        if self.wrist == 'pron':
            self.table = np.loadtxt('src/pinch_task/trialtable_pron.csv',dtype='str',delimiter=',',skiprows=1)
        elif self.wrist == 'flex':
            self.table = np.loadtxt('src/pinch_task/trialtable_flex.csv',dtype='str',delimiter=',',skiprows=1)
        else:
            raise NameError('Wrist position not found')

        try:
            self.prev_table = np.loadtxt(os.path.join(self.prev_blk, 'final_targets.csv'),dtype='str',delimiter=',',skiprows=1)
            indices = {}
            for i in range(self.prev_table.shape[0]):
                indices[self.prev_table[i,1]] = int(self.prev_table[i,0])-1
            for i in range(self.table.shape[0]):
                self.table[i,11] = self.prev_table[indices[self.table[i,1].strip()],11]
                self.table[i,12] = self.prev_table[indices[self.table[i,1].strip()],12]
                self.table[i,13] = self.prev_table[indices[self.table[i,1].strip()],13]
        except:
            print('Previous target file not found')
        
        self.table = np.array([[item.strip() for item in s] for s in self.table])

        ##################################################
        #only use rows relevant to this block
        #HARDCODED! NOTE IN LOG SHEET
        spec_table = []
        for i in range(self.table.shape[0]):
            if int(self.block)%4 == 0:
                if "(p)" in self.table[i,2]:
                    spec_table.append(self.table[i])
            elif int(self.block)%4 == 1:
                if "(t)" in self.table[i,2]:
                    spec_table.append(self.table[i])
            elif int(self.block)%4 == 2:
                if "(s)" in self.table[i,2]:
                    spec_table.append(self.table[i])
            elif int(self.block)%4 == 3:
                if "(t+s)" in self.table[i,2]:
                    spec_table.append(self.table[i])
        ###################################################
        self.table = np.array(spec_table)

        self.session_dir = os.path.join(self.DATA_DIR,'exp_1',self.sub_id,self.sess_id,self.wrist,self.hand)
        self.subjinfo = self.sub_id + '_' + self.sess_id + '_' + self.hand + '_log.yml'
        self.p_x,self.p_y,self.p_a = GET_POS(self.session_dir,self.subjinfo,self.hand,self.wrist)

        self.rotmat = ROT_MAT(self.p_a,self.hand)

        self.setup_text()
        self.setup_lights()
        self.setup_camera()
        
        self.trial_counter = 0
        self.load_models()
        self.load_audio()
        self.update_trial_command()
        self.countdown_timer = CountdownTimer()
        self.hold_timer = CountdownTimer()

        self.cTrav = CollisionTraverser()
        self.chandler = CollisionHandlerEvent()
        self.chandler.addInPattern('%fn-into-%in')
        self.chandler.addAgainPattern('%fn-again-%in')
        self.chandler.addOutPattern('%fn-outof-%in')
        self.attachcollnodes()

        taskMgr.add(self.read_data, 'read')
        for i in range(5):
            taskMgr.add(self.move_player, 'move%d' % i, extraArgs = [i], appendTask=True)
        taskMgr.add(self.log_data, 'log data')
        taskMgr.add(self.update_state, 'update_state', sort=1)

        self.accept('space', self.space_on)
        self.accept('escape', self.clean_up)
        self.space = False
        self.statenum = list()

        self.max_time = 20
        self.med_data = None

        self.grip_dir = os.path.join(self.DATA_DIR,'exp_1',self.sub_id,self.sess_id,self.wrist,self.hand,"B"+self.block)
        if not os.path.exists(self.grip_dir):
           print('Making new folders: ' + self.grip_dir)
           os.makedirs(self.grip_dir)

        self.dev = MpDevice(RightHand(calibration_files=['calibs/cal_mat_15.mat',  # thumb
                                               'calibs/cal_mat_31.mat',
                                               'calibs/cal_mat_8.mat',
                                               'calibs/cal_mat_21.mat',
                                               'calibs/cal_mat_13.mat'], clock=mono_clock.get_time))

        self.init_ser()

    ############
    #SET UP HUD#
    ############
    def setup_text(self):
        #OnscreenImage(parent=self.cam2dp, image='models/background.jpg')
        self.bgtext = OnscreenText(text='Not recording.', pos=(-0.8, 0.8),
                                 scale=0.08, fg=(0, 0, 0, 1),
                                 bg=(1, 1, 1, 1), frame=(0.2, 0.2, 0.8, 1),
                                 align=TextNode.ACenter)
        self.bgtext.reparentTo(self.aspect2d)

        self.dirtext = OnscreenText( pos=(-0.6, 0.65),
                                 scale=0.08, fg=(0, 0, 0, 1),
                                 bg=(1, 1, 1, 1), frame=(0.2, 0.2, 0.8, 1),
                                 align=TextNode.ACenter)
        self.dirtext.reparentTo(self.aspect2d)

    ##########################
    #SET UP SCENE AND PLAYERS#
    ##########################
    def setup_lights(self):
        pl = PointLight('pl')
        pl.setColor((1, 1, 1, 1))
        plNP = self.render.attachNewNode(pl)
        plNP.setPos(-10, -10, 10)
        self.render.setLight(plNP)
        pos = [[[0, 0, 50], [0, 0, -10]],
               [[0, -50, 0], [0, 10, 0]],
               [[-50, 0, 0], [10, 0, 0]]]
        for i in pos:
            dl = Spotlight('dl')
            dl.setColor((1, 1, 1, 1))
            dlNP = self.render.attachNewNode(dl)
            dlNP.setPos(*i[0])
            dlNP.lookAt(*i[1])
            dlNP.node().setShadowCaster(False)
            self.render.setLight(dlNP)

    def setup_camera(self):
        self.cam.setPos(0, -4, 12)
        self.cam.lookAt(0, 2, 0)
        self.camLens.setFov(90)

    def load_models(self):
        self.back_model = self.loader.loadModel('models/back')
        self.back_model.setScale(10, 10, 10)
        if self.hand == "Left":
            self.back_model.setH(90)
        self.back_model.reparentTo(self.render)

        self.player_offsets = [[self.p_x[0]-5, self.p_y[0]+3, 0], [self.p_x[1]-2.5, self.p_y[1]+4.5, 0], [self.p_x[2], self.p_y[2]+5, 0],
                                [self.p_x[3]+2.5, self.p_y[3]+4.5, 0], [self.p_x[4]+5, self.p_y[4]+3, 0]]
        self.p_col =[[0,0,250],[50,0,200],[125,0,125],[200,0,50],[250,0,0]]
        if self.hand == 'Left':
            self.p_col = self.p_col[::-1]

        self.players = list()
        self.contacts = list()        
        for counter, value in enumerate(self.player_offsets):
            self.players.append(self.loader.loadModel('models/target'))
            self.contacts.append(False)

            self.players[counter].setPos(*value)
            self.players[counter].setScale(0.2, 0.2, 0.2)
            self.players[counter].setColorScale(
                self.p_col[counter][0]/255, self.p_col[counter][1]/255, self.p_col[counter][2]/255, 1)
            self.players[counter].reparentTo(self.render)
            self.players[counter].show()

        self.target_select()

    def load_audio(self):
        self.pop = self.loader.loadSfx('audio/Blop.wav')
        self.buzz = self.loader.loadSfx('audio/Buzzer.wav')


    ############################
    #SET UP COLLISION MECHANICS#
    ############################
    def attachcollnodes(self):
        for i in range(5):
            self.fromObject = self.players[i].attachNewNode(CollisionNode('colfromNode'+str(i)))
            self.fromObject.node().addSolid(CollisionSphere(0,0,0,1))
            self.cTrav.addCollider(self.fromObject, self.chandler)

        for i in range(5):
            self.accept('colfromNode%d-into-colintoNode' % i, self.collide1,[i])
            self.accept('colfromNode%d-again-colintoNode' % i, self.collide2,[i])
            self.accept('colfromNode%d-outof-colintoNode' % i, self.collide3,[i])

    def collide1(self,f,collEntry):
        if f in self.highlighted_indices:
            self.players[f].setColorScale(0,1,0,0)
            self.tar.setColorScale(0.2,0.2,0.2,1)
            self.tar.setAlphaScale(0.7)
            self.contacts[f] = True
            taskMgr.doMethodLater(self.delay,self.too_long,'too_long%d' % f,extraArgs = [f])
            self.sendsig(1,f,100)
                
    def collide2(self,f,collEntry):
        if f in self.highlighted_indices:
            dist = np.sqrt(self.distances[f][1]^2+self.distances[f][2]^2+self.distances[f][3]^2)
            self.sendsig(2,f,int(10/dist)+100)
        for i in self.highlighted_indices:
            if self.contacts[i] == False:
                return
        taskMgr.remove('too_long%d' % f)

    def collide3(self,f,collEntry):
        taskMgr.remove('too_long%d' % f)
        self.reset_fing(f)
        self.tar.setColorScale(0.1,0.1,0.1,1)
        self.tar.setAlphaScale(0.7)

    def too_long(self,f):
        self.reset_fing(f)
        self.tar.setColorScale(0.5,0.2,0.2,1)
        self.tar.setAlphaScale(0.7)

    def reset_fing(self,f):
        self.players[f].setColorScale(
                self.p_col[f][0]/255, self.p_col[f][1]/255, self.p_col[f][2]/255, 1)
        self.contacts[f] = False
        self.sendsig(3,f,0)

    ###############
    #TARGET THINGS#
    ###############
    def show_target(self):
        self.target_select()
        self.intoObject = self.tar.attachNewNode(CollisionNode('colintoNode'))

        if self.table[self.trial_counter,7] == "sphere":
            self.intoObject.node().addSolid(CollisionSphere(0,0,0,1))
        elif self.table[self.trial_counter,7] == "cylinder":
            self.intoObject.node().addSolid(CollisionTube(0,0,-2,0,0,2,1))
        else:
            raise NameError("No such collision type")

        self.tar.show()

        #hide players not related to target
        for i in range(5):
            if i not in self.highlighted_indices:
                self.players[i].hide()
        
    def target_select(self):
        self.tgtscx=float(self.table[self.trial_counter,14])
        self.tgtscy=float(self.table[self.trial_counter,15])
        self.tgtscz=float(self.table[self.trial_counter,16])
        tgttsx=float(self.table[self.trial_counter,11])
        tgttsy=float(self.table[self.trial_counter,12])
        tgttsz=float(self.table[self.trial_counter,13])
        tgtrx=float(self.table[self.trial_counter,17])
        tgtry=float(self.table[self.trial_counter,18])
        tgtrz=float(self.table[self.trial_counter,19])
        if self.hand == 'Left':
            tgttsx *= -1
            tgtrx *= -1

        self.static_task = (str(self.table[self.trial_counter,5]) == "True")
        self.target_model = str(self.table[self.trial_counter,6])
        self.highlighted_indices=[int(s)-1 for s in self.table[self.trial_counter,4].split(' ')]
        if self.hand == 'Left':
            self.highlighted_indices=[4-i for i in self.highlighted_indices]

        #NOTE:this position finding is present in all three tasks
        #     it is somewhat hacky and can be improved upon
        self.tgtposx = np.mean(np.asarray(self.player_offsets)[self.highlighted_indices][[-2,-1],0]) + tgttsx
        self.tgtposy = np.mean(np.asarray(self.player_offsets)[self.highlighted_indices][[0,1],1]) + tgttsy
        if len(self.highlighted_indices) > 3: #for sphere, return to just average of all fingers
            self.tgtposx = np.mean(np.asarray(self.player_offsets)[self.highlighted_indices][:,0]) + tgttsx
            #self.tgtposy = np.mean(np.asarray(self.player_offsets)[self.highlighted_indices][:,1])
        self.tgtposz = np.mean(np.asarray(self.player_offsets)[self.highlighted_indices][:,2]) + tgttsz

        self.tar = self.loader.loadModel(self.target_model)
        self.tar.setScale(self.tgtscx,self.tgtscy,self.tgtscz)
        self.tar.setPos(self.tgtposx,self.tgtposy,self.tgtposz)
        self.tar.setHpr(tgtrx,tgtry,tgtrz)
        self.tar.setColorScale(0.1, 0.1, 0.1, 1)
        self.tar.setAlphaScale(0.7)
        self.tar.setTransparency(TransparencyAttrib.MAlpha) 
        self.tar.reparentTo(self.render)
        self.tar.hide()

        self.delay=float(self.table[self.trial_counter,8])
        self.loc_angle=math.radians(float(self.table[self.trial_counter,9]))
        self.invf=float(self.table[self.trial_counter,10])
        
        self.distances = [[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0]]

    ##############
    #MOVE FINGERS#
    ##############
    def read_data(self,task):
        error, data = self.dev.read()
        if data is not None:
            data *= 0.001
            self.ts = data.time
            data = np.dot(data,self.rotmat)
            self.data = data
            if self.med_data is None:
                self.med_data = np.median(data, axis=0)

            if self.space:
                self.statenum.extend(([self.checkstate()])*len(data.time))
                
        return task.cont
        
    def move_player(self,p,task):
        if self.data is not None :
            k = p*3
            new_x = 10*np.mean(self.data[-1,k]) + self.player_offsets[p][0] - 10*self.med_data[k]
            new_y = 10*np.mean(self.data[-1,k + 1]) + self.player_offsets[p][1] - 10*self.med_data[k + 1]
            new_z = 10*np.mean(self.data[-1,k + 2]) + self.player_offsets[p][2] - 10*self.med_data[k + 2]

            #make sure digits do not cross each other
            if ((p in range(1,3) and p+1 in self.highlighted_indices and new_x > self.players[p+1].getX())
                or (p in range(2,4) and p-1 in self.highlighted_indices and new_x < self.players[p-1].getX())):
                    new_x = self.players[p].getX()
            
            #make sure digits do not cross into target
            if self.space == True and p in self.highlighted_indices:
                self.distances[p][0] = new_x - self.tar.getX()
                self.distances[p][1] = new_y - self.tar.getY()
                self.distances[p][2] = new_z - self.tar.getZ()
                self.check_pos(p)
                
            self.players[p].setPos(new_x, new_y, new_z)
            
        return task.cont
    
    def check_pos(self,p):
        if (abs(self.distances[p][0]) < self.invf*self.tgtscx
            and abs(self.distances[p][1]) < self.invf*self.tgtscy
            and abs(self.distances[p][2]) < self.invf*self.tgtscz):
                self.too_long(p)

    ##################
    #CHECK COMPLETION#
    ##################
    def close_to_target(self):
        for i in self.highlighted_indices:
            if self.contacts[i] == False:
                return False

        if not self.check_angle():
            self.tar.setColorScale(0.1,0.1,0.1,1)
            self.tar.setAlphaScale(0.7)
            return False

        self.tar.setColorScale(0,1,1,1)
        return True

    def check_hold(self):
        if not self.close_to_target():
            self.hold_timer.reset(0.5)
            return False
        return self.hold_timer.elapsed() < 0

    def check_angle(self):
        #hardcoded condition may be able to be assimilated into old angle method somehow
        if self.table[self.trial_counter,1] == 'pts':
            vec = np.subtract(self.players[self.highlighted_indices[1]].getPos(), self.players[self.highlighted_indices[0]].getPos())
            xvec = [1,0,0]
            if self.hand == 'Left':
                xvec = [-1,0,0]
            print(math.degrees(math.acos(np.dot(vec,xvec)/(np.linalg.norm(vec)*np.linalg.norm(xvec)))))
            if math.acos(np.dot(vec,xvec)/(np.linalg.norm(vec)*np.linalg.norm(xvec))) < self.loc_angle:
                return True
            else: return False
        thumbindx = 0
        if self.hand == "Left": thumbindx = 4
        for i in self.highlighted_indices:
            if i == thumbindx:
                continue
            th = self.distances[thumbindx]
            fg = self.distances[i]
            if math.acos(np.dot(th,fg)/(np.linalg.norm(th)*np.linalg.norm(fg))) > self.loc_angle:
                return True
        return False

    def adjust_targets(self):
        #no adjustment if more than 2 fingers or position is prone
        if len(self.highlighted_indices) > 2 or self.wrist == 'pron':
            return

        xadj,yadj,zadj = np.mean(np.asarray(self.distances)[self.highlighted_indices],0)
        #yadj = np.mean(np.asarray(self.distances)[self.highlighted_indices][1])
        #zadj = np.mean(np.asarray(self.distances)[self.highlighted_indices][2])

        #do adjustment on all tasks with same name
        if self.hand == 'Left':
            xadj = -xadj
        for i in range(self.trial_counter+1,self.table.shape[0]):
            if self.table[i,1] == self.table[self.trial_counter,1]:
                self.table[i,11] = float(self.table[i,11]) + xadj
                self.table[i,12] = float(self.table[i,12]) + yadj
                self.table[i,13] = float(self.table[i,13]) + zadj


    #########
    #LOGGING#
    #########
    def play_success(self):
        if int(self.block) == 0:
            self.adjust_targets()
        self.pop.play()
        self.tar.hide()
        self.highlighted_indices = [0,1,2,3,4]

    def log_text(self):
        self.bgtext.setText('Now logging...')

    def log_data(self, task):
        if (self.trial_counter + 1) <= self.table.shape[0]:
            if self.space:
                self.log_file_name = os.path.join(self.grip_dir,
                                          self.sub_id+"_"+self.sess_id+"_"+self.hand+"_"+
                                              str(self.table[self.trial_counter,1])+"_"+str(self.table[self.trial_counter,0])+".csv" )
                self.movvars = np.column_stack((self.ts, self.statenum, self.data))
                self.statenum = []
                if self.mode=='task':
                    with open(self.log_file_name, 'ab') as f:
                        np.savetxt(f, self.movvars, fmt='%10.5f', delimiter=',')
            return task.cont
        else:
            pass

    def stoplog_text(self):
        self.dirtext.clearText()
        self.bgtext.setText('Done logging!')
        for i in range(5):
            self.players[i].show()

    #######
    #RESET#
    #######
    def delete_file(self):
        if (self.trial_counter + 1) <= self.table.shape[0]:
            self.log_file_name = os.path.join(self.grip_dir,
                                      self.sub_id+"_"+self.sess_id+"_"+self.hand+"_"+
                                          str(self.table[self.trial_counter,1])+"_"+str(self.table[self.trial_counter,0])+".csv" )
            try:
                os.remove(self.log_file_name)
            except OSError:
                pass
        else:
            pass

    def reset_baseline(self):
       self.med_data = None
                   
    def reset_keyboard_bool(self):
        self.space = False

    def hide_target(self):
        self.tar.hide()
        self.intoObject.removeNode()
        self.imageObject.destroy()

    def update_trial_command(self):
        self.dirtext.setText(str(self.table[self.trial_counter,2]))
        if self.hand == 'Left':
            xfac = -0.25
        else:
            xfac = 0.25
        self.imageObject = OnscreenImage(image = str(self.table[self.trial_counter,3]),scale=(xfac,0.25,0.25),pos=(-1.2, 0, 0.3))

    def increment_trial_counter(self):
        self.trial_counter += 1
        self.update_trial_command()

    ########
    #TIMERS#
    ########
    def start_trial_countdown(self):
        self.countdown_timer.reset(self.max_time)

    def start_hold_countdown(self):
        self.hold_timer.reset(0.5)

    def start_post_countdown(self):
        self.countdown_timer.reset(2)

    def time_elapsed(self):
        return self.countdown_timer.elapsed() < 0

    #########
    #MACHINE#
    #########
    def update_state(self, task):
        self.step()
        return task.cont

    def wait_for_space(self):
        return self.space

    def space_on(self):
        self.space = True

    #####
    #END#
    #####
    def trial_counter_exceeded(self):
        return (self.trial_counter+1) > self.table.shape[0]-1

    def clean_up(self):
        #write last known positions to 'final_targets' file
        f = open('src/pinch_task/trialtable_flex.csv')
        header = f.readline().rstrip()
        np.savetxt(self.grip_dir + '/final_targets.csv',self.table,fmt='%s',header = header, delimiter=',')
        f.close()
        sys.exit()

    ########
    #SERIAL#
    ########
    def init_ser(self):
        #CONNECT TO HAPTIC DEVICE
        ports = list_ports.comports()
        mydev = next((p.device for p in ports if p.pid == 1155))
        self.ser = serial.Serial(mydev,9600,timeout=.1)

    def sendsig(self,signal,finger,intensity):
        #would read from table, but table not available yet
        if intensity > 255:
            intensity = 255
        dur_int = [signal,finger,intensity]
        data = struct.pack('3B',*dur_int)
        self.ser.write(data)
Beispiel #18
0
class TunnelPinchTask(ShowBase, GripStateMachine):
    DATA_DIR = 'data'
    
    def __init__(self, id, session, hand, block, mode, wrist):
        ShowBase.__init__(self)
        GripStateMachine.__init__(self)
        base.disableMouse()
        wp = WindowProperties()
        wp.setSize(1920,1080)
        wp.setFullscreen(True)
        wp.setUndecorated(True)
        base.win.requestProperties(wp)

        self.sub_id = str(id)
        self.sess_id = str(session)
        self.hand = str(hand)
        self.block = str(block)
        self.mode = str(mode)
        self.wrist = str(wrist)
        
        self.prev_blk = os.path.join(self.DATA_DIR,'exp_2',self.sub_id,self.sess_id,self.wrist,self.hand,"B0")
        self.exp_blk0 = os.path.join(self.DATA_DIR,'exp_1',self.sub_id,self.sess_id,self.wrist,self.hand,"B0")
        self.table = np.loadtxt('src/tunnel_pinch_task/trialtable_flex.csv',dtype='str',delimiter=',',skiprows=1)

        indices = {}
        try:
            self.prev_table = np.loadtxt(os.path.join(self.prev_blk, 'final_targets.csv'),dtype='str',delimiter=',',skiprows=1)
        except:
            try:
                self.prev_table = np.loadtxt(os.path.join(self.exp_blk0, 'final_targets.csv'),dtype='str',delimiter=',',skiprows=1)
            except:
                print('Previous target file not found, results may be suboptimal')
        try:
            for i in range(self.prev_table.shape[0]):
                indices[self.prev_table[i,1]] = int(self.prev_table[i,0])-1
            for i in range(self.table.shape[0]):
                self.table[i,11] = self.prev_table[indices[self.table[i,1].strip()],11]
                self.table[i,12] = self.prev_table[indices[self.table[i,1].strip()],12]
                self.table[i,13] = self.prev_table[indices[self.table[i,1].strip()],13]
        except:
            print('Invalid target file')
        
        self.table = np.array([[item.strip() for item in s] for s in self.table])

        ###################################################
        #only use rows relevant to this block
        #HARDCODED! NOTE IN LOG SHEET
        spec_table = []
        for i in range(self.table.shape[0]):
            if int(self.block)%5 == 0: #block 0 to adjust positions
                if "(p)" in self.table[i,2]:
                    spec_table.append(self.table[i])
            elif int(self.block)%5 == 1:
                if "(L)" in self.table[i,2]:
                    spec_table.append(self.table[i])
            elif int(self.block)%5 == 2:
                if "(L+t)" in self.table[i,2]:
                    spec_table.append(self.table[i])
            elif int(self.block)%5 == 3:
                if "(S)" in self.table[i,2]:
                    spec_table.append(self.table[i])
            elif int(self.block)%5 == 4:
                if "(S+t)" in self.table[i,2]:
                    spec_table.append(self.table[i])
        ###################################################
        self.table = np.array(spec_table)

        self.session_dir = os.path.join(self.DATA_DIR,'exp_2',self.sub_id,self.sess_id,self.wrist,self.hand)
        self.subjinfo = self.sub_id + '_' + self.sess_id + '_' + self.hand + '_log.yml'
        self.p_x,self.p_y,self.p_a = GET_POS(self.session_dir,self.subjinfo,self.hand,self.wrist)

        self.rotmat = ROT_MAT(self.p_a,self.hand)

        self.setup_text()
        self.setup_lights()
        self.setup_camera()
        
        self.trial_counter = 0
        self.load_models()
        self.load_audio()
        self.update_trial_command()
        self.countdown_timer = CountdownTimer()
        self.hold_timer = CountdownTimer()

        self.cTrav = CollisionTraverser()
        self.chandler = CollisionHandlerEvent()
        self.chandler.addInPattern('%fn-into-%in')
        self.chandler.addOutPattern('%fn-outof-%in')
        self.chandler.addAgainPattern('%fn-again-%in')
        self.attachcollnodes()

        taskMgr.add(self.read_data, 'read')
        for i in range(5):
            taskMgr.add(self.move_player, 'move%d' % i, extraArgs = [i], appendTask=True)
        taskMgr.add(self.log_data, 'log_data')
        taskMgr.add(self.update_state, 'update_state', sort=1)

        self.accept('space', self.space_on)
        self.accept('escape', self.clean_up)
        self.space = False
        self.statenum = list()

        self.max_time = 20
        self.med_data = None

        self.grip_dir = os.path.join(self.DATA_DIR,'exp_2',self.sub_id,self.sess_id,self.wrist,self.hand,"B"+self.block)
        if not os.path.exists(self.grip_dir):
           print('Making new folders: ' + self.grip_dir)
           os.makedirs(self.grip_dir)

        self.dev = MpDevice(RightHand(calibration_files=['calibs/cal_mat_70_v2.mat',
                                                'calibs/cal_mat_73_v2.mat',
                                                'calibs/cal_mat_56.mat',
                                                'calibs/cal_mat_58_v2.mat',
                                                'calibs/cal_mat_50.mat'], clock=mono_clock.get_time))

    ############
    #SET UP HUD#
    ############
    def setup_text(self):
        self.bgtext = OnscreenText(text='Not recording.', pos=(-0.8, 0.8),
                                 scale=0.08, fg=(0, 0, 0, 1),
                                 bg=(1, 1, 1, 1), frame=(0.2, 0.2, 0.8, 1),
                                 align=TextNode.ACenter)
        self.bgtext.reparentTo(self.aspect2d)

        self.dirtext = OnscreenText( pos=(-0.6, 0.65),
                                 scale=0.08, fg=(0, 0, 0, 1),
                                 bg=(1, 1, 1, 1), frame=(0.2, 0.2, 0.8, 1),
                                 align=TextNode.ACenter)
        self.dirtext.reparentTo(self.aspect2d)
    
    ##########################
    #SET UP SCENE AND PLAYERS#
    ##########################
    def setup_lights(self):
        pl = PointLight('pl')
        pl.setColor((1, 1, 1, 1))
        plNP = self.render.attachNewNode(pl)
        plNP.setPos(-10, -10, 10)
        self.render.setLight(plNP)
        pos = [[[0, 0, 50], [0, 0, -10]],
               [[0, -50, 0], [0, 10, 0]],
               [[-50, 0, 0], [10, 0, 0]]]
        for i in pos:
            dl = Spotlight('dl')
            dl.setColor((1, 1, 1, 1))
            dlNP = self.render.attachNewNode(dl)
            dlNP.setPos(*i[0])
            dlNP.lookAt(*i[1])
            dlNP.node().setShadowCaster(False)
            self.render.setLight(dlNP)

    def setup_camera(self):
        self.cam.setPos(0, 0, 12)
        self.cam.lookAt(0, 2, 0)
        self.camLens.setFov(90)

    def load_models(self):
        self.back_model = self.loader.loadModel('models/back')
        self.back_model.setScale(10, 10, 10)
        if self.hand == "Left":
            self.back_model.setH(90)
        self.back_model.reparentTo(self.render)

        self.player_offsets = [[self.p_x[0]-5, self.p_y[0]+3, 0], [self.p_x[1]-2.5, self.p_y[1]+4.5, 0], [self.p_x[2], self.p_y[2]+5, 0],
                                [self.p_x[3]+2.5, self.p_y[3]+4.5, 0], [self.p_x[4]+5, self.p_y[4]+3, 0]]
        self.p_col =[[0,0,250],[50,0,200],[125,0,125],[200,0,50],[250,0,0]]
        if self.hand == 'Left':
            self.p_col = self.p_col[::-1]

        self.players = list()
        self.contacts = list()        
        for counter, value in enumerate(self.player_offsets):
            self.players.append(self.loader.loadModel('models/target'))
            self.contacts.append(False)

            self.players[counter].setPos(*value)
            self.players[counter].setScale(0.2, 0.2, 0.2)
            self.players[counter].setColorScale(
                self.p_col[counter][0]/255, self.p_col[counter][1]/255, self.p_col[counter][2]/255, 1)
            self.players[counter].reparentTo(self.render)
            self.players[counter].show()

        self.target_select()

    def load_audio(self):
        self.pop = self.loader.loadSfx('audio/Blop.wav')
        self.buzz = self.loader.loadSfx('audio/Buzzer.wav')


    ############################
    #SET UP COLLISION MECHANICS#
    ############################
    def attachcollnodes(self):
        self.inside = [False]*5
        for i in range(5):
            self.fromObject = self.players[i].attachNewNode(CollisionNode('colfromNode'+str(i)))
            self.fromObject.node().addSolid(CollisionSphere(0,0,0,1))
            self.cTrav.addCollider(self.fromObject, self.chandler)

        for i in range(5):
            self.accept('colfromNode%d-into-colintoNode' % i, self.collide1,[i])
            self.accept('colfromNode%d-again-colintoNode' % i, self.collide2,[i])
            self.accept('colfromNode%d-outof-colintoNode' % i, self.collide3,[i])

    def collide1(self,f,collEntry):
        if f in self.highlighted_indices:
            self.players[f].setColorScale(0,1,0,1)
            self.tar.setColorScale(0.2,0.2,0.2,1)
            self.tar.setAlphaScale(0.7)
            self.contacts[f] = True
            taskMgr.doMethodLater(self.delay,self.too_long,'too_long%d' % f,extraArgs = [f])
                
    def collide2(self,f,collEntry):
        for i in self.highlighted_indices:
            if self.contacts[i] == False:
                return
        taskMgr.remove('too_long%d' % f)

    def collide3(self,f,collEntry):
        taskMgr.remove('too_long%d' % f)
        self.reset_fing(f)
        self.tar.setColorScale(0.1,0.1,0.1,1)
        self.tar.setAlphaScale(0.7)

    def too_long(self,f):
        self.reset_fing(f)
        self.tar.setColorScale(0.5,0.2,0.2,1)
        self.tar.setAlphaScale(0.7)

    def reset_fing(self,f):
        self.players[f].setColorScale(
                self.p_col[f][0]/255, self.p_col[f][1]/255, self.p_col[f][2]/255, 1)
        self.contacts[f] = False

    ###############
    #TARGET THINGS#
    ###############
    def show_target(self):
        self.target_select()
        self.intoObject = self.tar.attachNewNode(CollisionNode('colintoNode'))

        if self.table[self.trial_counter,7] == "sphere":
            self.intoObject.node().addSolid(CollisionSphere(0,0,0,1))
        elif self.table[self.trial_counter,7] == "cylinder":
            self.intoObject.node().addSolid(CollisionTube(0,0,-2,0,0,2,1))
        else:
            raise NameError("No such collision type")

        self.tar.show()
        self.occSolid.show()
        self.occLines.show()

        for i in range(5):
            if i not in self.highlighted_indices:
                self.players[i].hide()

    def target_select(self):
        self.tgtscx=float(self.table[self.trial_counter,14])
        self.tgtscy=float(self.table[self.trial_counter,15])
        self.tgtscz=float(self.table[self.trial_counter,16])
        tgttsx=float(self.table[self.trial_counter,11])
        tgttsy=float(self.table[self.trial_counter,12])
        tgttsz=float(self.table[self.trial_counter,13])
        tgtrx=float(self.table[self.trial_counter,17])
        tgtry=float(self.table[self.trial_counter,18])
        tgtrz=float(self.table[self.trial_counter,19])
        if self.hand == 'Left':
            tgttsx *= -1
            tgtrx *= -1

        self.static_task = (str(self.table[self.trial_counter,5]) == "True")
        self.target_model = str(self.table[self.trial_counter,6])
        self.highlighted_indices=[int(s)-1 for s in self.table[self.trial_counter,4].split(' ')]
        if self.hand == 'Left':
            self.highlighted_indices=[4-i for i in self.highlighted_indices]

        self.tgtposx = np.mean(np.asarray(self.player_offsets)[self.highlighted_indices][[-2,-1],0]) + tgttsx
        self.tgtposy = np.mean(np.asarray(self.player_offsets)[self.highlighted_indices][[0,1],1]) + tgttsy
        if self.hand == 'Left':
            self.tgtposx = np.mean(np.asarray(self.player_offsets)[self.highlighted_indices][[0,1],0]) + tgttsx
            self.tgtposy = np.mean(np.asarray(self.player_offsets)[self.highlighted_indices][[-2,-1],1]) + tgttsy
        #self.tgtposx = np.mean(np.asarray(self.player_offsets)[self.highlighted_indices][:,0])
        #self.tgtposy = np.mean(np.asarray(self.player_offsets)[self.highlighted_indices][:,1])
        self.tgtposz = np.mean(np.asarray(self.player_offsets)[self.highlighted_indices][:,2]) + tgttsz
        
        self.tar = self.loader.loadModel(self.target_model)
        self.tar.setScale(self.tgtscx,self.tgtscy,self.tgtscz)
        self.tar.setPos(self.tgtposx,self.tgtposy,self.tgtposz)
        self.tar.setHpr(tgtrx,tgtry,tgtrz)
        self.tar.setColorScale(0.1, 0.1, 0.1, 1)
        self.tar.setAlphaScale(0.7)
        self.tar.setTransparency(TransparencyAttrib.MAlpha)
        self.tar.reparentTo(self.render)
        self.tar.hide()

        if len(self.highlighted_indices) == 2:
            dx = self.players[self.highlighted_indices[0]].getX() - self.players[self.highlighted_indices[1]].getX()
            dy = self.players[self.highlighted_indices[0]].getY() - self.players[self.highlighted_indices[1]].getY()
            angle = math.degrees(math.atan(dy/dx))
            self.table[self.trial_counter,9] =  str(angle) + ' ' + str(angle-180)
        
        self.angs=self.table[self.trial_counter,9].split(' ')
        self.angs = [float(a) for a in self.angs]
        self.tunn_width=float(self.table[self.trial_counter,10])
        self.r = 1.5
        if int(self.block) == 0:
            self.r = 0
        self.x = [self.r*math.cos(math.radians(a)) for a in self.angs]
        self.y = [self.r*math.sin(math.radians(a)) for a in self.angs]
        self.occ = draw_shape(self.angs,self.tunn_width,self.r)
        self.occSolid = render.attachNewNode(self.occ[0])
        self.occSolid.setPos(self.tgtposx,self.tgtposy,self.tgtposz)
        self.occSolid.setColorScale(0,1,1,0)
        self.occSolid.setTransparency(TransparencyAttrib.MAlpha)
        self.occSolid.setAlphaScale(0.6)
        self.occLines = render.attachNewNode(self.occ[1])
        self.occLines.setPos(self.tgtposx,self.tgtposy,self.tgtposz)
        self.occSolid.hide()
        self.occLines.hide()
        self.delay=float(self.table[self.trial_counter,8])

        self.distances = [[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0]]

        #change camera to be on top of target
        self.cam.setPos(self.tgtposx, self.tgtposy - 2, 12)
        self.back_model.setPos(self.tgtposx,self.tgtposy - 2,0)
        self.cam.lookAt(self.tgtposx, self.tgtposy, 0)

    ##############
    #MOVE FINGERS#
    ##############
    def read_data(self,task):
        error, data = self.dev.read()
        if data is not None:
            data *= 0.001
            self.ts = data.time
            data = np.dot(data,self.rotmat)
            self.data = data
            if self.med_data is None:
                self.med_data = np.median(data, axis=0)

            if self.space:
                self.statenum.extend(([self.checkstate()])*len(data.time))
                
        return task.cont
        
    def move_player(self,p,task):
        if self.data is not None :
            k = p*3
            new_x = 10*np.mean(self.data[-1,k]) + self.player_offsets[p][0] - 10*self.med_data[k]
            new_y = 10*np.mean(self.data[-1,k + 1]) + self.player_offsets[p][1] - 10*self.med_data[k + 1]
            new_z = 10*np.mean(self.data[-1,k + 2]) + self.player_offsets[p][2] - 10*self.med_data[k + 2]

            #make sure digits do not cross each other
            if ((p in range(1,3) and p+1 in self.highlighted_indices and new_x > self.players[p+1].getX())
                or (p in range(2,4) and p-1 in self.highlighted_indices and new_x < self.players[p-1].getX())):
                    new_x = self.players[p].getX()
            
            #make sure digits do not cross into target
            if self.space == True and p in self.highlighted_indices:
                self.distances[p][0] = new_x - self.tar.getX()
                self.distances[p][1] = new_y - self.tar.getY()
                self.distances[p][2] = new_z - self.tar.getZ()
                self.check_pos(p)
                
            self.players[p].setPos(new_x, new_y, new_z)
            
        return task.cont
    
    def check_pos(self, p):
        x = self.distances[p][0]
        y = self.distances[p][1]
        z = self.distances[p][2]
        hit = True
        for i in range(len(self.angs)):
            p_ang = math.acos((x*self.x[i]+y*self.y[i])/(self.r*(x**2+y**2)**0.5))
            if math.sin(p_ang)*(x**2+y**2)**0.5 < self.tunn_width and p_ang < math.pi/2:
                hit = False
                break
        if (abs(z) <= 1.2 #check z location
            and x**2 + y**2 <= self.r**2 #within radius of circle
            and hit == True):
                if self.inside[p] is False:
                    self.ignore('colfromNode%d-into-colintoNode' % p)
                    self.ignore('colfromNode%d-again-colintoNode' % p)
                    self.players[p].setColorScale(1,1,0,1)
                    self.inside[p] = True
        else:
            if self.inside[p] is True and x**2 + y**2 > self.r**2:
                self.accept('colfromNode%d-into-colintoNode' % p, self.collide1,[p])
                self.accept('colfromNode%d-again-colintoNode' % p, self.collide2,[p])
                self.players[p].setColorScale(
                    self.p_col[p][0]/255, self.p_col[p][1]/255, self.p_col[p][2]/255, 1)
                self.inside[p] = False

    ##################
    #CHECK COMPLETION#
    ##################
    def close_to_target(self):
        for i in self.highlighted_indices:
            if self.contacts[i] == False:
                return False

        self.tar.setColorScale(0,1,1,1)
        return True

    def check_hold(self):
        if not self.close_to_target():
            self.hold_timer.reset(0.5)
            return False
        return self.hold_timer.elapsed() < 0

    def adjust_targets(self):
        #no adjustment if more than 2 fingers or position is prone
        if len(self.highlighted_indices) > 2 or self.wrist == 'pron':
            return

        xadj,yadj,zadj = np.mean(np.asarray(self.distances)[self.highlighted_indices],0)
        #xadj = np.mean(np.asarray(self.distances)[self.highlighted_indices][0])
        #yadj = np.mean(np.asarray(self.distances)[self.highlighted_indices][1])
        #zadj = np.mean(np.asarray(self.distances)[self.highlighted_indices][2])

        #do adjustment on all tasks with same name
        if self.hand == 'Left':
            xadj = -xadj
        for i in range(self.trial_counter+1,self.table.shape[0]):
            if self.table[i,1] == self.table[self.trial_counter,1]:
                self.table[i,11] = float(self.table[i,11]) + xadj
                self.table[i,12] = float(self.table[i,12]) + yadj
                self.table[i,13] = float(self.table[i,13]) + zadj
    
    #########
    #LOGGING#
    #########
    def play_success(self):
        if int(self.block) == 0:
            self.adjust_targets()
        self.pop.play()
        self.tar.hide()
        self.highlighted_indices = [0,1,2,3,4]

    def log_text(self):
        self.bgtext.setText('Now logging...')

    def log_data(self, task):
        if (self.trial_counter + 1) <= self.table.shape[0]:
            if self.space:
                self.log_file_name = os.path.join(self.grip_dir,
                                          self.sub_id+"_"+self.sess_id+"_"+self.hand+"_"+
                                              str(self.table[self.trial_counter,1])+"_"+str(self.table[self.trial_counter,0])+".csv" )
                self.movvars = np.column_stack((self.ts, self.statenum, self.data))
                self.statenum = []
                if self.mode=='task':
                    with open(self.log_file_name, 'ab') as f:
                        np.savetxt(f, self.movvars, fmt='%10.5f', delimiter=',')
            return task.cont
        else:
            pass

    def stoplog_text(self):
        self.dirtext.clearText()
        self.bgtext.setText('Done logging!')
        for i in range(5):
            self.players[i].show()

    #######
    #RESET#
    #######
    def delete_file(self):
        if (self.trial_counter + 1) <= self.table.shape[0]:
            self.log_file_name = os.path.join(self.grip_dir,
                                      self.sub_id+"_"+self.sess_id+"_"+self.hand+"_"+
                                          str(self.table[self.trial_counter,1])+"_"+str(self.table[self.trial_counter,0])+".csv" )
            try:
                os.remove(self.log_file_name)
            except OSError:
                pass
        else:
            pass

    def reset_baseline(self):
       self.med_data = None
                   
    def reset_keyboard_bool(self):
        self.space = False

    def hide_target(self):
        self.tar.hide()
        self.occSolid.hide()
        self.occLines.hide()
        self.intoObject.removeNode()
        self.imageObject.destroy()

    def update_trial_command(self):
        self.dirtext.setText(str(self.table[self.trial_counter,2]))
        if self.hand == 'Left':
            xfac = -0.25
        else:
            xfac = 0.25
        self.imageObject = OnscreenImage(image = str(self.table[self.trial_counter,3]),scale=(xfac,0.25,0.25),pos=(-0.8, 0, 0.3))

    def increment_trial_counter(self):
        self.trial_counter += 1
        self.update_trial_command()

    ########
    #TIMERS#
    ########
    def start_trial_countdown(self):
        self.countdown_timer.reset(self.max_time)

    def start_hold_countdown(self):
        self.hold_timer.reset(0.5)

    def start_post_countdown(self):
        self.countdown_timer.reset(2)

    def time_elapsed(self):
        return self.countdown_timer.elapsed() < 0

    #########
    #MACHINE#
    #########
    def update_state(self, task):
        self.step()
        return task.cont

    def wait_for_space(self):
        return self.space

    def space_on(self):
        self.space = True

    #####
    #END#
    #####
    def trial_counter_exceeded(self):
        return (self.trial_counter+1) > self.table.shape[0]-1

    def clean_up(self):
        #write last known positions to 'final_targets' file
        f = open('src/pinch_task/trialtable_flex.csv')
        header = f.readline().rstrip()
        np.savetxt(self.grip_dir + '/final_targets.csv',self.table,fmt='%s',header = header, delimiter=',')
        f.close()
        sys.exit()
Beispiel #19
0
        # TODO: apply calibration?
        time = self.clock()
        return time, self._buffer

    def exit(self):
        self._device.stop()
        self._device.close()


if __name__ == '__main__':
    import time
    from toon.input import MpDevice
    dev = MpDevice(ForceKeyboard())

    times = []
    with dev:
        start = time.time()
        while time.time() - start < 240:
            dat = dev.read()
            if dat is not None:
                time, data = dat
                print(data)
                times.append(time)
            time.sleep(0.016)

    times = np.hstack(times)
    import matplotlib.pyplot as plt

    plt.plot(np.diff(times))
    plt.show()
Beispiel #20
0
class HandS(ShowBase, HandSetupMachine):
    def __init__(self, id, session, hand, wrist, trial, exp):
        self.sub_id = id
        self.trialid = trial
        self.session = session
        self.hand = hand
        self.wrist = wrist
        self.exp = exp

        self.DATA_DIR = 'data'

        ShowBase.__init__(self)
        HandSetupMachine.__init__(self)
        props = WindowProperties()
        props.setTitle('Hand Setup')

        self.session_dir = os.path.join(self.DATA_DIR, 'exp_' + self.exp,
                                        self.sub_id, self.session, self.wrist,
                                        self.hand, 'Setup_' + self.trialid)
        if not os.path.exists(self.session_dir):
            print('Making new folders: ' + self.session_dir)
            os.makedirs(self.session_dir)

        self.win.requestProperties(props)
        self.render.setAntialias(AntialiasAttrib.MMultisample)
        self.render.setShaderAuto()  # allows shadows
        self.setFrameRateMeter(True)
        self.space = False
        self.dev = MpDevice(
            RightHand(
                calibration_files=[
                    'calibs/cal_mat_15.mat',  # thumb
                    'calibs/cal_mat_31.mat',
                    'calibs/cal_mat_13.mat',
                    'calibs/cal_mat_21.mat',
                    'calibs/cal_mat_8.mat'
                ],
                clock=mono_clock.get_time))
        #self.finger = int(finger) * 3  # offset
        #self.f2 = int(finger)
        self.disableMouse()
        self.countdown_timer = CountdownTimer()

        # self.table = pd.read_table(trial_table)  # trial table
        self.setup_lights()
        self.setup_camera()
        self.load_models()

        # add tasks (run every frame)
        taskMgr.add(self.get_user_input, 'move')
        taskMgr.add(self.update_feedback_bar, 'update_feedback_bar', sort=1)
        self.accept('space', self.space_on)  # toggle a boolean somewhere
        self.accept('escape', self.clean_up)

        self.med_data = None
        self.noise1 = 0.0
        self.noise2 = 0.0
        self.noise3 = 0.0
        self.noise4 = 0.0
        self.noise5 = 0.0

        self.trial_counter = 0
        self.logging = False
        self.text = OnscreenText(text='Not recording.',
                                 pos=(-0.8, 0.7),
                                 scale=0.08,
                                 fg=(1, 1, 1, 1),
                                 bg=(0, 0, 0, 1),
                                 frame=(0.2, 0.2, 0.8, 1),
                                 align=TextNode.ACenter)
        self.button = DirectButton(text='Log data',
                                   scale=0.05,
                                   command=self.log_and_print,
                                   pos=(-0.9, 0, 0.9))
        self.button = DirectButton(text='Stop logging',
                                   scale=0.05,
                                   command=self.stop_logging,
                                   pos=(-0.9, 0, 0.8))

    def stop_logging(self):
        self.logging = False
        self.stoplog_text()

    def log_and_print(self):
        self.logging = True
        self.trial_counter += 1
        self.log_text()
        self.t = Timer(30, self.incrementfile)
        self.t.start()

    def incrementfile(self):
        if self.logging:
            self.t.cancel()
            self.log_and_print()

    def load_models(self):
        self.cam2dp.node().getDisplayRegion(0).setSort(-20)
        OnscreenImage(parent=self.cam2dp, image='models/background.jpg')

        self.bgtext = OnscreenText(pos=(-0.8, 0.8),
                                   scale=0.08,
                                   fg=(1, 1, 1, 1),
                                   bg=(0, 0, 0, 1),
                                   frame=(0.2, 0.2, 0.8, 1),
                                   align=TextNode.ACenter)
        self.bgtext.reparentTo(self.aspect2d)

        self.errorlevel = OnscreenText(text='10%',
                                       pos=(-0.99, -0.80),
                                       scale=0.08,
                                       fg=(1, 1, 1, 1),
                                       bg=(0, 0, 0, 1),
                                       frame=(0.2, 0.2, 0.8, 1),
                                       align=TextNode.ACenter)
        self.halfscale = OnscreenText(text='50%',
                                      pos=(-0.99, -0.4),
                                      scale=0.08,
                                      fg=(1, 1, 1, 1),
                                      bg=(0, 0, 0, 1),
                                      frame=(0.2, 0.2, 0.8, 1),
                                      align=TextNode.ACenter)
        self.fullscale = OnscreenText(text='100%',
                                      pos=(-0.99, 0.10),
                                      scale=0.08,
                                      fg=(1, 1, 1, 1),
                                      bg=(0, 0, 0, 1),
                                      frame=(0.2, 0.2, 0.8, 1),
                                      align=TextNode.ACenter)
        self.text = OnscreenText(text='Neutral position error',
                                 pos=(-0.08, 0.8),
                                 scale=0.08,
                                 fg=(1, 1, 1, 1),
                                 bg=(0, 0, 0, 1),
                                 frame=(0.2, 0.2, 0.8, 1),
                                 align=TextNode.ACenter)
        self.text.reparentTo(self.aspect2d)

        self.move_feedback = MeshDrawer2D()
        self.move_feedback.setBudget(
            100)  # this is the number of triangles needed (two per rect)
        feed_node = self.move_feedback.getRoot()
        feed_node.setTwoSided(True)
        feed_node.setDepthWrite(False)
        feed_node.setTransparency(True)
        feed_node.setBin('fixed', 0)
        feed_node.setLightOff(True)
        self.node = feed_node
        self.node.reparentTo(self.render2d)

    def setup_lights(self):
        pl = PointLight('pl')
        pl.setColor((1, 1, 1, 1))
        plNP = self.render.attachNewNode(pl)
        plNP.setPos(-0.5, -0.5, 0.5)
        self.render.setLight(plNP)

        pos = [[[0, 0, 3], [0, 0, -1]], [[0, -3, 0], [0, 1, 0]],
               [[-3, 0, 0], [1, 0, 0]]]
        for i in pos:
            dl = Spotlight('dl')
            dl.setColor((1, 1, 1, 1))
            dlNP = self.render.attachNewNode(dl)
            dlNP.setPos(*i[0])
            dlNP.lookAt(*i[1])
            dlNP.node().setShadowCaster(True)
            self.render.setLight(dlNP)

    def setup_camera(self):
        self.cam.setPos(-2, -4, 2)
        self.cam.lookAt(0, 0, 0)

    def get_user_input(self, task):
        error, data = self.dev.read()

        if data is not None:
            data *= 0.001
            if self.med_data is None:
                self.med_data = np.median(data, axis=0)

            self.data = data

            noise1 = np.sqrt(
                np.square(data[-1, 0] - self.med_data[0]) +
                np.square(data[-1, 1] - self.med_data[1]) +
                np.square(data[-1, 2] - self.med_data[2]))
            noise2 = np.sqrt(
                np.square(data[-1, 3] - self.med_data[3]) +
                np.square(data[-1, 4] - self.med_data[4]) +
                np.square(data[-1, 5] - self.med_data[5]))
            noise3 = np.sqrt(
                np.square(data[-1, 6] - self.med_data[6]) +
                np.square(data[-1, 7] - self.med_data[7]) +
                np.square(data[-1, 8] - self.med_data[8]))
            noise4 = np.sqrt(
                np.square(data[-1, 9] - self.med_data[9]) +
                np.square(data[-1, 10] - self.med_data[10]) +
                np.square(data[-1, 11] - self.med_data[11]))
            noise5 = np.sqrt(
                np.square(data[-1, 12] - self.med_data[12]) +
                np.square(data[-1, 13] - self.med_data[13]) +
                np.square(data[-1, 14] - self.med_data[14]))

            self.noise1 = noise1
            self.noise2 = noise2
            self.noise3 = noise3
            self.noise4 = noise4
            self.noise5 = noise5

            if self.logging:
                self.log_file_name = os.path.join(
                    self.session_dir,
                    "Setup_" + self.sub_id + "_" + self.session + "_" +
                    self.hand + "_" + str(self.trial_counter) + ".txt")
                with open(self.log_file_name, 'ab') as f:
                    np.savetxt(f, self.data, fmt='%10.5f', delimiter=',')
            else:
                pass

        return task.cont

    def update_feedback_bar(self, task):
        self.move_feedback.begin()
        self.move_feedback.rectangle_raw(-0.5, -0.9, 0.1, self.noise1, 0, 0, 0,
                                         0, Vec4(0.9, .2, .1, 1))
        self.move_feedback.rectangle_raw(-0.525, -0.9, 0.15, 0.015, 0, 0, 0, 0,
                                         Vec4(1, 1, 1, 1))
        self.move_feedback.rectangle_raw(-0.625, 0.1, 1.2, 0.015, 0, 0, 0, 0,
                                         Vec4(1, 1, 1, 1))
        self.move_feedback.rectangle_raw(-0.625, -0.4, 0.07, 0.015, 0, 0, 0, 0,
                                         Vec4(1, 1, 1, 1))
        self.move_feedback.rectangle_raw(-0.3, -0.9, 0.1, self.noise2, 0, 0, 0,
                                         0, Vec4(0.9, .2, .1, 1))
        self.move_feedback.rectangle_raw(-0.325, -0.9, 0.15, 0.015, 0, 0, 0, 0,
                                         Vec4(1, 1, 1, 1))
        self.move_feedback.rectangle_raw(-0.1, -0.9, 0.1, self.noise3, 0, 0, 0,
                                         0, Vec4(0.9, .2, .1, 1))
        self.move_feedback.rectangle_raw(-0.125, -0.9, 0.15, 0.015, 0, 0, 0, 0,
                                         Vec4(1, 1, 1, 1))
        self.move_feedback.rectangle_raw(0.1, -0.9, 0.1, self.noise4, 0, 0, 0,
                                         0, Vec4(0.9, .2, .1, 1))
        self.move_feedback.rectangle_raw(0.075, -0.9, 0.15, 0.015, 0, 0, 0, 0,
                                         Vec4(1, 1, 1, 1))
        self.move_feedback.rectangle_raw(0.3, -0.9, 0.1, self.noise5, 0, 0, 0,
                                         0, Vec4(0.9, .2, .1, 1))
        self.move_feedback.rectangle_raw(0.275, -0.9, 0.15, 0.015, 0, 0, 0, 0,
                                         Vec4(1, 1, 1, 1))
        self.move_feedback.rectangle_raw(-0.625, -0.80, 1.2, 0.015, 0, 0, 0, 0,
                                         Vec4(1, 1, 1, 1))
        self.move_feedback.end()
        return task.cont

    def space_on(self):
        self.space = True

    def update_state(self, task):
        self.step()
        return task.cont

    # state machine functions
    def wait_for_space(self):
        return self.space

    def log_text(self):
        self.text.setText('Now logging...')

    def stoplog_text(self):
        self.text.setText('Paused logging!')

    def time_elapsed(self):
        return self.countdown_timer.elapsed() < 0

    def post_text(self):
        self.text.setText('Relax.')

    def reset_baseline(self):
        self.med_data = None

    def clean_up(self):
        sys.exit()
Beispiel #21
0
if __name__ == '__main__':

    win = Win(vsync=1, screen=0)
    height = win.height
    cir = Circle(win, scale=0.1, fill_color=(0.2, 0.9, 0.7, 1))

    cl = Circle(win, scale=0.025, fill_color=(1, 1, 1, 1))
    cr = Circle(win, scale=0.025, fill_color=(0, 0, 0, 1))

    dev = MpDevice(Mouse())

    with dev:
        t0 = default_timer()
        t1 = t0 + 30
        while t1 > default_timer():
            res = dev.read()
            if res:
                time, data = res
                left = data[data['id'] == 0]
                right = data[data['id'] == 1]
                if left.shape[0] > 0:
                    cir.position.x += float(sum(left['dy'])) / win.height
                    cl.position.x += float(sum(left['dx'])) / win.height
                    cl.position.y -= float(sum(left['dy'])) / win.height
                if right.shape[0] > 0:
                    cir.position.y += float(sum(right['dx'])) / win.height
                    cr.position.x += float(sum(right['dx'])) / win.height
                    cr.position.y -= float(sum(right['dy'])) / win.height
            cir.draw()
            cl.draw()
            cr.draw()
Beispiel #22
0
    def enter(self):
        ports = list_ports.comports()
        mydev = next((p.device for p in ports if p.pid == 1155))
        self._device = serial.Serial(mydev)
        self._device.close()
        sleep(0.5)
        self._device.open()
        return self

    def exit(self, *args):
        self._device.close()

    def read(self):
        data = self._device.read(64)
        time = self.clock()
        if data:
            data = struct.unpack('<' + 'H' * 4, bytearray(data[:8]))
            return self.Returns(pos=self.Pos(time, data))
        else:
            return None, None

if __name__ == '__main__':
    from timeit import default_timer
    dev = MpDevice(TestSerial())
    with dev:
        t1 = default_timer() + 5
        while default_timer() < t1:
            data = dev.read()
            if data is not None:
                print(data)
Beispiel #23
0
def test_err():
    dev = MpDevice(Timebomb())
    with dev:
        sleep(0.2)
        with raises(ValueError):
            dat = dev.read()