diff --git a/Input Devices 2022.pdf b/Input Devices 2022.pdf new file mode 100644 index 0000000000000000000000000000000000000000..99763cbee53e2e31f8ab469d6298f25161463bfb Binary files /dev/null and b/Input Devices 2022.pdf differ diff --git a/README.md b/README.md new file mode 100644 index 0000000000000000000000000000000000000000..51d9195cc51f23f183db54f6663f15f6a7d982bc --- /dev/null +++ b/README.md @@ -0,0 +1,13 @@ +# Input Devices Recitation + +This recitation aims to introduce the basics of working with inputs on Arduino embeded devices. Slides are hosted [here](https://gitlab.cba.mit.edu/classes/863.22/site/-/blob/master/doc/input_devices/Input%20Devices%202022.pdf). + +### Example Code + +1) [inputDevices_1_basic.ino](https://gitlab.cba.mit.edu/classes/863.22/site/-/blob/master/doc/input_devices/inputDevices_1_basic.ino) is a simple sketch introducing analogRead(). + +2) [inputDevices_2_gauss.ino](https://gitlab.cba.mit.edu/classes/863.22/site/-/blob/master/doc/input_devices/inputDevices_1_basic.ino) adds a tare, ADC resolution, and conversion to Gauss. + +3) [inputDevices_3_filters.ino](https://gitlab.cba.mit.edu/classes/863.22/site/-/blob/master/doc/input_devices/inputDevices_1_basic.ino) shows various filtering approaches, including batch averaging, moving averaging, and low pass filters. + +4) [inputDevices_4_linearization.ino](https://gitlab.cba.mit.edu/classes/863.22/site/-/blob/master/doc/input_devices/inputDevices_1_basic.ino) shows a simple lookup table implementation with linearization. diff --git a/inputDevices_2_gauss.ino b/inputDevices_2_gauss.ino new file mode 100644 index 0000000000000000000000000000000000000000..7024489eabdc009bca642e39d76eaac7cf0ce721 --- /dev/null +++ b/inputDevices_2_gauss.ino @@ -0,0 +1,20 @@ +// Variables +const int sensorPin = 27; +float reading = 0; +float tare = 0; // initializing our tare +const int ADC_res = 10; // desired ADC resolution +const float sens = 0.005; // V/G, taken from datasheet +const float conversion_factor = 3.3/(pow(2,ADC_res))/sens; // [V/ADC] / [V/G] gives us Gauss/ADC + +void setup() { + Serial.begin(115200); + analogReadResolution(ADC_res); // Here we can set the number of bits used by our ADC + tare = analogRead(sensorPin); // Take one reading to use as our tare value +} + +void loop() { + float reading = (analogRead(sensorPin) - tare)*conversion_factor; // now we will subtract by our tare, and multiply by our conversion factor + Serial.print(reading); + Serial.println(" Gauss"); + delay(10); +} diff --git a/inputDevices_3_filters.ino b/inputDevices_3_filters.ino new file mode 100644 index 0000000000000000000000000000000000000000..32ef0f95be99668faff69865385b977f934e2203 --- /dev/null +++ b/inputDevices_3_filters.ino @@ -0,0 +1,67 @@ +// Variables + const int sensorPin = 27; + float reading = 0; + float tare = 0; + +// Variables for Averaging + const int totalSamples = 10; + int index_avg = 0; + int value = 0; + float sum = 0; + int readings[totalSamples]; // create an empty array of size totalSamples + +// Variables for Low Pass + float filteredOutputPrevious = 0; + const float RC = 0.159; + const float dT = 0.01; // time in seconds + const float C1 = dT/(RC+dT); // coefficient 1 + const float C2 = RC/(RC+dT); // coefficient 2 + +void setup() { + Serial.begin(115200); // initialize serial communication with computer: + analogReadResolution(10); // Here we can set the number of bits used by our ADC + + // Now for our tare, we can use our low pass filter several times to get more accuracy + filteredOutputPrevious = analogRead(sensorPin); // First let's initialize the previous value with a single new reading + for (int i = 0; i < 10; i++) { // Next let's repeat the measurement a few times to make sure we are getting a nice filtered output + tare = lowPassRead(); + } +} + +void loop() { + float reading = analogRead(sensorPin) - tare; + Serial.print(reading); + Serial.print(", "); + float filtered_reading = batchAverageRead() - tare; // Batch average reading + //float filtered_reading = movingAverageRead() - tare; // Moving average read + //float filtered_reading = lowPassRead() - tare; // Low pass read + Serial.println(filtered_reading); // send our reading over USB to the computer + delay(dT*1000); // delay between reads in miliseconds (necessary for low pass) +} + +// Batch Averaged sensor reading ---------------------------------------------------- +float batchAverageRead(){ + sum = 0; + for (int i = 0; i < totalSamples; i++){ + sum = sum + analogRead(sensorPin); // sum totalSamples readings + delay(dT*1000); // wait for every reading! This is bad :( + } + return sum / totalSamples; +} + +// Moving Average sensor reading ---------------------------------------------------- +float movingAverageRead(){ + sum = sum - readings[index_avg]; // Remove the oldest entry from the sum + value = analogRead(sensorPin); // Read the next sensor value + readings[index_avg] = value; // Add the newest reading to the window + sum = sum + value; // Add the newest reading to the sum + index_avg = (index_avg+1)%totalSamples; // Increment the index, and wrap to 0 if it exceeds the window size + return sum/(float(totalSamples)); // Divide the sum of the window by the window size for the result +} + +// Low Pass Filter sensor reading ------------------------------------------------- +float lowPassRead(){ + float filteredOutput = analogRead(sensorPin)*(C1) + filteredOutputPrevious*(C2); // All we need to do here is to measure once and do some fast multiplication with our coefficients! This is great :) + filteredOutputPrevious = filteredOutput; // And store our output for next time + return filteredOutput; +} diff --git a/inputDevices_4_linearization.ino b/inputDevices_4_linearization.ino new file mode 100644 index 0000000000000000000000000000000000000000..a8f7b8e614c8a1da605c5aebda390530272dec63 --- /dev/null +++ b/inputDevices_4_linearization.ino @@ -0,0 +1,61 @@ +// Variables +const int sensorPin = 27; +float reading = 0; +float tare = 0; + +// Variables for Low Pass +float filteredOutputPrevious = 0; +const float RC = 0.159; +const float dT = 0.01; // time in seconds +const float C1 = dT/(RC+dT); // coefficient 1 +const float C2 = RC/(RC+dT); // coefficient 2 + +// Variables for linearization +const int interp_samples = 10; +float interp_inputs[interp_samples] = {296, 200.3, 139.5, 100.8, 75, 57, 44.05, 35, 28, 23}; // Raw ADC readings +float interp_outputs[interp_samples] = {0, 2, 4, 6, 8, 10, 12, 14, 16, 18}; // Associated linear distances + +void setup() { + Serial.begin(115200); // Initialize serial communication with computer: + // Now for our tare, we can use our low pass filter several times to get more accuracy + filteredOutputPrevious = analogRead(sensorPin); // First let's initialize the previous value with a single new reading + for (int i = 0; i < 10; i++) { // Next let's repeat the measurement a few times to make sure we are getting a nice filtered output + tare = lowPassRead(); + } +} + +void loop() { + float filtered_reading = lowPassRead() - tare; // we will always subtract the tare from our readings + linearized(filtered_reading); // send our reading over USB to the computer + delay(dT*1000); // delay between reads in miliseconds +} + +// Low Pass Filter sensor reading ------------------------------------------------- +float lowPassRead(){ + float filteredOutput = analogRead(sensorPin)*(C1) + filteredOutputPrevious*(C2); + filteredOutputPrevious = filteredOutput; + return filteredOutput; +} + +// Linearization ------------------------------------------------------------------ +float linearized(float reading){ + float linear_output = reading; // Print our raw output for reference first + Serial.print("Raw reading: "); + Serial.print(reading); + if (reading <= interp_inputs[0] && reading >= interp_inputs[interp_samples-1]){ // If we are reading within the interpolation lookup range + for (int i = 0; i <= interp_samples; i++){ + if (reading > interp_inputs[i]){ // Find our exact location by iterating through the table and checking each time + float scaling_factor = abs((reading - interp_inputs[i]) / (interp_inputs[i] - interp_inputs[i-1])); // Calculate our percentage between two interpolation points + linear_output = (interp_outputs[i-1] - interp_outputs[i])*scaling_factor + interp_outputs[i]; // Apply that scaling factor to the associated conversion points + Serial.print(" Linearized reading: "); + Serial.print(linear_output); + Serial.println(" mm"); + break; + } + } + } + else { + Serial.println(" Outside of interpolation range"); + } + return linear_output; +}