Using two different readStringUntil "characters"

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;
}
1 Like

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():
Processing.org/reference/noLoop_.html

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:
Processing.org/reference/new.html

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);

Processing.org/reference/libraries/serial/Serial_bufferUntil_.html

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

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:
Processing.org/reference/arrayaccess.html

You can learn more about Java arrays here:
Docs.Oracle.com/javase/tutorial/java/nutsandbolts/arrays.html

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:
Processing.org/reference/libraries/serial/Serial_list_.html

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!

I guess what you’re actually attempting there is to move the line()'s current coordinates w/ the values received from Serial, right? :thinking:

I see that at the Arduino’s side, you use map() in order to constrain the sent values within the range of [-10 to 10]. :world_map:

My bet is that those values mean how much farther to draw the next line()'s coordinates in relation to the previous 1.:horse_racing:

So I’ve made some changes to my previous Serial posted sketch. :man_mechanic:

Now, instead of vals[], we’re gonna have a PVector mov variable:
Processing.org/reference/PVector.html

Variable mov is gonna store the values received from Serial::readString() using its method PVector::set():
Processing.org/reference/PVector_set_.html

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

We’re also gonna need a 2nd PVector named vec, which’s gonna store canvas’ current coordinates:
final PVector vec = new PVector(), mov = new PVector();

And we’re gonna initialize it w/ the canvas’ center coordinates:
vec.set(width>>1, height>>1);

Now, every time a new coordinate pair is received within serialEvent(), we’re gonna use PVector::add() method in order to move vec’s current coordinates to a new 1, passing mov as its argument:
Processing.org/reference/PVector_add_.html
line(vec.x, vec.y, vec.add(mov).x, vec.y);

Here’s the complete sketch “Serial TSV-Reading Line-Drawing”. Have fun: :smile_cat:

/**
 * Serial TSV-Reading Line-Drawing (v1.0)
 * GoToLoop (2019/May/02)
 *
 * https://Discourse.Processing.org/t/
 * using-two-different-readstringuntil-characters/10769/21
 */

import processing.serial.Serial;

static final String PORT = "COM12";
static final int BAUDS = 115200, INDEX = 1;

final PVector vec = new PVector(), mov = new PVector();

void setup() {
  size(1300, 700);
  noLoop();

  stroke(-1);
  clear();

  vec.set(width>>1, height>>1);

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

  new Serial(this, PORT, BAUDS).bufferUntil(ENTER);
  //new Serial(this, ports[INDEX], BAUDS).bufferUntil(ENTER);
}

void draw() {
  line(vec.x, vec.y, vec.add(mov).x, vec.y);

  if (outtaBounds(vec)) {
    vec.set(width>>1, height>>1);
    System.err.println("Coords reset back to center of canvas!");
  }

  println(vec, mov);
}

boolean outtaBounds(final PVector v) {
  return v.x < 0 | v.x >= width | v.y < 0 | v.y >= height;
}

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

Hmm I was actually prepping for a reply on the other thread I asked. It involved having potentiometer input from Arduino and feeding it to processing to draw lines

I have been a bit confused because it’s not behaving like ContinuousLines demo, rather it’s just really weird lines…

Yes!
Yes! It’s 10 and -10 to interact with the “coordinates” on screen
YES!!

So I’ll look into this and thank you very much for all the support and help! Thanks for being patient too

  • Now that it seems all’s been sorted out, how about some optimization?
  • The range [-10 to 10] is so small (5-bit) that it comfortably fits in a byte (8-bit).
  • So, rather than send those 2 small values as TSV, w/ lotsa extra separator characters, we can simply send 2 bytes only using Serial.write():
    https://www.Arduino.cc/reference/en/language/functions/communication/serial/write/
  • We just need to create a char array of length = 2: signed char xy[2];
#define BAUDS 115200
#define DELAY 10
#define BYTES 2

#define MIN 0
#define MAX 1023
#define MIN_RANGE -10
#define MAX_RANGE 10

signed char xy[BYTES];

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

void loop() {
  xy[0] = map(analogRead(A1), MIN, MAX, MIN_RANGE, MAX_RANGE);
  xy[1] = map(analogRead(A0), MIN, MAX, MIN_RANGE, MAX_RANGE);

  Serial.write(xy);
  delay(DELAY);
}
/**
 * Serial readBytes() Line-Drawing (v1.0)
 * GoToLoop (2019/May/02)
 *
 * https://Discourse.Processing.org/t/
 * using-two-different-readstringuntil-characters/10769/23
 */

import processing.serial.Serial;

static final String PORT = "COM12";
static final float FPS = 100;
static final int BAUDS = 115200, INDEX = 1, BYTES = 2;
static final color STROKE = -1;

final byte[] xy = new byte[BYTES];
final PVector vec = new PVector(), mov = new PVector();

void setup() {
  size(1300, 700);
  noLoop();
  frameRate(FPS);

  stroke(STROKE);
  clear();

  vec.set(width>>1, height>>1);

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

  new Serial(this, PORT, BAUDS).buffer(BYTES);
  //new Serial(this, ports[INDEX], BAUDS).buffer(BYTES);
}

void draw() {
  line(vec.x, vec.y, vec.add(mov).x, vec.y);

  if (outtaBounds(vec)) {
    vec.set(width>>1, height>>1);
    System.err.println("Coords reset back to center of canvas!");
  }

  println(vec, mov);
}

boolean outtaBounds(final PVector v) {
  return v.x < 0 | v.x >= width | v.y < 0 | v.y >= height;
}

void serialEvent(final Serial s) {
  s.readBytes(xy);
  mov.set(xy[0], xy[1]);
  redraw = true;
}