Go Down

Topic: Analog screen meter (Read 2833 times) previous topic - next topic

PaulS

Quote
But higher resolution isn't the answer. I think it must be in converting the high speed & jumpy stream of data with something like a for/next loop with small steps. I'll see how that goes.

The jumpy needle can be calmed down by telling the needle to move only if the value that it is to represent has changed by a significant amount. If the needle represents a voltage, and the input is a value from 0 to 1023, perhaps only move the needle if the value has changed by more then 3.

In a stream of values like 456, 457, 455, 480, 481, 479, etc., draw the needle at the 456 position. Skip the 457 and 456 values, since the needle is already close enough. Draw the needle in the new position, represented by the 480, and skip the 481 and 479 values.

Since this is the first time that you mention what you are doing with the Arduino, and that Processing is involved, along with serial transmission of data, perhaps you should post some code. There could be any number of reasons for the jumpy needle that you have not considered.

qmt5

I started with the built-in 10 bit ADC on a Freetronics Eleven which is an Australian Arduino Uno, then went to an external MCP3201 12 bit, then an MCP3301 12 bit and currently an MCP3422 which is 12,14,16 or 18bit. The onboard was simple , the 3201 was SPI, as was the 3301, and the 3422 has an I2C interface. None was any better than the other 'jitter-wise' so I'll post Arduino & Processing code for the on-board ADC.  I notice no-one seems to post quantities of code -- is it OK? (don't want to clog the system). I used handshaking with some, and with others I sent the data as binary and assembled in Processing. None made any real difference.
Going to bed.

qmt5

Here is what gives me such skittish needle movement.

/*ARDUINO CODE - Basic Data Reading with Averaging & Hysteresis.
* Using on-board 10 bit ADC, pot onto A1, 10 or 100 uF across
* power, 0.1 uF across pot. 5 volts in from USB bridged to Vref.
*/

float sensVal;
float previous, diff;         // for calculating hysteresis
int HYSTERESIS = 2;
void setup(){
Serial.begin(9600);
}
void loop(){
for (int i=0;i<10;i++){         // averaging 10 reads
sensVal = sensVal + analogRead(0);
delay(10);
}
sensVal = sensVal/10;
diff = abs(sensVal - previous);   // calculating hysteresis
if (diff <= HYSTERESIS){
  sensVal = previous;
}
previous = sensVal;
Serial.println(sensVal);
}

// PROCESSING CODE

import processing.serial.*;
Serial myPort;       
float radius = 900;                        //  radius of circle
float angle;
float px, py;                              //  needle point
  void setup (){
  size(1000, 1000);
myPort = new Serial(this, "COM18", 9600);
myPort.bufferUntil('\n');
}
void draw(){
}
void serialEvent(Serial myPort){
String val = myPort.readStringUntil('\n');
  if(val != null){
    angle = float(trim(val));
    angle = map(angle,0,1024,0,360);
}
   ellipse(width/2, height/2, radius, radius);    // dial pos/size
   px = width/2 + cos(radians(angle))*(radius/2); // needle point
   py = height/2 + sin(radians(angle))*(radius/2);// sets y co-ord
   line(width/2, height/2, px, py);
}

As I said, tried running it faster, slower, different baud rates. Tried handshaking. Tried sending data as binary instead of a string, assembling in Processing. Tried external ADC's. Tried different chips using SPI, and I2C. Shifted hysteresis routines into Processing instead of in Arduino. Tried using 'rotate()' instead of above trig routine. Tried avoiding 'serialEvent' and put code into draw(). Took trig routine out of  draw() and put it into a function. Viewed neighbours cute daughter and considered misc. heathen rites.  Came back to earth with a sickening thud......  I seem to just overload Processing with data faster than it can handle. I can only think of getting a value several ms down the track & putting in a for/next loop to bridge to it in a controlled fashion somehow. I think the needle movement is jerky because it skips data. Is that it ??

PaulS

Code: [Select]
int HYSTERESIS = 2;
By convention, all capital letters in the name are reserved for #define names.

Code: [Select]
sensVal = sensVal/10;
diff = abs(sensVal - previous);   // calculating hysteresis
if (diff <= HYSTERESIS){
  sensVal = previous;
}
previous = sensVal;
Serial.println(sensVal);

You could avoid all the floating point arithmetic, and simply have Processing do the divide by 10 part.

You should only send data if there is a difference. By not converting to a float, you could send the high order byte and low order byte, and have Processing re-assemble the integer value. Doing so would send just two bytes, instead of a minimum of 4 (x.xx) to a maximum of 7 (xxxx.xx).

Since the difference between 123 and 123.45 is going to be difficult to see when the value is divided by 1024/360 in Processing, anyway, I'd skip the floating point crap altogether. Just send, and receive, an int.

Code: [Select]
myPort = new Serial(this, "COM18", 9600);
Quit dragging your feet. Get the speed up to 115200.

