10

I have a pair of potentiometers, on the Arduino, the output seems to drift, by one or 2 digits, back and forth. I would prefer they were read as one fixed value, without variation when their knobs are not turning. You can see in the image, the first and second values are shifting back and forth slightly. How should I address this?

I'm thinking of making a standard deviation function, but then I thought that might be unnecessarily complex.

wandering pots

My code is that the 2 sensor values are setting points in an SVG polyline. Variance means extra points will get plotted, while the device waits for valid input.

How should I deal with the variance in potentiometer readings to avoid outputting noise?

Here's my source:

/**Fucntion Defs**/
void svgHeader();
void svgFooter();
void polyLineBegin();
void polyLineEnd();

int Reset = 4; //programmatically reset the arduino int potX = A0; int potY = A1;

int sensorValX = 0; int sensorValY = 0; int oldX = 0; int oldY = 0;

int del = 2; //a button on pin 2 for deleting drawn content int delbutton = 0; void setup() { Serial.begin(9600); pinMode(del, INPUT); svgHeader(); polyLineBegin(); delay(1000); }

void loop() { // close the svg and start over if (digitalRead(del) == LOW ) { delbutton = 1; polyLineEnd(); svgFooter(); delay(5000); digitalWrite(Reset, LOW); digitalWrite(Reset, HIGH); svgHeader(); polyLineBegin(); } else { delbutton = 0; //Serial.println(delbutton);

}

//dont draw if its not changing sensorValX = analogRead(potX); sensorValY = analogRead(potY); if (sensorValX == oldX && sensorValY == oldY) { ; //dont do shi. } else { Serial.print(sensorValX); Serial.print(","); Serial.print(sensorValY); Serial.print(","); oldX = sensorValX; oldY = sensorValY; // Serial.println(delbutton); delay(1000); } } /Functions/

void polyLineBegin() { Serial.println ("<polyline points=&quot;"); //x,y points go here

}

void polyLineEnd() { Serial.println ("0, 0&quot; stroke=&quot;red&quot; fill=&quot;transparent&quot; stroke-width=&quot;5&quot;/>"); //a dirty hack to avoid dealing with 1 last trailing comma.

}

void svgHeader() { Serial.println("<svg width=&quot;1023&quot; height=&quot;1023&quot; version=&quot;1.1&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;>"); };

void svgFooter() { Serial.println ("</svg>"); };

tim
  • 699
  • 6
  • 15
j0h
  • 902
  • 4
  • 13
  • 30

4 Answers4

10

ok, once I got the idea I would need to do it in code, it became simpler to solve. In looking around the terms of quantization, the term thresh-holding came up, and I realized how to solve the problem.

I created a threshold value, and compared the difference between old and new variables.

int threshold =3;
int xVariance = abs(sensorValX-oldX);
int yVariance = abs(sensorValY-oldY);
if (xVariance >=threshold && yVariance >= threshold ||xVariance >=threshold || yVariance >=threshold){
  Serial.print(sensorValX);
  Serial.print(",");
  Serial.print(sensorValY);
  Serial.print(",");
 oldX=sensorValX;
 oldY=sensorValY;

}else{ ; //dont do shi. // Serial.println(delbutton); delay(1000); }

now, when I turn either potentiometer, I get a response, and output I desire, but not while the device is just sitting there.

j0h
  • 902
  • 4
  • 13
  • 30
6

Remove the analog component from your device.

Use a rotary encoder.

It will sense the knob rotation digitally.

One huge advantage is that you can easily select the sensitivity of the input. One click can advance the counter by .001 just as easily as advancing by a 1000.

https://duckduckgo.com/?q=rotary+encoder&iar=images&iax=images&ia=images

enter image description here

jsotola
  • 1,554
  • 2
  • 12
  • 20
5

Some methods for "dealing" with the noise:

  1. Take multiple samples. Calculate the average ("mean"). Discard the decimal. This is "oversampling" along with resolution reduction (but reduction of the now increased oversampled resolution).
  2. Take multiple samples. Find the most common value ("mode").
  3. Divide the value by 2 (or 4 if needed). This reduces the range of values and the sampled resolution but discards the noise portion.

The problem you are suffering from is "quantisation noise". This is because an analog signal and a digital signal are not completely compatible. The ADC converts the analog signal into a digital value by successively comparing it to smaller and smaller voltages in steps ("quanta"). There is a limit to how small the steps can get (the resolution), but an analog voltage doesn't adhere to those steps, it will always be somewhere between the final two steps. Sometimes it will be detected as the lower step, sometimes the upper step. By taking multiple samples and averaging them you are estimating how close to one step or the other the value is and "refining" the result. This is "oversampling" and is used to increase the resolution of the ADC at the cost of sample speed.

With those extra samples you can either say "It's this much closer to the upper step" (take the "mean"), or say "It's more likely to be nearer the upper step" (take the "mode") to try and "fix" the value to one of the steps.

Majenko
  • 105,851
  • 5
  • 82
  • 139
2

I think you should handle the trailing comma within the Arduino by using leading commas instead, but omit the first leading comma using a flag to indicate the first coordinate:

bool firstCoordinate;

void loop() { . . . if (xVariance >= threshold || yVariance >= threshold) { if (!firstCoordinate) { Serial.print(","); firstCoordinate = false; } Serial.print(sensorValX); Serial.print(","); Serial.print(sensorValY); oldX = sensorValX; oldY = sensorValY; } . . . }

void polyLineBegin() { Serial.println("<polyline points=&quot;"); //x,y points go here firstCoordinate = true; }

void polyLineEnd() { // Clean line ending. Serial.println("&quot; stroke=&quot;red&quot; fill=&quot;transparent&quot; stroke-width=&quot;5&quot;/>"); }

Alternatively, the first coordinate could be added to the line when it begins, then there is no need for a flag:

void polyLineBegin()
{
    Serial.println("<polyline points=\""); //x,y points go here
    Serial.println(sensorValX);
    Serial.println(",");
    Serial.println(sensorValY);
}

void loop() { . . . if (xVariance >= threshold || yVariance >= threshold) { Serial.print(","); Serial.print(sensorValX); Serial.print(","); Serial.print(sensorValY); oldX = sensorValX; oldY = sensorValY; } . . . }

The thresholding technique is great, but, as an aside, I recently discovered this excellent statistics library by Majenko while working on a non-blocking averaging function for Arduino and looking at converting it into a class. I found that that library already does what I want.

tim
  • 699
  • 6
  • 15