diff --git a/quad/src/gen_diagram/network.dot b/quad/src/gen_diagram/network.dot
index 7321d05e93f9aec20e120f62657e66ad43cab924..25a5dc165c2dac141e2c6694b707ec96db8eaf4a 100644
--- a/quad/src/gen_diagram/network.dot
+++ b/quad/src/gen_diagram/network.dot
@@ -3,12 +3,12 @@ rankdir="LR"
 "Roll PID"[shape=record
 label="<f0>Roll PID  |<f1> --\>Cur point |<f2> --\>Setpoint |<f3> --\>dt |<f4> [Kp=15.000] |<f5> [Ki=0.000] |<f6> [Kd=0.200] |<f7> [alpha=0.000]"]
 "Roll" -> "Roll PID":f1 [label="Constant"]
-"RC Roll" -> "Roll PID":f2 [label="Constant"]
+"Y Vel PID" -> "Roll PID":f2 [label="Correction"]
 "Ts_IMU" -> "Roll PID":f3 [label="Constant"]
 "Pitch PID"[shape=record
 label="<f0>Pitch PID  |<f1> --\>Cur point |<f2> --\>Setpoint |<f3> --\>dt |<f4> [Kp=15.000] |<f5> [Ki=0.000] |<f6> [Kd=0.200] |<f7> [alpha=0.000]"]
 "Pitch trim add" -> "Pitch PID":f1 [label="Sum"]
-"RC Pitch" -> "Pitch PID":f2 [label="Constant"]
+"X Vel PID" -> "Pitch PID":f2 [label="Correction"]
 "Ts_IMU" -> "Pitch PID":f3 [label="Constant"]
 "Yaw PID"[shape=record
 label="<f0>Yaw PID  |<f1> --\>Cur point |<f2> --\>Setpoint |<f3> --\>dt |<f4> [Kp=2.600] |<f5> [Ki=0.000] |<f6> [Kd=0.000] |<f7> [alpha=0.000]"]
@@ -28,7 +28,7 @@ label="<f0>Pitch Rate PID  |<f1> --\>Cur point |<f2> --\>Setpoint |<f3> --\>dt |
 "Yaw Rate PID"[shape=record
 label="<f0>Yaw Rate PID  |<f1> --\>Cur point |<f2> --\>Setpoint |<f3> --\>dt |<f4> [Kp=29700.000] |<f5> [Ki=0.000] |<f6> [Kd=0.000] |<f7> [alpha=0.000]"]
 "dPsi" -> "Yaw Rate PID":f1 [label="Constant"]
-"RC Yaw" -> "Yaw Rate PID":f2 [label="Constant"]
+"Yaw PID" -> "Yaw Rate PID":f2 [label="Correction"]
 "Ts_IMU" -> "Yaw Rate PID":f3 [label="Constant"]
 "X pos PID"[shape=record
 label="<f0>X pos PID  |<f1> --\>Cur point |<f2> --\>Setpoint |<f3> --\>dt |<f4> [Kp=-0.015] |<f5> [Ki=-0.005] |<f6> [Kd=-0.030] |<f7> [alpha=0.000]"]
@@ -106,7 +106,7 @@ label="<f0>RC Yaw  |<f1> [Constant=0.000]"]
 label="<f0>RC Throttle  |<f1> [Constant=0.000]"]
 "Signal Mixer"[shape=record
 label="<f0>Signal Mixer  |<f1> --\>Throttle |<f2> --\>Pitch |<f3> --\>Roll |<f4> --\>Yaw"]
-"RC Throttle" -> "Signal Mixer":f1 [label="Constant"]
+"T trim add" -> "Signal Mixer":f1 [label="Sum"]
 "P PWM Clamp" -> "Signal Mixer":f2 [label="Bounded"]
 "R PWM Clamp" -> "Signal Mixer":f3 [label="Bounded"]
 "Y PWM Clamp" -> "Signal Mixer":f4 [label="Bounded"]
@@ -114,4 +114,36 @@ label="<f0>Signal Mixer  |<f1> --\>Throttle |<f2> --\>Pitch |<f3> --\>Roll |<f4>
 label="<f0>Ts_IMU  |<f1> [Constant=0.005]"]
 "Ts_VRPN"[shape=record
 label="<f0>Ts_VRPN  |<f1> [Constant=0.040]"]
