diff --git a/quad/src/quad_app/iic_utils.c b/quad/src/quad_app/iic_utils.c
index a9fbd272c723f5a81942a9edef2adcf7dae613fb..44af3357c805e340bc15670d7974582879f428fa 100644
--- a/quad/src/quad_app/iic_utils.c
+++ b/quad/src/quad_app/iic_utils.c
@@ -244,3 +244,85 @@ int iic0_lidarlite_read_distance(lidar_t *lidar) {
 
 	return status;
 }
+
+//////////////////////////////////////////////////
+// PX4FLOW
+//////////////////////////////////////////////////
+
+//TODO: Replace device-specific iic0_device_write/read with generic ones
+
+int iic0_px4flow_write(u8 register_addr, u8 data) {
+	u8 buf[] = {register_addr, data};
+
+	return i2c->write(i2c, PX4FLOW_DEVICE_ADDR, buf, 2);
+}
+
+int iic0_px4flow_read(u8* recv_buffer, u8 register_addr, int size) {
+	u8 buf[] = {register_addr};
+	int status = 0;
+
+	status |= i2c->write(i2c, PX4FLOW_DEVICE_ADDR, buf, 1);
+	status |= i2c->read(i2c, PX4FLOW_DEVICE_ADDR, recv_buffer, size);
+	return status;
+}
+
+int iic0_px4flow_init(px4flow_t *of) {
+	//Clear struct
+	of->xPos = 0;
+	of->yPos = 0;
+	of->xVel = 0;
+	of->yVel = 0;
+
+	//Perform initial update
+	return iic0_px4flow_update(of, 0.);
+}
+
+int iic0_px4flow_update(px4flow_t *of, double dt) {
+	static double time = 0.;
+
+	time += dt;
+	if(time >= 10.) {
+		time = 0.;
+	}
+
+	int status = 0;
+
+	struct {
+		uint16_t frameCount;
+
+		int16_t pixelFlowXSum;
+		int16_t pixelFlowYSum;
+		int16_t flowCompX;
+		int16_t flowCompY;
+		int16_t qual;
+
+		int16_t gyroXRate;
+		int16_t gyroYRate;
+		int16_t gyroZRate;
+
+		uint8_t gyroRange;
+		uint8_t sonarTimestamp;
+		int16_t groundDistance;
+	} i2cFrame;
+
+	u8 buf[sizeof(i2cFrame)];
+
+	// Read the sensor value
+	status = iic0_px4flow_read(buf, 0x00, sizeof(i2cFrame));
+
+	if(status == 0) {
+		//Copy into struct
+		memcpy(&i2cFrame, buf, sizeof(i2cFrame));
+
+		//As per documentation, disregard frames with low quality, as they contain unreliable data
+		if(i2cFrame.qual >= PX4FLOW_QUAL_MIN) {
+			of->xVel = i2cFrame.flowCompX / 1000.;
+			of->yVel = i2cFrame.flowCompY / 1000.;
+
+			of->xPos += of->xVel * dt;
+			of->yPos += of->yVel * dt;
+		}
+	}
+
+	return status;
+}
diff --git a/quad/src/quad_app/iic_utils.h b/quad/src/quad_app/iic_utils.h
index b1ccb6861d9fdb779debe8e42f56b866573f97d2..ccf88dde0e700eb90b023a97b8e6ac4f763784a0 100644
--- a/quad/src/quad_app/iic_utils.h
+++ b/quad/src/quad_app/iic_utils.h
@@ -128,4 +128,20 @@ int iic0_lidarlite_read_distance(lidar_t *lidar);
 int iic0_lidarlite_init();
 int iic0_lidarlite_sleep();
 
+////////////////////////////////////////////////////////////////////////////////////////////
+// PX4FLOW optical flow sensor functions/defines (based on information on from pixhawk.org)
+////////////////////////////////////////////////////////////////////////////////////////////
+
+#define PX4FLOW_DEVICE_ADDR			0x42
+#define PX4FLOW_QUAL_MIN			(100)
+
+
+int iic0_px4flow_write(u8 register_addr, u8 data);
+int iic0_px4flow_read(u8* recv_buffer, u8 register_addr, int size);
+
+int iic0_px4flow_update(px4flow_t *of, double dt);
+
+int iic0_px4flow_init(px4flow_t *of);
+
+
 #endif /*IIC_UTILS_H*/
diff --git a/quad/src/quad_app/type_def.h b/quad/src/quad_app/type_def.h
index d016134432b8e058601904a5013a296b7ecd7b00..9f1ef52bf3d63abf9129431c473526c062a3b0c7 100644
--- a/quad/src/quad_app/type_def.h
+++ b/quad/src/quad_app/type_def.h
@@ -115,6 +115,11 @@ typedef struct {
 	unsigned short distance_cm;
 } lidar_t;
 
