-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathThustMaster.ino
205 lines (175 loc) · 5.45 KB
/
ThustMaster.ino
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
#include <Arduino.h>
#include <SPI.h>
#include <SD.h>
#include "config.h"
#include "logger.h"
#include "hx.h"
File dataFile;
File profileFile;
bool start = false;
const unsigned long debounceDelay = 50;
static unsigned long lastInterruptTime = 0;
enum TestState {
WAITING,
RUNNING,
FINISHED
};
TestState testState = WAITING;
struct Measurement {
float time;
float force;
};
const int maxMeasurements = 1000;
Measurement measurements[maxMeasurements];
int measurementCount = 0;
unsigned long pyroStartTime = 0;
unsigned long testStartTime = 0;
float runTime = 0.0; // used in RUNNING state
void IRAM_ATTR handleButtonPress() {
unsigned long interruptTime = millis();
if (interruptTime - lastInterruptTime > debounceDelay) {
start = true;
// Remember the time of the (debounced) interrupt
lastInterruptTime = interruptTime;
}
}
void setup() {
#ifdef DEBUG
Serial.begin(115200);
#endif
initSDCard();
initHX711(PIN_ADC_DT, PIN_ADC_SCK);
pinMode(PIN_BTN, INPUT_PULLUP);
pinMode(PIN_LED, OUTPUT);
pinMode(PIN_PYRO, OUTPUT);
attachInterrupt(digitalPinToInterrupt(PIN_BTN), handleButtonPress, FALLING);
digitalWrite(PIN_LED, HIGH);
}
void loop() {
if (pyroStartTime > 0 && millis() - pyroStartTime > PYRO_DURATION) {
digitalWrite(PIN_PYRO, LOW);
pyroStartTime = 0; // Reset pyroStartTime to avoid multiple LOW signals
}
switch (testState) {
case WAITING:
if (start) {
startNotice();
digitalWrite(PIN_PYRO, HIGH);
pyroStartTime = millis();
testStartTime = millis();
testState = RUNNING;
}
break;
case RUNNING:
runTime = ((float)millis() - testStartTime) / 1000;
if (runTime < TEST_DURATION && measurementCount < maxMeasurements) {
float force = readForceValue() / 102; // 102 grams per newton
measurements[measurementCount].time = runTime;
measurements[measurementCount].force = force;
measurementCount++;
logDebug("Time: " + String(runTime) + ", Force: " + String(force));
} else {
logDebug("Stopping test.");
testState = FINISHED;
}
break;
case FINISHED:
logDebug("Test sequence finished");
writeTestData();
while (true) {
endNotice();
}
break;
}
}
void startNotice() {
for (int i = COUNTDOWN_TIME; i > 0; i--) {
digitalWrite(PIN_LED, HIGH);
#ifdef SPEAKER_ENABLE
tone(PIN_SPEAKER, 1000); // 1000 Hz tone
#endif
delay(500); // Half a second on
digitalWrite(PIN_LED, LOW);
#ifdef SPEAKER_ENABLE
noTone(PIN_SPEAKER);
#endif
delay(500); // Half a second off
}
digitalWrite(PIN_LED, HIGH);
}
void endNotice() {
for (int i = 0; i < 3; i++) {
digitalWrite(PIN_LED, HIGH);
#ifdef SPEAKER_ENABLE
tone(PIN_SPEAKER, 1000); // 1000 Hz tone
#endif
delay(100); // Beep for 100 milliseconds
digitalWrite(PIN_LED, LOW);
#ifdef SPEAKER_ENABLE
noTone(PIN_SPEAKER);
#endif
delay(100); // Off for 100 milliseconds
}
delay(1000); // 1 second pause
}
void initSDCard() {
logDebug("Initializing SD card...");
int attempts = 0;
while (attempts < 3 && !SD.begin(PIN_CS)) {
attempts++;
}
if (attempts == 3) {
logDebug("Failed to initialize SD card");
while (1);
}
dataFile = SD.open(DATA_FILENAME, FILE_WRITE);
dataFile.close();
profileFile = SD.open(PROFILE_FILENAME, FILE_WRITE);
profileFile.close();
}
void writeTestData() {
dataFile = SD.open(DATA_FILENAME, FILE_WRITE);
if (dataFile) {
dataFile.println("Time, Force");
for (int i = 0; i < measurementCount; i++) {
if (measurements[i].force >= 0.05) {
dataFile.print(measurements[i].time);
dataFile.print(",");
dataFile.println(measurements[i].force);
}
}
dataFile.close();
logDebug("Data written to SD card.");
} else {
logDebug("Error opening " + String(DATA_FILENAME));
}
float peakNewtons = 0.0;
float totalNewtonSeconds = 0.0;
float sumNewtons = 0.0; // Variable to store the sum of newtons for calculating average
int countNewtons = 0; // Counter for the number of measurements with force greater than zero
float totalBurnTime = 0.0; // Variable to store the total burn time
for (int i = 0; i < measurementCount; i++) {
if (measurements[i].force > peakNewtons) {
peakNewtons = measurements[i].force;
}
if (measurements[i].force > 0.05) {
float deltaTime = (i > 0 ? (measurements[i].time - measurements[i-1].time) : 0);
totalNewtonSeconds += measurements[i].force * deltaTime;
sumNewtons += measurements[i].force;
countNewtons++; // Increment count for each measurement with force greater than zero
totalBurnTime += deltaTime; // Accumulate burn time when force is greater than zero
}
}
float averageNewtons = countNewtons > 0 ? sumNewtons / countNewtons : 0; // Calculate average newtons using the count of measurements with force greater than zero
profileFile = SD.open(PROFILE_FILENAME, FILE_WRITE);
if (profileFile) {
profileFile.println("Peak Newtons: " + String(peakNewtons));
profileFile.println("Total Newton Seconds: " + String(totalNewtonSeconds));
profileFile.println("Average Newtons: " + String(averageNewtons));
profileFile.println("Total Burn Time: " + String(totalBurnTime)); // Write total burn time to file
profileFile.close();
logDebug("Profile data written to SD card.");
} else {
logDebug("Error opening " + String(PROFILE_FILENAME));
}
}