+"zero"[shape=record
+label="<f0>zero  |<f1> [Constant=0.000]"]
+"X Vel PID"[shape=record
+label="<f0>X Vel PID  |<f1> --\>Cur point |<f2> --\>Setpoint |<f3> --\>dt |<f4> [Kp=0.000] |<f5> [Ki=0.000] |<f6> [Kd=0.000] |<f7> [alpha=0.000]"]
+"X Vel" -> "X Vel PID":f1 [label="Correction"]
+"X Vel Clamp" -> "X Vel PID":f2 [label="Bounded"]
+"Ts_VRPN" -> "X Vel PID":f3 [label="Constant"]
+"Y Vel PID"[shape=record
+label="<f0>Y Vel PID  |<f1> --\>Cur point |<f2> --\>Setpoint |<f3> --\>dt |<f4> [Kp=0.000] |<f5> [Ki=0.000] |<f6> [Kd=0.000] |<f7> [alpha=0.000]"]
+"Y Vel" -> "Y Vel PID":f1 [label="Correction"]
+"Y vel Clamp" -> "Y Vel PID":f2 [label="Bounded"]
+"Ts_VRPN" -> "Y Vel PID":f3 [label="Constant"]
+"X Vel"[shape=record
+label="<f0>X Vel  |<f1> --\>Cur point |<f2> --\>Setpoint |<f3> --\>dt |<f4> [Kp=0.000] |<f5> [Ki=0.000] |<f6> [Kd=1.000] |<f7> [alpha=0.000]"]
+"VRPN X" -> "X Vel":f1 [label="Constant"]
+"zero" -> "X Vel":f2 [label="Constant"]
+"Ts_VRPN" -> "X Vel":f3 [label="Constant"]
+"Y Vel"[shape=record
+label="<f0>Y Vel  |<f1> --\>Cur point |<f2> --\>Setpoint |<f3> --\>dt |<f4> [Kp=0.000] |<f5> [Ki=0.000] |<f6> [Kd=1.000] |<f7> [alpha=0.000]"]
+"VRPN Y" -> "Y Vel":f1 [label="Constant"]
+"zero" -> "Y Vel":f2 [label="Constant"]
+"Ts_VRPN" -> "Y Vel":f3 [label="Constant"]
+"X Vel Clamp"[shape=record
+label="<f0>X Vel Clamp  |<f1> --\>Bounds in |<f2> [Min=-2.000] |<f3> [Max=2.000]"]
+"X pos PID" -> "X Vel Clamp":f1 [label="Correction"]
+"Y vel Clamp"[shape=record
+label="<f0>Y vel Clamp  |<f1> --\>Bounds in |<f2> [Min=-2.000] |<f3> [Max=2.000]"]
+"Y pos PID" -> "Y vel Clamp":f1 [label="Correction"]
+"X Stick Gain"[shape=record
+label="<f0>X Stick Gain  |<f1> --\>Input |<f2> [Gain=5.000]"]
+"Y Stick Gain"[shape=record
+label="<f0>Y Stick Gain  |<f1> --\>Input |<f2> [Gain=-5.000]"]
 }
\ No newline at end of file
diff --git a/quad/src/gen_diagram/network.png b/quad/src/gen_diagram/network.png
index 17aa66c2d549bb483b5812ec7e80e0d53933d358..6e1c3ebc4db038a6d42839315233e453f2e123fe 100644
Binary files a/quad/src/gen_diagram/network.png and b/quad/src/gen_diagram/network.png differ
diff --git a/quad/src/graph_blocks/node_pid.c b/quad/src/graph_blocks/node_pid.c
index df6b611100aec808a8728a3fbe435ecbe5078557..e776b7ed28e9295c9f30be9adb104ae3e9598647 100644
--- a/quad/src/graph_blocks/node_pid.c
+++ b/quad/src/graph_blocks/node_pid.c
@@ -6,9 +6,10 @@ static double FLT_EPSILON = 0.0001;
 
 
 struct pid_node_state {
-    double prev_error; // Previous error
+    double prev_val; // Previous input value
     double acc_error; // Accumulated error
     double last_filtered; // Last output from the filtered derivative
+    int just_reset; // Set to 1 after a call to reset
 };
 
 // The generic PID diagram. This function takes in pid inputs (CUR_POINT and SETOINT) and calculates the output "pid_correction"
