Go Down

### Topic: Reading very small adjustments from a potentiometer accurately? (Read 2599 times)previous topic - next topic

#### mahela007

##### Oct 28, 2011, 02:16 pmLast Edit: Oct 28, 2011, 02:18 pm by mahela007 Reason: 1
As some of you probably know from my previous posts, I'm building a coil gun with an arduino to control the timing. In other words, the arduino is used to swich a current pulse on an off in about 100mS (more or less).
However, this delay must be manually tuned before firing the coil gun. I'll be using a 10K potentiometer to do this. I need an accuracy of +- 1ms.
I ran into some problems trying to write a proper program to do this.

1). The potentiometer signal seems to pick up a bit of noise (is this normal?) and the analogRead function returns values that vary by +- 3. (on the standard 0 - 1023 scale).
My solution was as follows: Take two readings a few mS apart and then compare them to see if they have changed. Such a change would indicate that the pot wiper has been turned.
Code: [Select]
`void setup(){  Serial.begin(9600);}void loop(){  int first = analogRead(3);  delay(100);  int second = analogRead(3);    if (abs(first - second)>2){ //i.e if the value has changed by more than 2 (two avoid noise)     int mapped = map(second,0,1024,0,250);    Serial.println(mapped);    }}`

2.) This solution works well for fast movements of the wiper.. but when I try to move the wiper very slowly (such as when one tries to make very small changes), it breaks down. (because in 10ms, the wiper doesn't produce values that have a difference of 2. I can't reduce this difference further because of the noise issue..

What do you suggest?

#### pito

#1
##### Oct 28, 2011, 03:21 pm
a) put 100nf capacitor from wiper to gnd (from analoginput to gnd)
b) make 33 measurements and make an average
c) make a digital filter (new=A*old+B*new, A+B=1, B=0.05)
d) introduce hysteresis
p.

#### mahela007

#2
##### Oct 28, 2011, 03:37 pm
except for the first two, I don't know what the other ones mean..

#### pito

#3
##### Oct 28, 2011, 03:44 pm
c) it is a simple digital filter, works similar like putting an RC low-pass at analog pin
d) hysteresis - http://en.wikipedia.org/wiki/Hysteresis

#### mahela007

#4
##### Oct 28, 2011, 03:50 pm
Thanks.. I'll try those. The capacitor solution didn't work.. (my capacitor was 180nF but I thought that was close enough)

#### pito

#5
##### Oct 28, 2011, 03:54 pm
However, without an averaging or a hysteresis you may always get +/1bit..

#### mahela007

#6
##### Oct 28, 2011, 07:17 pm
Could you give me an example for some 'averaging' code?

#### robtillaart

#7
##### Oct 28, 2011, 07:24 pm
Quote
b) make 33 measurements and make an average

Better make that 32, no overflow and it can be optrimized to shift

Code: [Select]
`int sum = 0;for (uint8_t i=0; i< 32; i++) sum += analogRead(POTMETER);int val = sum / 32;`

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

#### mahela007

#8
##### Oct 28, 2011, 07:38 pm
Wow.. simple, but works.
However, the solution is not a perfect one.. there still is some jitter in the numbers.. but that's ok.

#### GuitarBuilder

#9
##### Oct 28, 2011, 07:49 pm
Your other option is to use a multi-turn (e.g. 10) potentiometer.

#### robtillaart

#10
##### Oct 28, 2011, 07:55 pm

How many distinct values you want?
The Arduino ADC reads 1024 different values and you may consider the last one to three noise (depends) leaving effectively 128-256 distinct values.
If your sketch uses two potmeters, one for bigsteps and the other for fine tuning you could have more steps.

Code: [Select]
`unsigned int val = (analogRead(POT1) /4) * 256 + analogRead(POT2)/4;   // DO NOT OPTIMIZE the /4 and the *256 !!! `

you could also use an averaging read for both POT's, which is left as an exercise

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

#### retrolefty

#11
##### Oct 28, 2011, 09:00 pm
Or use digital input switches, up and down and have you sketch increment or decrement the value as you wish with no worry about resolution limits or noise.

Lefty

#12
##### Oct 28, 2011, 09:31 pm
If you're doing a 4:1 mapping

if (abs(first - second)>2){ //i.e if the value has changed by more than 2 (two avoid noise)
int mapped = map(second,0,1024,0,250);

why not limit the change to require a difference of more than 3 instead?
0,1,2,3 all map to 0
4,5,6,7 all map to 1

I think I would just do a simpler mapping even: