How to draw real-time data in a specific canvas area?

A related topic:

Reference (just one of may):

:)

Your code is using:

The Processing float() function is this in Java:

PApplet.parseFloat("3.141927"); // Example

Which can be found buried in here:
processing4/core/src/processing/core/PApplet.java at main · processing/processing4 · GitHub

Which leads to here:
https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Float.html#parseFloat(java.lang.String)

And then to here:
https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Float.html#valueOf(java.lang.String)

Which states:

Leading and trailing whitespace characters in s are ignored

Which refers to this:
https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/String.html#trim()

Which states:

public String trim()

Returns a string whose value is this string, with all leading and trailing space removed

There is always a reason why things work… or do not work.

My use of serial communications goes beyond that of Arduino and Processing and the details are important.

:)

Hello @cola,

I am interested in your final solution.

I do not need to see the code… just an understanding of what you did for a solution to your project.

:)

My use of serial communications goes beyond that of Arduino and Processing and the details are important.

I’m curious if you use an Arduino? Most of the beginner questions revolve around Arduino and Processing, although the poster frequently omits the setup in their question.

I think you have to do whatever it takes to make it work. Sometimes it’s fairly easy and other times not. It’s more complicated than it might seem. Data ‘packets’ are not always split where we hope they are; eg, when sending a string of ‘123’ the ‘1’ might be sent at the end of one packet and the ‘23’ at the start of the next. Putting the soup back together has always been a challenge for me and markers such as line feeds and commas are necessary. When the going gets really tough I’ve had to resort to printing out every character that comes down the pike and have sometimes been surprised at the ‘garbage’ that gets sent, eg NBSP (non breaking space characters).

1 Like

I own several different flavors of Arduino boards, as well as other microcontrollers and IoT devices.

I can program them in assembly (not so much these days), C or Arduino code (simplified C++).

This is one (oldie but popular) of my many projects:

I can communicate to it with PC (USB or Bluetooth) or Android Phone (Bluetooth).
Sometimes when I leave the room they are talking to each other… :)

I have managed to resolve most of the issues with serial communications between Arduino and Processing (USB and Bluetooth) because of experience and understanding what is going on under the hood.
Sharing the Arduino println() reference is just one example of something that one should know; at the very least it encourages people to look at the reference which they should be doing. I know I asked the question of how it is handled on receiving end and found an answer. And if it comes up in other related serial communications (I send stuff to terminal software, other software platforms and other devices all the time) what is being communicated is known.

Sharing is caring. The choices people make are there own.

This may be of interest:
https://www.martyncurrey.com/arduino-serial-ascii-data-and-using-markers-to-separate-data/

Have fun!

:)

I have your PGraphic technique working with multiple streams of simulated data. I have also used a java thread with Arduino serial to paint a graphic in an AWT frame but have no experience with Processing PGraphics connected to a thread as you are proposing. As time permits would you mind posting a demo using an Arduino to send data to your demo as alluded to above? You could use the sawtooth Arduino code that I posted or some other pattern, but I would like to get it working. It’s not obvious to me how to hook a serialEvent() to a thread.

Simulated Data to 3 PGraphics Output:

Hello @svan,

I used Processing to send to Processing with a COM port redirector.

Transmit:

import processing.serial.*;
Serial txPort;

float [] num = new float[3];

void setup()
  {
  // List all the available serial ports:
  printArray(Serial.list());

  // Open the port you are using at the rate you want:
  txPort = new Serial(this, Serial.list()[2], 9600);
  //frameRate(10);
  }
  
void draw() 
  {    
  num[0] = 20*sin(frameCount%360*TAU/360);
  num[1] = 20*sin(frameCount%360*TAU/360 + TAU/3);
  num[2] = 20*sin(frameCount%360*TAU/360 + 2*TAU/3);
  txPort.write(str(num[0]));
  txPort.write(',');
  txPort.write(str(num[1]));
  txPort.write(',');
  txPort.write(str(num[2]));
  txPort.write('\n');  
  }

Receive:

import processing.serial.*;
Serial rxPort;

PGraphics d0, d1, d2;
FloatList data0, data1, data2;

float [] num = new float[3];

void setup()
  {
  size(400, 300);    
  d0 = createGraphics(400, 100);   
  
  data0 = new FloatList();
    
  // List all the available serial ports:
  printArray(Serial.list());

  // Open the port you are using at the rate you want:
  rxPort = new Serial(this, Serial.list()[3], 9600);
  
  rxPort.bufferUntil('\n');
  }

void draw() 
  {
  image(d0, 0, 0);
  }

int i;
  
void serialEvent(Serial myPort) 
  {
  String inString = myPort.readString();
  //println(inString);
  if (inString != null) 
    {
    inString = trim(inString);
    println(inString);
    
    String [] data = split(inString, ',');
    
    // Start adding to Lists
    println(i); 
    data0.append(float(data[0]));
    update(); 

    i = (i+1)%400;  // 0 to 399 to avoid drift from floating point math
    
    if (i == 0 )
    data0.clear();
    }
  }
    
void update()
  {
  d0.beginDraw();
  if (i == 0)
    d0.background(255, 255, 0);
  d0.stroke(0);
  d0.strokeWeight(2);
  d0.point(i, data0.get(i) + d0.height/2);
  d0.endDraw();
  }  

I only created one PGraphics in above code. You can add more!
It no longer scrolls but clears and starts again from left to right.

