Skip to content

Commit eee78b2

Browse files
Turned class WaveGeneratorArduino into module
1 parent daf40d5 commit eee78b2

File tree

7 files changed

+233
-335
lines changed

7 files changed

+233
-335
lines changed

WaveGeneratorArduino.py

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
#!/usr/bin/env python3
2+
# -*- coding: utf-8 -*-
3+
"""Provides classes `WaveGeneratorArduino` and `FakeWaveGeneratorArduino`.
4+
"""
5+
__author__ = "Dennis van Gils"
6+
__authoremail__ = "vangils.dennis@gmail.com"
7+
__url__ = "https://github.com/Dennis-van-Gils/DvG_Arduino_PyQt_multithread_demo"
8+
__date__ = "11-06-2024"
9+
__version__ = "9.0"
10+
11+
import time
12+
13+
from qtpy import QtCore
14+
import numpy as np
15+
16+
from dvg_devices.Arduino_protocol_serial import Arduino
17+
18+
# ------------------------------------------------------------------------------
19+
# WaveGeneratorArduino
20+
# ------------------------------------------------------------------------------
21+
22+
23+
class WaveGeneratorArduino(Arduino):
24+
"""Manages serial communication with an Arduino that is programmed as a wave
25+
generator."""
26+
27+
class State:
28+
"""Container for the process and measurement variables of the wave
29+
generator Arduino."""
30+
31+
time_0 = np.nan # [s] Start of data acquisition
32+
time = np.nan # [s]
33+
reading_1 = np.nan # [arbitrary units]
34+
35+
def __init__(
36+
self,
37+
name="Ard",
38+
long_name="Arduino",
39+
connect_to_specific_ID="Wave generator",
40+
):
41+
super().__init__(
42+
name=name,
43+
long_name=long_name,
44+
connect_to_specific_ID=connect_to_specific_ID,
45+
)
46+
47+
# Container for the process and measurement variables
48+
self.state = self.State
49+
50+
# Mutex for proper multithreading. If the state variables are not
51+
# atomic or thread-safe, you should lock and unlock this mutex for each
52+
# read and write operation. In this demo we don't need it, but I keep it
53+
# as reminder.
54+
self.mutex = QtCore.QMutex()
55+
56+
def set_waveform_to_sine(self):
57+
"""Send the instruction to the Arduino to change to a sine wave."""
58+
self.write("sine")
59+
60+
def set_waveform_to_square(self):
61+
"""Send the instruction to the Arduino to change to a square wave."""
62+
self.write("square")
63+
64+
def set_waveform_to_sawtooth(self):
65+
"""Send the instruction to the Arduino to change to a sawtooth wave."""
66+
self.write("sawtooth")
67+
68+
69+
# ------------------------------------------------------------------------------
70+
# FakeWaveGeneratorArduino
71+
# ------------------------------------------------------------------------------
72+
73+
74+
class FakeWaveGeneratorArduino:
75+
"""Simulates via software the serial communication with a faked Arduino that
76+
is programmed as a wave generator. Mimics class `WaveGeneratorArduino`.
77+
"""
78+
79+
class State:
80+
"""Container for the process and measurement variables of the wave
81+
generator Arduino."""
82+
83+
time_0 = np.nan # [s] Start of data acquisition
84+
time = np.nan # [s]
85+
reading_1 = np.nan # [arbitrary units]
86+
87+
def __init__(self, *args, **kwargs):
88+
self.serial_settings = {}
89+
self.name = "FakeArd"
90+
self.long_name = "FakeArduino"
91+
self.is_alive = True
92+
93+
# Container for the process and measurement variables
94+
self.state = self.State
95+
96+
# Mutex for proper multithreading. If the state variables are not
97+
# atomic or thread-safe, you should lock and unlock this mutex for each
98+
# read and write operation. In this demo we don't need it, but I keep it
99+
# as reminder.
100+
self.mutex = QtCore.QMutex()
101+
102+
self.wave_freq = 0.3 # [Hz]
103+
self.wave_type = "sine"
104+
105+
def set_waveform_to_sine(self):
106+
"""Send the instruction to the Arduino to change to a sine wave."""
107+
self.wave_type = "sine"
108+
109+
def set_waveform_to_square(self):
110+
"""Send the instruction to the Arduino to change to a sine wave."""
111+
self.wave_type = "square"
112+
113+
def set_waveform_to_sawtooth(self):
114+
"""Send the instruction to the Arduino to change to a sine wave."""
115+
self.wave_type = "sawtooth"
116+
117+
def query_ascii_values(self, *args, **kwargs):
118+
"""Query the Arduino for new readings and return them as a list."""
119+
t = time.perf_counter()
120+
121+
if self.wave_type == "sine":
122+
value = np.sin(2 * np.pi * self.wave_freq * t)
123+
124+
elif self.wave_type == "square":
125+
value = 1 if np.mod(self.wave_freq * t, 1.0) > 0.5 else -1
126+
127+
elif self.wave_type == "sawtooth":
128+
value = 2 * np.mod(self.wave_freq * t, 1.0) - 1
129+
130+
success = True
131+
readings = [t * 1000, value]
132+
133+
return success, readings
134+
135+
def close(self):
136+
"""Close the serial connection to the Arduino."""
137+
return
138+
139+
def auto_connect(self, *args, **kwargs):
140+
"""Auto connect to the Arduino via serial."""
141+
return True

