Pages: [1]   Go Down
Author Topic: Reading very small adjustments from a potentiometer accurately?  (Read 741 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Full Member
***
Karma: 0
Posts: 145
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
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?
Thanks in advance.
« Last Edit: October 28, 2011, 07:18:40 am by mahela007 » Logged

Rapa Nui
Offline Offline
Edison Member
*
Karma: 53
Posts: 1990
Pukao hats cleaning services
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

Offline Offline
Full Member
***
Karma: 0
Posts: 145
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

except for the first two, I don't know what the other ones mean..
Logged

Rapa Nui
Offline Offline
Edison Member
*
Karma: 53
Posts: 1990
Pukao hats cleaning services
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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
Logged

Offline Offline
Full Member
***
Karma: 0
Posts: 145
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks.. I'll try those. The capacitor solution didn't work.. (my capacitor was 180nF but I thought that was close enough)
Logged

Rapa Nui
Offline Offline
Edison Member
*
Karma: 53
Posts: 1990
Pukao hats cleaning services
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

..try to put a 10-100kohm resistor between the wiper and the analog in, and that 180nf from analog in to gnd..
However, without an averaging or a hysteresis you may always get +/1bit..
Logged

Offline Offline
Full Member
***
Karma: 0
Posts: 145
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Could you give me an example for some 'averaging' code?
Logged

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 170
Posts: 12483
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
b) make 33 measurements and make an average
Better make that 32, no overflow and it can be optrimized to shift

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

Logged

Rob Tillaart

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

Offline Offline
Full Member
***
Karma: 0
Posts: 145
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Wow.. simple, but works.
However, the solution is not a perfect one.. there still is some jitter in the numbers.. but that's ok.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 33
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Your other option is to use a multi-turn (e.g. 10) potentiometer.
Logged

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 170
Posts: 12483
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset


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:
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 smiley

 
Logged

Rob Tillaart

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

Left Coast, CA (USA)
Offline Offline
Brattain Member
*****
Karma: 331
Posts: 16548
Measurement changes behavior
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

Logged

Global Moderator
Boston area, metrowest
Offline Offline
Brattain Member
*****
Karma: 443
Posts: 23837
Author of "Arduino for Teens". Available for Design & Build services. Now with Unlimited Eagle board sizes!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
mapped = analogRead( 3) >>2;
and just dump the lower 2 bits altogether.
Logged

Designing & building electrical circuits for over 25 years. Check out the ATMega1284P based Bobuino and other '328P & '1284P creations & offerings at  www.crossroadsfencing.com/BobuinoRev17.
Arduino for Teens available at Amazon.com.

New Hampshire
Offline Offline
God Member
*****
Karma: 13
Posts: 779
There are 10 kinds of people, those who know binary, and those who don't.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Lefty's solution really is the most appropriate for this situation.  Using an analog input to adjust a digital value is combersome, error-prone, and unnecessarily complex.  If you absolutely want a dial input as opposed to button inputs, then opt for a rotary encoder.  While an encoder adds it's own layer of complexity to the project, it's still better than a pot tide to an ADC input.
Logged


Pages: [1]   Go Up
Jump to: