Loading...
Logo
Processing Forum
Hi,

Apologies if I posted this in the wrong place, or its off topic, I'm new at this. Hopefully someone can offer a few pointers please.

I'm trying to read a temperature in from an Arduino and graph it. So far I managed to cobble together the following code but something is seriously wrong.

 Occasionally I'm getting random text redraws at different sizes, the graph line changes colour and draws diagonally apparently randomly, origin to top right. Attempts to trace this issue seem to show correct data values but false plotting, which seems illogical to me. Generally the thing seems to function okay apart from this. Also why is the graph drawing over the trace, and how to display characters on screen and overwrite cleanly? Whew. Here's hoping.

 Season's Greetings.



import processing.serial.*;
 
 Serial myPort;           // The serial port
 int xPos = 60;           // horizontal position of the graph
 
 PFont f; //define variable for font
 

 void setup () { 
  
 size(420, 300);          // set the window size
 
 println(Serial.list());  // List all the available serial ports to window
 
 myPort = new Serial(this, Serial.list()[1], 9600); // Open whatever port is the one you're using.
 
 myPort.bufferUntil('\n'); // don't generate a serialEvent() unless you get a newline character:
 
 background(51,0,102);     // set inital background:
 
 }
 
 
 void draw () {
 
 
  f = loadFont ("ArialMT-12.vlw"); //load font into f
  
  textFont(f,16);         //Specify font to be used
  fill(200);               //Specify font color
  text("Temperature Graph and Arduino Controller",1,12);  //Display Text
 
 stroke(200,12,10);
  line(60, (height-(height/20)), width, (height-(height/20))); //setup horizontal graph lines
  line(60, (height-(height/20)*2), width, (height-(height/20)*2));
  line(60, (height-(height/20)*3), width, (height-(height/20)*3));
  line(60, (height-(height/20)*4), width, (height-(height/20)*4));
  line(60, (height-(height/20)*5), width, (height-(height/20)*5));
  line(60, (height-(height/20)*6), width, (height-(height/20)*6));
  line(60, (height-(height/20)*7), width, (height-(height/20)*7));
  line(60, (height-(height/20)*8), width, (height-(height/20)*8));
  line(60, (height-(height/20)*9), width, (height-(height/20)*9));
  line(60, (height-(height/20)*10), width, (height-(height/20)*10));
  line(60, (height-(height/20)*11), width, (height-(height/20)*11));
  line(60, (height-(height/20)*12), width, (height-(height/20)*12));
  line(60, (height-(height/20)*13), width, (height-(height/20)*13));
  line(60, (height-(height/20)*14), width, (height-(height/20)*14));
  line(60, (height-(height/20)*15), width, (height-(height/20)*15));
 
   line(60, 300, 60, (height-(height/20)*15)); //setup vertical graph lines
   line(120, 300, 120, (height-(height/20)*15));
   line(180, 300, 180, (height-(height/20)*15));
   line(240, 300, 240, (height-(height/20)*15));
   line(300, 300, 300, (height-(height/20)*15));
   line(360, 300, 360, (height-(height/20)*15));
  
   textFont(f,10);fill(200);                 //Specify font to be used
                                             //Specify font color fill
   //text positioning for temperature labels
   text("0C",10,(height-(height/20)*0));text("10C",10,(height-(height/20)*1));text("20C",10,(height-(height/20)*2));text("30C",10,(height-(height/20)*3));text("40C",10,(height-(height/20)*4));text("50C",10,(height-(height/20)*5));
   text("60C",10,(height-(height/20)*6));text("70C",10,(height-(height/20)*7));text("80C",10,(height-(height/20)*8));text("90C",10,(height-(height/20)*9));text("100C",10,(height-(height/20)*10));text("110C",10,(height-(height/20)*11));
   text("120C",10,(height-(height/20)*12));text("130C",10,(height-(height/20)*13));text("140C",10,(height-(height/20)*14));text("150C",10,(height-(height/20)*15));
 }                                //end of void draw statement
 
 void serialEvent (Serial myPort) {
 // get the ASCII string:
 String inString = myPort.readStringUntil('\n');
 
 if (inString != null) {
 // trim off any whitespace:
 inString = trim(inString);
 
 float inByte = float(inString);   // convert to an int and map to the screen height:
 inByte = map(inByte, 0, 1023, 0, height);
 println ("Time "+hour()+":"+minute()+":"+second()+" xPos:"+xPos+" "+"Height:"+height+" "+"inString:"+inString); //print xPos variable info
 
 // draw the line:
 stroke(255,102,0); //assign colour to graph - orange
 line(xPos, height, xPos, (height - ((inByte)*5)));

textFont(f,12);                 //Specify font to be used
  fill(200);                        //Specify font color
  text("Value: " + inString,1,30);
 
 // at the edge of the screen, go back to the beginning:
 if (xPos >= width) {          //if graph plot gets too wide, go back to start and refresh grid
 xPos = 60;                   
 background(51,0,102);           //reset background colour (refresh grid)
 }
 else {
 
 xPos++;                       // increment the horizontal position:
 
 
 }                             //return from xPos increment
 }
 }                             //End of Void Draw??

Replies(6)

Random (but classical) advices, unrelated to your issue:
- Don't loadFont in draw()! It will slow down your sketch. Do that in setup(). Since f is already global, you can just use your textFont() calls unchanged.
- Learn the power of for () loops to draw your grid! Search the parts that change on each line, and be DRY (don't repeat yourself), loop over a single line() call, using variables on the varying parts.
Eg.: line(60, height-i * height / 20, width, height - i * height / 20);

For the remainder, I don't know Arduino, so I can't help. But I move this from Programming Questions since your code is dependent on a given hardware.
Thanks for the reply! All noted. Regarding being an Arduino issue, only so much as it reads from an Arduino. Everything the serial reading does is fine, it is just the output in processing that is the problem. The code does its job, just not well :) Thanks for the advice, all welcome.
Another general advice, perhaps answering some of your questions / problems: in most Processing sketches, we start draw() with a background() call (with a color / tint), allowing to draw on a clear state.
Perhaps some of your overwriting issues come from this lack of clearing the sketch area.
Thanks for your help, apparently the problem was the screen was constantly overwriting in the draw loop - all text setup is done prior to running now.. I re-wrote the code based on your recommendations, and the thing so far is performing like a champ. It looks neater too.

One other thing, I require to output a number on the graph which will change/update as the temperature changes. do you know of a way to refresh just that area of the screen so I don't get flicker or previous text artifacts? At present its just overwriting and leaving a jumble.

Happy New Year!
Well, if you use background(), all the screen is refreshed on each frame, so there is no problem.
If you really need a local refresh, you can just write a rect() over the area to update.
I think I'm finally on top of it. I went down another route of outputting solid text characters in the background colour at an x,y location (effectively rectangles in text form) then at the same x,y location overprinting with the updated text. Works fine, though your method sounds more elegant.

I particularly liked your original math solution for the drawing of my grid, which I used for the grid lines, though being a bear of very little brain, I couldn't quite tidy up the degrees scale routine with more efficient math.

Next I have to construct a way to send commands to the Arduino to get it to control a stepper motor (this module is part of a solar water heater regulator circuit I'm prototyping).

Thanks for your quick replies and time, it is much appreciated. I'll post the amended code shortly in case anyone else wants to have a go.