diff --git a/integration/integrate.py b/integration/integrate.py
index 6d69a360b540c9fb825fca05adbcdb9926aa5e02..45d2f057c2a8ab60faa71bc6848301e01d422812 100644
--- a/integration/integrate.py
+++ b/integration/integrate.py
@@ -1,3 +1,4 @@
+import threading
 import tkinter as tk
 from tkinter import ttk
 from matplotlib.pyplot import Figure
@@ -8,6 +9,7 @@ import serial
 from math import atan2, asin, cos, sin
 from matplotlib.figure import Figure
 from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
+from mpl_toolkits.mplot3d.art3d import Poly3DCollection
 import numpy as np
 
 from vpython import canvas
@@ -27,30 +29,31 @@ class Interface:
 
     def create_popup(self):
         global frame1, frame2, frame3, frame4,width,height,popup
-        popup = tk.Tk()
-        popup.title("Project")
+        self.popup = tk.Tk()
+        self.popup.title("Project")
 
         # Set the initial size and position of the popup window
         width = 1000
         height = 600
-        screen_width = popup.winfo_screenwidth()
-        screen_height = popup.winfo_screenheight()
+        screen_width = self.popup.winfo_screenwidth()
+        screen_height = self.popup.winfo_screenheight()
         x = (screen_width // 2) - (width // 2)
         y = (screen_height // 2) - (height // 2)
-        popup.geometry(f"{width}x{height}+{x}+{y}")
+        self.popup.geometry(f"{width}x{height}+{x}+{y}")
 
         # Configure the grid to be expandable
-        popup.columnconfigure(0, weight=1)
-        popup.columnconfigure(1, weight=1)
-        popup.rowconfigure(0, weight=1)
-        popup.rowconfigure(1, weight=1)
+        self.popup.columnconfigure(0, weight=1)
+        self.popup.columnconfigure(1, weight=1)
+        self.popup.rowconfigure(0, weight=1)
+        self.popup.rowconfigure(1, weight=1)
 
         # First row, two sections
-        frame1 = ttk.Frame(popup, borderwidth=1, relief="solid",width=width/3,height=height/2)
-        frame1.grid(row=0, column=0, padx=10, pady=10, sticky="nsew")
+        self.frame1 = ttk.Frame(self.popup, borderwidth=1, relief="solid",width=width/3,height=height/2)
+        self.frame1.grid(row=0, column=0, padx=10, pady=10, sticky="nsew")
+        self._initialise_IMU_3D_graph()
 
 
-        frame2 = ttk.Frame(popup, borderwidth=1, relief="solid",width=width*2/3,height=height/2)
+        frame2 = ttk.Frame(self.popup, borderwidth=1, relief="solid",width=width*2/3,height=height/2)
         frame2.grid(row=0, column=1, padx=10, pady=10, sticky="nsew")
         label1 = ttk.Label(frame2, text="If IMU is connected to the laptop please click the Connect button",
                            wraplength=width / 2)
@@ -60,19 +63,19 @@ class Interface:
         frame2.update_idletasks()
 
         # Second row, two sections
-        frame3 = ttk.Frame(popup, borderwidth=1, relief="solid",width=width/3,height=height/2)
+        frame3 = ttk.Frame(self.popup, borderwidth=1, relief="solid",width=width/3,height=height/2)
         frame3.grid(row=1, column=0, padx=10, pady=10, sticky="nsew")
         label3 = ttk.Label(frame3, text="If EMG is connected to the laptop please click the Connect button",wraplength=width/4)
         label3.place(relx=0.5, rely=0.9, anchor='center')
         label4 = ttk.Label(frame3, text="Port: None ")
         label4.place(relx=0.35, rely=0.8, anchor='e')
 
-        frame4 = ttk.Frame(popup, borderwidth=1, relief="solid",width=width*2/3,height=height/2)
+        frame4 = ttk.Frame(self.popup, borderwidth=1, relief="solid",width=width*2/3,height=height/2)
         frame4.grid(row=1, column=1, padx=10, pady=10, sticky="nsew")
         frame4.grid_propagate(False)
         label4 = ttk.Label(frame4, text="Section 4")
         label4.place(relx=0.5, rely=0.5, anchor='center')
-        self._initialise_real_time_classification_graph()
+        #self._initialise_real_time_classification_graph()
 
         # Add a button to frame1 to trigger adding widgets
         add_button1 = ttk.Button(frame2, text="Connect", command=self.IMU_Connect)
@@ -85,91 +88,20 @@ class Interface:
         add_button4 = ttk.Button(frame3, text="Disconnect", command=self.EMG_disconnect())
         add_button4.place(relx=0.8, rely=0.8, anchor='center')
 
-        popup.mainloop()
+
 
     def IMU_Connect(self):
+        self.label2.config(text="Port: COM6")
         try:
             self._iMU_isConnected=True
-            self.arduino = serial.Serial('COM6', 115200, timeout=1)
-            column_limit = 9
-            self.label2 = ttk.Label(frame2, text="Port: COM6 ")
-            self.label2.place(relx=0.35, rely=0.8, anchor='center')
+
             print("Connected to IMU")
+            self.update_thread = threading.Thread(target=self.update_display)
+            self.update_thread.daemon = True
+            self.update_thread.start()
         except serial.SerialException:
             print("IMU is not connected")
             return
-        sleep(1)
-
-        scene.range = 5  # 修改场景的范围为10
-        scene.forward = vector(-1, -1, -1)  # 保持视角不变
-        scene.width = 300  # 修改场景的宽度为800
-        scene.height = 300  # 修改场景的高度为800
-        scene.center = vector(0, 0, 0)  # 将场景中心位置调整为 (0, 0, 0)
-
-        scene.width = 600
-        scene.height = 600
-
-        frontArrow = arrow(axis=vector(1, 0, 0), length=4, shaftwidth=.1, color=color.purple)
-        upArrow = arrow(axis=vector(0, 1, 0), length=1, shaftwidth=.1, color=color.magenta)
-        sideArrow = arrow(axis=vector(0, 0, 1), length=2, shaftwidth=.1, color=color.orange)
-
-        bBoard = box(length=3, width=4, height=.2, color=color.white, opacity=0.8, pos=vector(0, 0, 0))
-        bno = box(color=color.blue, length=1, width=.75, height=0.1, pos=vector(-0.5, 0.1 + 0.05, 0))
-        nano = box(length=1.75, width=.6, height=.1, pos=vector(-2, .1 + .05, 0), color=color.green)
-        myObj = compound([bBoard, bno, nano])
-        last_print_time = time()
-
-        try:
-            while (self._iMU_isConnected==True):
-                while self.arduino.inWaiting() == 0:
-                    pass
-
-                try:
-                    data_packet = self.arduino.readline().decode('utf-8').strip()
-                    data = data_packet.split(',')
-
-                    if len(data) == column_limit:
-                        emg = float(data[0])  # emg sensor data
-                        q0 = float(data[1])  # qw
-                        q1 = float(data[2])  # qx
-                        q2 = float(data[3])  # qy
-                        q3 = float(data[4])  # qz
-
-                        roll = atan2(2 * (q0 * q1 + q2 * q3), 1 - 2 * (q1 * q1 + q2 * q2))
-                        pitch = -asin(2 * (q0 * q2 - q3 * q1))
-                        yaw = -atan2(2 * (q0 * q3 + q1 * q2), 1 - 2 * (q2 * q2 + q3 * q3))
-                        current_time = time()
-
-                        if current_time - last_print_time >= 0.01:
-                            print(f"EMG: {emg}, Roll: {roll}, Pitch: {pitch}, Yaw: {yaw}")
-                        k = vector(cos(yaw) * cos(pitch), sin(pitch), sin(yaw) * cos(pitch))  # this is the x vector
-                        y = vector(0, 1, 0)  # y vector: pointing down
-                        s = cross(k, y)  # this is pointing to the side
-                        v = cross(s, k)  # the up vector
-                        vrot = v * cos(roll) + cross(k, v) * sin(roll)
-                        #    print(k,y,s,v)
-
-                        frontArrow.axis = k
-                        sideArrow.axis = cross(k, vrot)
-                        upArrow.axis = vrot
-                        myObj.axis = k
-                        myObj.up = vrot
-                        sideArrow.length = 2
-                        frontArrow.length = 4
-                        upArrow.length = 1
-                        last_print_time = current_time
-
-                    else:
-                        print("Data packet does not match column limit")
-
-                except ValueError:
-                    print("Error in data conversion")
-                except UnicodeDecodeError:
-                    print("Error in decoding data")
-
-        except KeyboardInterrupt:
-            self.arduino.close()
-            print("Disconnected from IMU")
 
     def IMU_disconnect(self):
         self._iMU_isConnected = False
@@ -224,6 +156,84 @@ class Interface:
             self.treeview.insert("", "end", values=("Gesture 1", f"{emg_data[0]:.2f}"))
             self.treeview.insert("", "end", values=("Gesture 2", f"{emg_data[1]:.2f}"))
 
+    def _initialise_IMU_3D_graph(self):
+
+        self.arduino = serial.Serial('COM6', 115200, timeout=1)
+        # Conversions
+        self.toRad = 2 * np.pi / 360
+        self.toDeg = 1 / self.toRad
+
+        # Initialize Parameters
+        self.count = 0
+        self.averageroll = 0
+        self.averageyaw = 0
+        self.averagepitch = 0
+        self.averageemg = 0
+        self.iterations = 10  # EMG measurements to get average
+
+        # Create a figure for the 3D plot
+        self.fig = Figure(figsize=((width / 300), (height / 200)))
+        self.ax = self.fig.add_subplot(111, projection='3d')
+
+        # Set Limits
+        self.ax.set_xlim(-2, 2)
+        self.ax.set_ylim(-2, 2)
+        self.ax.set_zlim(-2, 2)
+
+        # Set labels
+        self.ax.set_xlabel('X')
+        self.ax.set_ylabel('Y')
+        self.ax.set_zlabel('Z',labelpad=0)
+
+        # Draw Axes
+        self.ax.quiver(0, 0, 0, 2, 0, 0, color='red', label='X-Axis', arrow_length_ratio=0.1)  # X Axis (Red)
+        self.ax.quiver(0, 0, 0, 0, -2, 0, color='green', label='Y-Axis', arrow_length_ratio=0.1)  # Y Axis (Green)
+        self.ax.quiver(0, 0, 0, 0, 0, 4, color='blue', label='Z-Axis', arrow_length_ratio=0.1)  # Z Axis (Blue)
+
+        # Draw the board as a rectangular prism (solid)
+        self.prism_vertices = np.array([
+            [-1.5, -1, 0], [1.5, -1, 0], [1.5, 1, 0], [-1.5, 1, 0],  # bottom vertices
+            [-1.5, -1, 0.1], [1.5, -1, 0.1], [1.5, 1, 0.1], [-1.5, 1, 0.1]
+            # top vertices (height=0.1 for visual thickness)
+        ])
+
+        self.prism_faces = [
+            [self.prism_vertices[j] for j in [0, 1, 2, 3]],  # bottom face
+            [self.prism_vertices[j] for j in [4, 5, 6, 7]],  # top face
+            [self.prism_vertices[j] for j in [0, 1, 5, 4]],  # side face
+            [self.prism_vertices[j] for j in [1, 2, 6, 5]],  # side face
+            [self.prism_vertices[j] for j in [2, 3, 7, 6]],  # side face
+            [self.prism_vertices[j] for j in [3, 0, 4, 7]]  # side face
+        ]
+
+        self.prism_collection = Poly3DCollection(self.prism_faces, facecolors='gray', linewidths=1, edgecolors='black',
+                                                 alpha=0.25)
+        self.ax.add_collection3d(self.prism_collection)
+
+        # Front Arrow (Purple)
+        self.front_arrow, = self.ax.plot([0, 2], [0, 0], [0, 0], color='purple', marker='o', markersize=10,
+                                         label='Front Arrow')
+
+        # Up Arrow (Magenta)
+        self.up_arrow, = self.ax.plot([0, 0], [0, -1], [0, 1], color='magenta', marker='o', markersize=10,
+                                      label='Up Arrow')
+
+        # Side Arrow (Orange)
+        self.side_arrow, = self.ax.plot([0, 1], [0, -1], [0, 1], color='orange', marker='o', markersize=10,
+                                        label='Side Arrow')
+
+        # Create a canvas to draw on
+        self.canvas = FigureCanvasTkAgg(self.fig, master=self.frame1)
+        self.canvas.draw()
+        self.canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True)
+
+        self.update_display()
+
+        # Create a label for average EMG
+       # self.emg_label = tk.Label(self.frame1, text="Average EMG: 0", font=("Arial", 14))
+        #self.emg_label.pack(pady=10)
+
+
 
     def _initialise_real_time_classification_graph(self):
             # Create a figure and axis
@@ -255,7 +265,7 @@ class Interface:
             self.line2, = self.ax.plot([], [], color='blue', label='Inner Wrist Muscle (Flexor Carpi Radialis)')
             self.ax.legend(fontsize=9, loc='upper right')
 
-            
+
 
 
             # Embed the plot in the tkinter frame
@@ -263,6 +273,121 @@ class Interface:
             self.canvas.draw()
             self.canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True)
 
