import viz import hd import math import time import random import positions import fileOutput viz.go(viz.PROMPT) tracking = viz.get(viz.TRACKER) viz.cursor(viz.OFF) if tracking: headIsense = viz.add('intersense.dls') #PORT_INTERSENSE = 3 ppt = viz.add('vizppt.dls') #Average over 5 samples ppt.command(5,'',5) #Automatically track head position and orientation viz.tracker() # viz.eyeheight(0.0) ################################################################ # CONSTANTS ################################################################ BALL_FILE = 'generic_ball.wrl' NUM_BALLS = 6 INITIAL_BALL_SPAN = 1.0 BALL_SCALE = .1 BALL_COLOR = viz.GRAY MARKER_SCALE = .15 MARKER_COLOR = viz.YELLOW #MARK_DIRTY = 0 #MARK_CLEAN = 1 NUM_PEOPLE = 16 NUM_CONDITIONS = 20 TRIAL_ORDER_FILE = 'trial_order.txt' ################################################################ # GLOBAL VARS ################################################################ numSpotsLeft = 0 cleaned = [] finished = True nextTrial = 0 conditionID = 0 currVisuals = [] timeMarker = 0 subjectNum = str(viz.input('Enter a Subject ID number:')) fileOut = fileOutput.FileOutputTimer(subjectNum + ".txt", subjectNum) initialPos = viz.choose('Select Initial Pos:', ['COND_HIGH', 'COND_LOW']) # 'COND_HIGH' is 0 and 'COND_LOW' is 1 trialLookup = [] ################################################################ # INITIALIZATIONS ################################################################ # Randomize trial lookup array # *** Condition numbers begin with 1 instead of 0 faceConds = range(0, NUM_CONDITIONS, 2) chestConds = range(1, NUM_CONDITIONS, 2) random.shuffle(faceConds) random.shuffle(chestConds) if initialPos is 0: for i in range(0, NUM_CONDITIONS / 2): trialLookup.append(faceConds[i] + 1) trialLookup.append(chestConds[i] + 1) else: for i in range(0, NUM_CONDITIONS / 2): trialLookup.append(chestConds[i] + 1) trialLookup.append(faceConds[i] + 1) ## Initialize trial lookup array from input file #fileIn = open(TRIAL_ORDER_FILE, 'r') #for line in fileIn: # print line # trialLookup.append(int(line)) #fileIn.close() #Add 3d objects as usual ground = viz.add('tut_ground.wrl') people = [] people.append(viz.add('male.cfg')) people.append(viz.add('male.cfg')) people.append(viz.add('male.cfg')) people.append(viz.add('male.cfg')) people.append(viz.add('male.cfg')) people.append(viz.add('male.cfg')) people.append(viz.add('male.cfg')) people.append(viz.add('male.cfg')) people.append(viz.add('female.cfg')) people.append(viz.add('female.cfg')) people.append(viz.add('female.cfg')) people.append(viz.add('female.cfg')) people.append(viz.add('female.cfg')) people.append(viz.add('female.cfg')) people.append(viz.add('female.cfg')) people.append(viz.add('female.cfg')) s = .5 people.append(viz.add('blob.wrl')) people[16].scale(s,s,s) people.append(viz.add('blob.wrl')) people[17].scale(s,s,s) people.append(viz.add('blob.wrl')) people[18].scale(s,s,s) people[18].rotate(0, 1, 0, 180) people.append(viz.add('blob.wrl')) people[19].scale(s,s,s) people[19].rotate(0, 1, 0, 180) faces = [] faces.append(viz.add('M-089.vzf')) faces.append(viz.add('M-225.vzf')) faces.append(viz.add('M-224.vzf')) faces.append(viz.add('M-231.vzf')) faces.append(viz.add('M-0469.vzf')) faces.append(viz.add('M-270.vzf')) faces.append(viz.add('M-302.vzf')) faces.append(viz.add('M-0456.vzf')) faces.append(viz.add('F-066.vzf')) faces.append(viz.add('f-155.vzf')) faces.append(viz.add('F-108.vzf')) faces.append(viz.add('f-271.vzf')) faces.append(viz.add('F-0408.vzf')) faces.append(viz.add('F-0453.vzf')) faces.append(viz.add('F-0410.vzf')) faces.append(viz.add('F-0458.vzf')) for i in range(0, NUM_CONDITIONS): if i < NUM_PEOPLE: people[i].face(faces[i]) hd.add(people[i]) if i < NUM_PEOPLE: hd.add(faces[i]) faces[i].dynamicmesh(1) faces[i].enablehd(0) faces[i].visible(viz.OFF) people[i].dynamicmesh(1) people[i].enablehd(0) people[i].visible(viz.OFF) tempBallSpawn = viz.add(BALL_FILE) ## Initialize mouth guards #mouthGuards = [] #for i in range(0, NUM_CONDITIONS): # temp = tempBallSpawn.copy(people[i]) # temp.visible(viz.OFF) # temp.scale(.4, .4, .4) # mouthGuards.append(temp) #mouthGuard = tempBallSpawn.copy() #mouthGuard.visible(viz.OFF) #mouthGuard.translate(0, -100, 0) #mouthGuard.scale(.4, .4, .4) #hd.add(mouthGuard) #mouthGuard.enable(0) # ## Position mouth guard markers #positions.PositionMouthGuards(mouthGuards, NUM_CONDITIONS) # Initialize dirt spots visuals = [] for i in range(0, NUM_CONDITIONS): visuals.append([]) for j in range(0, NUM_BALLS): temp = tempBallSpawn.copy(people[i]) #temp.translate(-INITIAL_BALL_SPAN / 2 + INITIAL_BALL_SPAN * i / NUM_BALLS, 2, 0) temp.scale(BALL_SCALE, BALL_SCALE, BALL_SCALE) if i >= NUM_PEOPLE: temp.scale(2, 2, 2, viz.RELATIVE_LOCAL) temp.color(BALL_COLOR) hd.add(temp) temp.enablehd(0) visuals[i].append(temp) collidables = [] for i in range(0, NUM_BALLS): temp = tempBallSpawn.copy() # temp.collideSphere(0.1 * BALL_SCALE) #temp.translate(-INITIAL_BALL_SPAN / 2 + INITIAL_BALL_SPAN * i / NUM_BALLS, 2, 0) temp.scale(BALL_SCALE, BALL_SCALE, BALL_SCALE) temp.color(BALL_COLOR) temp.visible(viz.OFF) hd.add(temp) temp.enablehd(0) collidables.append(temp) # Position visuals... these are the ones that are seen positions.PositionVisuals(visuals, NUM_PEOPLE, NUM_BALLS) # Initialize marker object marker = viz.add(BALL_FILE) marker.scale(MARKER_SCALE, MARKER_SCALE, MARKER_SCALE) marker.color(MARKER_COLOR) marker.collideSphere(0.1 * MARKER_SCALE) hd.translate(0,1.7,1) hd.scale(0.5,0.5,0.5) hd.marker(marker) #Position people appropriately for i in range(0, NUM_PEOPLE): people[i].translate(0, 0, 1) people[i].rotate(0, 1, 0, 180) people[16].translate(0, 0, 1.5) people[16].rotate(0, 1, 0, 180) people[17].translate(0, 0, 1.5) people[17].rotate(0, 1, 0, 180) people[18].translate(0, 0, 1.6) people[18].rotate(0, 1, 0, 0) people[19].translate(0, 0, 1.6) people[19].rotate(0, 1, 0, 0) #Set background color to sky blue viz.clearcolor(viz.SKYBLUE) ################################################################ # FUNCTIONS ################################################################ def RunNextTrial(): global finished, nextTrial, currVisuals, numSpotsLeft, cleaned, conditionID, timeMarker if not finished: print "Cannot proceed: Current trial still in progress" elif nextTrial == NUM_CONDITIONS: status.message("Study complete!") else: CleanUpPreviousTrial() finished = False conditionID = GetConditionID(nextTrial) condIndex = conditionID - 1 # array elements start with 0 nextTrial += 1 people[condIndex].visible(viz.ON) if condIndex < NUM_PEOPLE: faces[condIndex].visible(viz.ON) currVisuals = visuals[condIndex] for spot in currVisuals: spot.visible(viz.ON) spot.enablehd(1) for i in range(0, NUM_BALLS): collidables[i].translate(currVisuals[i].get(viz.POSITION,viz.ABSOLUTE_WORLD)) collidables[i].enablehd(1) numSpotsLeft = NUM_BALLS cleaned = [] for i in range(0, NUM_BALLS): cleaned.append(False) people[condIndex].enablehd(1) if condIndex < NUM_PEOPLE: faces[condIndex].enablehd(1) timeMarker = time.time() # mouthGuard.translate(mouthGuards[condIndex].get(viz.POSITION,viz.ABSOLUTE_WORLD)) # mouthGuard.enablehd(1) def CleanUpPreviousTrial(): global finished for i in range(0, NUM_CONDITIONS): people[i].enablehd(0) if i < NUM_PEOPLE: faces[i].enablehd(0) # mouthGuard.enablehd(0) people[i].visible(viz.OFF) if i < NUM_PEOPLE: faces[i].visible(viz.OFF) for spot in currVisuals: spot.visible(viz.OFF) status.message("") def GetConditionID(trialID): global trialLookup return trialLookup[trialID] def outputFn(): global conditionID, timeMarker, nextTrial, initialPos DELIMITER = '\t' pos = marker.get(viz.POSITION) force = hd.get(hd.FORCE) forceMag = math.sqrt(force[0]*force[0]+force[1]*force[1]+force[2]*force[2]) torque = hd.get(hd.TORQUE) torqueMag = math.sqrt(torque[0]*torque[0]+torque[1]*torque[1]+torque[2]*torque[2]) if timeMarker is 0: cumulativeTime = 0 else: cumulativeTime = time.time() - timeMarker line = '' line += str(conditionID) + DELIMITER # trial number line += str(nextTrial) + DELIMITER # line += str(pos[0]) + DELIMITER # marker pos X line += str(pos[1]) + DELIMITER # marker pos Y line += str(pos[2]) + DELIMITER # marker pos Z line += str(forceMag) + DELIMITER # magnitude of force line += str(torqueMag) + DELIMITER # magnitude of "torque" line += str(cumulativeTime) + DELIMITER line += str(initialPos) return line # Make sure to set callback on fileOut, then start file output fileOut.setCallback(outputFn) fileOut.startOutputTimer() def CollisionHandler(id): global finished, numSpotsLeft, cleaned, timeMarker force = hd.get(hd.FORCE) print str(force) magnitude = math.sqrt(force[0]*force[0]+force[1]*force[1]+force[2]*force[2]) if magnitude > 0 and not cleaned[id]: cleaned[id] = True currVisuals[id].visible(viz.OFF) numSpotsLeft -= 1 if numSpotsLeft == 0: status.message("All clean!") finished = True timeMarker = 0 def onkeydown(key): global markerObj, totalForce, conditionID if key == ' ': RunNextTrial() if key == 'r': headIsense.reset() if key == '-': if conditionID - 1 < NUM_PEOPLE: faces[conditionID - 1].enablehd(0) if key == '=': if conditionID - 1 < NUM_PEOPLE: faces[conditionID - 1].enablehd(1) viz.callback(viz.KEYDOWN_EVENT,onkeydown) def ontimer(num): global collidables, hd print collidables print hd.get(hd.TOUCH_OBJECTS) #Check if ball is colliding with an object in the scene for i in range(0, len(collidables)): #Perform the collision check with the object if collidables[i] in hd.get(hd.TOUCH_OBJECTS) and collidables[i].visible: #if marker.collidingwith(collidables[i],0) == 1: CollisionHandler(i) viz.callback(viz.TIMER_EVENT,ontimer) viz.starttimer(0,0.01,viz.FOREVER) #def onCollide(e): # global marker, collidables # print "collided!" # # #Did ball collide with marker? # if e.obj2 == marker: # print "marker collided!" # for i in range(0, len(collidables)): # #Perform the collision check with the object # if e.obj2 == collidables[i] and collidables[i].visible == True: # CollisionHandler(i) # #viz.callback( viz.COLLIDE_BEGIN_EVENT, onCollide ) def hdbuttondown(button): #Check if button 1 or 2 is pressed if button == hd.BUTTON1 or button == hd.BUTTON2: RunNextTrial() #Create callbacks for haptic events hd.callback(hd.BUTTONDOWN_EVENT,hdbuttondown)