diff --git a/src/control.rs b/src/control.rs
index 906dd8e1af0e2082a897662c78f2cf7fa8bb9571..34aa11d9215e2e9085e7e8364afbbd2aff544b50 100644
--- a/src/control.rs
+++ b/src/control.rs
@@ -17,6 +17,7 @@ use crate::{
 
 const IMAGE_PACKET_QUEUE_LENGTH: usize = 8192;
 const TEMP_REFRESH_INTERVAL: Duration = Duration::from_secs(5);
+const SYNC_REFRESH_INTERVAL: Duration = Duration::from_secs(7);
 
 pub struct Controller {
     config: Config,
@@ -97,6 +98,7 @@ impl Controller {
 
         let mut text_msg_id = 0;
         let mut last_got_temp = Instant::now();
+        let mut last_synced_at = Instant::now();
         loop {
             while let Ok(tm) = telem_rx.try_recv() {
                 let tm = tm.into_raw(&mut text_msg_id).into();
@@ -131,6 +133,14 @@ impl Controller {
                     eprintln!("Could not send packet: {}", e);
                 }
             }
+
+            if Instant::now() - last_synced_at > SYNC_REFRESH_INTERVAL {
+                last_synced_at = Instant::now();
+
+                if let Err(e) = radio.sync() {
+                    eprintln!("Could not sync: {}", e);
+                }
+            }
         }
     }
 }
diff --git a/src/radio.rs b/src/radio.rs
index 101af05204c1050fbeed6aa9e15acf32ee2e5120..8c338422d33c1d2c74cc3df3d45c4c5d6a905f65 100644
--- a/src/radio.rs
+++ b/src/radio.rs
@@ -1,6 +1,6 @@
 use serial::{unix::TTYPort, BaudRate::BaudOther, SerialPort};
 use std::{
-    io::{Read, Write},
+    io::{self, Read, Write},
     thread::sleep,
     time::Duration,
 };
@@ -10,6 +10,9 @@ use crate::packet::FecPacket;
 const BUFFER_STATUS_CMD: u8 = 0x00;
 const SEND_PACKET_CMD: u8 = 0x01;
 const GET_TEMP_CMD: u8 = 0x02;
+const SYNC_CMD: u8 = 0x03;
+
+const PACKET_SPACE: u8 = 0x02;
 
 // Used for talking to an RF4463 via a microcontroller
 // The microcontroller takes in packet data over UART and sends it to the RF4463
@@ -28,18 +31,16 @@ impl UartRadio {
     pub fn send_packet(&mut self, packet: &FecPacket) -> anyhow::Result<()> {
         self.uart.write_all(&[SEND_PACKET_CMD])?;
         self.uart.write_all(&packet.0)?;
-        self.uart.flush()?;
 
         let mut buf = [0; 1];
         self.uart.read_exact(&mut buf)?;
 
         // wait until we have space for packets
-        while buf != [0x02] {
+        while buf != [PACKET_SPACE] {
             sleep(Duration::from_millis(10));
 
             // poll to see if the buffer has emptied yet
             self.uart.write_all(&[BUFFER_STATUS_CMD])?;
-            self.uart.flush()?;
 
             self.uart.read_exact(&mut buf)?;
         }
@@ -49,7 +50,6 @@ impl UartRadio {
 
     pub fn get_temp(&mut self) -> anyhow::Result<f32> {
         self.uart.write_all(&[GET_TEMP_CMD])?;
-        self.uart.flush()?;
 
         let mut buf = [0; 4];
         self.uart.read_exact(&mut buf)?;
@@ -58,4 +58,45 @@ impl UartRadio {
 
         Ok(temp)
     }
+
+    pub fn sync(&mut self) -> anyhow::Result<()> {
+        // clear any pending packets
+        let mut tries = 0;
+        let mut buf = [0; 100];
+        loop {
+            match self.uart.read(&mut buf) {
+                Ok(0) => break,
+                Ok(_) => {
+                    tries += 1;
+                }
+                Err(e) if matches!(e.kind(), io::ErrorKind::TimedOut) => break,
+                Err(e) => {
+                    return Err(e.into());
+                }
+            }
+        }
+
+        if tries > 0 {
+            eprintln!("[WARN] Sync had pending packets(tries={tries})");
+        }
+
+        tries = 0;
+        let mut buf = [0; 10];
+        loop {
+            self.uart.write_all(&[SYNC_CMD; 10])?;
+            match self.uart.read_exact(&mut buf) {
+                Ok(()) => break,
+                Err(e) if matches!(e.kind(), io::ErrorKind::TimedOut) => {
+                    tries += 1;
+                }
+                Err(e) => {
+                    return Err(e.into());
+                }
+            }
+        }
+
+        eprintln!("Synced in {tries} tries");
+
+        Ok(())
+    }
 }