servo/firmware/vizualize.py

88 lines
3.1 KiB
Python

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()