Code: [Select]
void serialEvent(Serial myPort){
String val = myPort.readStringUntil('\n');
  if(val != null){
    angle = float(trim(val));
    angle = map(angle,0,1024,0,360);
}

You've told Processing that the serialEvent() method should be called only when a carriage return arrives. Then, reading only a part of the serial data, even though it will be all of it, wastes resources. What is there to trim? The float() function will ignore leading white space, and stop reading at any non-numeric content in the string. Ergo, the trim() call is a waste of time.

Quote
Viewed neighbours cute daughter

Always a good diversion...

Quote
I seem to just overload Processing with data faster than it can handle.

I seriously doubt that. Printing the values received in Processing (and showing the output to us) might suggest a course of action that you have not considered, if the above suggestions do not pan out.

DirtGambit

Is it something like this your trying to do?



I had some problems getting mines nice and smooth, set a framerate in processing smooths it out a bit i set mines to 12. I made a post about this a while back and one of the forums members were good enough to point me in the right direction and now it works quite well.


extent

Is the needle jumping around all the time, or only when you're wiping the pot?  Is it just a little constant jitter or big swings to values way far away from the current actual value?

Have you actually examined the raw data stream being collected from the arduino, just as a sanity check?  Is your hysteresis of 2 based on your actual "noise floor" of your readings?  I've never played with the analog ins down to that resolution, but my first impression is that the value may be too low to be of any use, that's only barely more than .5 degrees

qmt5

Thanks all for your suggestions --- had some emergencies to handle ---will implement them in next couple of days.

Grumpy_Mike

What value is your pot, it is best to use 10K.

Also put a 0.1uF from the pot wiper to ground.

qmt5

PaulS --- I implemented your suggestions. The code below started off fairly 'jerky' still, but then, as you see,  I dropped hysteresis value to 1, only averaged 5 instead of 10 reads, dropped the delay between the 5 readings to 5 ms insstead of 10, and cut out the 100ms delay at the end of the arduino code. I've cut out all the floating point stuff, and avoided 'serialEvent()' and now transmit data in byte form instead of strings, re-assembling in Processing'. I'm running it at 115,200. If I'm careful and slow I can check and I seem to be catching reads at intervals of 3 to 5 mainly, both in Arduino and after the Processing sketch. I did what Mike suggested -- I already had a 0.1 uF cap from pot wiper to earth, and although I couldn't find a 10K pot I had a 100K which was a lot lower than the 1 Meg I was using (top leg of the divider network was 22k i.e.
( +ve -->22k-->A0-->1 meg pot-->-ve). If I wind the pot a little faster I thought originally I was dropping reads, but on checking it still runs (say) 324,327,332,335 etc. etc. on the 10 bit on board ADC. But if I really wind it fast I get a series in Processing like the following:- 1,27,135,283,386,461.... etc. etc.
Changing framerate from the defasult of 60 doesnt improove smoothness.
Needle still doesn't look as smooth as an analog needle but I have yet to try some code to 'dampen' it --- that is, fill in the gaps of 3 to 5 steps with 1's. And that is probably as good as it's going to get. Thanks again all for your help --- much appreciated.

ARDUINO CODE
int sensVal;
int previous, diff;
int hysteresis = 2;
void setup(){
  Serial.begin(115200);
}
void loop(){
  Serial.print('H');
  for(int i=0; i<10; i++){
    sensVal = sensVal + analogRead(0);
    delay(10);
  }
  sensVal = sensVal / 10;
  diff = abs(sensVal - previous);
  if(diff <= hysteresis){
      sensVal = previous;
  }
  previous = sensVal;
//  Serial.println(sensVal);                       // checking actual values
  Serial.print(lowByte(sensVal),BYTE);
  Serial.print(highByte(sensVal),BYTE);
delay(100);
}

PROCESSING CODE
import processing.serial.*;
Serial myPort;
char HEADER = 'H';
int val;
void setup(){
  size(1000,50);
  myPort = new Serial(this, "COM18", 115200);
}
void draw(){
  if (myPort.available() >= 5){
    if (myPort.read() == HEADER){
      val = myPort.read();                 // already gone past header, so can read data
      val = myPort.read() * 256 + val;
      background(255);
      println(); print(val);                // check values
      line(val, height, val, 0);          //  using this instead of trig routine to save space
    }
  }
}


PaulS

Code: [Select]
  Serial.print(lowByte(sensVal),BYTE);
I think you should spend a few minutes looking at the HardwareSerial class and the Print class (that HardwareSerial derives from). The print() functions that print a byte ultimately call the write() method. Skip the middle man.
Code: [Select]
  Serial.write(lowByte(sensVal));

Code: [Select]
  if (myPort.available() >= 5)
Each iteration of loop on the Arduino results in (an attempt being made) writing 3 bytes to the serial port. Why are you waiting for 5?

qmt5

Just a note to Mike --- I hadn't tried the 1 meg pot back on the new skech & did just then --- all over the pppplace like yyyou kkknow wwwhat! Put the 100k back on & smoothed like magic. As my dear old mother used to say--'nice lad but a bit thick'. So 10k is probably better still. Note toPaulS --- thanks for the pointer, I'll do some study.

Go Up