import serial import struct import threading import matplotlib.pyplot as plt from matplotlib.animation import FuncAnimation # Configure your serial port settings. SERIAL_PORT = '/dev/ttyUSB0' # Update to match your serial port. BAUD_RATE = 115200 # Update to match your settings. FLOAT_SIZE = 4 # Size of a float in bytes (usually 4 bytes) # Shared state, updated by the reading thread, read by the plotting function. # Initialize values with None. adc_values = [None, None, None] angle = None # Define the thread that will read the serial data. def read_serial_data(ser): global adc_values, angle try: while True: byte = ser.read(1) if byte == b'\xDE': next_byte = ser.read(1) if next_byte == b'\xAD': data = ser.read(FLOAT_SIZE * 4) if len(data) == FLOAT_SIZE * 4: floats = struct.unpack('<4f', data) packet_end = ser.read(2) if packet_end == bytes([0xBE, 0xAF]): # Update our shared state. adc_values = list(floats[0:3]) angle = floats[3] except serial.SerialException as e: print("Serial exception:", e) except struct.error as e: print("Unpacking error:", e) except: print("Other error or thread exiting.") # Start the serial reader in a separate thread. thread = threading.Thread(target=read_serial_data, args=(serial.Serial(SERIAL_PORT, BAUD_RATE, timeout=1),)) thread.daemon = True # Thread will be killed when the main thread exits. thread.start() # Set up the Matplotlib figures and axes. fig = plt.figure(figsize=(10, 5)) # Create a normal subplot for the bar graph. ax_bar = fig.add_subplot(1, 2, 1) # Create another subplot for the polar plot by specifying polar=True. ax_polar = fig.add_subplot(1, 2, 2, polar=True) # Set the properties for polar plot. ax_polar.set_theta_zero_location('N') ax_polar.set_theta_direction(-1) # Bar plot axis. bars = ax_bar.bar(['ADC0', 'ADC1', 'ADC2'], [0, 0, 0]) ax_bar.set_ylim(0, 0.4) # Set the limit for your ADC values. # Polar plot axis. ax_polar.set_theta_zero_location('N') ax_polar.set_theta_direction(-1) angle_plot, = ax_polar.plot([], [], 'go') # Initial empty plot. # Update function for the animation. def update(i): # Global variables holding the shared state. global adc_values, angle # Check if we have received new data. if all(v is not None for v in adc_values) and angle is not None: # Update the bar plot. for bar, value in zip(bars, adc_values): bar.set_height(value) # Update the polar plot. angle_rad = angle / 180.0 * 3.14159 # Convert degrees to radians. angle_plot.set_data([angle_rad], [1]) # Set angle for the plot, using radial distance of 1. return bars.patches + [angle_plot] # Create the animation itself, which will call update function repeatedly. ani = FuncAnimation(fig, update, blit=True, interval=1) # Update interval is in milliseconds. # Show the plot. plt.show()