Real Time Data Plotting
Introduction This lesson will show how to write a program plot data on a X-Y graph. On the Arduino, write a program to sample a sensor and print the voltage to the Serial interface. Send the sample once a second. The plotting program will read the data from the serial interface and plot it. This plotting program will plot the data in real time. It will display 400 samples along the X axis and then repeat over writing the previous samples.
The Plot The plot is going to be made in a rectangle. The top left corner of the rectangle will be positioned at 50,50 pixel location. The rectangle will be 400 by 400 pixels. X and Y labels will be added along with tick marks. Data will be plotted inside the rectangle.
First, two variables will be declared. Declaring them outside any function will make them global meaning they can be used in any function. Variable integer i will be an index variable. Variable data_plot will be an floating point array of 400 elements. int i; int[] data_plot = new int[400];
Next is the setup() function. The window is created with the size() function. All the elements in the data_plot array are initialized to zero. Variables always need to be initialized. Since the variable i was used, it has to be reset to zero. After the for() loop, the variable i has a value of 400. int i; float[] data_plot = new float[400]; void setup() size(500,500); for(i=0;i<400;i++) data_plot[i] = 0.0; i = 0;
Last item is to set the text size in the plot. This isn't required and can be changed depending on the desired look of the plot. int i; float[] data_plot = new float[400]; void setup() size(500,500); for(i=0;i<400;i++) data_plot[i] = 0.0; i = 0; textsize(14);
Two functions are created. The plot_data() function will generate the plot with the values in the data_plot variable array. The draw() function repeatedly calls the plot_data() function. Before it is called, the background() function is called. The background() function clears the screen so the plot can be redrawn with new data. If it is not called, the display will just have plots placed on top of plots. int i; float[] data_plot = new float[400]; void setup() size(500,500); for(i=0;i<400;i++) data_plot[i] = 0.0; i = 0; textsize(14); void draw() background(0); plot_data();
In the plot_data() function, the fill color is set to a dark gray which will set the color of the rectangle. The rect() function draws the rectangle starting at pixel 50,50 with a size of 400 by 400 pixels. Remember the starting position of the rectangle. The 50,50 coordinate will be the offset for drawing in the rectangle. int i; float[] data_plot = new float[400]; void setup() size(500,500); for(i=0;i<400;i++) data_plot[i] = 0.0; i = 0; textsize(14); void draw() background(0); plot_data();
The program can be run now. It will open a window and draw a rectangle on a black window that is dark grey. From now on, each step will add to the plot. The program can be run each time to see what was added. The setup() function and the draw() function will not be shown to save space. int i; float[] data_plot = new float[400]; void setup() size(500,500); for(i=0;i<400;i++) data_plot[i] = 0.0; i = 0; textsize(14); void draw() background(0); plot_data();
Import the Serial library. Create an instance of Serial called port. In the setup function, open the serial connection. Change the COM port number as needed. import processing.serial.*; Serial port; int i; float[] data_plot = new float[400]; void setup() port = new Serial(this, COM3,9600); size(500,500); for(i=0;i<400;i++) data_plot[i] = 0.0; i = 0; textsize(14); void draw() background(0); plot_data();
This section of code checks if the serial port had data in its buffer. If data is available, it is read into the String variable a. The String variable a is checked to make sure it is not empty. If it is not empty, the data is processed. First the variable a has the carriage return and linefeed characters removed. It is then converted to a floating point number and stored in the data_plot array at the element pointed to by i. i is incremented an checked to make sure it does not reach 400. When it does, it is reset to 0. //Previous code not shown for space void draw() background(0); if(port.available() > 0) String a = port.readstringuntil(10); if(a!= null) a = a.replaceall( (\\r \\n), ); data_plot[i] = float.parsefloat(a); i++; if(i == 400) i = 0; plot_data();
The two new functions inserted to modify how the rectangle is drawn. strokeweight() sets the line thickness. stroke() sets the color which is white. // only the plot function shown here strokeweight(4); stroke(255);
A label is added to the X axis. strokeweight(4); stroke(255); text( X Axis,250,480);
The next addition is adding the Y axis label. The label is rotated and moved into position. The translate() function moves the coordinate system. The rotate() function rotates the coordinate system. The text() function for the y Axis is then rendered. In order to not have everything else rotated and translated, the reverse rotation and translation is executed. strokeweight(4); stroke(255); line(50,250,400,250); text( X Axis,250,480); translate(20,250); rotate( PI/2); text("y axis",0,0); rotate(pi/2); translate( 20, 250);
Now, the data is plotted. First, the plot color is set to purple. The line thickness is set to 1. strokeweight(4); stroke(255); line(50,250,400,250); text( X Axis,250,480); translate(20,250); rotate( PI/2); text("y axis",0,0); rotate(pi/2); translate( 20, 250); stroke(200,0,200); strokeweight(1);
This section draws the data plot. First, the beginshape() function is called. This indicates the start of vector drawing. The parameter makes a line drawn between vector coordinates. The for() loop sequences through the data_plot array and creates a line to each coordinate specified in the vertex() function. When plotting the data is completed, the function endshape() is called. Setting Up the Plot strokeweight(4); stroke(255); line(50,250,400,250); text( X Axis,250,480); translate(20,250); rotate( PI/2); text("y axis",0,0); rotate(pi/2); translate( 20, 250); stroke(200,0,200); strokeweight(1); beginshape(lines); for(int b = 0;b < 400;b++) int y =map(data_plot[b],0,1023,400,0); vertex(b+50,y); endshape();
The map() function is used to scale the data to fit within the rectangle area that is being used as the plot. The height of the rectangle is 400 pixels. The data, if it is analog data has a range of 0 to 1023. The map function will scale the analog data to the range of 400 to 0. Notice the 400 is before 0. This inverts the data plot since the screen coordinates start at the top left corner. strokeweight(4); stroke(255); line(50,250,400,250); text( X Axis,250,480); translate(20,250); rotate( PI/2); text("y axis",0,0); rotate(pi/2); translate( 20, 250); stroke(200,0,200); strokeweight(1); beginshape(lines); for(int b = 0;b < 400;b++) int y =map(data_plot[b],0,1023,400,0); vertex(b+50,y+50); endshape();
Notice in the vertex() function that 50 is added to the x coordinate. This is because the rectangle at the 50 x coordinate. 50 is also added to the Y coordinate for the same reason. You have to take in into account the position of the rectangle. Run the program and have the arduino processor board send data from the analog port with a sensor connected. Use the serial.println() function to send the data. strokeweight(4); stroke(255); line(50,250,400,250); text( X Axis,250,480); translate(20,250); rotate( PI/2); text("y axis",0,0); rotate(pi/2); translate( 20, 250); stroke(200,0,200); strokeweight(1); beginshape(lines); for(int b = 0;b < 400;b++) int y =map(data_plot[b],0,1023,400,0); vertex(b+50,250 data_plot[b]); endshape();
Notice in the vertex() function that 50 is added to the x coordinate. This is because the rectangle at the 50 x coordinate. 50 is also added to the Y coordinate for the same reason. You have to take in into account the position of the rectangle. Run the program and have the arduino processor board send data from the analog port with a sensor connected. Use the serial.println() function to send the data. strokeweight(4); stroke(255); line(50,250,400,250); text( X Axis,250,480); translate(20,250); rotate( PI/2); text("y axis",0,0); rotate(pi/2); translate( 20, 250); stroke(200,0,200); strokeweight(1); beginshape(lines); for(int b = 0;b < 400;b++) int y =map(data_plot[b],0,1023,400,0); vertex(b+50,250 data_plot[b]); endshape();
It is time to add more features. The for() loop inserted adds tick marks along both axis on the plot. The tick marks are separated by 50 pixels and are 5 pixels long. The X axis tick marks are labelled with the text statement. strokeweight(4); stroke(255); line(50,250,400,250); text( X Axis,250,480); translate(20,250); rotate( PI/2); text("y axis",0,0); rotate(pi/2); translate( 20, 250); for(int x=0;x<400;x = x + 50) text(x,x+50,465); line(x+50,445,x+50,450); line(50,x+50,55,x+50); stroke(200,0,200); strokeweight(1); beginshape(lines); for(int b = 0;b < 400;b++) int y =map(data_plot[b],0,1023,400,0); vertex(b+51,data_plot[b] + 251); endshape();
This lesson showed the basics of creating a plot and filling it with data. Done More can be done with the plot. The tick marks can be labelled with values. The tick marks can be extended to create a grid. The window can be made larger and a second plot added to plot more data.