demo_A_GUI_full.py

Lines changed: 16 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
__author__ = "Dennis van Gils"
77
__authoremail__ = "vangils.dennis@gmail.com"
88
__url__ = "https://github.com/Dennis-van-Gils/DvG_Arduino_PyQt_multithread_demo"
9-
__date__ = "30-05-2024"
10-
__version__ = "8.4"
9+
__date__ = "11-06-2024"
10+
__version__ = "9.0"
1111
# pylint: disable=missing-function-docstring, unnecessary-lambda
1212

1313
import os
@@ -20,17 +20,15 @@
2020
from qtpy.QtCore import Slot # type: ignore
2121

2222
import psutil
23-
import numpy as np
2423
import pyqtgraph as pg
2524

2625
from dvg_debug_functions import tprint, dprint, print_fancy_traceback as pft
2726
from dvg_pyqtgraph_threadsafe import HistoryChartCurve, PlotManager
2827
from dvg_pyqt_filelogger import FileLogger
2928
import dvg_pyqt_controls as controls
30-
31-
from dvg_devices.Arduino_protocol_serial import Arduino
3229
from dvg_qdeviceio import QDeviceIO, DAQ_TRIGGER
33-
from dvg_fakearduino import FakeArduino
30+
31+
from WaveGeneratorArduino import WaveGeneratorArduino, FakeWaveGeneratorArduino
3432

3533
# fmt: off
3634
# Constants
@@ -85,45 +83,6 @@ def current_date_time_strings():
8583
)
8684

8785

88-
# ------------------------------------------------------------------------------
89-
# WaveGeneratorArduino
90-
# ------------------------------------------------------------------------------
91-
92-
93-
class WaveGeneratorArduino(Arduino):
94-
"""Provides higher-level general I/O methods for communicating with an
95-
Arduino that is programmed as a wave generator."""
96-
97-
class State:
98-
"""Reflects the actual readings, parsed into separate variables, of the
99-
wave generator Arduino.
100-
"""
101-
102-
time = np.nan # [s]
103-
reading_1 = np.nan # [arbitrary units]
104-
105-
def __init__(
106-
self,
107-
name="Ard",
108-
long_name="Arduino",
109-
connect_to_specific_ID="Wave generator",
110-
):
111-
super().__init__(
112-
name=name,
113-
long_name=long_name,
114-
connect_to_specific_ID=connect_to_specific_ID,
115-
)
116-
117-
# Container for the process and measurement variables
118-
self.state = self.State
119-
120-
# Mutex for proper multithreading. If the state variables are not
121-
# atomic or thread-safe, you should lock and unlock this mutex for each
122-
# read and write operation. In this demo we don't need it, but I keep it
123-
# as reminder.
124-
self.mutex = QtCore.QMutex()
125-
126-
12786
# ------------------------------------------------------------------------------
12887
# WaveGeneratorArduino_qdev
12988
# ------------------------------------------------------------------------------
@@ -135,7 +94,7 @@ class WaveGeneratorArduino_qdev(QDeviceIO):
13594

