diff --git a/ci-build.sh b/ci-build.sh
index 3d236441d6664bac2dc512112ddc10742d3e9991..1828210237358ecbb38b5c82a26536f112281781 100644
--- a/ci-build.sh
+++ b/ci-build.sh
@@ -4,4 +4,4 @@ set -e
 
 # Quad Libraries and Boot image
 (cd quad && make)
-#(cd groundStation && make) 
+#(cd groundStation && make)
diff --git a/ci-test.sh b/ci-test.sh
index 4504f9a6d9d422964da0fc469bcba52befdb65e2..c79ad9703580d64f4db35e914c7d5c2eb7134fb6 100644
--- a/ci-test.sh
+++ b/ci-test.sh
@@ -1,6 +1,7 @@
 #!/bin/bash
 
 set -e
+export PATH=/usr/local/bin:$PATH
 
 # Quad
-cd quad && make && make test
+(cd quad && make test)
diff --git a/controls/model/loggingAnalysis/logAnalysis.m b/controls/model/loggingAnalysis/logAnalysis.m
index e427bf141ec9003dd7d5dc1e896dd1f1d1fe0411..b240f0dcb7a3fb25ac8ffd1737bd60b3fc2bc6b7 100644
--- a/controls/model/loggingAnalysis/logAnalysis.m
+++ b/controls/model/loggingAnalysis/logAnalysis.m
@@ -208,7 +208,7 @@ legend('Log', 'Model', 'location', 'northwest');
 figure(6); subplot(2, 1, 1);
 stairs(time, pitch_measured_IMU, '.-'); hold on; grid minor;
 stairs(time_model_5ms, pitch_accel, '.-'); hold off;
-title('Pitch Complimentary Filter Output');
+title('Pitch Complementary Filter Output');
 xlabel('Time (s)');
 ylabel('Pitch Angle (rad)');
 legend('Log', 'Model', 'location', 'northwest');
@@ -216,9 +216,7 @@ legend('Log', 'Model', 'location', 'northwest');
 subplot(2, 1, 2);
 stairs(time, roll_measured_IMU, '.-'); hold on; grid minor;
 stairs(time_model_5ms, roll_accel, '.-'); hold off;
-title('Roll Complimentary Filter Output');
+title('Roll Complementary Filter Output');
 xlabel('Time (s)');
 ylabel('Roll Angle (rad)');
 legend('Log', 'Model', 'location', 'northwest');
-
-
diff --git a/controls/model/modelParameters.m b/controls/model/modelParameters.m
index 4ff541ead94489dbfb5d7da83ae62d4adf8fcdd4..42bf4b89f56c1310c30d16d57576a61ab92ca9fe 100644
--- a/controls/model/modelParameters.m
+++ b/controls/model/modelParameters.m
@@ -1,4 +1,3 @@
-temp = 1;
 % Log Analysis Toggle    
     logAnalysisToggle = 1;          % 1 for log analysis, 0 for normal operation
 
@@ -43,9 +42,9 @@ temp = 1;
     
     % Equilibrium height controller output
     height_controlled_o = (((Rm*If + ...
-    + (((omega0_o * 2 * Rm * Kv * Kq  ...
+    + (((omega0_o * 2 * Rm * Kv * Kq ...
     * Kd + 1)^2) - 1)/(4* Rm*Kv^2*Kq ...
-    *Kd))/Vb)*(Pmax- Pmin)+Pmin);
+    * Kd))/Vb)*(Pmax- Pmin) + Pmin);
 
     % Equilibrium positions
     x_o = 0;
@@ -67,133 +66,7 @@ temp = 1;
     pitchrate_o = 0;
     yawrate_o = 0;
     
-% Import Data and determine errors
-if logAnalysisToggle == 1 && temp == 0
-    % Import Data to Workspace
-    %data = importdata('loggingAnalysis/logFiles/logData.csv');
-    data = importdata('loggingAnalysis/logFiles/test.csv');
-
-    % Set up time vector
-    time = data.data(:, 1);
-    runtime = max(time);
-   
-    % Determine x position error
-    x_setpoint = data.data(:, 25);
-    x_position = data.data(:, 20);
-    x_error = timeseries(x_setpoint - x_position, time);
-
-    % Determine y position error
-    y_setpoint = data.data(:, 26);
-    y_position = data.data(:, 21);
-    y_error = timeseries(y_setpoint - y_position, time);
-
-    % Determine z position error
-    z_setpoint = data.data(:, 27);
-    z_position = data.data(:, 22);
-    z_error = timeseries(z_setpoint - z_position, time);
-
-    % Determine pitch error
-    pitch_setpoint = data.data(:, 9);
-    pitch_value = data.data(:, 23);
-    pitch_error = timeseries(pitch_setpoint - pitch_value, time);
-
-    % Determine roll error
-    roll_setpoint = data.data(:, 10);
-    roll_value = data.data(:, 24);
-    roll_error = timeseries(roll_setpoint - roll_value, time);
-
-    % Determine yaw error
-    yaw_setpoint = zeros(length(time), 1); % NEEDS UPDATED WHEN LOG FILE INCLUDES YAW SETPOINT
-    yaw_value = data.data(:,10);%(length(time), 1); % NEEDS UPDATED WHEN LOG FILE INCLUDES YAW VALUE
-    yaw_error = timeseries(yaw_setpoint - yaw_value, time);
-
-    % Determine pitch rate error
-    pitchrate_setpoint = data.data(:, 11);
-    pitchrate_value = data.data(:, 6);
-    pitchrate_error = timeseries(pitchrate_setpoint - pitchrate_value, time);
-
-    % Determine roll rate error
-    rollrate_setpoint = data.data(:, 12);
-    rollrate_value = data.data(:, 5);
-    rollrate_error = timeseries(rollrate_setpoint - rollrate_value, time);
-
-    % Determine yaw rate error
-    yawrate_setpoint = data.data(:, 13);
-    yawrate_value = data.data(:, 7);
-    yawrate_error = timeseries(yawrate_setpoint - yawrate_value, time);
-
-    % Pull motor commands from log
-    x_command = data.data(:, 14);
-    y_command = data.data(:, 15);
-    z_command = data.data(:, 8);
-    yaw_command = data.data(:, 16);
-    
-    %Create time series object for z command
-    throttle_command = timeseries(z_command, time);
-    
-    % Determine signal mix PWM values
-    PWM0 = data.data(:, 28);
-    PWM1 = data.data(:, 29);
-    PWM2 = data.data(:, 30);
-    PWM3 = data.data(:, 31);
-    
-    %Pull the measurements from the acceleratometer
-    raw_accel_data_x = data.data(:, 2);
-    raw_accel_data_y = data.data(:, 3);
-    raw_accel_data_z = data.data(:, 4);
-    raw_accel_data_arr = ...
-        [ raw_accel_data_x , raw_accel_data_y , raw_accel_data_z ];
-    raw_accel_data = timeseries( raw_accel_data_arr , time );
-    
-    %Pull the measurements from the gyroscope
-    raw_gyro_data_x = data.data(:, 5);
-    raw_gyro_data_y = data.data(:, 6);
-    raw_gyro_data_z = data.data(:, 7);
-    raw_gyro_data_arr = ...
-        [ raw_gyro_data_x , raw_gyro_data_y , raw_gyro_data_z ];
-    raw_gyro_data = timeseries( raw_gyro_data_arr , time );
-    
-    
-    % Determine the initial height controller command
-    % height_controlled_o = 1; % NEEDS UPDATED WHEN LOG FILES INCLUDE THROTTLE COMMAND
-    
-    % Determine the initial rotor speeds based on PWM inputs
-    u_P0 = (PWM0(1) - Pmin) / (Pmax - Pmin);
-    u_P1 = (PWM1(1) - Pmin) / (Pmax - Pmin);
-    u_P2 = (PWM2(1) - Pmin) / (Pmax - Pmin);
-    u_P3 = (PWM3(1) - Pmin) / (Pmax - Pmin);
-    
-    Vb_eff_0 = u_P0 * Vb;
-    Vb_eff_1 = u_P1 * Vb;
-    Vb_eff_2 = u_P2 * Vb;
-    Vb_eff_3 = u_P3 * Vb;
-    
-    omega0_o = (-1 + sqrt(1 - 4*Rm*Kv*Kq*Kd*( Kv*Rm*If - Kv*Vb_eff_0))) / (2*Rm*Kv*Kq*Kd);
-    omega1_o = (-1 + sqrt(1 - 4*Rm*Kv*Kq*Kd*( Kv*Rm*If - Kv*Vb_eff_1))) / (2*Rm*Kv*Kq*Kd);
-    omega2_o = (-1 + sqrt(1 - 4*Rm*Kv*Kq*Kd*( Kv*Rm*If - Kv*Vb_eff_2))) / (2*Rm*Kv*Kq*Kd);
-    omega3_o = (-1 + sqrt(1 - 4*Rm*Kv*Kq*Kd*( Kv*Rm*If - Kv*Vb_eff_3))) / (2*Rm*Kv*Kq*Kd);
-    
-    % Determine initial positions for x, y, and z
-    x_o = x_position(1);
-    y_o = y_position(1);
-    z_o = z_position(1);
-    
-    % Determine initial velocity for x, y, and z
-    x_vel_o = (x_position(2) - x_position(1)) / (time(2) - time(1));
-    y_vel_o = (y_position(2) - y_position(1)) / (time(2) - time(1));
-    z_vel_o = (z_position(2) - z_position(1)) / (time(2) - time(1));
-    
-    % Determine initial angles
-    roll_o = roll_value(1);
-    pitch_o = pitch_value(1);
-    yaw_o = yaw_value(1);
-    
-    % Determine initial angular rates
-    rollrate_o = rollrate_value(1);
-    pitchrate_o = pitchrate_value(1);
-    yawrate_o = yawrate_value(1);
-
-elseif logAnalysisToggle == 1 && temp == 1
+if logAnalysisToggle == 1
     %%%%%% Commented out section until logging is .txt file based %%%%%%
     % FNAME
     % if you know the name of the log file that you want to parse, set the it
@@ -218,6 +91,9 @@ elseif logAnalysisToggle == 1 && temp == 1
     time = dataStruct.Time.data;
     time = time - time(1);
     
+    time = time(1):0.005:time(length(time)-7);
+    time = time';
+    
     runtime = max(time);
  
     % Determine x position error
diff --git a/controls/model/parse_log_model.m b/controls/model/parse_log_model.m
index 59aef835bd0d5077e9619b7c02880a8390d95643..cb7cd4aa2d95314e075ed4129ea2e723c30405a1 100644
--- a/controls/model/parse_log_model.m
+++ b/controls/model/parse_log_model.m
@@ -1,4 +1,4 @@
-function [loggedData, headers] = parse_log_model(filename, params, expData)
+function [loggedData, headers] = parse_log_model(filename)
 %parse_log This independent function parses the data stored in the file and
 %returns a structure containing the data
 %   filename    - this is the complete path of the file with the filename
