add serial readout. finish graph layout

This commit is contained in:
2025-04-22 22:14:43 +02:00
parent c81b2e3fbb
commit 58ebddcd48
7 changed files with 90 additions and 39 deletions

View File

@@ -5,7 +5,8 @@ Display display;
Adafruit_NAU7802 nau; Adafruit_NAU7802 nau;
unsigned long _millis = 0; unsigned long _millis = 0;
int32_t val = 0; int32_t val = 0;
bool goToSleep = False; bool goToSleep = false;
#if BLE #if BLE
BLEServer *pServer = NULL; BLEServer *pServer = NULL;
BLECharacteristic *millisCharacteristic = NULL; BLECharacteristic *millisCharacteristic = NULL;
@@ -127,6 +128,8 @@ void loop() {
} }
val = nau.read(); val = nau.read();
Serial.print(millis()); Serial.print(","); Serial.println(val);
#if BLE #if BLE
if (deviceConnected) { if (deviceConnected) {
// Send the sensor reading // Send the sensor reading
@@ -148,7 +151,5 @@ void loop() {
// do stuff here on connecting // do stuff here on connecting
oldDeviceConnected = deviceConnected; oldDeviceConnected = deviceConnected;
} }
#else
Serial.print(millis()); Serial.print(","); Serial.println(val);
#endif #endif
} }

View File

@@ -1,6 +1,6 @@
import tkinter as tk import tkinter as tk
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk
import asyncio import asyncio
@@ -20,19 +20,9 @@ class FilterDevApp(tk.Tk):
self.title("JannTers Filter Evaluation Tool") self.title("JannTers Filter Evaluation Tool")
# Create a frame for the plot and sliders
self.frame = tk.Frame(self)
self.frame.pack(side=tk.LEFT, fill=tk.BOTH)
# Create a figure for plotting
self.fig, self.ax = plt.subplots()
self.ax2 = self.ax.twinx()
self.canvas = FigureCanvasTkAgg(self.fig, master=self.frame)
self.canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH)
# Create a frame for sliders # Create a frame for sliders
self.toolbar = tk.Frame(self, width=200, padx=10) self.toolbar = tk.Frame(self, width=200, padx=10)
self.toolbar.pack(side=tk.RIGHT, fill=tk.Y) self.toolbar.pack(side=tk.LEFT)
# Device Settings # Device Settings
self.record_form = RecordForm(self.toolbar, self.record_data) self.record_form = RecordForm(self.toolbar, self.record_data)
@@ -46,6 +36,16 @@ class FilterDevApp(tk.Tk):
self.data_stats = DataStats(self.toolbar, self.reset) self.data_stats = DataStats(self.toolbar, self.reset)
# Create a figure for plotting
self.frame = tk.Frame(self)
self.frame.pack(side=tk.RIGHT)
self.fig, self.ax = plt.subplots()
self.ax2 = self.ax.twinx()
self.canvas = FigureCanvasTkAgg(self.fig, master=self.frame)
self.canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH)
NavigationToolbar2Tk(self.canvas, self.frame)
def update_plot(self): def update_plot(self):
if self.filter is None: if self.filter is None:
return return
@@ -61,19 +61,27 @@ class FilterDevApp(tk.Tk):
# Generate data # Generate data
x = df['timestamps'] x = df['timestamps']
y1 = df['weights'] y1 = df['weights']
# y1_g = df['calib_weights'] y2 = df['filtered']
# y2 = df['filtered']
y2_g = df['filtered_calib'] y2_g = df['filtered_calib']
# Plot the data # Plot the data
self.ax.plot(x, y1) self.ax.plot(x, y1, label="raw")
# self.ax.plot(x, y2) self.ax.plot(x, y2, label="filtered")
# self.ax2.plot(x, y1_g)
self.ax2.plot(x, y2_g, label="filtered", color='green')
self.ax2.set_ylabel("Weight", color="green")
self.ax.set_xlabel("Time in ms") self.ax.set_xlabel("Time in ms")
self.ax.set_ylabel("Raw Weight") self.ax.set_ylabel("Raw Weight")
self.ax.grid() self.ax.grid()
self.ax.legend(loc='upper left')
self.ax2.yaxis.set_label_position("right")
self.ax2.yaxis.tick_right()
self.ax2.legend(loc='lower right')
# self.ax2.plot(x, y1_g) self.fig.tight_layout()
self.ax2.plot(x, y2_g, color="orange") self.canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH)
# Draw the updated plot # Draw the updated plot
self.canvas.draw() self.canvas.draw()

View File

@@ -3,4 +3,4 @@ SERVICE_UUID = "9f0dfdb2-e978-494c-8f15-68dbe8d28672"
MILLIS_UUID = "abb92561-a809-453c-8c7c-71d3fff5b86e" MILLIS_UUID = "abb92561-a809-453c-8c7c-71d3fff5b86e"
WEIGHT_UUID = "123e4567-e89b-12d3-a456-426614174000" WEIGHT_UUID = "123e4567-e89b-12d3-a456-426614174000"
DEFAULT_CALIB = 104167.17 DEFAULT_CALIB = 307333.83

