jittery touchscreen voltages

Hallo board
I'm using an eGalax 4-wire touchscreen panel to get X-Y axis touch-location data into MaxMSP. There appear to be a number of 'correct' ways to wire this. I tried the most obvious (but apparently incorrect) way first: pin-out1 to +5v; pin-out4 to GND, and the other 2 pins for X and Y. This gives the same reading in Arduino serial monitor for both axes and doesn't work. The other method, from Practical Arduino connects the 4 outPins in alternating pairs to 4 analog inPins ONLY and uses code to cycle the states (GND, +5v, read) of the pins to give discrete readings for X and Y. This almost works perfectly, but when there is no contact, the voltage reading maxes out, and during touch contact the values will occasionally jump back up to this maximum - very jittery. The last suggestion was this:
XL -> GND
XR -> Arduino pin 1//X Resistor -> +5V
YU -> GND
YD -> Arduino pin 2//Y Resistor -> +5V
which I haven't tried yet.
Can a kind person suggest how best to get non-jittery voltage values off a cheap touchpanel please?

Thanks
Brendan

My guess is with these cheap 4-wire resistive touch sensors you're not going to get non-jittery outputs.

If you're getting more good readings than bad, then the thing to do is to take several readings and compute the median (not the average) of those.

Also, from what I understand about the operation of these you can only read from one axis at a time. Putting each axis in a wheatstone bridge configuration (and powering them from Digital pins) should allow you to use the entire dynamic range of your ADC too.

@mspguy
hey, thanks for the reply. After trying a number of HW configs, I realised that the jitter was gonna be unavoidable. I think I know how to get an average reading (either in Max or Arduino), using an array - could you advise me how to get a median? My maths ain't too hot, thanks
Brendan

My maths ain't too hot, thanks

Like our weather...

You don't need an array.

int cnt = 20; // Or however many you want
int tot = 0;
int pin = 0; // Or whatever pin you are using
int val;
int ave;

for(int i=0; i<cnt; i++)
{
   val = analogRead(pin);
   tot += val;
}
if(cnt > 0)
  ave = tot/cnt;
else
  ave = -1;

@PaulS
Hi and thanks

The weather (like my math(s)) is warming up (here in N.Ireland);
I think I can see how this for loop will work; do you see a problem with the fact that the rest of the code has a 'toggle' element for the analog inPins: every 10ms I switch pinModes from analogRead (input) to low (output):

int xVal = 0;
int yVal = 0;

void setup()
{
Serial.begin(38400);
}

void loop()
{
//read one axis, via pins 0, 1, 2
pinMode(14, OUTPUT); //analog 0 = gnd;
pinMode(15, INPUT); //analog 1 = signalRead;
pinMode(16, OUTPUT); //analog 2 = +5v;
pinMode(17, INPUT); //switch3
digitalWrite(14, LOW); //gnd
digitalWrite(16, HIGH); //+5v
delay(5); //let voltage settle
xVal = analogRead(1); //read pin 1
xVal/=4;

//switch pinModes to read other axis, via 0, 1, 3
pinMode(14, INPUT); //analog 0 = signalRead
pinMode(15, OUTPUT); //analog 1 = gnd
pinMode(16, INPUT); //switch2
pinMode(17, OUTPUT); //analog 3 = +5v

digitalWrite(15, LOW); //gnd
digitalWrite(17, HIGH); //+5v
delay(5);
yVal = analogRead(0);
yVal/=4;
//send data to Max
Serial.print(xVal, BYTE);
Serial.print(255, BYTE); //punctuation byte
Serial.print(yVal, BYTE);
delay(100);
}

thanks
ps
very very helpful board

The jittery input is due to having a floating input. You need to pull down two of the lines. For example:

Touchscreen    Y1     X2    Y2    X1
Measure X      ADC    0V    I/L    5V
Measure Y      0V    ADC   5V   I/L
Arduino Pin     A0     A1     8     9 
Pulldown      w/PD  w/PD

I/L = Input Low
w/PD = 100k pulldown to 0V

When you apply 5V, you need to put in a delay(1) before reading the ADC voltage.

@Cloudy

i'll evince my noobness by asking:

how are the vals 'floating', i define them as ints?

I'm very convinced by your reply, but the code snippet you posted, I'm too stoopid to realise in code, can you please expand/elucidate?

humble thanks ninjas!
Brendan

By floating, I mean they have nothing connected to them so they will read a random value. So that's why you need to put a pulldown resistor to two lines.

As for the code, I think your code may be fine. Give me a few minutes to check it over.

doood

tmoro will do

thanks for your help

all going towards an accessible DMI PhD, much appreciated

Brendan

Stick pulldown resistors on 14 and 15. For the code, just bring the 5V lines back down to 0V after reading.

//read one axis, via pins 0, 1, 2
pinMode(14, OUTPUT);      //analog 0 = gnd;            
pinMode(15, INPUT);         //analog 1 = signalRead;      
pinMode(16, OUTPUT);      //analog 2 = +5v;            
pinMode(17, INPUT);              //switch3                  
digitalWrite(14, LOW);        //gnd
digitalWrite(16, HIGH);      //+5v
delay(5);                            //let voltage settle
xVal = analogRead(1);      //read pin 1
xVal/=4;
[glow]digitalWrite(16, LOW);      //back to 0V[/glow]

//switch pinModes to read other axis, via 0, 1, 3
pinMode(14, INPUT);              //analog 0 = signalRead
pinMode(15, OUTPUT);      //analog 1 = gnd
pinMode(16, INPUT);              //switch2
pinMode(17, OUTPUT);      //analog 3 = +5v

digitalWrite(15, LOW);        //gnd
digitalWrite(17, HIGH);      //+5v
delay(5);
yVal = analogRead(0);
yVal/=4;
[glow]digitalWrite(17, LOW);      //back to 0V[/glow]

It sounds like you've run into the "floating input" problem that some other people have seen, but I've never actually been able to replicate on the touchscreens that I have. If you put a 10K pull-down resistor onto each analog input it should give you clean readings. There's more info about it here:

http://kalshagar.wikispaces.com/Arduino+and+a+Nintendo+DS+touch+screen

You can probably also save a little bit of work by using the TouchScreen library, which is the code from Practical Arduino wrapped up in a handy class:

With that you can simplify your own code quite a bit. This is the example sketch in the library:

#include <TouchScreen.h>

TouchScreen ts(3, 1, 0, 2);

void setup()
{
  Serial.begin(38400);
}

void loop()
{
  int coords[2];
  ts.read(coords);
  Serial.print(coords[0]);
  Serial.print(",");
  Serial.println(coords[1]);
  delay (1000);
}

@PaulS

I said median not mean. Also the code you gave is slow and takes N samples to get one point. A sliding window is better unless you can afford to throw away so much data.

Its a pretty common mistake to use the mean to filter outlier data. An averaging fliter is great for steady noise (like Gaussian noise) but if you have noise where you get occasional extreme outliers (like bouncing on a resistive touch screen) a median filter will work better.

unfortunately, you do need to keep a history (a circular queue would work) to compute either median or mean in sliding window (median will need a list even if you don't have a sliding window).

The basic idea in a median filter is to sort your data and choose the middle value.

thanks to all those who replied:
pulldown resistors on the analogRead pins plus pulldown power pins to 0v in the code works perfectly - you guys RAWK

thanks again
Brendan