diff --git a/controls/model/test_model.slx b/controls/model/test_model.slx
index 714e5c977f6c505ea95c96d4cb0ac6325d7dd456..92b139549538c6faa45058b6f41784f2c238384b 100644
Binary files a/controls/model/test_model.slx and b/controls/model/test_model.slx differ
diff --git a/quad/Makefile b/quad/Makefile
index 01dfc58321c31b86e93d0d50386fba1eccc6ca45..f27a39d37141e31878c324788ef9c141db241be5 100644
--- a/quad/Makefile
+++ b/quad/Makefile
@@ -6,7 +6,7 @@ WS = $(CURDIR)/xsdk_workspace
 
 BOOT = $(OUTDIR)/BOOT.bin
 
-.PHONY: all libs zybo boot test clean deep-clean
+.PHONY: all libs zybo boot run-virt-quad test clean deep-clean
 
 all: libs bins
 
@@ -31,10 +31,15 @@ gen_diagram:
 
 boot: $(BOOT)
 
-test:
+run-virt-quad:
+	$(MAKE) -C src/virt_quad run
+
+test: all
 	$(MAKE) -C src/queue test
 	$(MAKE) -C src/computation_graph test
 	$(MAKE) -C src/quad_app test
+	ruby scripts/tests/test_safety_checks.rb
+	ruby scripts/tests/test_unix_uart.rb
 
 clean:
 	rm -rf $(INCDIR) $(LIBDIR) $(OUTDIR) $(EXEDIR)
@@ -47,10 +52,9 @@ deep-clean:
 	$(MAKE) -C src/graph_blocks clean
 	$(MAKE) -C src/commands clean
 	$(MAKE) -C src/quad_app clean
-	bash scripts/clean_xsdk_workspace.sh
 
 $(OUTDIR):
 	mkdir $(OUTDIR)
 
 $(BOOT): zybo | $(OUTDIR)
-	bash scripts/create_zybo_boot.sh
+	bash scripts/xsdk/create_zybo_boot.sh
diff --git a/quad/README.md b/quad/README.md
index 8f857b03bcd9bba8e4e76f3617313d0ad7dd2b2d..33deb7170d5f6cf49231ecbc98a10715f7d5cd1d 100644
--- a/quad/README.md
+++ b/quad/README.md
@@ -6,12 +6,17 @@ the quad, and the XSDK main project that runs on the Zybo.
 
 The main quad application is written as a library, and located at:
 ```
-src/quad_app/quad_app.c
+src/quad_app/   ("main" function in quad_app.c)
 ```
 
 The main XSDK project that actually runs on the Zybo is located at:
 ```
-xsdk_workspace/modular_quad_pid/main.c
+xsdk_workspace/real_quad/
+```
+
+We also have a complemetary "virtual quad" to ease testing:
+```
+src/virt_quad/
 ```
 
 ## Building
diff --git a/quad/scripts/#send_raw.py# b/quad/scripts/#send_raw.py#
deleted file mode 100755
index f2312f463a95cf94c3408b01e78fe3986e0602fe..0000000000000000000000000000000000000000
--- a/quad/scripts/#send_raw.py#
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/
-
-import sys
-
-print(sys.version_info)
-import serial
-
-if __name__ == '__main__':
-    data = bytes.fromhex('be040002001c0002000000d80471be5732703f9d16093f8bf7a03d0586ab3d006d3a40c1')
-
-    with serial.Serial('/dev/ttyUSB0', 115200) as ser:
-        ser.write(data)
diff --git a/quad/scripts/__pycache__/uart_stress_tests.cpython-36.pyc b/quad/scripts/__pycache__/uart_stress_tests.cpython-36.pyc
deleted file mode 100644
index 4b92a40fddc351f17e205b35da850c41744a373c..0000000000000000000000000000000000000000
Binary files a/quad/scripts/__pycache__/uart_stress_tests.cpython-36.pyc and /dev/null differ
diff --git a/quad/scripts/send_raw.py b/quad/scripts/send_raw.py
deleted file mode 100755
index 32cd0efb13591ea7018be0f7947ad143474445ef..0000000000000000000000000000000000000000
--- a/quad/scripts/send_raw.py
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/usr/bin/python
-
-import sys
-
-print(sys.version_info)
-import serial
-
-if __name__ == '__main__':
-    data = bytes.fromhex('be040002001c0002000000d80471be5732703f9d16093f8bf7a03d0586ab3d006d3a40c1')
-
-    with serial.Serial('/dev/ttyUSB0', 921600) as ser:
-        ser.write(data)
diff --git a/quad/scripts/send_raw.sh b/quad/scripts/send_raw.sh
deleted file mode 100755
index a92551e78fbe4aa161d5a745f619ef90d8d3e723..0000000000000000000000000000000000000000
--- a/quad/scripts/send_raw.sh
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/bin/bash
-
-# Use the usb port on this machine that you are using for UART
-USB_UART=ttyUSB0
-
-MSG="\xbe\x04\x00\x02\x00\x1c\x00\x02\x00\x00\x00\xd8\x04\x71\xbe\x57\x32\x70\x3f\x9d\x16\x09\x3f\x8b\xf7\xa0\x3d\x05\x86\xab\x3d\x00\x6d\x3a\x40\xc1"
-#MSG="\xbe\x04\x00\x02\x00\x1c\x00\x02\x00\x00\x00"
-#MSG="hello"
-
-echo -en $MSG > /dev/$USB_UART
\ No newline at end of file
diff --git a/quad/scripts/setup_usb_uart.sh b/quad/scripts/setup_usb_uart.sh
deleted file mode 100755
index be12f0e9d1921c16009b5218ad95bc4d3eaa3f06..0000000000000000000000000000000000000000
--- a/quad/scripts/setup_usb_uart.sh
+++ /dev/null
@@ -1,6 +0,0 @@
-#!/bin/bash
-
-# The USB device that you are using for UART
-USB_DEV=ttyUSB0
-
-stty -F /dev/$USB_DEV raw speed 115200
diff --git a/quad/scripts/test_uart_comm.py~ b/quad/scripts/test_uart_comm.py~
deleted file mode 100644
index 2a5c7203a69b03ac667f905e82c95a74e1aaa7dc..0000000000000000000000000000000000000000
--- a/quad/scripts/test_uart_comm.py~
+++ /dev/null
@@ -1,50 +0,0 @@
-#!/usr/bin/python
-
-import sys
-
-print(sys.version_info)
-import serial
-
-def create_msg(main_type, subtype, msg_id, data):
-    msg = bytes()
-    msg += b'\xBE'
-    msg += main_type.to_bytes(1, 'little')
-    msg += subtype.to_bytes(1, 'little')
-    msg += msg_id.to_bytes(2, 'little')
-    msg += len(data).to_bytes(2, 'little')
-    msg += data
-    
-    checksum = 0
-    for b in msg:
-        checksum ^= b
-    msg += checksum.to_bytes(1, 'little')
-    return msg
-
-def create_test_packet(size=8):
-    data = bytes((i % 256 for i in range(size)))
-    return create_msg(0, 2, 0, data)
-
-def read_packet(ser):
-    header = ser.read(7)
-    length = int.from_bytes(header[5:7], byteorder='little')
-    data = ser.read(length)
-    checksum = ser.read()
-    return data
-
-def query_received(ser):
-    # Send request
-    query_msg = create_msg(0, 3, 0, b'')
-    ser.write(query_msg)
-    ser.flush()
-    
-    resp = read_packet(ser)
-    received_str = resp[:-1].decode()
-
-    return tuple(map(int, received_str.split(',')))
-
-if __name__ == '__main__':
-    with serial.Serial('/dev/ttyUSB0', 921600, timeout=5) as ser:
-        ser.write(create_test_packet(500))
-        ser.flush()
-        print(query_received(ser))
-
diff --git a/quad/scripts/tests/run_virtual_test_flight.rb b/quad/scripts/tests/run_virtual_test_flight.rb
new file mode 100644
index 0000000000000000000000000000000000000000..9bc3afa362eb0fcbe4e99d0c6c130c6da5a1fe6a
--- /dev/null
+++ b/quad/scripts/tests/run_virtual_test_flight.rb
@@ -0,0 +1,106 @@
+#!/usr/bin/env ruby
+
+# Test Flight
+#
+# A simple virtual test flight (take off, hover, and set back down)
+#
+
+THROTTLE_MIN = 110200
+THROTTLE_MAX = 191900
+THROTTLE_MID = (THROTTLE_MAX + THROTTLE_MIN)/2
+THROTTLE_3_4 = (THROTTLE_MAX + THROTTLE_MID)/2
+THROTTLE_QUAR = (THROTTLE_MID + THROTTLE_MIN)/2
+THROTTLE_EIGHTH = (THROTTLE_QUAR + THROTTLE_MIN)/2
+THROTTLE_16 = (THROTTLE_EIGHTH + THROTTLE_MIN)/2
+MOTOR_MIN = 100000
+MOTOR_MAX = 200000
+GEAR_ON = 170800
+GEAR_OFF = 118300
+GRAVITY = 4096
+
+MOTOR1 = "virt-quad-fifos/pwm-output-motor1"
+MOTOR2 = "virt-quad-fifos/pwm-output-motor2"
+MOTOR3 = "virt-quad-fifos/pwm-output-motor3"
+MOTOR4 = "virt-quad-fifos/pwm-output-motor4"
+
+UART_TX = "virt-quad-fifos/uart-tx"
+
+GEAR = "virt-quad-fifos/pwm-input-gear"
+THROTTLE = "virt-quad-fifos/pwm-input-throttle"
+
+LED = "virt-quad-fifos/mio7-led"
+
+I2C_MPU_ACCEL_X = "virt-quad-fifos/i2c-mpu-accel-x"
+I2C_MPU_ACCEL_Y = "virt-quad-fifos/i2c-mpu-accel-y"
+I2C_MPU_ACCEL_Z = "virt-quad-fifos/i2c-mpu-accel-z"
+
+require 'test/unit/assertions'
+require 'thread'
+include Test::Unit::Assertions
+
+script_dir = File.expand_path(File.dirname(__FILE__))
+bin_dir = script_dir + "/../../bin/"
+Dir.chdir(bin_dir)
+
+# Start virtual quad
+quad = Process.spawn("./virt-quad")
+
+sleep 1
+
+##################
+#  Begin Flight!
+##################
+
+begin
+  puts("Starting flight")
+
+  # Set gravity
+  File.write(I2C_MPU_ACCEL_Z, -1 * GRAVITY)
+
+  puts("Turning on GEAR...")
+  File.write(GEAR, GEAR_ON)
+  sleep 0.015
+
+  puts("Increasing Thrust to half maximum...")
+  for i in (THROTTLE_MIN..THROTTLE_MID).step(1000)
+    File.write(THROTTLE, i)
+    sleep 0.005
+  end
+
+  puts("Hovering for 10 seconds")
+  sleep 10
+
+  puts("Relaxing thrust to zero")
+  i = THROTTLE_MID
+  while i > THROTTLE_MIN
+    i -= 1000
+    File.write(THROTTLE, i)
+    sleep 0.005
+  end
+
+  puts("Swiching off GEAR...")
+  File.write(GEAR, GEAR_OFF)
+
+  # puts("Collecting logs...")
+  # msg = ""
+  # misses = 0
+  # fifo = File::open(UART_TX)
+  # while misses < 10
+  #   puts "trying..."
+  #   if fifo.eof?
+  #     misses += 1
+  #     next
+  #   end
+  #   msg += fifo.read()
+  # end
+  
+  # fifo.close()
+
+  # puts msg
+
+ensure
+
+  Process.kill(9, quad)
+
+end
+
diff --git a/quad/scripts/tcp_stress_tests.py b/quad/scripts/tests/tcp_stress_tests.py
similarity index 100%
rename from quad/scripts/tcp_stress_tests.py
rename to quad/scripts/tests/tcp_stress_tests.py
diff --git a/quad/scripts/tests/test_safety_checks.rb b/quad/scripts/tests/test_safety_checks.rb
new file mode 100644
index 0000000000000000000000000000000000000000..f4e6904955db2d2fd99a220c6c79257e4ed4956a
--- /dev/null
+++ b/quad/scripts/tests/test_safety_checks.rb
@@ -0,0 +1,169 @@
+#!/usr/bin/env ruby
+
+# Safety Checks
+#
+# Startup the virtual quad and make sure it doesn't allow combinations of things
+# that could hurt people.
+THROTTLE_MIN = 110200
+THROTTLE_MAX = 191900
+THROTTLE_MID = (THROTTLE_MAX + THROTTLE_MIN)/2
+THROTTLE_3_4 = (THROTTLE_MAX + THROTTLE_MID)/2
+THROTTLE_QUAR = (THROTTLE_MID + THROTTLE_MIN)/2
+THROTTLE_EIGHTH = (THROTTLE_QUAR + THROTTLE_MIN)/2
+THROTTLE_16 = (THROTTLE_EIGHTH + THROTTLE_MIN)/2
+MOTOR_MIN = 100000
+MOTOR_MAX = 200000
+GEAR_ON = 170800
+GEAR_OFF = 118300
+GRAVITY = 4096
+
+MOTOR1 = "virt-quad-fifos/pwm-output-motor1"
+MOTOR2 = "virt-quad-fifos/pwm-output-motor2"
+MOTOR3 = "virt-quad-fifos/pwm-output-motor3"
+MOTOR4 = "virt-quad-fifos/pwm-output-motor4"
+
+GEAR = "virt-quad-fifos/pwm-input-gear"
+THROTTLE = "virt-quad-fifos/pwm-input-throttle"
+
+LED = "virt-quad-fifos/mio7-led"
+
+I2C_MPU_ACCEL_X = "virt-quad-fifos/i2c-mpu-accel-x"
+I2C_MPU_ACCEL_Y = "virt-quad-fifos/i2c-mpu-accel-y"
+I2C_MPU_ACCEL_Z = "virt-quad-fifos/i2c-mpu-accel-z"
+
+require 'test/unit/assertions'
+require 'thread'
+include Test::Unit::Assertions
+
+$fifos = Hash.new
+
+def read_fifo_num(f)
+  if not $fifos.key?(f)
+    $fifos[f] = File.open(f)
+  end
+  $fifos[f].read().chomp.split("\n").last.to_i
+end
+
+# Utility functions
+def check_motors_are_off
+  motor1 = read_fifo_num(MOTOR1)
+  motor2 = read_fifo_num(MOTOR2)
+  motor3 = read_fifo_num(MOTOR3)
+  motor4 = read_fifo_num(MOTOR4)
+  assert_operator motor1, :<=, THROTTLE_MIN
+  assert_operator motor2, :<=, THROTTLE_MIN
+  assert_operator motor3, :<=, THROTTLE_MIN
+  assert_operator motor4, :<=, THROTTLE_MIN
+end
+
+def get_motor_averages
+  motors = [[], [], [], []]
+  for i in 0..100
+    motors[0].push(read_fifo_num(MOTOR1))
+    motors[1].push(read_fifo_num(MOTOR2))
+    motors[2].push(read_fifo_num(MOTOR3))
+    motors[3].push(read_fifo_num(MOTOR4))
+    sleep 0.010
+  end
+  average = []
+  average[0] = motors[0].inject(:+).to_f / motors[0].size
+  average[1] = motors[1].inject(:+).to_f / motors[1].size
+  average[2] = motors[2].inject(:+).to_f / motors[2].size
+  average[3] = motors[3].inject(:+).to_f / motors[3].size
+  average
+end
+
+def check_led(on)
+  led = read_fifo_num(LED)
+  assert_equal(led, on)
+end
+
+script_dir = File.expand_path(File.dirname(__FILE__))
+bin_dir = script_dir + "/../../bin/"
+Dir.chdir(bin_dir)
+
+# Start virtual quad
+quad = Process.spawn("./virt-quad")
+
+sleep 1
+
+#################
+#  Begin Tests
+#################
+
+begin
+  puts("beginning tests")
+  
+  # Set gravity
+  File.write(I2C_MPU_ACCEL_Z, -1 * GRAVITY)
+
+  puts("Check that motors are off at startup")
+  check_motors_are_off
+
+  puts("Check that LED is off at startup")
+  check_led(0)
+
+  puts("Check that increasing the throttle does nothing to motors")
+  # (because gear is still off)
+  for i in (THROTTLE_MIN..THROTTLE_MAX).step(1000)
+    File.write(THROTTLE, i)
+    check_motors_are_off
+    sleep 0.005
+  end
+
+  puts("Check that flipping gear to 1 while throttle is high does nothing")
+  # (motors should still be off, LED should still be off)
+  File.write(GEAR, GEAR_ON)
+  sleep 0.015
+  check_motors_are_off
+  i = THROTTLE_MAX
+  while i > THROTTLE_MID
+    i -= 1000
+    File.write(THROTTLE, i)
+    check_motors_are_off
+    check_led 0
+    sleep 0.005
+  end
+
+  # (swtich GEAR back to off and bring throttle off)
+  File.write(GEAR, GEAR_OFF)
+  File.write(THROTTLE, THROTTLE_MIN)
+
+  puts("Check that the LED turns on when gear is flipped on")
+  # (motors should still be off because our throttle is low)
+  File.write(GEAR, GEAR_ON)
+  sleep 0.020
+  check_led 1
+  check_motors_are_off
+
+  puts("Check that motors turn on")
+  File.write(THROTTLE, THROTTLE_MID)
+  averages = get_motor_averages
+  average = (averages[0] + averages[1] + averages[2] + averages[3])/4
+  puts averages, "(#{average})"
+  assert average.between?(THROTTLE_EIGHTH, MOTOR_MAX)
+
+  # Check that gear switch kills the motors
+  # (and that light goes off)
+  File.write(GEAR, GEAR_OFF)
+  sleep 0.040
+  check_motors_are_off
+  check_led 0
+
+  # (Bring the RC throttle back down)
+  File.write(THROTTLE, THROTTLE_MIN)
+
+  # Check that we can resume flight
+  File.write(GEAR, GEAR_ON)
+  sleep 0.040
+  check_led 1
+
+  sleep 1
+  puts "All safety checks passed."
+
+ensure
+
+  Process.kill(9, quad)
+
+end
+
diff --git a/quad/scripts/test_uart_comm.py b/quad/scripts/tests/test_uart_comm.py
similarity index 100%
rename from quad/scripts/test_uart_comm.py
rename to quad/scripts/tests/test_uart_comm.py
diff --git a/quad/scripts/tests/test_unix_uart.rb b/quad/scripts/tests/test_unix_uart.rb
new file mode 100644
index 0000000000000000000000000000000000000000..6621744e33f2a789bf191b33a58586b769f533f4
--- /dev/null
+++ b/quad/scripts/tests/test_unix_uart.rb
@@ -0,0 +1,68 @@
+#!/usr/bin/env ruby
+
+
+# UART test
+#
+# This test is pretty simple, just a UART smoke test, using
+# the debug callback on the quad
+
+GEAR_ON = 170800
+GEAR_OFF = 118300
+
+GEAR = "virt-quad-fifos/pwm-input-gear"
+UART_RX = "virt-quad-fifos/uart-rx"
+UART_TX = "virt-quad-fifos/uart-tx"
+
+require 'test/unit/assertions'
+require 'thread'
+include Test::Unit::Assertions
+
+script_dir = File.expand_path(File.dirname(__FILE__))
+bin_dir = script_dir + "/../../bin/"
+Dir.chdir(bin_dir)
+
+# Start virtual quad
+quad = Process.spawn("./virt-quad")
+
+sleep 1
+
+#################
+#  Begin Tests
+#################
+
+begin
+
+  # Flip gear on
+  File.write(GEAR, GEAR_ON)
+  sleep 0.015
+
+  for j in 1..10
+    # Send a debug command
+    File.write(UART_RX, [0xBE, 1, 0, 0, 0, 0, 0, 0xBF].pack("CCCCCCCC"))
+
+    fifo = File.open(UART_TX)
+    msg = []
+    for i in 1..7
+      sleep 0.010
+      msg.push(fifo.read(1))
+    end
+    length = msg[5..7].join().unpack("S")[0]
+    msg = []
+    for i in 1..length
+      sleep 0.010
+      msg.push(fifo.read(1))
+    end
+    fifo.close
+
+    puts msg.join()
+    assert_equal(msg.join().force_encoding("UTF-8"), "Packets received: #{j}")
+  end
+
+  puts "Basic UART test passed."
+
+ensure
+
+  Process.kill(9, quad)
+
+end
+
diff --git a/quad/scripts/test_zybo_uart.py b/quad/scripts/tests/test_zybo_uart.py
similarity index 100%
rename from quad/scripts/test_zybo_uart.py
rename to quad/scripts/tests/test_zybo_uart.py
diff --git a/quad/scripts/uart_stress_tests.py b/quad/scripts/tests/uart_stress_tests.py
similarity index 100%
rename from quad/scripts/uart_stress_tests.py
rename to quad/scripts/tests/uart_stress_tests.py
diff --git a/quad/scripts/uart_comm_listen.py b/quad/scripts/uart_comm_listen.py
deleted file mode 100755
index 0a251b5df409f1ffcb1dfc121b8efc793a1ee220..0000000000000000000000000000000000000000
--- a/quad/scripts/uart_comm_listen.py
+++ /dev/null
@@ -1,28 +0,0 @@
-#!/usr/local/bin/python3.6
-
-import sys
-import time
-
-import serial
-
-def read_packet(ser):
-    header = ser.read(7)
-    length = int.from_bytes(header[5:7], byteorder='little')
-    data = ser.read(length)
-    checksum = ser.read()
-    return data
-
-if __name__ == '__main__':
-    with serial.Serial('/dev/ttyUSB0', 921600, timeout=5) as ser:
-        i = 0
-        while True:
-            ser.reset_input_buffer()
-            time.sleep(0.05)
-            while ser.in_waiting != 0:
-                resp = read_packet(ser)
-                elapsed = int.from_bytes(resp[0:3], byteorder='little')
-                processed = int.from_bytes(resp[4:7], byteorder='little')
-                print("{} {} {}".format(i, elapsed, processed))
-                i += 1
-            ser.flush()
-
diff --git a/quad/scripts/uart_comm_send.py b/quad/scripts/uart_comm_send.py
deleted file mode 100755
index 430a6b2874232192be2a6d79436eb1c4807e5115..0000000000000000000000000000000000000000
--- a/quad/scripts/uart_comm_send.py
+++ /dev/null
@@ -1,35 +0,0 @@
-#!/usr/local/bin/python3.6
-
-import sys
-import time
-
-import serial
-
-def create_msg(main_type, subtype, msg_id, data):
-    msg = bytes()
-    msg += b'\xBE'
-    msg += main_type.to_bytes(1, 'little')
-    msg += subtype.to_bytes(1, 'little')
-    msg += msg_id.to_bytes(2, 'little')
-    msg += len(data).to_bytes(2, 'little')
-    msg += data
-    
-    checksum = 0
-    for b in msg:
-        checksum ^= b
-    msg += checksum.to_bytes(1, 'little')
-    return msg
-
-def create_test_packet(size=8):
-    data = bytes((i % 256 for i in range(size)))
-    return create_msg(0, 2, 0, data)
-
-if __name__ == '__main__':
-    with serial.Serial('/dev/ttyUSB0', 921600, timeout=5) as ser:
-        for i in range(5):
-            ser.reset_input_buffer()
-            data = bytes.fromhex('be040002001c0002000000d80471be5732703f9d16093f8bf7a03d0586ab3d006d3a40c1')
-            #ser.write(create_test_packet(24))
-            ser.write(data)
-            #ser.flush()
-            #time.sleep(0.5)
diff --git a/quad/scripts/build_zybo.sh b/quad/scripts/xsdk/build_zybo.sh
similarity index 100%
rename from quad/scripts/build_zybo.sh
rename to quad/scripts/xsdk/build_zybo.sh
diff --git a/quad/scripts/clean_xsdk_workspace.sh b/quad/scripts/xsdk/clean_xsdk_workspace.sh
similarity index 100%
rename from quad/scripts/clean_xsdk_workspace.sh
rename to quad/scripts/xsdk/clean_xsdk_workspace.sh
diff --git a/quad/scripts/create_zybo_boot.sh b/quad/scripts/xsdk/create_zybo_boot.sh
similarity index 100%
rename from quad/scripts/create_zybo_boot.sh
rename to quad/scripts/xsdk/create_zybo_boot.sh
diff --git a/quad/scripts/old_quad_build.sh b/quad/scripts/xsdk/old_quad_build.sh
similarity index 100%
rename from quad/scripts/old_quad_build.sh
rename to quad/scripts/xsdk/old_quad_build.sh
diff --git a/quad/src/quad_app/callbacks.c b/quad/src/quad_app/callbacks.c
index 8acc3cc7c77cf97b3e3d4365d8de546baa382779..cb99d83ad9d108e297121666df94159e96fbaedd 100644
--- a/quad/src/quad_app/callbacks.c
+++ b/quad/src/quad_app/callbacks.c
@@ -36,8 +36,11 @@ int cb_debug(struct modular_structs *structs, struct metadata *meta, unsigned ch
   * counts the number of packet logs.
   */
 int cb_packetlog(struct modular_structs* structs, struct metadata *meta, u8 *data, u16 length) {
+	char buf[64];
 	n_msg_received += 1;
 	total_payload_received += length;
+	int len = sprintf(buf, "Packets received: %d", n_msg_received);
+	send_data(&structs->hardware_struct.uart, PACKETLOG_ID, 0, buf, len);
 	return 0;
 }
 
diff --git a/quad/src/quad_app/controllers.h b/quad/src/quad_app/controllers.h
index 33b6237957b49d4253c3fec7c26b917cdfe3f74e..1e12c7590e5fe661b81a1bca31b7398da3e457d3 100644
--- a/quad/src/quad_app/controllers.h
+++ b/quad/src/quad_app/controllers.h
@@ -102,6 +102,9 @@
 #define min 100000
 #define max 200000
 
+#define MOTOR_MIN 100000
+#define MOTOR_MAX 200000
+
 void filter_PWMs(int* mixer);
 void PWMS_to_Aero(int* PWMs, int* aero); // <= javey: unused
 void Aero_to_PWMS(int* PWMs, int* aero);
diff --git a/quad/src/quad_app/hw_iface.h b/quad/src/quad_app/hw_iface.h
index bbd6bb6fc14171d0f506151a1b87bffb9b869b21..bde0aa3f8170f465e8ab33be4576804850abfee8 100644
--- a/quad/src/quad_app/hw_iface.h
+++ b/quad/src/quad_app/hw_iface.h
@@ -1,6 +1,20 @@
 #ifndef HW_IFACE_H
 #define HW_IFACE_H
 
+/**
+ * Hardware Interfaces
+ *
+ * These interfaces are used to accomplish separation between the application
+ * layer and the hardware layer in the program that runs on the quadcopter.
+ *
+ * NOTE:
+ * If you wound up here after following some IDE function declaration trail,
+ * you've hit the end of the application layer. Go to the location of the
+ * hardware layer appropriate for your circumstance:p
+ * ../../xsdk_worksapce/modular_quad_pid -> running quad_app on the Zybo
+ * ../virt_quad -> running quad_app in a Unix environment
+ */
+
 struct I2CDriver {
   void *state;
   int (*reset)(struct I2CDriver *self);
diff --git a/quad/src/quad_app/initialize_components.c b/quad/src/quad_app/initialize_components.c
index 858c0e9ffb80525c72c04726698a98eac45b518f..57d3e2b96eaef8951425652c4fb61ac5ec4b1529 100644
--- a/quad/src/quad_app/initialize_components.c
+++ b/quad/src/quad_app/initialize_components.c
@@ -7,6 +7,7 @@
  
 #include "initialize_components.h"
 #include "communication.h"
+#include "controllers.h"
 #include "sensor.h"
 #include "iic_utils.h"
 
@@ -83,6 +84,12 @@ int init_structs(modular_structs_t *structs) {
   struct PWMOutputDriver *pwm_outputs = &structs->hardware_struct.pwm_outputs;
   if (pwm_outputs->reset(pwm_outputs)) return -1;
 
+  // Set motor outputs to off
+  int i;
+  for (i = 0; i < 4; i += 1) {
+    pwm_outputs->write(pwm_outputs, i, MOTOR_MIN);
+  }
+
   // Initialize sensors
 
   //manual flight mode
diff --git a/quad/src/quad_app/quad_app.c b/quad/src/quad_app/quad_app.c
index 49386e9b9a689e99b979dafab743a4e3e57125e3..1e301732814d8cf7faba2984ca192c99387afb00 100644
--- a/quad/src/quad_app/quad_app.c
+++ b/quad/src/quad_app/quad_app.c
@@ -18,9 +18,6 @@
 #include "communication.h"
 #include "mio7_led.h"
 
-//#define BENCH_TEST
-//#define UART_BENCHMARK
-
 int quad_main(int (*setup_hardware)(hardware_t *hardware_struct))
 {
 	// Structures to be used throughout
@@ -38,10 +35,8 @@ int quad_main(int (*setup_hardware)(hardware_t *hardware_struct))
 		return -1;
 	}
 
-#ifndef BENCH_TEST
 	// Loops to make sure the quad is responding correctly before starting the control loop
 	protection_loops(&structs);
-#endif
 
 	int last_kill_condition = kill_condition(&(structs.user_input_struct));
 
@@ -55,23 +50,8 @@ int quad_main(int (*setup_hardware)(hardware_t *hardware_struct))
 
 		// Process all received data
 
-#ifdef UART_BENCHMARK
-		usleep(500000);
-		u32 start_time = timer_get_count();
-#endif
 		process_received(&structs);
 
-#ifdef UART_BENCHMARK
-		u32 end_time = timer_get_count();
-		u32 duration = end_time - start_time;
-		u32 packets_processed = uart_buff_packets_processed();
-		u32 data[2];
-		data[0] = duration;
-		data[1] = packets_processed;
-		send_data(0, 0, 0, (char *) &data, 8);
-#endif
-
-#ifndef BENCH_TEST
 		// Get the user input and put it into user_input_struct
 		get_user_input(&(structs.hardware_struct), &(structs.log_struct), &(structs.user_input_struct));
 
@@ -94,7 +74,7 @@ int quad_main(int (*setup_hardware)(hardware_t *hardware_struct))
 		}
 		// update the GUI
 		update_GUI(&(structs.log_struct));
-#endif
+
 		// Processing of loop timer at the end of the control loop
 		timer_end_loop(&(structs.log_struct));
 
diff --git a/quad/src/quad_app/util.c b/quad/src/quad_app/util.c
index c021fef37cc1daeb6adafe20a75b25e1ec99e558..2f1512a0e407385648f442083b2e5152b3fa8dac 100644
--- a/quad/src/quad_app/util.c
+++ b/quad/src/quad_app/util.c
@@ -68,10 +68,10 @@ int read_flap(int flap)
  * Turns off the motors
  */
 void kill_motors(struct PWMOutputDriver *pwm_outputs) {
-  pwm_outputs->write(pwm_outputs, 0, 0);
-  pwm_outputs->write(pwm_outputs, 1, 0);
-  pwm_outputs->write(pwm_outputs, 2, 0);
-  pwm_outputs->write(pwm_outputs, 3, 0);
+  pwm_outputs->write(pwm_outputs, 0, MOTOR_MIN);
+  pwm_outputs->write(pwm_outputs, 1, MOTOR_MIN);
+  pwm_outputs->write(pwm_outputs, 2, MOTOR_MIN);
+  pwm_outputs->write(pwm_outputs, 3, MOTOR_MIN);
 }
 
 int build_int(u8 *buff) {
diff --git a/quad/src/virt_quad/Makefile b/quad/src/virt_quad/Makefile
index 008468333bac4f1e9bc5387671111648b48f5a24..acf6d27cbbea07d639fadfda691a01d6edd89fb7 100644
--- a/quad/src/virt_quad/Makefile
+++ b/quad/src/virt_quad/Makefile
@@ -1,7 +1,7 @@
 TOP=../..
 
 NAME = virt-quad
-REQLIBS = -Wl,--whole-archive -lquad_app -Wl,--no-whole-archive -lcommands -lgraph_blocks -lcomputation_graph -lm
+REQLIBS = -Wl,--whole-archive -lquad_app -Wl,--no-whole-archive -lcommands -lgraph_blocks -lcomputation_graph -lm -lpthread
 
 include $(TOP)/executable.mk
 
diff --git a/quad/src/virt_quad/hw_impl_unix_i2c.c b/quad/src/virt_quad/hw_impl_unix_i2c.c
index 09ab43c8b83b82d60dff7623a31efb1d29c3fd60..9de9815c2f7a941b0b553df525a3436f069ae0c4 100644
--- a/quad/src/virt_quad/hw_impl_unix_i2c.c
+++ b/quad/src/virt_quad/hw_impl_unix_i2c.c
@@ -1,6 +1,59 @@
 #include "hw_impl_unix.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include "iic_utils.h"
+
+void * update_i2c_input_cache(void *);
+
+union val {
+  unsigned char b[2];
+  unsigned short s;
+};
+
+static char *input_names[6];
+static int fifos[6];
+static union val cache[6];
+
+static short last_dev;
+static short last_reg;
+static short last_val;
+
+static int zero = 0;
+static int one = 1;
+static int two = 2;
+static int three = 3;
+static int four = 4;
+static int five = 5;
+
+static pthread_t worker;
 
 int unix_i2c_reset(struct I2CDriver *self) {
+  input_names[0] = "i2c-mpu-accel-x";
+  input_names[1] = "i2c-mpu-accel-y";
+  input_names[2] = "i2c-mpu-accel-z";
+  input_names[3] = "i2c-mpu-gryo-x";
+  input_names[4] = "i2c-mpu-gryo-y";
+  input_names[5] = "i2c-mpu-gyro-z";
+
+  mkdir(VIRT_QUAD_FIFOS_DIR, 0777);
+
+  // Start up worker thread whose job is to update the caches
+  pthread_create(&worker, 0, update_i2c_input_cache, &zero);
+  pthread_create(&worker, 0, update_i2c_input_cache, &one);
+  pthread_create(&worker, 0, update_i2c_input_cache, &two);
+  pthread_create(&worker, 0, update_i2c_input_cache, &three);
+  pthread_create(&worker, 0, update_i2c_input_cache, &four);
+  pthread_create(&worker, 0, update_i2c_input_cache, &five);
+
+  cache[0].s = 0;
+  cache[1].s = 0;
+  cache[2].s = 0;
+  cache[3].s = 0;
+  cache[4].s = 0;
+  cache[5].s = 0;
+
   return 0;
 }
 
@@ -8,6 +61,11 @@ int unix_i2c_write(struct I2CDriver *self,
                    unsigned short device_addr,
                    unsigned char *data,
                    unsigned int length) {
+  if (length == 2) {
+    last_dev = device_addr;
+    last_reg = data[0];
+    last_val = data[1];
+  }
   return 0;
 }
 
@@ -15,5 +73,53 @@ int unix_i2c_read(struct I2CDriver *self,
                   unsigned short device_addr,
                   unsigned char *buff,
                   unsigned int length) {
+  if (last_dev != device_addr) {
+    return -1;
+  }
+
+  switch (device_addr) {
+  case MPU9150_DEVICE_ADDR:
+    if (last_reg == ACCEL_GYRO_BASE_ADDR) {
+      buff[0] = cache[0].b[0];
+      buff[1] = cache[0].b[1];
+      buff[2] = cache[1].b[0];
+      buff[3] = cache[1].b[1];
+      buff[4] = cache[2].b[0];
+      buff[5] = cache[2].b[1];
+      buff[6] = 0;
+      buff[7] = 0;
+      buff[8] = cache[3].b[0];
+      buff[9] = cache[3].b[1];
+      buff[10] = cache[4].b[0];
+      buff[11] = cache[4].b[1];
+      buff[12] = cache[5].b[0];
+      buff[13] = cache[5].b[1];
+    }
+  }
   return 0;
 }
+
+void * update_i2c_input_cache(void *arg) {
+  int *cache_index = arg;
+  int i = *cache_index;
+  char buff[16];
+
+  // Setup FIFO
+  unlink(input_names[i]);
+  char fifoname[64];
+  sprintf(fifoname, "%s/%s", VIRT_QUAD_FIFOS_DIR, input_names[i]);
+  mkfifo(fifoname, 0666);
+  fifos[i] = open(fifoname, O_RDONLY);
+
+  // Block while waiting for reads
+  while (1) {
+    int bytes_read = read(fifos[i], buff, 15);
+    if (bytes_read > 0) {
+      buff[bytes_read] = '\0';
+      unsigned long val = strtoll(buff, NULL, 10);
+      cache[i].s = val;
+      printf("%s: %ld\n", input_names[i], val);
+    }
+  }
+  return NULL;
+}
diff --git a/quad/src/virt_quad/hw_impl_unix_mio7_led.c b/quad/src/virt_quad/hw_impl_unix_mio7_led.c
index f96fda029e0c0a9664be8bd81e76a93af606e7ba..6aef66752f9859faf55ec15c200e68440e6b4f7f 100644
--- a/quad/src/virt_quad/hw_impl_unix_mio7_led.c
+++ b/quad/src/virt_quad/hw_impl_unix_mio7_led.c
@@ -1,8 +1,31 @@
 #include "hw_impl_unix.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <pthread.h>
+
+void * output_cached_led();
 
 int on;
+static char *led_fifo_name;
+pthread_t worker;
 
 int unix_mio7_led_reset(struct LEDDriver *self) {
+  led_fifo_name = VIRT_QUAD_FIFOS_DIR "/mio7-led";
+
+  mkdir(VIRT_QUAD_FIFOS_DIR, 0777);
+  int i;
+  for (i = 0; i < 4; i += 1) {
+    unlink(led_fifo_name);
+    mkfifo(led_fifo_name, 0666);
+  }
+
+  // Start up worker thread whose job is to update the caches
+  pthread_create(&worker, 0, output_cached_led, NULL);
+
   return 0;
 }
 
@@ -21,3 +44,14 @@ int unix_mio7_led_turn_off(struct LEDDriver *self) {
   }
   return 0;
 }
+
+void * output_cached_led() {
+  char buff[16];
+  while (1) {
+    int fifo = open(led_fifo_name, O_WRONLY);
+    sprintf(buff, "%d\n", on);
+    write(fifo, buff, strlen(buff));
+    close(fifo);
+    usleep(500); // don't spam the reader
+  }
+}
diff --git a/quad/src/virt_quad/hw_impl_unix_pwm_input.c b/quad/src/virt_quad/hw_impl_unix_pwm_input.c
index c49e466ce0470f60fda3bff49874e298e606380b..b487461095d1a900c16ea2f515454c650d197f3f 100644
--- a/quad/src/virt_quad/hw_impl_unix_pwm_input.c
+++ b/quad/src/virt_quad/hw_impl_unix_pwm_input.c
@@ -3,27 +3,29 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
+#include <pthread.h>
 
-static char *pwms[6];
+void * update_input_cache();
+
+static char *input_names[6];
 static int fifos[6];
 static unsigned long cache[6];
+pthread_t worker;
 
 int unix_pwm_input_reset(struct PWMInputDriver *self) {
-  pwms[0] = "pwm-input-throttle";
-  pwms[1] = "pwm-input-roll";
-  pwms[2] = "pwm-input-pitch";
-  pwms[3] = "pwm-input-yaw";
-  pwms[4] = "pwm-input-gear";
-  pwms[5] = "pwm-input-flap";
+  input_names[0] = "pwm-input-throttle";
+  input_names[1] = "pwm-input-roll";
+  input_names[2] = "pwm-input-pitch";
+  input_names[3] = "pwm-input-yaw";
+  input_names[4] = "pwm-input-gear";
+  input_names[5] = "pwm-input-flap";
 
   mkdir(VIRT_QUAD_FIFOS_DIR, 0777);
+
+  // Start up worker thread whose job is to update the caches
   int i;
   for (i = 0; i < 6; i += 1) {
-    unlink(pwms[i]);
-    char fifoname[64];
-    sprintf(fifoname, "%s/%s", VIRT_QUAD_FIFOS_DIR, pwms[i]);
-    mkfifo(fifoname, 0666);
-    fifos[i] = open(fifoname, O_RDONLY | O_NONBLOCK);
+    pthread_create(&worker, 0, update_input_cache, &i);
   }
 
   cache[0] = THROTTLE_MIN;
@@ -34,7 +36,7 @@ int unix_pwm_input_reset(struct PWMInputDriver *self) {
   cache[5] = FLAP_1;
 
   for (i = 0; i < 6; i += 1) {
-    printf("%s: %d\n", pwms[i], cache[i]);
+    printf("%s: %d\n", input_names[i], cache[i]);
   }
 
   return 0;
@@ -44,17 +46,36 @@ int unix_pwm_input_read(struct PWMInputDriver *self,
                         unsigned int channel,
                         unsigned long *pulse_width_us) {
 
+  *pulse_width_us = cache[channel];
+  return 0;
+}
+
+void * update_input_cache(void *arg) {
+  int *cache_index = arg;
+  int i = *cache_index;
   char buff[16];
-  int bytes_read = read(fifos[channel], buff, 15);
-  if (bytes_read >= 6) {
-    buff[bytes_read] = '\0';
-    unsigned long val = strtoll(buff, NULL, 10);
-    if (val < max && val > min) {
-      cache[channel] = val;
-      printf("%s: %d\n", pwms[channel], val);
+
+  // Setup FIFO
+  unlink(input_names[i]);
+  char fifoname[64];
+  sprintf(fifoname, "%s/%s", VIRT_QUAD_FIFOS_DIR, input_names[i]);
+  mkfifo(fifoname, 0666);
+  fifos[i] = open(fifoname, O_RDONLY);
+
+  // Block while waiting for reads
+  while (1) {
+    int bytes_read = read(fifos[i], buff, 15);
+    if (bytes_read > 0) {
+      buff[bytes_read] = '\0';
+      unsigned long val = strtoll(buff, NULL, 10);
+      if (val < max && val > min) {
+	cache[i] = val;
+	printf("%s: %d\n", input_names[i], val);
+      }
+      else {
+	printf("%s: Bad value - input not received\n", input_names[i]);
+      }
     }
   }
-
-  *pulse_width_us = cache[channel];
-  return 0;
+  return NULL;
 }
diff --git a/quad/src/virt_quad/hw_impl_unix_pwm_output.c b/quad/src/virt_quad/hw_impl_unix_pwm_output.c
index 3bd757f96d1c146d5bd3e1724dea0e2fe8222618..71b89c4f4b0d8465780f39a77267301aaafc39cc 100644
--- a/quad/src/virt_quad/hw_impl_unix_pwm_output.c
+++ b/quad/src/virt_quad/hw_impl_unix_pwm_output.c
@@ -3,8 +3,19 @@
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <string.h>
+#include <pthread.h>
+#include <unistd.h>
+
+void * output_cache();
 
 static char *output_pwms[4];
+static unsigned long cache[4];
+pthread_t worker;
+
+static int zero = 0;
+static int one = 1;
+static int two = 2;
+static int three = 3;
 
 int unix_pwm_output_reset(struct PWMOutputDriver *self) {
   output_pwms[0] = VIRT_QUAD_FIFOS_DIR "/pwm-output-motor1";
@@ -13,11 +24,12 @@ int unix_pwm_output_reset(struct PWMOutputDriver *self) {
   output_pwms[3] = VIRT_QUAD_FIFOS_DIR "/pwm-output-motor4";
 
   mkdir(VIRT_QUAD_FIFOS_DIR, 0777);
-  int i;
-  for (i = 0; i < 4; i += 1) {
-    unlink(output_pwms[i]);
-    mkfifo(output_pwms[i], 0666);
-  }
+
+  // Start up worker thread whose job is to update the caches
+  pthread_create(&worker, 0, output_cache, &zero);
+  pthread_create(&worker, 0, output_cache, &one);
+  pthread_create(&worker, 0, output_cache, &two);
+  pthread_create(&worker, 0, output_cache, &three);
 
   return 0;
 }
@@ -25,12 +37,29 @@ int unix_pwm_output_reset(struct PWMOutputDriver *self) {
 int unix_pwm_output_write(struct PWMOutputDriver *self,
                           unsigned int channel,
                           unsigned long pulse_width_us) {
-  char buff[16];
-  int fifo = open(output_pwms[channel], O_WRONLY | O_NONBLOCK);
-  if (fifo >= 0) {
-    sprintf(buff, "%d\0", pulse_width_us);
-    int bytes_read = write(fifo, buff, strlen(buff));
+  if (cache[channel] != pulse_width_us) {
+    printf("%s: %ld\n", output_pwms[channel], pulse_width_us);
   }
-  close(fifo);
+  cache[channel] = pulse_width_us;
   return 0;
 }
+
+void * output_cache(void *arg) {
+  int *output_index = arg;
+  char buff[16];
+  int i = *output_index;
+
+  // Setup FIFO
+  unlink(output_pwms[i]);
+  mkfifo(output_pwms[i], 0666);
+
+  // Block while waiting for someone to listen
+  while (1) {
+    int fifo = open(output_pwms[i], O_WRONLY);
+    sprintf(buff, "%ld\n", cache[i]);
+    write(fifo, buff, strlen(buff));
+    close(fifo);
+    usleep(500); // don't spam the reader
+  }
+  return NULL;
+}
diff --git a/quad/src/virt_quad/hw_impl_unix_uart.c b/quad/src/virt_quad/hw_impl_unix_uart.c
index 27bdfcb8d2c0271ea8a9f4d0c22e131519e866ef..e39fbedfc06f93a75a8e682cb44d81be98f790bf 100644
--- a/quad/src/virt_quad/hw_impl_unix_uart.c
+++ b/quad/src/virt_quad/hw_impl_unix_uart.c
@@ -1,70 +1,44 @@
 #include "hw_impl_unix.h"
-#include <sys/types.h>       
-#include <sys/socket.h>
 #include <stdio.h>
-#include <sys/un.h>
-#include <sys/ioctl.h>
-#include <err.h>
-#include <netinet/in.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
 
-#define DEFAULT_SOCKET "../../groundStation/virtquad.socket"
-#define SOCKET_ENV "VIRT_QUAD_SOCKET"
-
-static int backendSocket;
-static int client;
+static char *fifo_full_name_rx;
+static char *fifo_full_name_tx;
+static int fifo_rx;
 
 int unix_uart_reset(struct UARTDriver *self) {
-	char * backend_socket_path = DEFAULT_SOCKET;
-	if (getenv(SOCKET_ENV)) {
-		backend_socket_path = getenv(SOCKET_ENV);
-	}
-
-	/* Unlink if it exists */
-	unlink(backend_socket_path);
-	printf("using socket '%s'\n", backend_socket_path);
-
-	/* Create socket */
-	backendSocket = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0);
+  fifo_full_name_rx = VIRT_QUAD_FIFOS_DIR "/uart-rx";
+  fifo_full_name_tx = VIRT_QUAD_FIFOS_DIR "/uart-tx";
 
+  char fifoname[64];
+  mkdir(VIRT_QUAD_FIFOS_DIR, 0777);
 
-	/* Create sockaddr and bind */
-	struct sockaddr_un sa;
-	sa.sun_family = AF_UNIX;
-	strncpy(sa.sun_path, backend_socket_path, strlen(backend_socket_path));
-	sa.sun_path[strlen(backend_socket_path)+1] = '\0';
-	if (bind(backendSocket, (struct sockaddr *) &sa, sizeof(sa))) {
-		err(-1, "bind");
-	}
+  unlink(fifo_full_name_rx);
+  mkfifo(fifo_full_name_rx, 0666);
+  fifo_rx = open(fifo_full_name_rx, O_RDONLY | O_NONBLOCK);
 
-	/* Listen */
-	if (listen(backendSocket, 1)) {
-		err(-1, "listen");
-	}
+  unlink(fifo_full_name_tx);
+  mkfifo(fifo_full_name_tx, 0666);
 
-	printf("Waiting for backend to connect\n");
-
-	while (1) {
-		client = accept(backendSocket, NULL, NULL);
-		if (client > 0)
-			break;
-	}
-	printf("backend connection found on socket %d.\n", client);
   return 0;
 }
 
 int unix_uart_write(struct UARTDriver *self, unsigned char c) {
-	send(client, &c, 1, MSG_DONTWAIT);
-	return 0;
+  int fifo = open(fifo_full_name_tx, O_WRONLY | O_NONBLOCK);
+  if (fifo >= 0) {
+    printf("%s: %x\n", "uart-tx", c);
+    write(fifo, &c, 1);
+  }
+  close(fifo);
+  return 0;
 }
 
 int unix_uart_read(struct UARTDriver *self, unsigned char *c) {
-	int bytes_available;
-	ioctl(client,FIONREAD,&bytes_available);
-	
-	if (bytes_available > 0) {
-		int bytes = recv(client, c, 1, 0);
-		return 0;
-	} else {
-		return 1;
-	}
-}
\ No newline at end of file
+  int err = read(fifo_rx, c, 1);
+  if (err > 0) {
+    printf("%s: %x\n", "uart-rx", *c);
+  }
+  return err <= 0;
+}
diff --git a/quad/xsdk_workspace/README.md b/quad/xsdk_workspace/README.md
index 7e1cd0af615127935c4e2cec8b727b0ca1d5ef66..83a1f07277af48ac235145531a7032ffa58c1b82 100644
--- a/quad/xsdk_workspace/README.md
+++ b/quad/xsdk_workspace/README.md
@@ -1 +1,21 @@
-# Branch for hardware/software designs for Quadcopter
+# XSDK Workspace
+
+This directory is reserved for XSDK projects.
+
+## Setup
+XSDK, being based on Ecplise, is rather fragile, so do yourself a favor
+and read this section so things get setup correctly.
+
+1. When you first open eclipse, select this directory, xsdk_workspace, as
+   your workspace (see what we did there?).
+
+2. When you get to your workbench, your project pane should be empty. To
+   add these projects, right-click on the project pane, and click on something
+   like "import projects".
+
+  1. Select "Import Existing Projects" (whereever that is)
+  2. And then select the xsd_workspace as the folder where you want to import
+     projects. Add them all.
+
+3. If things are going swimmingly, then you should be able to build everyhing
+   and be off on your merry embedded endeavors.
\ No newline at end of file
diff --git a/quad/xsdk_workspace/modular_quad_pid/src/queue.c b/quad/xsdk_workspace/modular_quad_pid/src/queue.c
deleted file mode 120000
index 6b67b81f59670abf26db748c7d699d766c909ae8..0000000000000000000000000000000000000000
--- a/quad/xsdk_workspace/modular_quad_pid/src/queue.c
+++ /dev/null
@@ -1 +0,0 @@
-../../../../lib/queue/queue.c
\ No newline at end of file
diff --git a/quad/xsdk_workspace/modular_quad_pid/src/queue.h b/quad/xsdk_workspace/modular_quad_pid/src/queue.h
deleted file mode 120000
index b9524b35495f9ec9badf16668b107d0f72d38556..0000000000000000000000000000000000000000
--- a/quad/xsdk_workspace/modular_quad_pid/src/queue.h
+++ /dev/null
@@ -1 +0,0 @@
-../../../../lib/queue/queue.h
\ No newline at end of file
diff --git a/quad/xsdk_workspace/modular_quad_pid/.cproject b/quad/xsdk_workspace/real_quad/.cproject
similarity index 98%
rename from quad/xsdk_workspace/modular_quad_pid/.cproject
rename to quad/xsdk_workspace/real_quad/.cproject
index f17eeafddf9cc8821dcdd8ee953460b8a2f47b55..e787d278c421ad198fca83ab658206e3fca10d6c 100644
--- a/quad/xsdk_workspace/modular_quad_pid/.cproject
+++ b/quad/xsdk_workspace/real_quad/.cproject
@@ -27,7 +27,7 @@
 							<tool id="xilinx.gnu.arm.c.toolchain.compiler.debug.177835003" name="ARM gcc compiler" superClass="xilinx.gnu.arm.c.toolchain.compiler.debug">
 								<option defaultValue="gnu.c.optimization.level.none" id="xilinx.gnu.compiler.option.optimization.level.1900496019" name="Optimization Level" superClass="xilinx.gnu.compiler.option.optimization.level" value="gnu.c.optimization.level.none" valueType="enumerated"/>
 								<option id="xilinx.gnu.compiler.option.debugging.level.1207856754" name="Debug Level" superClass="xilinx.gnu.compiler.option.debugging.level" value="gnu.c.debugging.level.max" valueType="enumerated"/>
-								<option id="xilinx.gnu.compiler.inferred.swplatform.includes.2123463819" name="Software Platform Include Path" superClass="xilinx.gnu.compiler.inferred.swplatform.includes" valueType="includePath"/>
+								<option id="xilinx.gnu.compiler.inferred.swplatform.includes.2123463819" name="Software Platform Include Path" superClass="xilinx.gnu.compiler.inferred.swplatform.includes"/>
 								<option id="xilinx.gnu.compiler.symbols.defined.1696008720" name="Defined symbols (-D)" superClass="xilinx.gnu.compiler.symbols.defined"/>
 								<option id="xilinx.gnu.compiler.dircategory.includes.1211006365" name="Include Paths" superClass="xilinx.gnu.compiler.dircategory.includes" valueType="includePath">
 									<listOptionValue builtIn="false" value="../../system_bsp/ps7_cortexa9_0/include"/>
@@ -114,11 +114,11 @@
 								</option>
 								<option id="xilinx.gnu.compiler.dircategory.includes.1873624761" name="Include Paths" superClass="xilinx.gnu.compiler.dircategory.includes" valueType="includePath">
 									<listOptionValue builtIn="false" value="../../system_bsp/ps7_cortexa9_0/include"/>
-									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/modular_quad_pid/ext/computation_graph}&quot;"/>
-									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/modular_quad_pid/ext/quad_app}&quot;"/>
-									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/modular_quad_pid/ext/queue}&quot;"/>
-									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/modular_quad_pid/ext/commands}&quot;"/>
-									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/modular_quad_pid/ext/graph_blocks}&quot;"/>
+									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/real_quad/ext/computation_graph}&quot;"/>
+									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/real_quad/ext/quad_app}&quot;"/>
+									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/real_quad/ext/queue}&quot;"/>
+									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/real_quad/ext/commands}&quot;"/>
+									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/real_quad/ext/graph_blocks}&quot;"/>
 								</option>
 								<inputType id="xilinx.gnu.arm.c.compiler.input.846429887" name="C source files" superClass="xilinx.gnu.arm.c.compiler.input"/>
 							</tool>
diff --git a/quad/xsdk_workspace/modular_quad_pid/.gitignore b/quad/xsdk_workspace/real_quad/.gitignore
similarity index 100%
rename from quad/xsdk_workspace/modular_quad_pid/.gitignore
rename to quad/xsdk_workspace/real_quad/.gitignore
diff --git a/quad/xsdk_workspace/modular_quad_pid/.project b/quad/xsdk_workspace/real_quad/.project
similarity index 98%
rename from quad/xsdk_workspace/modular_quad_pid/.project
rename to quad/xsdk_workspace/real_quad/.project
index 734130fb55d695ee28de0b41cc6b8f0f4bccd05e..656e663a791cc120b54900b1a44f258822da422b 100644
--- a/quad/xsdk_workspace/modular_quad_pid/.project
+++ b/quad/xsdk_workspace/real_quad/.project
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <projectDescription>
-	<name>modular_quad_pid</name>
+	<name>real_quad</name>
 	<comment></comment>
 	<projects>
 		<project>system_bsp</project>
@@ -53,7 +53,7 @@
 	</linkedResources>
 	<filteredResources>
 		<filter>
-			<id>1489164394345</id>
+			<id>0</id>
 			<name></name>
 			<type>10</type>
 			<matcher>
diff --git a/quad/xsdk_workspace/modular_quad_pid/Debug/ext/commands/subdir.mk b/quad/xsdk_workspace/real_quad/Debug/ext/commands/subdir.mk
similarity index 100%
rename from quad/xsdk_workspace/modular_quad_pid/Debug/ext/commands/subdir.mk
rename to quad/xsdk_workspace/real_quad/Debug/ext/commands/subdir.mk
diff --git a/quad/xsdk_workspace/modular_quad_pid/Debug/ext/computation_graph/subdir.mk b/quad/xsdk_workspace/real_quad/Debug/ext/computation_graph/subdir.mk
similarity index 100%
rename from quad/xsdk_workspace/modular_quad_pid/Debug/ext/computation_graph/subdir.mk
rename to quad/xsdk_workspace/real_quad/Debug/ext/computation_graph/subdir.mk
diff --git a/quad/xsdk_workspace/modular_quad_pid/Debug/ext/graph_blocks/subdir.mk b/quad/xsdk_workspace/real_quad/Debug/ext/graph_blocks/subdir.mk
similarity index 100%
rename from quad/xsdk_workspace/modular_quad_pid/Debug/ext/graph_blocks/subdir.mk
rename to quad/xsdk_workspace/real_quad/Debug/ext/graph_blocks/subdir.mk
diff --git a/quad/xsdk_workspace/modular_quad_pid/Debug/ext/quad_app/subdir.mk b/quad/xsdk_workspace/real_quad/Debug/ext/quad_app/subdir.mk
similarity index 100%
rename from quad/xsdk_workspace/modular_quad_pid/Debug/ext/quad_app/subdir.mk
rename to quad/xsdk_workspace/real_quad/Debug/ext/quad_app/subdir.mk
diff --git a/quad/xsdk_workspace/modular_quad_pid/Debug/ext/queue/subdir.mk b/quad/xsdk_workspace/real_quad/Debug/ext/queue/subdir.mk
similarity index 100%
rename from quad/xsdk_workspace/modular_quad_pid/Debug/ext/queue/subdir.mk
rename to quad/xsdk_workspace/real_quad/Debug/ext/queue/subdir.mk
diff --git a/quad/xsdk_workspace/modular_quad_pid/Debug/makefile b/quad/xsdk_workspace/real_quad/Debug/makefile
similarity index 100%
rename from quad/xsdk_workspace/modular_quad_pid/Debug/makefile
rename to quad/xsdk_workspace/real_quad/Debug/makefile
diff --git a/quad/xsdk_workspace/modular_quad_pid/Debug/objects.mk b/quad/xsdk_workspace/real_quad/Debug/objects.mk
similarity index 100%
rename from quad/xsdk_workspace/modular_quad_pid/Debug/objects.mk
rename to quad/xsdk_workspace/real_quad/Debug/objects.mk
diff --git a/quad/xsdk_workspace/modular_quad_pid/Debug/sources.mk b/quad/xsdk_workspace/real_quad/Debug/sources.mk
similarity index 100%
rename from quad/xsdk_workspace/modular_quad_pid/Debug/sources.mk
rename to quad/xsdk_workspace/real_quad/Debug/sources.mk
diff --git a/quad/xsdk_workspace/modular_quad_pid/Debug/src/subdir.mk b/quad/xsdk_workspace/real_quad/Debug/src/subdir.mk
similarity index 100%
rename from quad/xsdk_workspace/modular_quad_pid/Debug/src/subdir.mk
rename to quad/xsdk_workspace/real_quad/Debug/src/subdir.mk
diff --git a/quad/xsdk_workspace/modular_quad_pid/Release/ext/commands/subdir.mk b/quad/xsdk_workspace/real_quad/Release/ext/commands/subdir.mk
similarity index 100%
rename from quad/xsdk_workspace/modular_quad_pid/Release/ext/commands/subdir.mk
rename to quad/xsdk_workspace/real_quad/Release/ext/commands/subdir.mk
diff --git a/quad/xsdk_workspace/modular_quad_pid/Release/ext/computation_graph/subdir.mk b/quad/xsdk_workspace/real_quad/Release/ext/computation_graph/subdir.mk
similarity index 100%
rename from quad/xsdk_workspace/modular_quad_pid/Release/ext/computation_graph/subdir.mk
rename to quad/xsdk_workspace/real_quad/Release/ext/computation_graph/subdir.mk
diff --git a/quad/xsdk_workspace/modular_quad_pid/Release/ext/graph_blocks/subdir.mk b/quad/xsdk_workspace/real_quad/Release/ext/graph_blocks/subdir.mk
similarity index 100%
rename from quad/xsdk_workspace/modular_quad_pid/Release/ext/graph_blocks/subdir.mk
rename to quad/xsdk_workspace/real_quad/Release/ext/graph_blocks/subdir.mk
diff --git a/quad/xsdk_workspace/modular_quad_pid/Release/ext/quad_app/subdir.mk b/quad/xsdk_workspace/real_quad/Release/ext/quad_app/subdir.mk
similarity index 100%
rename from quad/xsdk_workspace/modular_quad_pid/Release/ext/quad_app/subdir.mk
rename to quad/xsdk_workspace/real_quad/Release/ext/quad_app/subdir.mk
diff --git a/quad/xsdk_workspace/modular_quad_pid/Release/ext/queue/subdir.mk b/quad/xsdk_workspace/real_quad/Release/ext/queue/subdir.mk
similarity index 100%
rename from quad/xsdk_workspace/modular_quad_pid/Release/ext/queue/subdir.mk
rename to quad/xsdk_workspace/real_quad/Release/ext/queue/subdir.mk
diff --git a/quad/xsdk_workspace/modular_quad_pid/Release/makefile b/quad/xsdk_workspace/real_quad/Release/makefile
similarity index 78%
rename from quad/xsdk_workspace/modular_quad_pid/Release/makefile
rename to quad/xsdk_workspace/real_quad/Release/makefile
index 928243ba307f1025a6d169fd83c3abad121074c9..2038c020623a84db9fa6fd917bf0a8727ed2011f 100644
--- a/quad/xsdk_workspace/modular_quad_pid/Release/makefile
+++ b/quad/xsdk_workspace/real_quad/Release/makefile
@@ -30,29 +30,29 @@ endif
 
 # Add inputs and outputs from these tool invocations to the build variables 
 ELFSIZE += \
-modular_quad_pid.elf.size \
+real_quad.elf.size \
 
 
 # All Target
-all: modular_quad_pid.elf secondary-outputs
+all: real_quad.elf secondary-outputs
 
 # Tool invocations
-modular_quad_pid.elf: $(OBJS) ../src/lscript.ld $(USER_OBJS)
+real_quad.elf: $(OBJS) ../src/lscript.ld $(USER_OBJS)
 	@echo 'Building target: $@'
 	@echo 'Invoking: ARM gcc linker'
-	arm-xilinx-eabi-gcc -Wl,-T -Wl,../src/lscript.ld -L../../system_bsp/ps7_cortexa9_0/lib -o "modular_quad_pid.elf" $(OBJS) $(USER_OBJS) $(LIBS)
+	arm-xilinx-eabi-gcc -Wl,-T -Wl,../src/lscript.ld -L../../system_bsp/ps7_cortexa9_0/lib -o "real_quad.elf" $(OBJS) $(USER_OBJS) $(LIBS)
 	@echo 'Finished building target: $@'
 	@echo ' '
 
-modular_quad_pid.elf.size: modular_quad_pid.elf
+real_quad.elf.size: real_quad.elf
 	@echo 'Invoking: ARM Print Size'
-	arm-xilinx-eabi-size modular_quad_pid.elf  |tee "modular_quad_pid.elf.size"
+	arm-xilinx-eabi-size real_quad.elf  |tee "real_quad.elf.size"
 	@echo 'Finished building: $@'
 	@echo ' '
 
 # Other Targets
 clean:
-	-$(RM) $(OBJS)$(C_DEPS)$(EXECUTABLES)$(ELFSIZE)$(S_UPPER_DEPS) modular_quad_pid.elf
+	-$(RM) $(OBJS)$(C_DEPS)$(EXECUTABLES)$(ELFSIZE)$(S_UPPER_DEPS) real_quad.elf
 	-@echo ' '
 
 secondary-outputs: $(ELFSIZE)
diff --git a/quad/xsdk_workspace/modular_quad_pid/Release/objects.mk b/quad/xsdk_workspace/real_quad/Release/objects.mk
similarity index 100%
rename from quad/xsdk_workspace/modular_quad_pid/Release/objects.mk
rename to quad/xsdk_workspace/real_quad/Release/objects.mk
diff --git a/quad/xsdk_workspace/modular_quad_pid/Release/sources.mk b/quad/xsdk_workspace/real_quad/Release/sources.mk
similarity index 100%
rename from quad/xsdk_workspace/modular_quad_pid/Release/sources.mk
rename to quad/xsdk_workspace/real_quad/Release/sources.mk
diff --git a/quad/xsdk_workspace/modular_quad_pid/Release/src/subdir.mk b/quad/xsdk_workspace/real_quad/Release/src/subdir.mk
similarity index 100%
rename from quad/xsdk_workspace/modular_quad_pid/Release/src/subdir.mk
rename to quad/xsdk_workspace/real_quad/Release/src/subdir.mk
diff --git a/quad/xsdk_workspace/modular_quad_pid/ext/__CAUTION__.md b/quad/xsdk_workspace/real_quad/ext/__CAUTION__.md
similarity index 100%
rename from quad/xsdk_workspace/modular_quad_pid/ext/__CAUTION__.md
rename to quad/xsdk_workspace/real_quad/ext/__CAUTION__.md
diff --git a/quad/xsdk_workspace/modular_quad_pid/src/hw_impl_zybo.c b/quad/xsdk_workspace/real_quad/src/hw_impl_zybo.c
similarity index 100%
rename from quad/xsdk_workspace/modular_quad_pid/src/hw_impl_zybo.c
rename to quad/xsdk_workspace/real_quad/src/hw_impl_zybo.c
diff --git a/quad/xsdk_workspace/modular_quad_pid/src/hw_impl_zybo.h b/quad/xsdk_workspace/real_quad/src/hw_impl_zybo.h
similarity index 100%
rename from quad/xsdk_workspace/modular_quad_pid/src/hw_impl_zybo.h
rename to quad/xsdk_workspace/real_quad/src/hw_impl_zybo.h
diff --git a/quad/xsdk_workspace/modular_quad_pid/src/hw_impl_zybo_axi_timer.c b/quad/xsdk_workspace/real_quad/src/hw_impl_zybo_axi_timer.c
similarity index 100%
rename from quad/xsdk_workspace/modular_quad_pid/src/hw_impl_zybo_axi_timer.c
rename to quad/xsdk_workspace/real_quad/src/hw_impl_zybo_axi_timer.c
diff --git a/quad/xsdk_workspace/modular_quad_pid/src/hw_impl_zybo_global_timer.c b/quad/xsdk_workspace/real_quad/src/hw_impl_zybo_global_timer.c
similarity index 100%
rename from quad/xsdk_workspace/modular_quad_pid/src/hw_impl_zybo_global_timer.c
rename to quad/xsdk_workspace/real_quad/src/hw_impl_zybo_global_timer.c
diff --git a/quad/xsdk_workspace/modular_quad_pid/src/hw_impl_zybo_i2c.c b/quad/xsdk_workspace/real_quad/src/hw_impl_zybo_i2c.c
similarity index 100%
rename from quad/xsdk_workspace/modular_quad_pid/src/hw_impl_zybo_i2c.c
rename to quad/xsdk_workspace/real_quad/src/hw_impl_zybo_i2c.c
diff --git a/quad/xsdk_workspace/modular_quad_pid/src/hw_impl_zybo_mio7_led.c b/quad/xsdk_workspace/real_quad/src/hw_impl_zybo_mio7_led.c
similarity index 100%
rename from quad/xsdk_workspace/modular_quad_pid/src/hw_impl_zybo_mio7_led.c
rename to quad/xsdk_workspace/real_quad/src/hw_impl_zybo_mio7_led.c
diff --git a/quad/xsdk_workspace/modular_quad_pid/src/hw_impl_zybo_pwm_input.c b/quad/xsdk_workspace/real_quad/src/hw_impl_zybo_pwm_input.c
similarity index 100%
rename from quad/xsdk_workspace/modular_quad_pid/src/hw_impl_zybo_pwm_input.c
rename to quad/xsdk_workspace/real_quad/src/hw_impl_zybo_pwm_input.c
diff --git a/quad/xsdk_workspace/modular_quad_pid/src/hw_impl_zybo_pwm_output.c b/quad/xsdk_workspace/real_quad/src/hw_impl_zybo_pwm_output.c
similarity index 100%
rename from quad/xsdk_workspace/modular_quad_pid/src/hw_impl_zybo_pwm_output.c
rename to quad/xsdk_workspace/real_quad/src/hw_impl_zybo_pwm_output.c
diff --git a/quad/xsdk_workspace/modular_quad_pid/src/hw_impl_zybo_system.c b/quad/xsdk_workspace/real_quad/src/hw_impl_zybo_system.c
similarity index 100%
rename from quad/xsdk_workspace/modular_quad_pid/src/hw_impl_zybo_system.c
rename to quad/xsdk_workspace/real_quad/src/hw_impl_zybo_system.c
diff --git a/quad/xsdk_workspace/modular_quad_pid/src/hw_impl_zybo_tests.c b/quad/xsdk_workspace/real_quad/src/hw_impl_zybo_tests.c
similarity index 99%
rename from quad/xsdk_workspace/modular_quad_pid/src/hw_impl_zybo_tests.c
rename to quad/xsdk_workspace/real_quad/src/hw_impl_zybo_tests.c
index 8fa79cbb283532fed1a65e8c37a80d1c4c489e28..2f5e5ab43e06ae7091ba3b0b1eba5d66ffbf0e7c 100644
--- a/quad/xsdk_workspace/modular_quad_pid/src/hw_impl_zybo_tests.c
+++ b/quad/xsdk_workspace/real_quad/src/hw_impl_zybo_tests.c
@@ -230,7 +230,7 @@ int test_zybo_global_timer() {
  * 2) Set the RUN_TESTS macro in main.c
  * 3) Uncomment only this test in main.c
  * 4) Run main.c