View File

@@ -32,6 +32,10 @@ class Filter:
def __call__(self) -> pd.DataFrame: def __call__(self) -> pd.DataFrame:
calib_factor = 100. / float(self.calib_entry.get()) calib_factor = 100. / float(self.calib_entry.get())
df = self.device.data df = self.device.data
df = df[df['weights'] < 10e9]
df['timestamps'] -= df['timestamps'].min()
df['filtered'], df['filtered_calib'] = self.filter(df, calib_factor) df['filtered'], df['filtered_calib'] = self.filter(df, calib_factor)
df['calib_weights'] = df['weights'] * calib_factor df['calib_weights'] = df['weights'] * calib_factor
return df return df

View File

@@ -2,8 +2,8 @@ from bleak import BleakClient, BleakScanner
import pandas as pd import pandas as pd
from tkinter.ttk import Entry from tkinter.ttk import Entry
from tkinter.messagebox import showerror, showinfo from tkinter.messagebox import showerror, showinfo
import asyncio
from time import time from time import time
from serial import Serial
from ..config import MILLIS_UUID, WEIGHT_UUID from ..config import MILLIS_UUID, WEIGHT_UUID
@@ -27,6 +27,11 @@ class Device:
self.weights = [] self.weights = []
async def connect(self): async def connect(self):
device_name = self.device_name.get()
if device_name.startswith('/dev'):
self.device = device_name
else:
self.device = await BleakScanner.find_device_by_name(self.device_name.get()) self.device = await BleakScanner.find_device_by_name(self.device_name.get())
return self.device is not None return self.device is not None
@@ -35,13 +40,36 @@ class Device:
self.device = None self.device = None
async def read_values(self, duration): async def read_values(self, duration):
duration = int(duration)
if not await self.connect(): if not await self.connect():
showerror("Record Data", f"Device {self.device_name.get()} not found!") showerror("Record Data", f"Device {self.device_name.get()} not found!")
return return
if isinstance(self.device, str):
self._read_values_serial(duration)
else:
await self._read_values_ble(duration)
def _read_values_serial(self, duration):
with Serial(self.device, baudrate=115200) as ser:
showinfo("Record Data", f"Recording data for {duration} seconds.")
time_start = time()
time_passed = 0
while time_passed < duration:
line = ser.readline()
_timestamp, _raw_weight = line.decode('utf-8').split(',')
self.timestamps.append(int(_timestamp))
self.weights.append(int(_raw_weight))
time_passed = time() - time_start
async def _read_values_ble(self, duration):
self.clear_data() self.clear_data()
try:
async with BleakClient(self.device.address) as client: async with BleakClient(self.device.address) as client:
showinfo("Recording Data", f"Recording data for {duration} seconds.") showinfo("Record Data", f"Recording data for {duration} seconds.")
time_start = time() time_start = time()
time_passed = 0 time_passed = 0
while time_passed < duration: while time_passed < duration:
@@ -54,6 +82,8 @@ class Device:
self.weights.append(weight) self.weights.append(weight)
time_passed = time() - time_start time_passed = time() - time_start
except:
showerror("Record Data", f"Client could not be started for {self.device_name.get()}: {self.device.address}.")
def clear_data(self): def clear_data(self):

View File

@@ -3,17 +3,24 @@ from tkinter import ttk
from ..slider import Slider from ..slider import Slider
from serial.tools import list_ports
class RecordForm(tk.Frame): class RecordForm(tk.Frame):
def __init__(self, master, record_command, **kwargs): def __init__(self, master, record_command, **kwargs):
super().__init__(master, **kwargs) super().__init__(master, **kwargs)
self.device_label = ttk.Label(self, text="Device Name:") # get serial ports
serials = [d.device for d in list_ports.grep('usbmodem')]
devices = serials + ["Smaage"]
default_record_len = 10 if len(serials) > 0 else 30
self.device_label = ttk.Label(self, text="Device:")
self.device_label.pack(pady=10) self.device_label.pack(pady=10)
self.device_name = ttk.Entry(self) self.device_name = ttk.Combobox(self, values=devices)
self.device_name.insert(0, "Smaage") # Set default value self.device_name.set(devices[0])
self.device_name.pack() self.device_name.pack()
self.record_time = Slider(self, "Record Time:", 10, 30, 10, lambda: None) self.record_time = Slider(self, "Record Time:", 10, 60, default_record_len, lambda: None)
self.record_time.pack(pady=10) self.record_time.pack(pady=10)
self.record_button = ttk.Button(self, text="Record Data", command=record_command) self.record_button = ttk.Button(self, text="Record Data", command=record_command)
self.record_button.pack(pady=10) self.record_button.pack(pady=10)

View File

@@ -3,3 +3,4 @@ bleak
pandas pandas
tqdm tqdm
numpy numpy
pyserial