13695
def __init__(
13796
self,
138-
dev: Union[WaveGeneratorArduino, FakeArduino],
97+
dev: Union[WaveGeneratorArduino, FakeWaveGeneratorArduino],
13998
DAQ_interval_ms=DAQ_INTERVAL_MS,
14099
DAQ_timer_type=QtCore.Qt.TimerType.PreciseTimer,
141100
critical_not_alive_count=1,
@@ -166,13 +125,13 @@ def set_DAQ_enabled(self, state: bool):
166125
self.worker_DAQ.DAQ_function = None
167126

168127
def set_waveform_to_sine(self):
169-
self.send(self.dev.write, "sine")
128+
self.send(self.dev.set_waveform_to_sine)
170129

171130
def set_waveform_to_square(self):
172-
self.send(self.dev.write, "square")
131+
self.send(self.dev.set_waveform_to_square)
173132

174133
def set_waveform_to_sawtooth(self):
175-
self.send(self.dev.write, "sawtooth")
134+
self.send(self.dev.set_waveform_to_sawtooth)
176135

177136
# --------------------------------------------------------------------------
178137
# DAQ_function
@@ -202,8 +161,13 @@ def DAQ_function(self) -> bool:
202161
)
203162
return False
204163

205-
if USE_PC_TIME:
206-
self.dev.state.time = time.perf_counter()
164+
# Use Arduino time or PC time?
165+
now = time.perf_counter() if USE_PC_TIME else self.dev.state.time
166+
if self.update_counter_DAQ == 1:
167+
self.dev.state.time_0 = now
168+
self.dev.state.time = 0
169+
else:
170+
self.dev.state.time = now - self.dev.state.time_0
207171

208172
# Return success
209173
return True
@@ -516,7 +480,7 @@ def update_chart(self):
516480
# --------------------------------------------------------------------------
517481

518482
if SIMULATE_ARDUINO:
519-
ard = FakeArduino()
483+
ard = FakeWaveGeneratorArduino()
520484
else:
521485
ard = WaveGeneratorArduino()
522486

demo_B_GUI_minimal.py

Lines changed: 16 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
__author__ = "Dennis van Gils"
77
__authoremail__ = "vangils.dennis@gmail.com"
88
__url__ = "https://github.com/Dennis-van-Gils/DvG_Arduino_PyQt_multithread_demo"
9-
__date__ = "30-05-2024"
10-
__version__ = "8.4"
9+
__date__ = "11-06-2024"
10+
__version__ = "9.0"
1111
# pylint: disable=missing-function-docstring
1212

1313
import os
@@ -20,15 +20,13 @@
2020
from qtpy.QtCore import Slot # type: ignore
2121

2222
import psutil
23-
import numpy as np
2423
import pyqtgraph as pg
2524

2625
from dvg_debug_functions import dprint, print_fancy_traceback as pft
2726
from dvg_pyqtgraph_threadsafe import HistoryChartCurve
28-
29-
from dvg_devices.Arduino_protocol_serial import Arduino
3027
from dvg_qdeviceio import QDeviceIO, DAQ_TRIGGER
31-
from dvg_fakearduino import FakeArduino
28+
29+
from WaveGeneratorArduino import WaveGeneratorArduino, FakeWaveGeneratorArduino
3230

