7.3 Thresholding, smoothing
Let’s hook up our potentiometer and have a look at what it is outputting. To do this uncomment the potentiometer section of your code and then compile it and upload it to the Arduino.
The continuous flow of data from our potentiometer is not as much of a problem in theory since it will be used to manipulate a Control Change and repeatedly sending the same data will not have a noticeable effect. However, in practice I have found that bombarding software with a constant stream of MIDI data can sometimes overrun it’s capacity to deal with it.
An easy but inelegant solution would be to add a delay() function to the main loop to slow it down. Instead we will implement state change strategy like we did for the button - however because the potentiometer has more than 2 states we will need to implement a different approach.
Also, you might have also noticed that the value of the potentiometer is floating a bit even when you don’t move it. The floating values are due to the analog nature of the sensor that makes it susceptible to random variations caused by things like thermal vibrations of atomic particles. The sum of these interfering forces is referred to as noise.
There are a many strategies for dealing with noise. We’ll look at a couple:
Thresholding. With this strategy we don’t register a change unless it is greater than our defined threshold value. To implement this in our code we would declare our threshold value at the start of our program e.g.
int THRESHOLD = 2; //define a threshold amount
and then in our main loop we would check our new potentiometer values against our threshold e.g.
if( abs(newPotVal - oldPotVal) >= THRESHOLD)
//value has really changed - do something with the new value
The abs() function always returns a positive value so -2 and 2 would both evaluate to 2 - this lets us check for values above and below our current value with a single statement.
Smoothing, or averaging is a strategy where you store the last N values and average them together. As the name implies this also has a smoothing effect which can be desirable for user interfaces. There is a good example of it in File->Sketchbook->Examples->Analog->Smoothing.
This approach may still require thresholding and needs state change code if we only want to transmit data when a value changes. Since smoothing requires a more complex data structure (array) - we will stick with a basic threshold strategy.
Cut and paste the following code into your Arduino environment and then compile and upload it to your Arduino. Adjust the THRESHOLD value as necessary.
/*
* 6.3 Theshold example
* roguescience.org
*
* digital pin 11 (OUTPUT/PWM) --> LED
* digital pin 2 (INPUT) <-- button
* analog pin 0 <-- pot
*
* Sends a message using serial communication - only sends a message when the
* state of the button changes or when the pot value changes.
*/
int ledPin = 11; //choose the pin for the LED - needs to be (3,5,6,9,10, or 11)
int buttonPin = 2; //choose the input pin for a pushbutton
int potPin = 0; //choose the input pin for a potentometer
int buttonVal = 0; //variable for reading the button status
int buttonState = 0; //variable to hold the buttons current state
int bounceCheck = 0; //variable for debouncing
int potVal = 0; //variable for reading potentiometer value
int mappedPotVal = 0; //variable for holding remapped pot value
int prevPotVal = 0; //variable for storing our prev pot value
int THRESHOLD = 2; //threshold amount
void setup() {
pinMode(ledPin, OUTPUT); //declare LED as output
pinMode(buttonPin, INPUT); //declare pushbutton as input
Serial.begin(9600); //begin serial communication at 9600 baud
}
void loop(){
buttonVal = digitalRead(buttonPin); //read input value from button
delay(10); //wait 10ms
bounceCheck = digitalRead(buttonPin); //check again
if(buttonVal == bounceCheck){ //if val is the same then not a bounce
if (buttonVal == HIGH && buttonState == 1) { //check if the input is HIGH
digitalWrite(ledPin, LOW); //turn LED OFF
Serial.println("OFF");
buttonState = 0;
}
if(buttonVal == LOW && buttonState == 0){
digitalWrite(ledPin, HIGH); //turn LED ON
Serial.println("ON");
buttonState = 1;
}
}
potVal = analogRead(potPin); //read input from potentiometer
mappedPotVal = map(potVal, 0, 1023, 0, 255); //map value to 0-255
if(abs(mappedPotVal - prevPotVal) >= THRESHOLD){
Serial.println(mappedPotVal); //send potVal via serial
analogWrite(ledPin, mappedPotVal); //use PWM to set LED brightness
prevPotVal = mappedPotVal;
}
}