def config_run(cfg_module): cfg = imp.load_source(cfg_module, cfg_module) tdef = trigger_def(cfg.TRIGGER_DEF) refresh_delay = 1.0 / cfg.REFRESH_RATE # visualizer keys = {'left':81, 'right':83, 'up':82, 'down':84, 'pgup':85, 'pgdn':86, 'home':80, 'end':87, 'space':32, 'esc':27, ',':44, '.':46, 's':115, 'c':99, '[':91, ']':93, '1':49, '!':33, '2':50, '@':64, '3':51, '#':35} color = dict(G=(20, 140, 0), B=(210, 0, 0), R=(0, 50, 200), Y=(0, 215, 235), K=(0, 0, 0), w=(200, 200, 200)) dir_sequence = [] for x in range(cfg.TRIALS_EACH): dir_sequence.extend(cfg.DIRECTIONS) random.shuffle(dir_sequence) num_trials = len(cfg.DIRECTIONS) * cfg.TRIALS_EACH event = 'start' trial = 1 # Hardware trigger if cfg.TRIGGER_DEVICE is None: input('\n** Warning: No trigger device set. Press Ctrl+C to stop or Enter to continue.') trigger = pyLptControl.Trigger(cfg.TRIGGER_DEVICE) if trigger.init(50) == False: print('\n** Error connecting to USB2LPT device. Use a mock trigger instead?') input('Press Ctrl+C to stop or Enter to continue.') trigger = pyLptControl.MockTrigger() trigger.init(50) timer_trigger = qc.Timer() timer_dir = qc.Timer() timer_refresh = qc.Timer() bar = BarVisual(cfg.GLASS_USE, screen_pos=cfg.SCREEN_POS, screen_size=cfg.SCREEN_SIZE) bar.fill() bar.glass_draw_cue() # start while trial <= num_trials: timer_refresh.sleep_atleast(refresh_delay) timer_refresh.reset() # segment= { 'cue':(s,e), 'dir':(s,e), 'label':0-4 } (zero-based) if event == 'start' and timer_trigger.sec() > cfg.T_INIT: event = 'gap_s' bar.fill() timer_trigger.reset() trigger.signal(tdef.INIT) elif event == 'gap_s': bar.put_text('Trial %d / %d' % (trial, num_trials)) event = 'gap' elif event == 'gap' and timer_trigger.sec() > cfg.T_GAP: event = 'cue' bar.fill() bar.draw_cue() trigger.signal(tdef.CUE) timer_trigger.reset() elif event == 'cue' and timer_trigger.sec() > cfg.T_CUE: event = 'dir_r' dir = dir_sequence[trial - 1] if dir == 'L': # left bar.move('L', 100, overlay=True) trigger.signal(tdef.LEFT_READY) elif dir == 'R': # right bar.move('R', 100, overlay=True) trigger.signal(tdef.RIGHT_READY) elif dir == 'U': # up bar.move('U', 100, overlay=True) trigger.signal(tdef.UP_READY) elif dir == 'D': # down bar.move('D', 100, overlay=True) trigger.signal(tdef.DOWN_READY) elif dir == 'B': # both hands bar.move('L', 100, overlay=True) bar.move('R', 100, overlay=True) trigger.signal(tdef.BOTH_READY) else: raise RuntimeError('Unknown direction %d' % dir) timer_trigger.reset() elif event == 'dir_r' and timer_trigger.sec() > cfg.T_DIR_READY: bar.fill() bar.draw_cue() event = 'dir' timer_trigger.reset() timer_dir.reset() if dir == 'L': # left trigger.signal(tdef.LEFT_GO) elif dir == 'R': # right trigger.signal(tdef.RIGHT_GO) elif dir == 'U': # up trigger.signal(tdef.UP_GO) elif dir == 'D': # down trigger.signal(tdef.DOWN_GO) elif dir == 'B': # both trigger.signal(tdef.BOTH_GO) else: raise RuntimeError('Unknown direction %d' % dir) elif event == 'dir' and timer_trigger.sec() > cfg.T_DIR: event = 'gap_s' bar.fill() trial += 1 print('trial ' + str(trial - 1) + ' done') trigger.signal(tdef.BLANK) timer_trigger.reset() # protocol if event == 'dir': dx = min(100, int(100.0 * timer_dir.sec() / cfg.T_DIR) + 1) if dir == 'L': # L bar.move('L', dx, overlay=True) elif dir == 'R': # R bar.move('R', dx, overlay=True) elif dir == 'U': # U bar.move('U', dx, overlay=True) elif dir == 'D': # D bar.move('D', dx, overlay=True) elif dir == 'B': # Both bar.move('L', dx, overlay=True) bar.move('R', dx, overlay=True) # wait for start if event == 'start': bar.put_text('Waiting to start') bar.update() key = 0xFF & cv2.waitKey(1) if key == keys['esc']: break
def config_run(cfg_module): cfg = load_cfg(cfg_module) # visualizer keys = { 'left': 81, 'right': 83, 'up': 82, 'down': 84, 'pgup': 85, 'pgdn': 86, 'home': 80, 'end': 87, 'space': 32, 'esc': 27, ',': 44, '.': 46, 's': 115, 'c': 99, '[': 91, ']': 93, '1': 49, '!': 33, '2': 50, '@': 64, '3': 51, '#': 35 } color = dict(G=(20, 140, 0), B=(210, 0, 0), R=(0, 50, 200), Y=(0, 215, 235), K=(0, 0, 0), W=(255, 255, 255), w=(200, 200, 200)) dir_sequence = [] for x in range(cfg.TRIALS_EACH): dir_sequence.extend(cfg.DIRECTIONS) random.shuffle(dir_sequence) num_trials = len(cfg.DIRECTIONS) * cfg.TRIALS_EACH tdef = trigger_def(cfg.TRIGGER_DEF) refresh_delay = 1.0 / cfg.REFRESH_RATE state = 'start' trial = 1 # STIMO protocol if cfg.WITH_STIMO is True: print('Opening STIMO serial port (%s / %d bps)' % (cfg.STIMO_COMPORT, cfg.STIMO_BAUDRATE)) import serial ser = serial.Serial(cfg.STIMO_COMPORT, cfg.STIMO_BAUDRATE) print('STIMO serial port %s is_open = %s' % (cfg.STIMO_COMPORT, ser.is_open)) # init trigger if cfg.TRIGGER_DEVICE is None: input( '\n** Warning: No trigger device set. Press Ctrl+C to stop or Enter to continue.' ) trigger = pyLptControl.Trigger(cfg.TRIGGER_DEVICE) if trigger.init(50) == False: print( '\n# Error connecting to USB2LPT device. Use a mock trigger instead?' ) input('Press Ctrl+C to stop or Enter to continue.') trigger = pyLptControl.MockTrigger() trigger.init(50) # visual feedback if cfg.FEEDBACK_TYPE == 'BAR': from pycnbi.protocols.viz_bars import BarVisual visual = BarVisual(cfg.GLASS_USE, screen_pos=cfg.SCREEN_POS, screen_size=cfg.SCREEN_SIZE) elif cfg.FEEDBACK_TYPE == 'BODY': if not hasattr(cfg, 'IMAGE_PATH'): raise ValueError('IMAGE_PATH is undefined in your config.') from pycnbi.protocols.viz_human import BodyVisual visual = BodyVisual(cfg.IMAGE_PATH, use_glass=cfg.GLASS_USE, screen_pos=cfg.SCREEN_POS, screen_size=cfg.SCREEN_SIZE) visual.put_text('Waiting to start ') timer_trigger = qc.Timer() timer_dir = qc.Timer() timer_refresh = qc.Timer() # start while trial <= num_trials: timer_refresh.sleep_atleast(refresh_delay) timer_refresh.reset() # segment= { 'cue':(s,e), 'dir':(s,e), 'label':0-4 } (zero-based) if state == 'start' and timer_trigger.sec() > cfg.T_INIT: state = 'gap_s' visual.fill() timer_trigger.reset() trigger.signal(tdef.INIT) elif state == 'gap_s': visual.put_text('Trial %d / %d' % (trial, num_trials)) state = 'gap' elif state == 'gap' and timer_trigger.sec() > cfg.T_GAP: state = 'cue' visual.fill() visual.draw_cue() trigger.signal(tdef.CUE) timer_trigger.reset() elif state == 'cue' and timer_trigger.sec() > cfg.T_CUE: state = 'dir_r' dir = dir_sequence[trial - 1] if dir == 'L': # left if cfg.FEEDBACK_TYPE == 'BAR': visual.move('L', 100) else: visual.put_text('LEFT') trigger.signal(tdef.LEFT_READY) elif dir == 'R': # right if cfg.FEEDBACK_TYPE == 'BAR': visual.move('R', 100) else: visual.put_text('RIGHT') trigger.signal(tdef.RIGHT_READY) elif dir == 'U': # up if cfg.FEEDBACK_TYPE == 'BAR': visual.move('U', 100) else: visual.put_text('UP') trigger.signal(tdef.UP_READY) elif dir == 'D': # down if cfg.FEEDBACK_TYPE == 'BAR': visual.move('D', 100) else: visual.put_text('DOWN') trigger.signal(tdef.DOWN_READY) elif dir == 'B': # both hands if cfg.FEEDBACK_TYPE == 'BAR': visual.move('L', 100) visual.move('R', 100) else: visual.put_text('BOTH') trigger.signal(tdef.BOTH_READY) else: raise RuntimeError('Unknown direction %d' % dir) gait_steps = 1 timer_trigger.reset() elif state == 'dir_r' and timer_trigger.sec() > cfg.T_DIR_READY: visual.draw_cue() state = 'dir' timer_trigger.reset() timer_dir.reset() t_step = cfg.T_DIR + random.random() * cfg.RANDOMIZE_LENGTH if dir == 'L': # left trigger.signal(tdef.LEFT_GO) elif dir == 'R': # right trigger.signal(tdef.RIGHT_GO) elif dir == 'U': # up trigger.signal(tdef.UP_GO) elif dir == 'D': # down trigger.signal(tdef.DOWN_GO) elif dir == 'B': # both trigger.signal(tdef.BOTH_GO) else: raise RuntimeError('Unknown direction %d' % dir) elif state == 'dir': if timer_trigger.sec() > t_step: if cfg.FEEDBACK_TYPE == 'BODY': if cfg.WITH_STIMO is True: if dir == 'L': # left ser.write(b'1') qc.print_c('STIMO: Sent 1', 'g') trigger.signal(tdef.LEFT_STIMO) elif dir == 'R': # right ser.write(b'2') qc.print_c('STIMO: Sent 2', 'g') trigger.signal(tdef.RIGHT_STIMO) else: if dir == 'L': # left trigger.signal(tdef.LEFT_RETURN) elif dir == 'R': # right trigger.signal(tdef.RIGHT_RETURN) else: trigger.signal(tdef.FEEDBACK) state = 'return' timer_trigger.reset() else: dx = min(100, int(100.0 * timer_dir.sec() / t_step) + 1) if dir == 'L': # L visual.move('L', dx, overlay=True) elif dir == 'R': # R visual.move('R', dx, overlay=True) elif dir == 'U': # U visual.move('U', dx, overlay=True) elif dir == 'D': # D visual.move('D', dx, overlay=True) elif dir == 'B': # Both visual.move('L', dx, overlay=True) visual.move('R', dx, overlay=True) elif state == 'return': if timer_trigger.sec() > cfg.T_RETURN: if gait_steps < cfg.GAIT_STEPS: gait_steps += 1 state = 'dir' visual.move('L', 0) if dir == 'L': dir = 'R' trigger.signal(tdef.RIGHT_GO) else: dir = 'L' trigger.signal(tdef.LEFT_GO) timer_dir.reset() t_step = cfg.T_DIR + random.random() * cfg.RANDOMIZE_LENGTH else: state = 'gap_s' visual.fill() trial += 1 print('trial ' + str(trial - 1) + ' done') trigger.signal(tdef.BLANK) timer_trigger.reset() else: dx = max( 0, int(100.0 * (cfg.T_RETURN - timer_trigger.sec()) / cfg.T_RETURN)) if dir == 'L': # L visual.move('L', dx, overlay=True) elif dir == 'R': # R visual.move('R', dx, overlay=True) elif dir == 'U': # U visual.move('U', dx, overlay=True) elif dir == 'D': # D visual.move('D', dx, overlay=True) elif dir == 'B': # Both visual.move('L', dx, overlay=True) visual.move('R', dx, overlay=True) # wait for start if state == 'start': visual.put_text('Waiting to start ') visual.update() key = 0xFF & cv2.waitKey(1) if key == keys['esc']: break # STIMO protocol if cfg.WITH_STIMO is True: ser.close() print('Closed STIMO serial port %s' % cfg.STIMO_COMPORT)
def run(cfg, state=mp.Value('i', 1), queue=None): redirect_stdout_to_queue(logger, queue, 'INFO') # Wait the recording to start (GUI) while state.value == 2: # 0: stop, 1:start, 2:wait pass # Protocol start if equals to 1 if not state.value: sys.exit() refresh_delay = 1.0 / cfg.REFRESH_RATE cfg.tdef = trigger_def(cfg.TRIGGER_FILE) # visualizer keys = { 'left': 81, 'right': 83, 'up': 82, 'down': 84, 'pgup': 85, 'pgdn': 86, 'home': 80, 'end': 87, 'space': 32, 'esc': 27, ',': 44, '.': 46, 's': 115, 'c': 99, '[': 91, ']': 93, '1': 49, '!': 33, '2': 50, '@': 64, '3': 51, '#': 35 } color = dict(G=(20, 140, 0), B=(210, 0, 0), R=(0, 50, 200), Y=(0, 215, 235), K=(0, 0, 0), w=(200, 200, 200)) dir_sequence = [] for x in range(cfg.TRIALS_EACH): dir_sequence.extend(cfg.DIRECTIONS) random.shuffle(dir_sequence) num_trials = len(cfg.DIRECTIONS) * cfg.TRIALS_EACH event = 'start' trial = 1 # Hardware trigger if cfg.TRIGGER_DEVICE is None: logger.warning( 'No trigger device set. Press Ctrl+C to stop or Enter to continue.' ) #input() trigger = pyLptControl.Trigger(state, cfg.TRIGGER_DEVICE) if trigger.init(50) == False: logger.error( '\n** Error connecting to USB2LPT device. Use a mock trigger instead?' ) input('Press Ctrl+C to stop or Enter to continue.') trigger = pyLptControl.MockTrigger() trigger.init(50) # timers timer_trigger = qc.Timer() timer_dir = qc.Timer() timer_refresh = qc.Timer() t_dir = cfg.TIMINGS['DIR'] + random.uniform(-cfg.TIMINGS['DIR_RANDOMIZE'], cfg.TIMINGS['DIR_RANDOMIZE']) t_dir_ready = cfg.TIMINGS['READY'] + random.uniform( -cfg.TIMINGS['READY_RANDOMIZE'], cfg.TIMINGS['READY_RANDOMIZE']) bar = BarVisual(cfg.GLASS_USE, screen_pos=cfg.SCREEN_POS, screen_size=cfg.SCREEN_SIZE) bar.fill() bar.glass_draw_cue() # start while trial <= num_trials: timer_refresh.sleep_atleast(refresh_delay) timer_refresh.reset() # segment= { 'cue':(s,e), 'dir':(s,e), 'label':0-4 } (zero-based) if event == 'start' and timer_trigger.sec() > cfg.TIMINGS['INIT']: event = 'gap_s' bar.fill() timer_trigger.reset() trigger.signal(cfg.tdef.INIT) elif event == 'gap_s': if cfg.TRIAL_PAUSE: bar.put_text('Press any key') bar.update() key = cv2.waitKey() if key == keys['esc'] or not state.value: break bar.fill() bar.put_text('Trial %d / %d' % (trial, num_trials)) event = 'gap' timer_trigger.reset() elif event == 'gap' and timer_trigger.sec() > cfg.TIMINGS['GAP']: event = 'cue' bar.fill() bar.draw_cue() trigger.signal(cfg.tdef.CUE) timer_trigger.reset() elif event == 'cue' and timer_trigger.sec() > cfg.TIMINGS['CUE']: event = 'dir_r' dir = dir_sequence[trial - 1] if dir == 'L': # left bar.move('L', 100, overlay=True) trigger.signal(cfg.tdef.LEFT_READY) elif dir == 'R': # right bar.move('R', 100, overlay=True) trigger.signal(cfg.tdef.RIGHT_READY) elif dir == 'U': # up bar.move('U', 100, overlay=True) trigger.signal(cfg.tdef.UP_READY) elif dir == 'D': # down bar.move('D', 100, overlay=True) trigger.signal(cfg.tdef.DOWN_READY) elif dir == 'B': # both hands bar.move('L', 100, overlay=True) bar.move('R', 100, overlay=True) trigger.signal(cfg.tdef.BOTH_READY) else: raise RuntimeError('Unknown direction %d' % dir) timer_trigger.reset() elif event == 'dir_r' and timer_trigger.sec() > t_dir_ready: bar.fill() bar.draw_cue() event = 'dir' timer_trigger.reset() timer_dir.reset() if dir == 'L': # left trigger.signal(cfg.tdef.LEFT_GO) elif dir == 'R': # right trigger.signal(cfg.tdef.RIGHT_GO) elif dir == 'U': # up trigger.signal(cfg.tdef.UP_GO) elif dir == 'D': # down trigger.signal(cfg.tdef.DOWN_GO) elif dir == 'B': # both trigger.signal(cfg.tdef.BOTH_GO) else: raise RuntimeError('Unknown direction %d' % dir) elif event == 'dir' and timer_trigger.sec() > t_dir: event = 'gap_s' bar.fill() trial += 1 logger.info('trial ' + str(trial - 1) + ' done') trigger.signal(cfg.tdef.BLANK) timer_trigger.reset() t_dir = cfg.TIMINGS['DIR'] + random.uniform( -cfg.TIMINGS['DIR_RANDOMIZE'], cfg.TIMINGS['DIR_RANDOMIZE']) t_dir_ready = cfg.TIMINGS['READY'] + random.uniform( -cfg.TIMINGS['READY_RANDOMIZE'], cfg.TIMINGS['READY_RANDOMIZE']) # protocol if event == 'dir': dx = min(100, int(100.0 * timer_dir.sec() / t_dir) + 1) if dir == 'L': # L bar.move('L', dx, overlay=True) elif dir == 'R': # R bar.move('R', dx, overlay=True) elif dir == 'U': # U bar.move('U', dx, overlay=True) elif dir == 'D': # D bar.move('D', dx, overlay=True) elif dir == 'B': # Both bar.move('L', dx, overlay=True) bar.move('R', dx, overlay=True) # wait for start if event == 'start': bar.put_text('Waiting to start') bar.update() key = 0xFF & cv2.waitKey(1) if key == keys['esc'] or not state.value: break bar.finish() with state.get_lock(): state.value = 0