Files
guadaloop_lev_control/AltSensorTesting/AltSensorTesting.ino
2026-04-11 21:15:01 -05:00

197 lines
5.9 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include <Arduino.h>
#include <util/atomic.h>
// ── ADC Interrupt-driven 3-channel read (A2, A3, A0) ─────────
// Channel index: 0 → A2 (sensor 0), 1 → A3 (sensor 1), 2 → A0 (raw ref)
static const uint8_t adc_mux[3] = {2, 3, 0};
volatile uint16_t adc_result[3] = {0, 0, 0};
volatile bool adc_ready[3] = {false, false, false};
volatile uint8_t adc_channel = 0;
void setupADC() {
ADMUX = (1 << REFS0) | adc_mux[0]; // AVCC ref, start on A2
ADCSRA = (1 << ADEN) | (1 << ADIE) | (1 << ADPS2); // /16 prescaler
ADCSRA |= (1 << ADSC);
}
// ── OOR digital inputs ───────────────────────────────────────
#define OOR_PIN_0 12 // HIGH = out of range, sensor 0 (A2)
#define OOR_PIN_1 13 // HIGH = out of range, sensor 1 (A3)
volatile bool OOR[2];
ISR(ADC_vect) {
uint16_t sample = ADC;
uint8_t ch = adc_channel;
uint8_t next = (ch + 1) % 3;
if (ch < 2) {
// Sensor channels: filter by OOR
OOR[ch] = digitalRead(ch == 0 ? OOR_PIN_0 : OOR_PIN_1);
if (!OOR[ch]) {
adc_result[ch] = sample;
adc_ready[ch] = true;
}
} else {
// A0: no OOR, always store
adc_result[2] = sample;
adc_ready[2] = true;
}
ADMUX = (ADMUX & 0xF0) | adc_mux[next];
adc_channel = next;
ADCSRA |= (1 << ADSC);
}
// ── ADC → mm linear mappings (raw range: 1626 mm) ──────────
#define adcToMM0(adc) ((float)map(adc, 178, 895, 1600, 2600) / 100.0f)
#define adcToMM1(adc) ((float)map(adc, 176, 885, 1600, 2600) / 100.0f)
// Subtract mounting offsets so both sensors share the same position frame:
// Sensor 0 raw 1626 mm 16 → 010 mm
// Sensor 1 raw 1626 mm 6 → 1020 mm
#define OFFSET_MM0 15.6f
#define OFFSET_MM1 6.2f
// ── Boundary tracking (in-range only, per sensor) ────────────
#define TRACK_N 10
uint16_t lowestVals[2][TRACK_N];
uint16_t highestVals[2][TRACK_N];
uint8_t lowestCount[2] = {0, 0};
uint8_t highestCount[2] = {0, 0};
static void trackLowest(uint8_t s, uint16_t val) {
uint16_t *lv = lowestVals[s];
uint8_t &lc = lowestCount[s];
if (lc < TRACK_N) {
uint8_t i = lc;
while (i > 0 && lv[i - 1] > val) { lv[i] = lv[i - 1]; i--; }
lv[i] = val;
lc++;
} else if (val < lv[TRACK_N - 1]) {
uint8_t i = TRACK_N - 1;
while (i > 0 && lv[i - 1] > val) { lv[i] = lv[i - 1]; i--; }
lv[i] = val;
}
}
static void trackHighest(uint8_t s, uint16_t val) {
uint16_t *hv = highestVals[s];
uint8_t &hc = highestCount[s];
if (hc < TRACK_N) {
uint8_t i = hc;
while (i > 0 && hv[i - 1] < val) { hv[i] = hv[i - 1]; i--; }
hv[i] = val;
hc++;
} else if (val > hv[TRACK_N - 1]) {
uint8_t i = TRACK_N - 1;
while (i > 0 && hv[i - 1] < val) { hv[i] = hv[i - 1]; i--; }
hv[i] = val;
}
}
static void resetTracking() {
lowestCount[0] = highestCount[0] = 0;
lowestCount[1] = highestCount[1] = 0;
}
static void printBoundaries() {
for (uint8_t s = 0; s < 2; s++) {
Serial.print(F("--- Sensor "));
Serial.print(s);
Serial.println(F(": 10 Lowest In-Range ADC Values ---"));
for (uint8_t i = 0; i < lowestCount[s]; i++) Serial.println(lowestVals[s][i]);
Serial.print(F("--- Sensor "));
Serial.print(s);
Serial.println(F(": 10 Highest In-Range ADC Values ---"));
for (uint8_t i = 0; i < highestCount[s]; i++) Serial.println(highestVals[s][i]);
}
}
// ── State ────────────────────────────────────────────────────
bool sampling = false;
bool rawMode = false;
// ═════════════════════════════════════════════════════════════
void setup() {
Serial.begin(115200);
pinMode(OOR_PIN_0, INPUT);
pinMode(OOR_PIN_1, INPUT);
setupADC();
Serial.println(F("Send '1' to start sampling, '0' to stop and print bounds, '2' for raw ADC output."));
}
void loop() {
// ── Serial command handling ──────────────────────────────
if (Serial.available() > 0) {
String cmd = Serial.readStringUntil('\n');
cmd.trim();
if (cmd.charAt(0) == '1') {
sampling = true;
rawMode = false;
resetTracking();
Serial.println(F("Sampling started."));
} else if (cmd.charAt(0) == '2') {
sampling = true;
rawMode = true;
Serial.println(F("Raw ADC output started."));
} else if (cmd.charAt(0) == '0') {
sampling = false;
rawMode = false;
Serial.println(F("Sampling stopped."));
printBoundaries();
}
}
// ── Main sample path ────────────────────────────────────
if (!sampling) return;
uint16_t val[3];
bool ready[3];
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
for (uint8_t i = 0; i < 3; i++) {
ready[i] = adc_ready[i];
val[i] = adc_result[i];
adc_ready[i] = false;
}
}
if (!ready[0] && !ready[1]) return;
if (rawMode) {
if (ready[0]) {
Serial.print(adcToMM0(val[0]) - OFFSET_MM0);
Serial.print(F(", "));
Serial.println(val[2]);
}
if (ready[1]) {
Serial.print(adcToMM1(val[1]) - OFFSET_MM1);
Serial.print(F(", "));
Serial.println(val[2]);
}
return;
}
// Apply offset for whichever sensor(s) are in range
if (ready[0]) {
float mm = adcToMM0(val[0]) - OFFSET_MM0;
trackLowest(0, val[0]);
trackHighest(0, val[0]);
Serial.print(val[0]);
Serial.print(F(", "));
Serial.print(mm, 2);
Serial.println(F(" mm (s0)"));
}
if (ready[1]) {
float mm = adcToMM1(val[1]) - OFFSET_MM1;
trackLowest(1, val[1]);
trackHighest(1, val[1]);
Serial.print(val[1]);
Serial.print(F(", "));
Serial.print(mm, 2);
Serial.println(F(" mm (s1)"));
}
}