Using two different readStringUntil "characters"

Hello.

I am not sure what to call the value inside the bufferUntil, but as my title implies I need to use two different characters, rather than just the newline (\n).

Is it possible that, inside the serialEvent() function, I have something like

...
void serialEvent(Serial port){
   x = float(port.readStringUntil("X"));
   y = float(port.readStringUntil("Y"))
}

//statements
...

where the values from serial look something like:

(note: for the sake of using the values for Processing, I appended the "X" and "Y")
X1.34
Y5.12
X1.25
Y5.23

I am really confused and I hope I can be helped. Thanks in advanced

1 Like

Alright so letā€™s say that for some reason I canā€™t readStringUntil(some_random_input), how about this?

***generic alg; language might be off, but idea is here
  float xval, yval;
  
  input = float(port.readStringUntil('\n');
  xval = input;
  input = float(port.readStringUntil('\n');
  yval = input;
  
  line(pxval, pyval, xval, yval);
  //previous values
  pxval = xval;
  pyval = yval;

Acknowledged, will give it a read. Thanks for replying!

Well, I was lost after the first 3 replies, however I think I can use an array and index the place of it

Like maybe:

float val[2];
int index = 0;

//given that we are already reading from serial port called "port"...
...
void func(){  //not sure which real function to put in the real code
  input = port.readStringUntil('\n');
  val[index] = input;
  index = index + 1;
  input = port.readStringUntil('\n');
  val[index] = input;
  index = index + 1;
   if (index > 1){
    index = 0;
  }
  pxval = val[0];
  pyval = val[1];
}

...
//another external function here
void draw(){
  background(1);
  stroke(255);
  line(pxval, pyval, val[0], val[1]);
}

Note: being new to Processing and coming from a slight Arduino background, I am still learning.

Another note: I had no time to read the reply you gave, as well as the whole question, due to me having a load of schoolwork. Apologies for any incompetence.

EDIT: I have read a bit of the link within the one you sent me:

I think within my arduino code I should output the accelerometer values with a [0] or [1] appended to it, and from there use readStingUntil. I hope this is solved; I will do some testing but for the meantime if there are any errors you can see, please get back to me

Thank you

The solution I gave on that link expects the Arduino C code to send the multi-data as if they were a row of tab-separated values (TSV): :face_with_monocle:

That is, each value is followed by a \t character; except last 1, which is followed by an \n instead: :nerd_face:

Serial.print(temperature);
Serial.write('\t');
Serial.print(masse);
Serial.write('\t');
Serial.print(humidite);
Serial.write('\t');
Serial.print(comptage);
Serial.write('\t');
Serial.println(son); // implies '\n'

At the Processing Java side, each data row is received whole via Serial::readString(), then split as an array via PApplet::splitTokens(), and then converted to float[] via PApplet::float(): :coffee:

  1. Processing.org/reference/libraries/serial/Serial_readString_.html
  2. Processing.org/reference/splitTokens_.html
  3. Processing.org/reference/floatconvert_.html
float[] vals = {};

void serialEvent(final Serial s) {
  vals = float(splitTokens(s.readString()));
  redraw = true;
}

Full code from the original post: :sunglasses:

/**
 * Efficient Serial Multi-Value Reading (v1.1.2)
 * GoToLoop (2015-Feb-18)
 *
 * Forum.Processing.org/two/discussion/14988/
 * drawing-of-graphs-from-i2c-imu#Item_3
 *
 * Forum.Processing.org/two/discussion/16618/
 * processing-with-arduino-void-serialevent#Item_1
 *
 * Discourse.processing.org/t/
 * using-two-different-readstringuntil-characters/10769/6
 */

import processing.serial.Serial;

static final int PORT_INDEX = 0, BAUDS = 9600;

int[] vals = {};
//float[] vals = {};

void setup() {
  noLoop();
  final String[] ports = Serial.list();
  printArray(ports);
  new Serial(this, ports[PORT_INDEX], BAUDS).bufferUntil(ENTER);
}

void draw() {
  println(vals);
}

void serialEvent(final Serial s) {
  vals = int(splitTokens(s.readString()));
  //vals = float(splitTokens(s.readString()));
  redraw = true;
}
2 Likes

allow me to be ecstatic hereā€¦

OMG THANKS THIS IS GREAT AND THANK YOU!!!

Anywayā€¦

Itā€™s making more sense on the language part of this as well as the logic part behind it. Additionally the explanation of this made it less daunting to read the whole forum you initially linked hehe.

It turns out Iā€™ve been using TSV in arduinoā€¦on my code I use:

Serial.print(val); Serial.print('\t');
...

EDIT: However I am still a bit confused as to how I will go about using values that the serial port in Processing receives. Iā€™m a bit confused about arrays and all I know is once a value is put in an index it can be called like: val[1]

Thank you, but now I have schoolwork! Iā€™m glad Iā€™ve been helped!

Have a good day. Cheers

https://processing.org/reference/splitTokens_.html

This helps I guessā€¦

I apologize for many reply and edit.

Alright, so far I have been having issues with this

On processing I have:


import processing.serial.*;
float[] val = {};
Serial port;

int len = 1200; // set length
int wid = 700;  // set width
float x, y;
float px = 600;
float py = 350;

void setup() {
  size(1200,700);
  port = new Serial (this, "COM12", 115200);
  port.bufferUntil('\n');
}

void serialEvent(final Serial port) {
  val = float(splitTokens(port.readString()));
  redraw = true;
}
void draw(){
  gyroline();
}

void gyroline() {
  //...
  x = val[0];
  y = val[1];
  line(px, py, x + px, y + py);
  px = x;
  py = y;
  
  print(x); println(y); // for debugging
}

However this gives me ā€œArrayIndexOutOfBoundsException 0ā€

And for referenceā€™s sake, hereā€™s my Arduino (but only the loop() part):

//...
void loop() {
  mpu.getMotion6(&rawaccx, &rawaccy, &rawaccz, &rawgyrx, &rawgyry, &rawgyrz);
  getaccel(rawaccx, rawaccy, rawaccz);

  Serial.print(realaccx); Serial.write("\t"); // TSV
  Serial.print(realaccy); Serial.write("\t"); // TSV
  Serial.println('\n'); // NEWLINE
  delay(10);
}

Please reply soon :frowning_face: Thank you
EDIT: Iā€™ve been trying to work on a solution while reading the links you sent and I have this. Now i am getting NullPointerException



import processing.serial.*;
String index;
float[] val;
Serial port;

int len = 1200; // set length
int wid = 700;  // set width
float x, y;
float px = 600;
float py = 350;

void setup() {
  noLoop();
  final String[] port = Serial.list();
  // port = new Serial (this, "COM12", 115200);
  new Serial(this, "COM12", 115200).bufferUntil('\n');
  // port.bufferUntil('\n');
}

void serialEvent(final Serial port) {
  val = float(splitTokens(port.readString()));
  redraw = true;
}
void draw() {
  while (port.available() > 0) {
    String input = port.readString();
    val = float(splitTokens(input));
    gyroline();
  }
}

void gyroline() {
  //...
  x = val[0];
  y = val[1];
  line(px, py, x + px, y + py);
  px = x;
  py = y;

  print(x); 
  println(y);
}

That means the val[] array variable is of length = 0.

That means the val[] array variable is still null. That is, it has not been initialized yet.

So, why are those errors happening? Pay attention to this line of code below inside serialEvent():

Variable val[] is properly assigned w/ a float[] array only when serialEvent() is called back.

As you know, draw() is called back (much probably many times) much earlier before serialEvent() is called back for the 1st time!

However, youā€™re assuming that val[] is already an array of length = 2 at the lines below:

Given you expect to receive exactly 2 values from Serial::readString() each time itā€™s called back, you should pre-initialize val[] w/ an array of length = 2 (or more if you wish), so it doesnā€™t crash the sketch when draw() is called back for the 1st time:

float[] val = {}; ā†’ float[] val = new float[2];

P.S.: You donā€™t need redraw = true; when not using noLoop():

1 Like

The last line of code gives me an error.

float[] val = {}; ->  float[] val = float[2];

"Error on ā€˜.classā€™ "

How do you propose I read the serial values and store each one separated by tsv onto my array?

Should I put the splitTokens withing draw? It doesnā€™t necessarily have to be in serialEvent right?

Edit: I tried to do something with this and itā€™s a null error:

import processing.serial.*;
String index;
float[] val;

Serial port;

float x, y;
float px = 600;
float py = 350;

void setup() {
  size(200, 200);
  noLoop();
  new Serial(this, "COM12", 115200).bufferUntil('\n');
}

//void serialEvent(final Serial port) {
//  val = float(splitTokens(port.readString()));
//}

void draw() {
  while (port.available() > 0) {
    String input = port.readString(); //takes serial input from Arduino
    val = float(splitTokens(input));  //assuming that all values until \n are caputured, split into array
    x = val[0];
    y = val[1];
    line(px, py, x + px, y + py);     //draw line
    px = x;
    py = y;
  }
}

Oops! I knew I was forgetting something, the operator new: float[] val = new float[2];. :confounded:

Alright so nothing is working yet. Iā€™m currently trying it on a simpler scale ā€“ using potentiometer and drawing lines. Itā€™s similar anyway, so I thought Iā€™d figure this thing out using potentiometer

I just have a question: Does the value for the array index reset to 0? From as far as I know (which is probably wrong :thinking:), the splitTokens() parses a string and puts it into array as

 val [strIndex0] 

where this is the first value from the serial.

Now, as the serial is being read, given that it has 2 values, does the index reset after \n?

On another noteā€¦Iā€™m working on this and this is what I have

import processing.serial.*;

Serial port;
float[] coords = new float [2];

float x, y;
float px, py;

void setup(){
  background(1);
  port = new Serial (this, "COM12", 115200);
}

void serialEvent(final Serial port){
  coords = float(splitTokens(port.readStringUntil('\n')));
}

void draw(){
  if(port.available() > 0){
    index = 0;
    serialEvent(port);
    x = coords[0];
    y = coords[1];
    line(px, py, x, y);
    px = x;
    py = y;
  }
}

The Arduino:




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

void loop() {
  int x = analogRead(A1);
  int y = analogRead(A0);

  int x1 = map(x, 1023, 0, -10, 10);
  int y1 = map(y, 0, 1023, -10, 10);

  Serial.print(x1); Serial.write('\t');
  Serial.print(y1); Serial.write('\t');
  Serial.println('\n');

}

Is the arduino side correct? I wont want to be referring to tsv and newline and then it turns out Iā€™m wrong :disappointed:

Dunno much about Arduino, but it seems correct to me. :flushed:
Although you can simplify it a lilā€™ more like this: :nerd_face:

Serial.print(x1);
Serial.write('\t');
Serial.println(y1);

Iā€™m also noticing youā€™re sending 2 int values, not float 1s: :see_no_evil:

int x1 = map(x, 1023, 0, -10, 10);
int y1 = map(y, 0, 1023, -10, 10);

So itā€™ll be more efficient to replace all float to int in the Processing side as well. :bulb:

Also in your Processing code side, Iā€™ve spotted some bugs which wouldnā€™t be there if you had followed my own sketch model more closely! :roll_eyes:

Whereā€™s Serial::bufferUntil() after this statement: :grimacing:
port = new Serial(this, "COM12", 115200);

And do not use Serial::available() when using serialEvent()! :no_good_man:

1 Like

Thanks!

Oops I, too, knew I was missing something :laughing:

Iā€™ll take the time to slowly read because often times I skim (idk itā€™s a natural thing I do). Proves to be ineffective with programming hehe

Will do :+1: but maybe Iā€™ll just replace the Arduino code parts to float. If weā€™re going for code efficiency, I guess Iā€™ll change it to int

At the time I wrote this reply this is what I have so far (implementing your recent suggestionsā€¦)

import processing.serial.*;

Serial port;
float[] coords = new float [2];

float x, y;
float px = 250;
float py = 250;

void setup(){
  size(500,500);
  final String[] str = Serial.list(); //not sure why i need this but copied it anyway
  printArray(str);                    //this one too
  port = new Serial (this, "COM12", 115200);
  port.bufferUntil('\n');
}

void draw(){
  background(1);
    //serialEvent(port);
    //coords = float(splitTokens(port.readString()));
    stroke(255);
    x = coords[0];
    y = coords[1];
    line(px, py, x + px, y + py);
    print(x);
    print(y);
    println(" ");
    px = x;
    py = y;
}

void serialEvent(final Serial port){
  coords = float(splitTokens(port.readString()));
  //redraw = true; //added just because it's on your model code
}

With a weird output

[code]
[0] ā€œCOM12ā€
0.00.0

ā€¦

0.00.0
0.00.0
ArrayIndexOutOfBoundsException: 0

[/code]:

TL:DR the end of the output has an error on it

Itā€™s also not drawing anything

@GoToLoop I have tried and tried and even copied the code on the links you gave as though it was a template, but I have gotten nothing

I did, however, watch a video about multiple serial values and acting on it. After watching it I got this:

import processing.serial.*;

Serial port;

int index = 0;
int[] input_arr = new int[2];
int px, py;
int x, y;

void setup() {
  background(0);
  size(500, 500);

  port = new Serial(this, "COM12", 115200);
  stroke(255);
}

void draw() {
}

void serialEvent() {
  while (port.available() > 0) {
    String raw = port.readStringUntil('\n');
    input_arr[index] = int(raw);
    index++;

    if (index > 1) {
      x = px + input_arr[0];
      y = py + input_arr[1];
      port.clear();
      println(input_arr[0]); //debug; this doesnt print anything
      px = x;
      py = y;
    }
  }
  line(x, y, px, py);
  port.bufferUntil('\n');
}

I might start a new thread about this specific oneā€¦

Well, I donā€™t have any Arduino hardware and neither even seen 1 in front of me yet! :woozy_face:

So I can only do blind coding in the dark for you. :dark_sunglasses:

Theoretically, an Arduino C code like this 1: :thinking:

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

void loop() {
  const int x = map(analogRead(A1), 0, 1023, -10, 10);
  const int y = map(analogRead(A0), 0, 1023, -10, 10);

  Serial.print(x);    // "-5"
  Serial.write('\t'); // '\t'
  Serial.println(y);  // "10" + "\r\n"

  delay(2);
}

Should expect to send an output similar to this 1 on each of its loop(), right: :grey_question:

String tsv = "-5" + '\t' + "10" + "\r\n";
println(tsv); // -5      10

int[] vals = int(splitTokens(tsv));
println(vals); // [0] -5  [1] 10

exit();

So AFAIK, a Processing Java code like this 1 should hopefully work for your case: :pleading_face:

import processing.serial.Serial;

static final int VALS = 2;
int[] vals = new int[VALS];

void setup() {
  size(800, 600);
  noLoop();

  stroke(-1);
  clear();

  final String[] ports = Serial.list();
  printArray(ports);

  new Serial(this, "COM12", 115200).bufferUntil(ENTER);
}

void draw() {
  println(vals);
}

void serialEvent(final Serial s) {
  vals = int(splitTokens(s.readString()));
  redraw = true;
}

BtW, here are some Arduino API references: :wink:

  1. https://www.Arduino.cc/reference/en/
  2. https://www.Arduino.cc/reference/en/language/functions/communication/serial/

Yes it definitely works (i feel like Iā€™m cheating hereā€¦). Thanks so much

Now, Iā€™m wonderingā€¦what in the WORLD did I miss? Iā€™ve been at this for 12 hours and it took you less than an hour

Problem solved, but I just want to know why after missing meals and sitting in front of a screen I still couldnā€™t get it myself. Reading documentations just became a drag after stressing, so it was pointless to do so :angry:

Thanks though, but I hate getting the answer without learning my mistake.

Now I am trying to add the draw line and SO FAR this is what I haveā€¦

import processing.serial.Serial;

static final int VALS = 2;
int[] vals = new int[VALS];

//
int px = 400, py = 300;

void setup() {
  size(800, 600);
  noLoop();

  stroke(-1);
  clear();

  final String[] ports = Serial.list();
  printArray(ports);

  new Serial(this, "COM12", 115200).bufferUntil(ENTER);
}

void draw() {
  println(vals);
  line(px, py, vals[0], vals[1]);
  px = vals[0];
  py = vals[1];
}

void serialEvent(final Serial s) {
  vals = int(splitTokens(s.readString()));
  redraw = true;
}

EDIT: I noticed that println(vals) works just fine but why not println(vals[0])
I think this has been causing my confusion and Iā€™m glad I found it

Well, println(vals); logs the whole content of the array val[].
While println(vals[0]); logs only the value stored at index 0.

The [] is called the array access operator btW:

You can learn more about Java arrays here:

The sketch Iā€™ve posted in this thread is about 90% the same from my posted link:

Basically, Iā€™ve simply replaced:

static final int PORT_INDEX = 0, BAUDS = 9600;
int[] vals = {};

new Serial(this, ports[PORT_INDEX], BAUDS).bufferUntil(ENTER);

w/

static final int VALS = 2;
int[] vals = new int[VALS];

new Serial(this, "COM12", 115200).bufferUntil(ENTER);

BtW, the constant PORT_INDEX has to match an index value from the array returned by Serial.list() which corresponds to the port thatā€™s gonna receive bytes from the Arduino:

In your computer, that seems ā€œCOM12ā€ matches the 1 connected to your Arduino.

However, if you simply copy & paste it on some other computer, chances are ā€œCOM12ā€ might fail!

Also, even if in the same computer, but w/ a diff. OS, like some Linux distro, ā€œCOM12ā€ wonā€™t work at all; b/c Linux uses a completely diff. string for ports!

Also, if you happen to send a TSV row w/ more data than just 2, int[] vals = new int[2]; isnā€™t enough, obviously!

Therefore, when dealing w/ any Arduino code, we should consider such code a template.

B/c each computer and OS will have its own port number!

Thus we have to slightly customize such code to the values used by own particular computer configuration rather than directly use an unmodified copy & paste serial program!