summaryrefslogtreecommitdiff
path: root/api_layers/firmware/esp32_stringPot
diff options
context:
space:
mode:
Diffstat (limited to 'api_layers/firmware/esp32_stringPot')
-rw-r--r--api_layers/firmware/esp32_stringPot/esp32_stringPot.ino282
1 files changed, 247 insertions, 35 deletions
diff --git a/api_layers/firmware/esp32_stringPot/esp32_stringPot.ino b/api_layers/firmware/esp32_stringPot/esp32_stringPot.ino
index 3fde958..63d4349 100644
--- a/api_layers/firmware/esp32_stringPot/esp32_stringPot.ino
+++ b/api_layers/firmware/esp32_stringPot/esp32_stringPot.ino
@@ -1,5 +1,5 @@
/*
- LabUI ESP32 Firmware v1.0
+ LabUI ESP32 Firmware v1.1
─────────────────────────────────────────────────────────────────────────
Author: Adam Shatila
Co-Author: Christian Kolset
@@ -8,36 +8,69 @@
Required library: esp32 by Espressif Systems
- Calibration:
- 1. Flash board with calibrationMODE = true.
- 2. Set to position #1 and record actual position (measuredRange[0]) and
- output position (readingRange[0]).
- 3. Move to position #2 and record actual position (measuredRange[1])
- and output position (readingRange[1]).
- 4. Flash board with calibrationMODE = false.
+ Calibration procedure:
+ Send calibrate and follow the prompts (recommended — pauses the data
+ stream and walks through both points). Or drive it manually:
+ 1. Move sensor to known position #1, send CAL:0:<actual_position>
+ Board captures its current raw reading and pairs it with that position.
+ 2. Move sensor to known position #2, send CAL:1:<actual_position>
+ Board recomputes calibration_factor / calibration_offset and saves
+ to EEPROM.
+ Send FILT:<cutoffHz> to change the Butterworth low-pass cutoff
+ (also saved to EEPROM). Send config at any time to print the current
+ calibration and filter configuration.
+
+ Serial commands (newline-terminated):
+ calibrate Guided calibration wizard (recommended)
+ CAL:0:<pos> Capture current raw reading as calibration point 0
+ CAL:1:<pos> Capture current raw reading as calibration point 1
+ FILT:<hz> Set Butterworth cutoff frequency
+ config Print current calibration + filter configuration
+ help Print this command list
+
+ Replies:
+ ACK:<command>\n Command executed
+ ERR:<message>\n Command failed / not recognized
─────────────────────────────────────────────────────────────────────────
*/
+#include <EEPROM.h>
const int sensorPin = A0;
const unsigned long sampleInterval = 2000;
unsigned long lastSampleTime = 0;
-//Calibration
-float calibration_factor = 1.0;
-float calibration_offset;
-// 2 point calibration used for scaling factor
-bool calibrationMODE = false;
-float measuredRange[2] = {0, 150};
-float readingRange[2] = {260.26, 421.3};
+// EEPROM-persisted configuration
+#define EEPROM_SIZE 64
+#define EEPROM_MAGIC 0xC1
+
+struct StoredConfig {
+ uint8_t magic;
+ float calibrationPosition[2];
+ float calibrationRange[2];
+ float butterworth_cutoffHz;
+};
+StoredConfig cfg = {
+ EEPROM_MAGIC,
+ {0, 150},
+ {260.26, 421.3},
+ 0.5
+};
+
+// Calibration (mirrors cfg, kept as separate globals for fast access in loop())
+float calibration_factor = 1.0;
+float calibration_offset = 0.0;
// 2nd-order Butterworth low-pass (biquad, direct form II transposed)
-float butterworth_cutoffHz = 0.5;
const float butterworth_sampleHz = 1000000.0 / sampleInterval;
float butter_b0, butter_b1, butter_b2, butter_a1, butter_a2;
float butter_z1 = 0.0, butter_z2 = 0.0;
+String serialLine;
+bool streamingEnabled = true;
+bool calibPointSet[2] = {false, false};
+
void setup() {
Serial.begin(115200);
@@ -46,10 +79,11 @@ void setup() {
}
analogReadResolution(12);
- computeButterworthCoeffs(butterworth_cutoffHz, butterworth_sampleHz);
- if (calibrationMODE == false){
- computeCalibrationParameters(measuredRange, readingRange);
- }
+
+ EEPROM.begin(EEPROM_SIZE);
+ loadConfig();
+ computeButterworthCoeffs(cfg.butterworth_cutoffHz, butterworth_sampleHz);
+ computeCalibrationParameters(cfg.calibrationPosition, cfg.calibrationRange);
}
void loop() {
@@ -58,28 +92,103 @@ void loop() {
if (currentTime - lastSampleTime >= sampleInterval) {
lastSampleTime = currentTime;
- uint32_t millivolts = analogReadMilliVolts(sensorPin);
- float displacement = convert_mV_to_mm(millivolts);
- float filtered_displacement = butterworthLowPass(displacement);
- float volts = filtered_displacement;
+ float filtered_displacement = butterworthLowPass(readCalibratedPosition());
+ if (streamingEnabled) {
+ Serial.println(filtered_displacement, 2);
+ }
+ }
+
+ readSerialCommands();
+}
+
+void readSerialCommands() {
+ while (Serial.available()) {
+ char c = Serial.read();
+ if (c == '\n') {
+ serialLine.trim();
+ if (serialLine.length() > 0) {
+ handleCommand(serialLine);
+ }
+ serialLine = "";
+ } else if (c != '\r') {
+ serialLine += c;
+ }
+ }
+}
+
+void handleCommand(String line) {
+ if (line.startsWith("CAL:0:") || line.startsWith("CAL:1:")) {
+ int idx = line.charAt(4) - '0';
+ float actualPos = line.substring(6).toFloat();
+ float rawReading = readRawPosition();
+ int otherIdx = 1 - idx;
+
+ if (calibPointSet[otherIdx] && rawReading == cfg.calibrationRange[otherIdx]) {
+ Serial.println("ERR:Calibration points cannot have equal raw reading");
+ return;
+ }
+
+ cfg.calibrationPosition[idx] = actualPos;
+ cfg.calibrationRange[idx] = rawReading;
+ calibPointSet[idx] = true;
+
+ if (!calibPointSet[otherIdx]) {
+ Serial.println("ACK:" + line + " (waiting on CAL:" + String(otherIdx) + ")");
+ return;
+ }
+
+ computeCalibrationParameters(cfg.calibrationPosition, cfg.calibrationRange);
+ saveConfig();
- // Output the voltage to the serial monitor with 3 decimal places
- //Serial.print(displacement, 3);
- //Serial.print(", ");
- Serial.println(filtered_displacement, 2);
- //Serial.println(millivolts);
+ Serial.println("ACK:" + line);
+ } else if (line.startsWith("FILT:")) {
+ float hz = line.substring(5).toFloat();
+ if (hz <= 0) {
+ Serial.println("ERR:Invalid cutoff frequency");
+ return;
+ }
+ cfg.butterworth_cutoffHz = hz;
+ computeButterworthCoeffs(cfg.butterworth_cutoffHz, butterworth_sampleHz);
+ saveConfig();
+
+ Serial.println("ACK:" + line);
+ } else if (line == "config") {
+ printConfig();
+ } else if (line == "help") {
+ printHelp();
+ } else if (line == "calibrate") {
+ calibrationWizard();
+ } else {
+ Serial.println("ERR:Unknown command");
+ }
+}
+
+void loadConfig() {
+ EEPROM.get(0, cfg);
+ if (cfg.magic != EEPROM_MAGIC) {
+ cfg = { EEPROM_MAGIC, {0, 150}, {260.26, 421.3}, 0.5 };
+ saveConfig();
}
}
-float convert_mV_to_mm(float mVolts){
- // Reads mV from sensor and output in mm from lower limit
- float voltage = mVolts / 1000.0;
+void saveConfig() {
+ EEPROM.put(0, cfg);
+ EEPROM.commit();
+}
+
+// Fixed sensor scaling, pre calibration_factor/offset
+float readRawPosition() {
+ uint32_t millivolts = analogReadMilliVolts(sensorPin);
+ float voltage = millivolts / 1000.0;
float raw_val = voltage * (635.0 / 2.863);
- float volts = raw_val * (635.0 / 637.0);
- return calibration_factor * volts + calibration_offset;
+ return raw_val * (635.0 / 637.0);
}
-void computeCalibrationParameters(float x[2], float y[2]){
+float readCalibratedPosition() {
+ return calibration_factor * readRawPosition() + calibration_offset;
+}
+
+void computeCalibrationParameters(float x[2], float y[2]) {
calibration_factor = (x[1] - x[0]) / (y[1] - y[0]);
calibration_offset = x[0] - calibration_factor * y[0];
}
@@ -105,3 +214,106 @@ float butterworthLowPass(float newSample) {
butter_z2 = butter_b2 * newSample - butter_a2 * output;
return output;
}
+
+void printConfig() {
+ Serial.println("Calibration:");
+ Serial.print("\tPosition:\t");
+ Serial.print(cfg.calibrationPosition[0], 3);
+ Serial.print(",\t");
+ Serial.println(cfg.calibrationPosition[1], 3);
+ Serial.print("\tRaw values:\t");
+ Serial.print(cfg.calibrationRange[0], 3);
+ Serial.print(",\t");
+ Serial.println(cfg.calibrationRange[1], 3);
+ Serial.print("\tFactor:\t");
+ Serial.println(calibration_factor, 6);
+ Serial.print("\tOffset:\t");
+ Serial.println(calibration_offset, 6);
+ Serial.print("Butterworth cutoff (Hz):\t");
+ Serial.println(cfg.butterworth_cutoffHz, 3);
+}
+
+void printHelp() {
+ Serial.println("Commands:");
+ Serial.println("\tcalibrate Guided calibration wizard (recommended)");
+ Serial.println("\tCAL:0:<pos> Capture current raw reading as calibration point 0");
+ Serial.println("\tCAL:1:<pos> Capture current raw reading as calibration point 1");
+ Serial.println("\tFILT:<hz> Set Butterworth cutoff frequency");
+ Serial.println("\tconfig Print current calibration + filter configuration");
+ Serial.println("\thelp Print this command list");
+ interruptibleDelay(10000);
+}
+
+// Waits up to ms, returns early (without consuming input) if a command starts arriving.
+void interruptibleDelay(unsigned long ms) {
+ unsigned long start = millis();
+ while (millis() - start < ms) {
+ if (Serial.available()) {
+ return;
+ }
+ }
+}
+
+// Blocks until a newline-terminated line arrives; used only inside calibrationWizard(),
+// where halting loop() to walk the user through steps is the point.
+String blockingReadLine() {
+ String buf = "";
+ while (true) {
+ if (Serial.available()) {
+ char c = Serial.read();
+ if (c == '\n') {
+ buf.trim();
+ return buf;
+ } else if (c != '\r') {
+ buf += c;
+ }
+ }
+ }
+}
+
+void calibrationWizard() {
+ bool wasStreaming = streamingEnabled;
+ streamingEnabled = false;
+
+ Serial.println("=== Calibration wizard (type 'cancel' anytime to abort) ===");
+
+ float pos[2];
+ float raw[2];
+
+ for (int i = 0; i < 2; i++) {
+ Serial.println("Move sensor to known position #" + String(i + 1) + ", enter actual position, press Enter:");
+ String input = blockingReadLine();
+
+ if (input.equalsIgnoreCase("cancel")) {
+ Serial.println("Calibration cancelled. Previous calibration unchanged.");
+ streamingEnabled = wasStreaming;
+ return;
+ }
+
+ pos[i] = input.toFloat();
+ raw[i] = readRawPosition();
+
+ if (i == 1 && raw[1] == raw[0]) {
+ Serial.println("ERR:Calibration points cannot have equal raw reading. Wizard aborted, previous calibration unchanged.");
+ streamingEnabled = wasStreaming;
+ return;
+ }
+
+ Serial.println("Point " + String(i) + " captured: position=" + String(pos[i], 3) + " raw=" + String(raw[i], 3));
+ }
+
+ cfg.calibrationPosition[0] = pos[0];
+ cfg.calibrationPosition[1] = pos[1];
+ cfg.calibrationRange[0] = raw[0];
+ cfg.calibrationRange[1] = raw[1];
+ calibPointSet[0] = true;
+ calibPointSet[1] = true;
+
+ computeCalibrationParameters(cfg.calibrationPosition, cfg.calibrationRange);
+ saveConfig();
+
+ Serial.println("Calibration saved.");
+ printConfig();
+
+ streamingEnabled = wasStreaming;
+}