3331
# fmt: off
3432
# Constants
@@ -82,45 +80,6 @@ def current_date_time_strings():
8280
)
8381

8482

85-
# ------------------------------------------------------------------------------
86-
# WaveGeneratorArduino
87-
# ------------------------------------------------------------------------------
88-
89-
90-
class WaveGeneratorArduino(Arduino):
91-
"""Provides higher-level general I/O methods for communicating with an
92-
Arduino that is programmed as a wave generator."""
93-
94-
class State:
95-
"""Reflects the actual readings, parsed into separate variables, of the
96-
wave generator Arduino.
97-
"""
98-
99-
time = np.nan # [s]
100-
reading_1 = np.nan # [arbitrary units]
101-
102-
def __init__(
103-
self,
104-
name="Ard",
105-
long_name="Arduino",
106-
connect_to_specific_ID="Wave generator",
107-
):
108-
super().__init__(
109-
name=name,
110-
long_name=long_name,
111-
connect_to_specific_ID=connect_to_specific_ID,
112-
)
113-
114-
# Container for the process and measurement variables
115-
self.state = self.State
116-
117-
# Mutex for proper multithreading. If the state variables are not
118-
# atomic or thread-safe, you should lock and unlock this mutex for each
119-
# read and write operation. In this demo we don't need it, but I keep it
120-
# as reminder.
121-
self.mutex = QtCore.QMutex()
122-
123-
12483
# ------------------------------------------------------------------------------
12584
# WaveGeneratorArduino_qdev
12685
# ------------------------------------------------------------------------------
@@ -132,7 +91,7 @@ class WaveGeneratorArduino_qdev(QDeviceIO):
13291

13392
def __init__(
13493
self,
135-
dev: Union[WaveGeneratorArduino, FakeArduino],
94+
dev: Union[WaveGeneratorArduino, FakeWaveGeneratorArduino],
13695
DAQ_interval_ms=DAQ_INTERVAL_MS,
13796
DAQ_timer_type=QtCore.Qt.TimerType.PreciseTimer,
13897
critical_not_alive_count=1,
@@ -163,13 +122,13 @@ def set_DAQ_enabled(self, state: bool):
163122
self.worker_DAQ.DAQ_function = None
164123

165124
def set_waveform_to_sine(self):
166-
self.send(self.dev.write, "sine")
125+
self.send(self.dev.set_waveform_to_sine)
167126

168127
def set_waveform_to_square(self):
169-
self.send(self.dev.write, "square")
128+
self.send(self.dev.set_waveform_to_square)
170129

171130
def set_waveform_to_sawtooth(self):
172-
self.send(self.dev.write, "sawtooth")
131+
self.send(self.dev.set_waveform_to_sawtooth)
173132

174133
# --------------------------------------------------------------------------
175134
# DAQ_function
@@ -199,8 +158,13 @@ def DAQ_function(self) -> bool:
199158
)
200159
return False
201160

202-
if USE_PC_TIME:
203-
self.dev.state.time = time.perf_counter()
161+
# Use Arduino time or PC time?
162+
now = time.perf_counter() if USE_PC_TIME else self.dev.state.time
163+
if self.update_counter_DAQ == 1:
164+
self.dev.state.time_0 = now
165+
self.dev.state.time = 0
166+
else:
167+
self.dev.state.time = now - self.dev.state.time_0
204168

205169
# Return success
206170
return True
@@ -270,7 +234,7 @@ def __init__(self, parent=None, **kwargs):
270234
# --------------------------------------------------------------------------
271235

272236
if SIMULATE_ARDUINO:
273-
ard = FakeArduino()
237+
ard = FakeWaveGeneratorArduino()
274238
else:
275239
ard = WaveGeneratorArduino()
276240

0 commit comments

Comments
 (0)