- * 5) Execute quad/scripts/test_zybo_uart.py
+ * 5) Execute quad/scripts/tests/test_zybo_uart.py
  *    - Observe test results on terminal
  *    - You might be able to see LED MIO7 blink when it receives bytes
  */
diff --git a/quad/xsdk_workspace/modular_quad_pid/src/hw_impl_zybo_uart.c b/quad/xsdk_workspace/real_quad/src/hw_impl_zybo_uart.c
similarity index 100%
rename from quad/xsdk_workspace/modular_quad_pid/src/hw_impl_zybo_uart.c
rename to quad/xsdk_workspace/real_quad/src/hw_impl_zybo_uart.c
diff --git a/quad/xsdk_workspace/modular_quad_pid/src/lscript.ld b/quad/xsdk_workspace/real_quad/src/lscript.ld
similarity index 100%
rename from quad/xsdk_workspace/modular_quad_pid/src/lscript.ld
rename to quad/xsdk_workspace/real_quad/src/lscript.ld
diff --git a/quad/xsdk_workspace/modular_quad_pid/src/main.c b/quad/xsdk_workspace/real_quad/src/main.c
similarity index 100%
rename from quad/xsdk_workspace/modular_quad_pid/src/main.c
rename to quad/xsdk_workspace/real_quad/src/main.c
diff --git a/quad/xsdk_workspace/modular_quad_pid/src/platform.c b/quad/xsdk_workspace/real_quad/src/platform.c
similarity index 100%
rename from quad/xsdk_workspace/modular_quad_pid/src/platform.c
rename to quad/xsdk_workspace/real_quad/src/platform.c
diff --git a/quad/xsdk_workspace/modular_quad_pid/src/platform.h b/quad/xsdk_workspace/real_quad/src/platform.h
similarity index 100%
rename from quad/xsdk_workspace/modular_quad_pid/src/platform.h
rename to quad/xsdk_workspace/real_quad/src/platform.h
diff --git a/quad/xsdk_workspace/modular_quad_pid/src/platform_config.h b/quad/xsdk_workspace/real_quad/src/platform_config.h
similarity index 100%
rename from quad/xsdk_workspace/modular_quad_pid/src/platform_config.h
rename to quad/xsdk_workspace/real_quad/src/platform_config.h
diff --git a/quad/xsdk_workspace/modular_quad_pid/test/.gitignore b/quad/xsdk_workspace/real_quad/test/.gitignore
similarity index 100%
rename from quad/xsdk_workspace/modular_quad_pid/test/.gitignore
rename to quad/xsdk_workspace/real_quad/test/.gitignore
diff --git a/quad/xsdk_workspace/modular_quad_pid/test/Makefile b/quad/xsdk_workspace/real_quad/test/Makefile
similarity index 100%
rename from quad/xsdk_workspace/modular_quad_pid/test/Makefile
rename to quad/xsdk_workspace/real_quad/test/Makefile
diff --git a/quad/xsdk_workspace/modular_quad_pid/test/test_uart_buff.c b/quad/xsdk_workspace/real_quad/test/test_uart_buff.c
similarity index 100%
rename from quad/xsdk_workspace/modular_quad_pid/test/test_uart_buff.c
rename to quad/xsdk_workspace/real_quad/test/test_uart_buff.c
diff --git a/quad/xsdk_workspace/modular_quad_pid/test/xil_types.h b/quad/xsdk_workspace/real_quad/test/xil_types.h
similarity index 100%
rename from quad/xsdk_workspace/modular_quad_pid/test/xil_types.h
rename to quad/xsdk_workspace/real_quad/test/xil_types.h