@@ -50,23 +51,29 @@ static void pid_computation(void *state, const double* params, const double *inp
       pid_state->acc_error += error;
     }
 
+    if (pid_state->just_reset) {
+        // On first call after a reset, set the previous value to
+        // the current value to prevent a spike in derivative
+        pid_state->prev_val = inputs[PID_CUR_POINT];
+        pid_state->just_reset = 0;
+    }
 
     // Compute each term's contribution
     P = params[PID_KP] * error;
     I = params[PID_KI] * pid_state->acc_error * inputs[PID_DT];
     // Low-pass filter on derivative
-    double change_in_error = error - pid_state->prev_error;
+    double change_in_value = inputs[PID_CUR_POINT] - pid_state->prev_val;
     double term1 = params[PID_ALPHA] * pid_state->last_filtered;
-    double derivative = change_in_error / inputs[PID_DT];
+    double derivative = change_in_value / inputs[PID_DT];
     if (inputs[PID_DT] == 0) { // Divide by zero check
         derivative = 0;
     }
     double term2 = params[PID_KD] * (1.0f - params[PID_ALPHA]) * derivative;
     D = term1 + term2;
     pid_state->last_filtered = D; // Store filtered value for next filter iteration
-    pid_state->prev_error = error; // Store the current error into the state
+    pid_state->prev_val = inputs[PID_CUR_POINT]; // Store the current error into the state
 
-    outputs[PID_CORRECTION] = P + I + D; // Store the computed correction
+    outputs[PID_CORRECTION] = P + I - D; // Store the computed correction
 }
 
 // This function sets the accumulated error and previous error to 0