+    def update_display(self):
+        try:
+            while self.arduino.inWaiting() > 0:
+                dataPacket = self.arduino.readline()
+                dataPacket = dataPacket.decode()
+                cleandata = dataPacket.replace("\r\n", "")
+                row = cleandata.strip().split(',')
+
+                if len(row) == 9:
+                    splitPacket = cleandata.split(',')
+
+                    emg = float(splitPacket[0])  # EMG sensor data
+                    q0 = float(splitPacket[1])  # qw
+                    q1 = float(splitPacket[2])  # qx
+                    q2 = float(splitPacket[3])  # qy
+                    q3 = float(splitPacket[4])  # qz
+
+                    # Calculate Angles
+                    roll = atan2(2 * (q0 * q1 + q2 * q3), 1 - 2 * (q1 * q1 + q2 * q2))
+                    pitch = -asin(2 * (q0 * q2 - q3 * q1))
+                    yaw = -atan2(2 * (q0 * q3 + q1 * q2), 1 - 2 * (q2 * q2 + q3 * q3))
+
+                    # Rotation matrices
+                    Rz = np.array([
+                        [np.cos(yaw), -np.sin(yaw), 0],
+                        [np.sin(yaw), np.cos(yaw), 0],
+                        [0, 0, 1]
+                    ])
+
+                    Ry = np.array([
+                        [np.cos(pitch), 0, np.sin(pitch)],
+                        [0, 1, 0],
+                        [-np.sin(pitch), 0, np.cos(pitch)]
+                    ])
+
+                    Rx = np.array([
+                        [1, 0, 0],
+                        [0, np.cos(roll), -np.sin(roll)],
+                        [0, np.sin(roll), np.cos(roll)]
+                    ])
+
+                    R = Rz @ Ry @ Rx  # Combined rotation matrix
+
+                    # Apply the rotation
+                    rotated_vertices = (R @ self.prism_vertices.T).T
+
+                    prism_faces_rotated = [
+                        [rotated_vertices[j] for j in [0, 1, 2, 3]],  # bottom face
+                        [rotated_vertices[j] for j in [4, 5, 6, 7]],  # top face
+                        [rotated_vertices[j] for j in [0, 1, 5, 4]],  # side face
+                        [rotated_vertices[j] for j in [1, 2, 6, 5]],  # side face
+                        [rotated_vertices[j] for j in [2, 3, 7, 6]],  # side face
+                        [rotated_vertices[j] for j in [3, 0, 4, 7]]  # side face
+                    ]
+
+                    # Update the collection
+                    self.prism_collection.set_verts(prism_faces_rotated)
+
+                    # Update Arrows
+                    k = np.array([np.cos(yaw) * np.cos(pitch), np.sin(pitch), np.sin(yaw) * np.cos(pitch)])  # X vector
+                    y = np.array([0, 1, 0])  # Y vector: pointing down
+                    s = np.cross(k, y)  # Side vector
+                    v = np.cross(s, k)  # Up vector
+                    vrot = v * np.cos(roll) + np.cross(k, v) * np.sin(roll)  # Rotated Up vector
+
+                    self.front_arrow.set_data([0, k[0] * 2], [0, k[1] * 2])
+                    self.front_arrow.set_3d_properties([0, k[2] * 2])
+                    self.up_arrow.set_data([0, vrot[0] * 1], [0, vrot[1] * 1])
+                    self.up_arrow.set_3d_properties([0, vrot[2] * 1])
+                    self.side_arrow.set_data([0, s[0] * 1], [0, s[1] * 1])
+                    self.side_arrow.set_3d_properties([0, s[2] * 1])
+
+                    # Update canvas
+                    self.canvas.draw()
+
+                    self.averageroll += roll * self.toDeg
+                    self.averageyaw += yaw * self.toDeg
+                    self.averagepitch += pitch * self.toDeg
+                    self.averageemg += emg
+
+                    if self.count == self.iterations:
+                        self.averageroll = self.averageroll / self.iterations
+                        self.averageyaw = self.averageyaw / self.iterations
+                        self.averagepitch = self.averagepitch / self.iterations
+                        self.averageemg = self.averageemg / self.iterations
+
+                        self.averageroll = round(self.averageroll)
+                        self.averageyaw = round(self.averageyaw)
+                        self.averagepitch = round(self.averagepitch)
+
+                        # Print the averaged results
+                        print("iterations:", self.iterations)
+                        print("averageroll is", self.averageroll)
+                        print("averageyaw is", self.averageyaw)
+                        print("averagepitch is", self.averagepitch)
+                        print("averageemg=", self.averageemg)
+
+                        self.count = 0
+
+                        self.averageyaw = 0
+                        self.averageroll = 0
+                        self.averagepitch = 0
+                        self.averageemg = 0
+                    else:
+                        self.count += 1
+
+                    # Update EMG Label
+                   # self.emg_label.config(text=f"Average EMG: {self.averageemg:.2f}")
+
+        except Exception as e:
+            print(f"An error occurred: {e}")
+
+        # Call update_display() again after 50 milliseconds
+        self.popup.after(50, self.update_display)
+
 
 
 
@@ -270,6 +395,7 @@ class Interface:
 if __name__ == "__main__":
     windows = Interface()
     windows.create_popup()
+    windows.popup.mainloop()