/// <summary> /// Handles task data logging which runs on FixedUpdate. /// Logs data from sensors registered in the AvatarSystem and ExperimentSystem by default. /// Can be exteded to add more data by implementing an override method in the derived class which first adds data /// to the logData string (e.g. logData += myDataString + ","), and then calls base.HandleTaskDataLogging(). /// </summary> public override void HandleTaskDataLogging() { // Add your custom data logging here // e.g. the magic number! logData += targetOrder[iterationNumber - 1] + ","; // Make sure you always end your custom data with a comma! Using CSV for data logging. // Continue with data logging. base.HandleTaskDataLogging(); // Performance evaluation data buffering if (!debug) { if (evaluatorType == EvaluatorType.Compensation) { Vector3 shPos = new Vector3(shoulderTracker.GetProcessedData("X_Pos"), shoulderTracker.GetProcessedData("Y_Pos"), shoulderTracker.GetProcessedData("Z_Pos")); Vector3 c7Pos = new Vector3(c7Tracker.GetProcessedData("X_Pos"), c7Tracker.GetProcessedData("Y_Pos"), c7Tracker.GetProcessedData("Z_Pos")); shDataBuffer.Add(shPos); c7DataBuffer.Add(c7Pos); } else if (evaluatorType == EvaluatorType.KinematicEnergy) { throw new System.NotImplementedException("KE method not yet implemented"); } } }
private bool IsAtRightPosition(float qShoudlerRef, float qElbowRef, float tolerance) { // Check that upper and lower arms are within the tolerated start position. float qShoulder = leftySign * Mathf.Rad2Deg * (upperArmTracker.GetProcessedData(5) + Mathf.PI); // Offsetting to horizontal position being 0. float qElbow = 0; HudManager.colour = HUDManager.HUDColour.Orange; qElbow = Mathf.Rad2Deg * (lowerArmTracker.GetProcessedData(5)) - qShoulder; // Offsetting to horizontal position being 0. // The difference to the start position float qSDiff = qShoulder - qShoudlerRef; float qEDiff = qElbow - qElbowRef; // // Update information displayed for debugging purposes // //InstructionManager.DisplayText(qShoulder.ToString() + "\n" + qElbow.ToString() + "\n"); if (Mathf.Abs(qSDiff) < tolerance && Mathf.Abs(qEDiff) < tolerance) { HudManager.colour = HUDManager.HUDColour.Orange; return(true); } // Provide instructions when not there yet else { string helpText = ""; if (qSDiff < 0 && Mathf.Abs(qSDiff) > tolerance) { helpText += "SH: up (" + qShoulder.ToString("F0") + "/" + qShoudlerRef.ToString("F0") + ").\n"; } else if (qSDiff > 0 && Mathf.Abs(qSDiff) > tolerance) { helpText += "SH: down (" + qShoulder.ToString("F0") + "/" + qShoudlerRef.ToString("F0") + ").\n"; } else { helpText += "SH: ok (" + qShoulder.ToString("F0") + "/" + qShoudlerRef.ToString("F0") + ").\n"; } if (qEDiff < 0 && Mathf.Abs(qEDiff) > tolerance) { helpText += "EB: up (" + qElbow.ToString("F0") + "/" + qElbowRef.ToString("F0") + ").\n"; } else if (qEDiff > 0 && Mathf.Abs(qEDiff) > tolerance) { helpText += "EB: down (" + qElbow.ToString("F0") + "/" + qElbowRef.ToString("F0") + ").\n"; } else { helpText += "EB: ok (" + qElbow.ToString("F0") + "/" + qElbowRef.ToString("F0") + ").\n"; } HudManager.DisplayText(helpText); HudManager.colour = HUDManager.HUDColour.Red; return(false); } }
/// <summary> /// Checks whether the subject is ready to start performing the task. /// </summary> /// <returns>True if ready to start.</returns> public override bool IsReadyToStart() { // Check that upper and lower arms are within the tolerated start position. float qShoulder = leftySign * Mathf.Rad2Deg * (upperArmTracker.GetProcessedData(5) + Mathf.PI); // Offsetting to horizontal position being 0. float qElbow = 0; if (experimentType == ExperimentType.TypeOne) { qElbow = Mathf.Rad2Deg * (lowerArmTracker.GetProcessedData(5)) - qShoulder; // Offsetting to horizontal position being 0. } else if (experimentType == ExperimentType.TypeTwo) { qElbow = -Mathf.Rad2Deg * elbowManager.GetElbowAngle(); } // The difference to the start position float qSDiff = qShoulder - startShoulderAngle; float qEDiff = qElbow - startElbowAngle; // // Update information displayed for debugging purposes // if (debug) { debugText.text = experimentState.ToString() + "\n"; if (experimentState == ExperimentState.WaitingForStart) { debugText.text += waitState.ToString() + "\n"; } debugText.text += qShoulder.ToString() + "\n"; debugText.text += qElbow.ToString() + "\n"; } // Make sure the user knows the elbow is not enabled. if (experimentType == ExperimentType.TypeTwo) { if (!elbowManager.IsEnabled) { HudManager.centreColour = HUDManager.HUDCentreColour.Yellow; } else { HudManager.centreColour = HUDManager.HUDCentreColour.None; } } if (Mathf.Abs(qSDiff) < startTolerance && Mathf.Abs(qEDiff) < startTolerance) { HudManager.colour = HUDManager.HUDColour.Orange; return(true); } // Provide instructions when not there yet else { string helpText = ""; if (qSDiff < 0 && Mathf.Abs(qSDiff) > startTolerance) { helpText += "UA: ++.\n"; } else if (qSDiff > 0 && Mathf.Abs(qSDiff) > startTolerance) { helpText += "UA: --.\n"; } if (qEDiff < 0 && Mathf.Abs(qEDiff) > startTolerance) { helpText += "LA: ++.\n"; } else if (qEDiff > 0 && Mathf.Abs(qEDiff) > startTolerance) { helpText += "LA: --.\n"; } HudManager.DisplayText(helpText); HudManager.colour = HUDManager.HUDColour.Red; return(false); } }
// Update is called once per frame void Update() { switch (experimentState) { /* ************************************************* * HelloWorld ************************************************* */ // Welcome subject to the virtual world. case ExperimentState.Welcome: if (WaitFlag) { if (debug) { TeleportToStartPosition(); } HudManager.ClearText(); experimentState = ExperimentState.Initialising; } else { HudManager.DisplayText("Welcome!"); InstructionManager.DisplayText("Hello world!"); } break; /* ************************************************* * InitializingApplication ************************************************* */ // Perform initialization functions before starting experiment. case ExperimentState.Initialising: // // Perform experiment initialization procedures // // // Initialize data logs // // // Go to training // experimentState = ExperimentState.Training; break; /* ************************************************* * Practice ************************************************* */ // Perform initialization functions before starting experiment. case ExperimentState.Training: // // Guide subject through training // // // Go to instructions // experimentState = ExperimentState.Instructions; break; /* ************************************************* * GivingInstructions ************************************************* */ case ExperimentState.Instructions: // Skip instructions when repeating sessions if (SkipInstructions) { HudManager.DisplayText("Move to start", 2.0f); // Turn targets clear experimentState = ExperimentState.WaitingForStart; break; } // // Give instructions // // // Go to waiting for start // HudManager.DisplayText("Move to start", 2.0f); // Turn targets clear experimentState = ExperimentState.WaitingForStart; break; /* ************************************************* * WaitingForStart ************************************************* */ case ExperimentState.WaitingForStart: // Show status to subject infoText = GetInfoText(); InstructionManager.DisplayText(infoText); // Check if pause requested UpdatePause(); switch (waitState) { // Waiting for subject to get to start position. case WaitState.Waiting: if (IsReadyToStart()) { startEnable = true; // Select target gridManager.SelectBall(iterationNumber - 1); waitState = WaitState.Countdown; } break; // HUD countdown for reaching action. case WaitState.Countdown: // If all is good and haven't started counting, start. if (startEnable && !counting && !CountdownDone) { // Manage countdown HudManager.ClearText(); StopHUDCountDown(); counting = true; HUDCountDown(3); } // If all is good and the countdownDone flag is raised, switch to reaching. else if (CountdownDone) { // Reset flags startEnable = false; counting = false; countdownDone = false; // Continue experimentState = ExperimentState.PerformingTask; waitState = WaitState.Waiting; break; } // If hand goes out of target reset countdown and wait for position else if (!IsReadyToStart() && !CountdownDone) { StopHUDCountDown(); startEnable = false; counting = false; countdownDone = false; // Clear ball gridManager.ResetBallSelection(); // Indicate to move back HudManager.DisplayText("Move to start", 2.0f); waitState = WaitState.Waiting; break; } break; default: break; } break; /* ************************************************* * PerformingTask ************************************************* */ case ExperimentState.PerformingTask: // Task performance is handled deterministically in FixedUpdate. break; /* ************************************************* * AnalizingResults ************************************************* */ case ExperimentState.AnalizingResults: // Allow 3 seconds after task end to do calculations SetWaitFlag(3.0f); // // Data analysis and calculations // // // System update // // // Data logging // // // Flow managment // // Rest for some time when required if (IsRestTime()) { SetWaitFlag(RestTime); experimentState = ExperimentState.Resting; } // Check whether the new session condition is met else if (IsEndOfSession()) { experimentState = ExperimentState.InitializingNext; } // Check whether the experiment end condition is met else if (IsEndOfExperiment()) { experimentState = ExperimentState.End; } else { experimentState = ExperimentState.UpdatingApplication; } break; /* ************************************************* * UpdatingApplication ************************************************* */ case ExperimentState.UpdatingApplication: if (WaitFlag) { // // Update iterations and flow control // iterationNumber++; completedIterations++; // // Update log requirements // // // // Go to start of next iteration experimentState = ExperimentState.WaitingForStart; } break; /* ************************************************* * InitializingNext ************************************************* */ case ExperimentState.InitializingNext: // // Perform session closure procedures // // // Initialize new session variables and flow control // iterationNumber = 1; sessionNumber++; skipInstructions = true; // // Initialize data logging // ExperimentSystem.GetActiveLogger(1).AddNewLogFile(sessionNumber, iterationNumber, "Data format"); experimentState = ExperimentState.Initialising; // Initialize next session break; /* ************************************************* * Resting ************************************************* */ case ExperimentState.Resting: // // Check for session change or end request from experimenter // if (UpdateNext()) { ConfigureNextSession(); break; } else if (UpdateEnd()) { EndExperiment(); break; } // // Restart after flag is set by wait coroutine // if (WaitFlag) { HudManager.DisplayText("Get ready to restart!", 3.0f); SetWaitFlag(5.0f); experimentState = ExperimentState.UpdatingApplication; break; } break; /* ************************************************* * Paused ************************************************* */ case ExperimentState.Paused: // // Check for session change or end request from experimenter // UpdatePause(); if (UpdateNext()) { ConfigureNextSession(); break; } else if (UpdateEnd()) { EndExperiment(); break; } break; /* ************************************************* * End ************************************************* */ case ExperimentState.End: // // Update log data and close logs. // // // Return to main menu // default: break; } // // Update information displayed on monitor // // // Update information displayed for debugging purposes // if (debug) { debugText.text = experimentState.ToString() + "\n"; if (experimentState == ExperimentState.WaitingForStart) { debugText.text += waitState.ToString() + "\n"; } float qShoulder = Mathf.Rad2Deg * (upperArmTracker.GetProcessedData(5) + Mathf.PI); // Offsetting to horizontal position being 0. float qElbow = Mathf.Rad2Deg * (lowerArmTracker.GetProcessedData(5)) - qShoulder; // Offsetting to horizontal position being 0. debugText.text += qShoulder.ToString() + "\n"; debugText.text += qElbow.ToString() + "\n"; } }