+typedef struct {
+	double xVel, yVel;
+	double xPos, yPos;
+} px4flow_t;
+
 typedef struct PID_t {
 	float current_point;	// Current value of the system
 	float setpoint;		// Desired value of the system
diff --git a/quad/xsdk_workspace/real_quad/src/hw_impl_zybo_i2c.c b/quad/xsdk_workspace/real_quad/src/hw_impl_zybo_i2c.c
index c24a2b7a706db55469e50b56584120a1def9701a..368adf3c4e51db81c1a4760bd4a282a4b909a38d 100644
--- a/quad/xsdk_workspace/real_quad/src/hw_impl_zybo_i2c.c
+++ b/quad/xsdk_workspace/real_quad/src/hw_impl_zybo_i2c.c
@@ -1,4 +1,5 @@
 #include "hw_impl_zybo.h"
+#include "iic_utils.h"
 
 #define IO_CLK_CONTROL_REG_ADDR	(0xF800012C)
 
@@ -45,7 +46,16 @@ int zybo_i2c_write(struct I2CDriver *self,
                    unsigned char *data,
                    unsigned int length) {
   XIicPs *inst = self->state;
-  return XIicPs_MasterSendPolled_ours(inst, data, length, device_addr);
+  if (device_addr == PX4FLOW_DEVICE_ADDR) {
+	  // If we are sending a request to optical flow, drop down to 100kHz
+	  XIicPs_SetSClk(inst, 100000);
+  }
+  int error = XIicPs_MasterSendPolled_ours(inst, data, length, device_addr);
+  if (device_addr == PX4FLOW_DEVICE_ADDR) {
+	  // Put it back to 400kHz
+	  XIicPs_SetSClk(inst, 400000);
+  }
+  return error;
 }
 
 int zybo_i2c_read(struct I2CDriver *self,
@@ -53,7 +63,16 @@ int zybo_i2c_read(struct I2CDriver *self,
                   unsigned char *buff,
                   unsigned int length) {
   XIicPs *inst = self->state;
-  return XIicPs_MasterRecvPolled(inst, buff, length, device_addr);
+  if (device_addr == PX4FLOW_DEVICE_ADDR) {
+	  // If we are sending a request to optical flow, drop down to 100kHz
+	  XIicPs_SetSClk(inst, 100000);
+  }
+  int error = XIicPs_MasterRecvPolled(inst, buff, length, device_addr);
+  if (device_addr == PX4FLOW_DEVICE_ADDR) {
+	  // Put it back to 400kHz
+	  XIicPs_SetSClk(inst, 400000);
+  }
+  return error;
 }
 
 /*****************************************************************************/
diff --git a/quad/xsdk_workspace/real_quad/src/hw_impl_zybo_tests.c b/quad/xsdk_workspace/real_quad/src/hw_impl_zybo_tests.c
index 2f5e5ab43e06ae7091ba3b0b1eba5d66ffbf0e7c..0d669fb66a69ed1898314e6a3a31970d40528155 100644
--- a/quad/xsdk_workspace/real_quad/src/hw_impl_zybo_tests.c
+++ b/quad/xsdk_workspace/real_quad/src/hw_impl_zybo_tests.c
@@ -33,10 +33,7 @@ int test_zybo_mio7_led_and_system() {
 }
 
 /**
- * Test for the I2CDriver.
- *
- * Raw I2C tests are tedius, so we are going to cheat a bit, and use
- * some of the LIDAR code we have.
+ * Tests for the I2CDriver (one for each I2C device we use)
  *
  * Instructions:
  * 1) Connect Zybo Board to computer by USB cable.
@@ -86,6 +83,54 @@ int test_zybo_i2c_imu() {
   return 0;
 }
 
+int test_zybo_i2c_px4flow() {
+  struct I2CDriver i2c = create_zybo_i2c();
+  struct SystemDriver sys = create_zybo_system();
+  i2c.reset(&i2c);
+  sys.reset(&sys);
+
+  px4flow_t of;
+  iic_set_globals(&i2c, &sys);
+
+  if(iic0_px4flow_init(&of)) return 0;
+
+  for(;;) {
+    unsigned int delay = 5;
+
+    sys.sleep(&sys, delay * 1000);
+
+    iic0_px4flow_update(&of, delay / 1000.);
+  }
+  return 0;
+}
+
+int test_zybo_i2c_all() {
+  struct I2CDriver i2c = create_zybo_i2c();
+  struct SystemDriver sys = create_zybo_system();
+  i2c.reset(&i2c);
+  sys.reset(&sys);
+
+  lidar_t lidar = { };
+  px4flow_t of = { };
+  gam_t gam = { };
+  iic_set_globals(&i2c, &sys);
+
+  if (iic0_px4flow_init(&of)) return 0;
+  if (iic0_mpu9150_start()) return 0;
+  if (iic0_lidarlite_init()) return 0;
+
+  for(;;) {
+    unsigned int delay = 5;
+
+    sys.sleep(&sys, delay * 1000);
+
+    iic0_px4flow_update(&of, delay / 1000.);
+    iic0_mpu9150_read_gam(&gam);
+    iic0_lidarlite_read_distance(&lidar);
+  }
+  return 0;
+}
+
 /**
  * Test for the PWMInputDriver.
  *
diff --git a/quad/xsdk_workspace/real_quad/src/main.c b/quad/xsdk_workspace/real_quad/src/main.c
index 337212a68b5c4829b95de861b9a97f08d4bb93be..ef3971feb9c63c531073afa30651d7cb9f3e9959 100644
--- a/quad/xsdk_workspace/real_quad/src/main.c
+++ b/quad/xsdk_workspace/real_quad/src/main.c
@@ -27,6 +27,8 @@ int main()
   //test_zybo_mio7_led_and_system();
   //test_zybo_i2c();
   //test_zybo_i2c_imu();
+  //test_zybo_i2c_px4flow();
+  //test_zybo_i2c_all();
   //test_zybo_pwm_inputs();
   //test_zybo_pwm_outputs();
   //test_zybo_uart();