package Code.graphics.GestureProgrammer;
import java.awt.Color;
import Code.graphics.GestureProgrammer.GestureProgrammerUtils.*;
import edu.cmu.ri.createlab.terk.robot.finch.Finch;
/**
* Gesture programmer allows the user to record the Finch's motions and play
* them back. Users record motions by picking up the Finch and tilting and rolling it,
* which is then mapped onto forward, backward, or turning motion of the Finch during
* playback. This is an excellent program to demonstrate simple gestural programming
* with kids as young as four.
* @author Alex Styler (astyler@gmail.com)
*/
public class GestureProgrammer
{
//Program that is recorded to when recording
private static GestureProgram recordingProgram = new GestureProgram();
//The recorded program that is played back when Play is hit
private static GestureProgram recordedProgram = new GestureProgram();
private static double[] accelerometerOffsets = new double[3];
public static void main(final String[] args) throws InterruptedException
{
//Create the finch and the GUI
final Finch finch = new Finch();
final GestureProgrammerView view = new GestureProgrammerView();
int calibrateCounter = 0;
final double[] calibrationSums = new double[3];
while (true)
{
//Update accelerations in the view panel
final double[] accelerometerState = finch.getAccelerations();
accelerometerState[0] -= accelerometerOffsets[0];
accelerometerState[1] -= accelerometerOffsets[1];
accelerometerState[2] -= accelerometerOffsets[2];
view.updateAccelerations(accelerometerState);
//Current command from accelerometer state
GestureCommand currentCommand = createGestureCommand(accelerometerState);
//beak color to set
Color beakColor;
switch (view.getProgrammerState())
{
case PLAYING:
//Grab command from recorded program, execute on finch,
//set beak green
beakColor = Color.GREEN;
currentCommand = recordedProgram.getNextCommand();
currentCommand.execute(finch);
//If the end of the program is reached, switch to idle state
if (currentCommand instanceof GestureCommand.StopCommand)
{
view.setProgrammerState(GestureProgrammerView.State.IDLE);
}
break;
case RECORDING:
//Execute command on finch for feedback, append to
//recording program, set beak red
beakColor = Color.RED;
currentCommand.execute(finch);
recordingProgram.appendCommand(currentCommand);
break;
case CALIBRATING:
//sum accelerometer states for 20 iterations, use
//average on last iteration as offsets in the future,
//make sure finch wheels are stopped, and set beak blue
beakColor = Color.BLUE;
(new GestureCommand.StopCommand()).execute(finch);
calibrationSums[0] += accelerometerState[0];
calibrationSums[1] += accelerometerState[1];
calibrationSums[2] += accelerometerState[2] - 1;
calibrateCounter++;
//last iteration reached
if (calibrateCounter >= 20)
{
//reset counter
calibrateCounter = 0;
//store averages as offsets for the future
accelerometerOffsets[0] = calibrationSums[0] / 20.0;
accelerometerOffsets[1] = calibrationSums[1] / 20.0;
accelerometerOffsets[2] = calibrationSums[2] / 20.0;
//set state back to idle because calibration is done
view.setProgrammerState(GestureProgrammerView.State.IDLE);
}
break;
case QUIT:
//tell the finch to quit, destory the GUI, and exit the program
finch.quit();
view.dispose();
System.exit(0);
case IDLE:
default:
//Turn the beak off, Reset the program to the beginning for next playback,
//make sure the wheels are stopped, and check if RecordingProgram has data
beakColor = Color.BLACK;
recordedProgram.resetProgram();
new GestureCommand.StopCommand().execute(finch);
//if recordingProgram has data, a program was just recorded
//store into recordedProgram and create a new recordingProgram
//for future recordings
if(recordingProgram.hasCommands()){
recordedProgram = recordingProgram;
recordingProgram = new GestureProgram();
}
break;
}
//have the finch set its beak to the appropriate color
finch.setLED(beakColor);
//tell the view to update the simulator with this data
view.updateSim(currentCommand.leftVel, currentCommand.rightVel, beakColor);
}
}
private static GestureCommand createGestureCommand(double[] accelerometerState)
{
double left = 160 * accelerometerState[0];
double right = 160 * accelerometerState[0];
left = left - 100 * accelerometerState[1];
right = right + 100 * accelerometerState[1];
return new GestureCommand(left, right);
}
}