This is what it would look like complete:

Reference:

:)

Thanks for the demo I will take time to study it.
In the meantime I have this working and it still scrolls. Basically I just stuck the serialEvent() code into your requestData(). The only problem is the dots when I need lines in the PGraphic. Is it possible to draw lines?

// Modified glv demo https://discourse.processing.org/t/how-to-draw-real-time-data-in-a-specific-canvas-area/45631/27
import processing.serial.*;

PGraphics d0;
FloatList data0;

int i;
String inStr;     // Data received from the serial port
Serial myPort;
int lf = 10;      // ASCII linefeed
float inByte = 0;

int _wndW = 800;
int _wndH = 600;
void setup() {
  size(600, 500);
  printArray(Serial.list());
  // Enter correct number for your system
  myPort = new Serial(this, Serial.list()[1], 9600);
  myPort.bufferUntil(lf);
  strokeWeight(2);
  d0 = createGraphics(_wndW, 300);
  data0 = new FloatList();

  thread("requestData");   // start thread to generate data
}

void draw() {
  background(0);
  update();
  image(d0, 0, 0);
}

void requestData() {
  while (true) {
    delay(3);
    inStr = myPort.readStringUntil('\n');
    if (inStr != null) {
      //trim whitespace and formatting characters (like line feed, carriage return)
      inStr = trim(inStr);
      inByte = float(inStr);
      data0.append(inByte);
      println(int(inByte));
    }
    if (data0.size() > d0.width)
      data0.remove(0);
    i = (i+1)%d0.width;  // 0 to 399 to avoid drift from floating point math
  }
}

void update() {
  d0.beginDraw();
  d0.background(255, 255, 0);
  d0.stroke(0);
  d0.strokeWeight(2);
  for (int i=0; i<data0.size(); i++) {
    d0.point(i, data0.get(i)+d0.height/2);
  }
  d0.endDraw();
}

Arduino code:

byte outputValue = 0;

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

void loop() {
    outputValue += 8;
    Serial.println(outputValue);
 }

Addendum:
An other issue is the dots are descending when they should be ascending and then dropping back down to zero. It looks backwards, but it is printed left to right as expected.

d0.point(i, height - 200 - data0.get(i));

Fixes this issue; now plots correctly, but still need lines.

Addendum2:
This adds the lines, but it’s very jittery when scrolling for some reason:

  for (int i = 0; i < data0.size(); i++) {
    y1 = data0.get(i);
    d0.line(i,height - 200 - y1, i++, height - 200 - y2);
    y2 = y1;
  }

where y1, y2 are floats.
**


**

Addendum3:
This fixes the jitters (don’t augment second x value):

    d0.line(i,height - 200 - y1, i, height - 200 - y2);

The thread() was only intended to simulate data in place of serialEvent().
Not everyone has an Arduino and I wanted a working example.

I had a comment in original code:

:)

Yes I know, I quoted it in my earlier post. That’s how I got the idea to try substituting serialEvent(), plus the fact that I recognized the while(true) construct which I had used in my java demo. At any rate, I think it’s going to be a good technique if I can solve the jitters.

hello @glv,
In fact, I am very confused about the problems you mentioned about serial port transmission. I may not have thought too much about these.

Regarding drawing, I currently refer to the protocentral_openview method. For details, you can check the following link. My transmission protocol also complies with its regulations. For multiple devices, you can modify it according to its transmission protocol.

I imagine that the packets of each device are output separately, but this requires considering whether the time interval between each device in transmitting the data packet is reasonable, otherwise the data transmission will not be possible due to data congestion. After using the above transmission method, I only need to add identifiers of different data sources.

In fact, I think I should start with the design of Arduino. Thank you for your enthusiastic answer, and I’m sorry for the late reply.

Best wishes! :handshake:

1 Like

I’m sorry but I can’t get this to run. You have two Processing apps using the same serial port and that won’t work on my system. Unless you want to send on one serial port and receive on another serial port and I can’t figure out how to do that. Once I unplug my Arduino I only see one bluetooth port listed.

I don’t understand where you’re hung up. If you are going to use proprietary software then you’ll need to use their sensor devices. If you use the devices listed in their drop down menu it should just work; no programming necessary. Your initial post seemed to indicate that you wanted programming assistance for display of data from multiple devices.

The ECG acquisition device I used was ADS1292R, and I added a GSR acquisition device myself. I have tried it successfully in my project. But my original purpose was indeed to draw multiple devices. In the above description, I originally wrote the transmission protocol myself. My transmission protocol was based on the premise that each data packet transmission would not be blocked, but I found that this was putting the cart before the horse.

Using the above was the fastest way to solve my problem, but I still wanted to write my own transport protocol, which was the reason I posted in the first place. :flushed:

All in all, I’ve sort of solved this problem for me.

1 Like

Sounds like you have it solved and we can move on to something else.

1 Like

Thank you very much for your enthusiastic answer. I will seriously consider the issues discussed in this article in the following projects. Best wishes! :handshake:

1 Like

I misunderstood your demo. I thought you were implying that a thread had to be used to direct output to a PGraphic. I was trying to use serialEvent() inside of the thread when in fact we don’t need the thread to get a PGraphic to display output. PGraphic offscreen plotting does work with just serialEvent() as shown below.

I am using two different serial ports.

See comment:

You can write Arduino code for the Processing Transmit code.

:)

:+1:

Best wishes to you as well!

:)