@@ -74,8 +81,8 @@ static void pid_computation(void *state, const double* params, const double *inp
 static void reset_pid(void *state) {
     struct pid_node_state* pid_state = (struct pid_node_state*)state;
     pid_state->acc_error = 0;
-    pid_state->prev_error = 0;
     pid_state->last_filtered = 0;
+    pid_state->just_reset = 1;
 }
 
 
diff --git a/quad/src/quad_app/biquad_filter.c b/quad/src/quad_app/biquad_filter.c
new file mode 100644
index 0000000000000000000000000000000000000000..3fb3327e4106aea63f68b1f017508b20879337e3
--- /dev/null
+++ b/quad/src/quad_app/biquad_filter.c
@@ -0,0 +1,29 @@
+#include "biquad_filter.h"
+
+struct biquadState filter_make_state(float a0, float a1, float a2,
+                              float b1, float b2) {
+    struct biquadState state = {
+        .delayed = {0,0},
+        .a0 = a0,
+        .a1 = a1,
+        .a2 = a2,
+        .b1 = b1,
+        .b2 = b2
+    };
+    return state;
+}
+
+// http://www.earlevel.com/main/2003/02/28/biquads/
+// Direct form II
+float biquad_execute(struct biquadState* state, float new_input) {
+    float left_sum = new_input -
+                     (state->delayed[0] * state->b1) -
+                     (state->delayed[1] * state->b2);
+    float output = (left_sum * state->a0) +
+                   (state->delayed[0] * state->a1) +
+                   (state->delayed[1] * state->a2);
+
+    state->delayed[1] = state->delayed[0];
+    state->delayed[0] = left_sum;
+    return output;
+}
\ No newline at end of file
diff --git a/quad/src/quad_app/biquad_filter.h b/quad/src/quad_app/biquad_filter.h
new file mode 100644
index 0000000000000000000000000000000000000000..a9076573883767901440683df9fe1c45abd52ae7
--- /dev/null
+++ b/quad/src/quad_app/biquad_filter.h
@@ -0,0 +1,14 @@
+#ifndef BIQUAD_FILTER_H
+#define BIQUAD_FILTER_H
+
+struct biquadState {
+	float delayed[2];
+    float a0, a1, a2, b1, b2;
+};
+
+float biquad_execute(struct biquadState* state, float new_input);
+
+
+struct biquadState filter_make_state(float a0, float a1, float a2,
+                              float b1, float b2);
+#endif // BIQUAD_FILTER_H
\ No newline at end of file
diff --git a/quad/src/quad_app/control_algorithm.c b/quad/src/quad_app/control_algorithm.c
index 0391ca2dd23cca86ae5b5c0fd9191da3e28eaca1..710f26b34144c2827d46aa0363575541a12aae97 100644
--- a/quad/src/quad_app/control_algorithm.c
+++ b/quad/src/quad_app/control_algorithm.c
@@ -19,9 +19,11 @@
 
 void connect_autonomous(parameter_t* ps) {
 	struct computation_graph* graph = ps->graph;
-	graph_set_source(graph, ps->pitch_pid, PID_SETPOINT, ps->x_pos_pid, PID_CORRECTION);
-	graph_set_source(graph, ps->roll_pid, PID_SETPOINT, ps->y_pos_pid, PID_CORRECTION);
-	//graph_set_source(graph, ps->mixer, MIXER_THROTTLE, ps->throttle_trim_add, ADD_SUM);
+	//graph_set_source(graph, ps->pitch_pid, PID_SETPOINT, ps->x_pos_pid, PID_CORRECTION);
+	//graph_set_source(graph, ps->roll_pid, PID_SETPOINT, ps->y_pos_pid, PID_CORRECTION);
+	graph_set_source(graph, ps->pitch_pid, PID_SETPOINT, ps->x_vel_pid, PID_CORRECTION);
+	graph_set_source(graph, ps->roll_pid, PID_SETPOINT, ps->y_vel_pid, PID_CORRECTION);
+	graph_set_source(graph, ps->mixer, MIXER_THROTTLE, ps->throttle_trim_add, ADD_SUM);
 	graph_set_source(graph, ps->yaw_r_pid, PID_SETPOINT, ps->yaw_pid, PID_CORRECTION);
 }
 
@@ -195,6 +197,58 @@ int control_algorithm_init(parameter_t * ps)
     graph_set_param_val(graph, ps->clamp_d_pwmY, BOUNDS_MIN, -PWM_DIFF_BOUNDS);
     graph_set_param_val(graph, ps->clamp_d_pwmY, BOUNDS_MAX, PWM_DIFF_BOUNDS);
 
+
+    // Velocity stuff
+    int zero_block = graph_add_defined_block(graph, BLOCK_CONSTANT, "zero");
+
+    ps->x_vel_pid = graph_add_defined_block(graph, BLOCK_PID, "X Vel PID");
+    ps->y_vel_pid = graph_add_defined_block(graph, BLOCK_PID, "Y Vel PID");
+    ps->x_vel = graph_add_defined_block(graph, BLOCK_PID, "X Vel");
+    ps->y_vel = graph_add_defined_block(graph, BLOCK_PID, "Y Vel");
+    ps->x_vel_clamp = graph_add_defined_block(graph, BLOCK_BOUNDS, "X Vel Clamp");
+    ps->y_vel_clamp = graph_add_defined_block(graph, BLOCK_BOUNDS, "Y vel Clamp");
+    ps->vel_x_gain = graph_add_defined_block(graph, BLOCK_GAIN, "X Stick Gain");
+    ps->vel_y_gain = graph_add_defined_block(graph, BLOCK_GAIN, "Y Stick Gain");
+
+    graph_set_source(graph, ps->x_vel_pid, PID_DT, ps->pos_time, CONST_VAL);
+    graph_set_source(graph, ps->y_vel_pid, PID_DT, ps->pos_time, CONST_VAL);
+    graph_set_source(graph, ps->x_vel, PID_DT, ps->pos_time, CONST_VAL);
+    graph_set_source(graph, ps->y_vel, PID_DT, ps->pos_time, CONST_VAL);
+
+    graph_set_source(graph, ps->x_vel_pid, PID_SETPOINT, ps->x_vel, PID_CORRECTION);
+    graph_set_source(graph, ps->y_vel_pid, PID_SETPOINT, ps->y_vel, PID_CORRECTION);
+    graph_set_source(graph, ps->x_vel_pid, PID_CUR_POINT, ps->x_vel, PID_CORRECTION);
+    graph_set_source(graph, ps->y_vel_pid, PID_CUR_POINT, ps->y_vel, PID_CORRECTION);
+
+    graph_set_source(graph, ps->x_vel, PID_CUR_POINT, ps->vrpn_x, CONST_VAL);
+    graph_set_source(graph, ps->y_vel, PID_CUR_POINT, ps->vrpn_y, CONST_VAL);
+    graph_set_source(graph, ps->x_vel, PID_SETPOINT, zero_block, CONST_VAL);
+    graph_set_source(graph, ps->y_vel, PID_SETPOINT, zero_block, CONST_VAL);
+
+    graph_set_source(graph, ps->x_vel_pid, PID_SETPOINT, ps->x_vel_clamp, GAIN_RESULT);
+    graph_set_source(graph, ps->y_vel_pid, PID_SETPOINT, ps->y_vel_clamp, GAIN_RESULT);
+
+    graph_set_source(graph, ps->x_vel_clamp, BOUNDS_IN, ps->x_pos_pid, PID_CORRECTION);
+    graph_set_source(graph, ps->y_vel_clamp, BOUNDS_IN, ps->y_pos_pid, PID_CORRECTION);
+    //graph_set_source(graph, ps->vel_x_gain, GAIN_INPUT, ps->rc_pitch, CONST_VAL);
+    //graph_set_source(graph, ps->vel_y_gain, GAIN_INPUT, ps->rc_roll, CONST_VAL);
+    //graph_set_source(graph, ps->x_vel_clamp, BOUNDS_IN, ps->vel_x_gain, GAIN_RESULT);
+    //graph_set_source(graph, ps->y_vel_clamp, BOUNDS_IN, ps->vel_y_gain, GAIN_RESULT);
+
+    float vel_clamps = 2;
+    graph_set_param_val(graph, ps->x_vel_clamp, BOUNDS_MIN, -vel_clamps);
+    graph_set_param_val(graph, ps->x_vel_clamp, BOUNDS_MAX, vel_clamps);
+    graph_set_param_val(graph, ps->y_vel_clamp, BOUNDS_MIN, -vel_clamps);
+    graph_set_param_val(graph, ps->y_vel_clamp, BOUNDS_MAX, vel_clamps);
+
+
+    graph_set_param_val(graph, ps->x_vel, PID_KD, 1);
+    graph_set_param_val(graph, ps->y_vel, PID_KD, 1);
+
+    graph_set_param_val(graph, ps->vel_x_gain, GAIN_GAIN, 5);
+    graph_set_param_val(graph, ps->vel_y_gain, GAIN_GAIN, -5);
+
+
     // Set trims
     graph_set_param_val(graph, ps->pitch_trim, CONST_SET, 0.02);
 
diff --git a/quad/src/quad_app/iic_utils.c b/quad/src/quad_app/iic_utils.c
index a0061e6b00432768feded1b15495c850fad5a914..a9fbd272c723f5a81942a9edef2adcf7dae613fb 100644
--- a/quad/src/quad_app/iic_utils.c
+++ b/quad/src/quad_app/iic_utils.c
@@ -30,7 +30,7 @@ int iic0_mpu9150_start(){
 	// Set clock reference to Z Gyro
 	iic0_mpu9150_write(0x6B, 0x03);
 	// Configure Digital Low/High Pass filter
-	iic0_mpu9150_write(0x1A,0x05); // Level 5 low pass on gyroscope
+	iic0_mpu9150_write(0x1A,0x03); // Level 3 low pass on gyroscope
 
 	// Configure Gyro to 2000dps, Accel. to +/-8G
 	iic0_mpu9150_write(0x1B, 0x18);
@@ -182,10 +182,6 @@ int iic0_mpu9150_read_gam(gam_t* gam) {
 	gam->accel_y = (raw_accel_y / 4096.0) + ACCEL_Y_BIAS;
 	gam->accel_z = (raw_accel_z / 4096.0) + ACCEL_Z_BIAS;
 
-	//Get X and Y angles
-	// javey: this assigns accel_(pitch/roll) in units of radians
-	gam->accel_pitch = atan(gam->accel_x / sqrt(gam->accel_y*gam->accel_y + gam->accel_z*gam->accel_z));
-	gam->accel_roll = -atan(gam->accel_y / sqrt(gam->accel_x*gam->accel_x + gam->accel_z*gam->accel_z)); // negative because sensor board is upside down
 
 	//Convert gyro data to rate (we're only using the most 12 significant bits)
 	gyro_x = (sensor_data[GYR_X_H] << 8) | (sensor_data[GYR_X_L]); //* G_GAIN;
diff --git a/quad/src/quad_app/initialize_components.c b/quad/src/quad_app/initialize_components.c
index 57d3e2b96eaef8951425652c4fb61ac5ec4b1529..967eaa6294b342641fc1dcdfb0b3327ea4490427 100644
--- a/quad/src/quad_app/initialize_components.c
+++ b/quad/src/quad_app/initialize_components.c
@@ -99,5 +99,7 @@ int init_structs(modular_structs_t *structs) {
   if(sensor_init(&structs->raw_sensor_struct, &structs->sensor_struct) == -1)
     return -1;
 
+  sensor_processing_init(&structs->sensor_struct);
+
   return 0;
 }
diff --git a/quad/src/quad_app/log_data.c b/quad/src/quad_app/log_data.c
index 3e67c14aa36862cae1ad885955e944a86056007b..e67a075394ee6099d89f0c326a07f656a72694ee 100644
--- a/quad/src/quad_app/log_data.c
+++ b/quad/src/quad_app/log_data.c
@@ -95,6 +95,7 @@ void initialize_logging(log_t* log_struct, parameter_t* ps) {
 	char* rad_s = "rad/s";
 	char* pwm_val = "10ns_dutycycle";
 	char* m = "m";
+	char* m_s = "m/s";
 	addOutputToLog(log_struct, ps->alt_pid, PID_CORRECTION, pwm_val);
 	addOutputToLog(log_struct, ps->x_pos_pid, PID_CORRECTION, rad);
 	addOutputToLog(log_struct, ps->y_pos_pid, PID_CORRECTION, rad);
@@ -104,7 +105,7 @@ void initialize_logging(log_t* log_struct, parameter_t* ps) {
 	addOutputToLog(log_struct, ps->pitch_r_pid, PID_CORRECTION, pwm_val);
 	addOutputToLog(log_struct, ps->roll_r_pid, PID_CORRECTION, pwm_val);
 	addOutputToLog(log_struct, ps->yaw_r_pid, PID_CORRECTION, pwm_val);
-	addOutputToLog(log_struct, ps->cur_pitch, CONST_VAL, rad);
+	addOutputToLog(log_struct, ps->pitch_trim_add, CONST_VAL, rad);
 	addOutputToLog(log_struct, ps->cur_roll, CONST_VAL, rad);
 	addOutputToLog(log_struct, ps->cur_yaw, CONST_VAL, rad);
 	addOutputToLog(log_struct, ps->vrpn_x, CONST_VAL, m);
@@ -122,6 +123,10 @@ void initialize_logging(log_t* log_struct, parameter_t* ps) {
 	addOutputToLog(log_struct, ps->rc_throttle, PID_CORRECTION, pwm_val);
 	addOutputToLog(log_struct, ps->rc_pitch, PID_CORRECTION, pwm_val);
 	addOutputToLog(log_struct, ps->rc_roll, PID_CORRECTION, pwm_val);
+	addOutputToLog(log_struct, ps->x_vel_pid, PID_CORRECTION, rad);
+	addOutputToLog(log_struct, ps->y_vel_pid, PID_CORRECTION, rad);
+	addOutputToLog(log_struct, ps->x_vel, PID_CORRECTION, m_s);
+	addOutputToLog(log_struct, ps->y_vel, PID_CORRECTION, m_s);
 
 	// TODO: Make this not stupid. Adding 6 for IMU and 1 for timestamp
 	row_size = n_outputs + n_params + 6 + 1;
@@ -184,12 +189,27 @@ void printLogging(hardware_t *hardware_struct, log_t* log_struct, parameter_t* p
 		send_data(&hardware_struct->uart, LOG_ID, 0, buf.str, buf.size);
 		return;
 	}
+
+	int i;
 	// Comment header
 	safe_sprintf_cat(&buf, "# MicroCART On-board Quad Log\n# Sample size: %d\n", arrayIndex);
+
+	// List Pid Constants
+	for (i = 0; i < ps->graph->n_nodes; ++i) {
+		struct graph_node* node = &ps->graph->nodes[i];
+		if (node->type->type_id == BLOCK_PID) {
+			double kp, ki, kd;
+			kp = graph_get_param_val(ps->graph, i, 0);
+			ki = graph_get_param_val(ps->graph, i, 1);
+			kd = graph_get_param_val(ps->graph, i, 2);
+			safe_sprintf_cat(&buf, "# %s :\tKp = %lf Ki = %lf Kd = %lf\n", node->name, kp, ki, kd);
+
+		}
+	}
+
 	// Header names for the pre-defined values
 	safe_sprintf_cat(&buf, "%%Time\taccel_x\taccel_y\taccel_z\tgyro_x\tgyro_y\tgyro_z");
 
-	int i;
 	// Print all the recorded block parameters
 	for (i = 0; i < n_params; i++) {
 		const char* block_name = ps->graph->nodes[log_params[i].block_id].name;
diff --git a/quad/src/quad_app/sensor_processing.c b/quad/src/quad_app/sensor_processing.c
index d7bd7b707ac23b2b87e8c5aab8029840dce80b31..3e3b48bd1bbcb16dca49f198494ce05f847b6dfd 100644
--- a/quad/src/quad_app/sensor_processing.c
+++ b/quad/src/quad_app/sensor_processing.c
@@ -14,8 +14,33 @@
 #include "timer.h"
 #include <math.h>
 
+#define ALPHA 0.99
+
+int sensor_processing_init(sensor_t* sensor_struct) {
+	float a0 = 0.0200833310260;
+	float a1 = 0.0401666620520;
+	float a2 = 0.0200833310260;
+	float b1 = -1.561015391253;
+	float b2 = 0.6413487153577;
+	sensor_struct->accel_x_filt = filter_make_state(a0, a1, a2, b1, b2);
+	sensor_struct->accel_y_filt = filter_make_state(a0, a1, a2, b1, b2);
+	sensor_struct->accel_z_filt = filter_make_state(a0, a1, a2, b1, b2);
+	return 0;
+}
+
 int sensor_processing(log_t* log_struct, user_input_t *user_input_struct, raw_sensor_t* raw_sensor_struct, sensor_t* sensor_struct)
 {
+	// Filter accelerometer values
+	gam_t* gam = &(raw_sensor_struct->gam);
+	float accel_x = biquad_execute(&sensor_struct->accel_x_filt, gam->accel_x);
+	float accel_y = biquad_execute(&sensor_struct->accel_y_filt, gam->accel_y);
+	float accel_z = biquad_execute(&sensor_struct->accel_z_filt, gam->accel_z);
+	//Get X and Y angles
+	// javey: this assigns accel_(pitch/roll) in units of radians
+	float accel_pitch = atan(accel_x / sqrt(accel_y*accel_y + accel_z*accel_z));
+	float accel_roll = -atan(accel_y / sqrt(accel_x*accel_x + accel_z*accel_z)); // negative because sensor board is upside down
+
+
 	// copy currentQuadPosition and trimmedRCValues from raw_sensor_struct to sensor_struct
 	deep_copy_Qpos(&(sensor_struct->currentQuadPosition), &(raw_sensor_struct->currentQuadPosition));
 
@@ -31,13 +56,14 @@ int sensor_processing(log_t* log_struct, user_input_t *user_input_struct, raw_se
 	// |local y|  = |sin(yaw angle)   cos(yaw angle)  0| |camera given y|
 	// |local z|	|       0               0         1| |camera given z|
 
+
 	sensor_struct->currentQuadPosition.x_pos =
-			sensor_struct->currentQuadPosition.x_pos * cos(sensor_struct->currentQuadPosition.yaw) +
-			sensor_struct->currentQuadPosition.y_pos * -sin(sensor_struct->currentQuadPosition.yaw);
+			raw_sensor_struct->currentQuadPosition.x_pos * cos(raw_sensor_struct->currentQuadPosition.yaw) +
+			raw_sensor_struct->currentQuadPosition.y_pos * -sin(raw_sensor_struct->currentQuadPosition.yaw);
 
 	sensor_struct->currentQuadPosition.y_pos =
-			sensor_struct->currentQuadPosition.x_pos * sin(sensor_struct->currentQuadPosition.yaw) +
-			sensor_struct->currentQuadPosition.y_pos * cos(sensor_struct->currentQuadPosition.yaw);
+			raw_sensor_struct->currentQuadPosition.x_pos * sin(raw_sensor_struct->currentQuadPosition.yaw) +
+			raw_sensor_struct->currentQuadPosition.y_pos * cos(raw_sensor_struct->currentQuadPosition.yaw);
 
 
 	// Calculate Euler angles and velocities using Gimbal Equations below
@@ -85,11 +111,11 @@ int sensor_processing(log_t* log_struct, user_input_t *user_input_struct, raw_se
 	sensor_struct->gyr_z = raw_sensor_struct->gam.gyro_zVel_r;
 
 	// Complementary Filter Calculations
-	sensor_struct->pitch_angle_filtered = 0.98 * (sensor_struct->pitch_angle_filtered + sensor_struct->theta_dot * get_last_loop_time())
-			+ 0.02 * raw_sensor_struct->gam.accel_pitch;
+	sensor_struct->pitch_angle_filtered = ALPHA * (sensor_struct->pitch_angle_filtered + sensor_struct->theta_dot * get_last_loop_time())
+			+ (1. - ALPHA) * accel_pitch;
 
-	sensor_struct->roll_angle_filtered = 0.98 * (sensor_struct->roll_angle_filtered + sensor_struct->phi_dot* get_last_loop_time())
-			+ 0.02 * raw_sensor_struct->gam.accel_roll;
+	sensor_struct->roll_angle_filtered = ALPHA * (sensor_struct->roll_angle_filtered + sensor_struct->phi_dot* get_last_loop_time())
+			+ (1. - ALPHA) * accel_roll;
 
 //	static int loop_counter = 0;
 //	loop_counter++;
diff --git a/quad/src/quad_app/sensor_processing.h b/quad/src/quad_app/sensor_processing.h
index 04b5efebe48ab20bdecfcfaab11e1ffe2f63a540..52b626eafa173ac5c806ad29d52ca03138017060 100644
--- a/quad/src/quad_app/sensor_processing.h
+++ b/quad/src/quad_app/sensor_processing.h
@@ -77,6 +77,7 @@
  */
 
 int sensor_processing(log_t* log_struct, user_input_t *user_input_struct, raw_sensor_t * raw_sensor_struct, sensor_t* sensor_struct);
+int sensor_processing_init(sensor_t* sensor_struct);
 void deep_copy_Qpos(quadPosition_t * dest, quadPosition_t * src);
 void set_pitch_angle_filtered(sensor_t * sensor_struct, float accel_roll);
 void set_roll_angle_filtered(sensor_t * sensor_struct, float accel_roll);
diff --git a/quad/src/quad_app/type_def.h b/quad/src/quad_app/type_def.h
index c32b202fa201762212adc068a3cee21e43c109f4..d016134432b8e058601904a5013a296b7ecd7b00 100644
--- a/quad/src/quad_app/type_def.h
+++ b/quad/src/quad_app/type_def.h
@@ -12,6 +12,7 @@
 #include "commands.h"
 #include "computation_graph.h"
 #include "hw_iface.h"
+#include "biquad_filter.h"
 
 typedef unsigned char u8;
 typedef unsigned short u16;
@@ -278,6 +279,10 @@ typedef struct sensor {
 	quadPosition_t currentQuadPosition;
 	quadTrims_t trims;
 
+	struct biquadState accel_x_filt;
+	struct biquadState accel_y_filt;
+	struct biquadState accel_z_filt;
+
 } sensor_t;
 
 /**
@@ -343,6 +348,15 @@ typedef struct parameter_t {
 	int throttle_trim_add;
 	int pitch_trim;
 	int pitch_trim_add;
+	// Velocity nodes
+	int x_vel_pid;
+	int y_vel_pid;
+	int x_vel;
+	int y_vel;
+	int x_vel_clamp;
+	int y_vel_clamp;
+	int vel_x_gain;
+	int vel_y_gain;
 } parameter_t;
 
 /**