Need assistance reading sequential inputs from Arduino serial

EDIT: Got it sorted, thanks everyone.

My arduino program and device appears to be working correctly, sending the appropriate info out to serial. From reading through the console prints in processing, it is reading the inputs into strings correctly. I’m just hitting a wall in terms of figuring out how to do different things with the sequential inputs.

The arduino device uses a 4x4 keypad to perform various unit conversions, triggered by the A/B/C/D keys. It sends over the letter of the key pressed, followed by the numbers entered into, and returned by the function. The D key toggles between Imperial to Metric, and Metric to Imperial, and outputs a boolean state status.

All the variables are Strings, since I’m using the info from serial for text displays and they don’t have to be used for any calculations within processing.

Copied below is a section of the serial.read code. Inputs from arduino are in the format of:

  • D 1 or D 0 ( letter D followed by the boolean state of conversion direction)
  • A # # (the letter A, B, or C followed by 2 separate numbers, the entered value to convert, and the resulting converted value)

How should I go about changing things to be able to accept those 2 or 3 inputs into separate, useable items, and then acting off of them?

while (myPort.available() > 0)
  {
    // set myPort.read() to a readable variable
    //    using read string until to collect the entirety of the arduino input.
    inPort = myPort.readStringUntil(10);
    // what do i do to get it to operate on following inputs?
    //    a trigger when it hits the newline command?
    
    // printing for troubleshooting
    println(inPort);
    
    // trigger actions based on input from arduino
    if(inPort == "D")
    {
      String dPort = inPort;
      // set variable to display selected conversion mode
      if(dPort == "1")
      {
        conDis = "I->M";
      }
      else if(dPort == "0")
      {
        conDis = "M->I";
      }
    }
    // differences in the A/B/C inputs is really only the trigger of the units
    else if(inPort == "A")
    {
      // really need to figure out how to get these to read properly
      inSum = myPort.readStringUntil(10);
      inVal = myPort.readStringUntil(10);
      // printing to console for debugging
      println("inSum");
      println(inSum);
      println("inVal");
      println(inVal);    
      // set unitString to A units, based on current conversion path
      if(conDis == "I->M")
      {
        unitString = "Meters";
      }
      else if(conDis =="M->I")
      {
        unitString = "Feet";
      }
    }

Was suggested to look into Serial Event as a possibility, but I am not understanding the formatting and syntax for how that works.
https://processing.org/reference/libraries/serial/serialEvent_.html

void serialEvent(Serial whichPort) {
  statements
}

that is the given general format, but the example code looks like

void serialEvent(Serial p) { 
  inString = p.readString(); 
} 

is the choice of “whichPort” just whatever you arbitrarily want it to be, or do you have to use something like your actual myPort variable declaration?

Ok, so I played around with it, and that does seem to be whatever. Arduino site talks about using it for when you have multiple serial inputs, so I’m assuming it’s similar here? Since I only have one serial input, it’s an arbitrary choice.
Still leaves me with figuring out how to sort the inputs, which is essentially square 1.

1 Like

I see that you are assigning dPort to inPort then comparing to “1” and “0”.
The trouble is that the variable inPort must have been equal to “D” just before that.

If your first message is coming in as “D 0\n” (has a space) then you can split the string “inPort” into parts using

String[] parts = inPort.split(" ");

then parts[0] is “D” and parts[1] is “0”.
Use those to do comparisons but, since strings are objects, use the .equals() method.

2 Likes

the .equals() method definitely gives me a big step needed, because I couldn’t figure out how to get it to recognize specific inputs.

It is currently sending everything as separate lines, like:
D\n
0\n

@noahbuddy
I’m currently using the following processing code:

import processing.serial.*;
Serial myPort;
String inPort;
String aVal1;
String aVal2;
String aVar = "A";
float aValArray[] = {0.0, 0.0};;

// reference strings for triggers
String aString = "A";
String bString = "B";
String cString = "C";
String dString = "D";

String testString;

void setup()
{
  // List all the available serial ports:
  printArray(Serial.list());
  myPort = new Serial(this, Serial.list()[0], 9600);
    myPort.clear();
  // Throw out the first reading, in case we started reading
  // in the middle of a string from the sender.
  //inPort = myPort.readStringUntil('\n');
  //inPort = null;
   size(50,50);
}
  void draw(){
    background(#FFFFFF);
  }
  void serialEvent(Serial p) {
  inPort = p.readStringUntil('\n');
  testString = inPort;
  if(inPort != null) //this check is the key to making code in draw work
  {
    println(trim(inPort));  
    if(testString.equals(aString) == true)
    {
      println("A WORKED");
    }
    else if(inPort.equals(bString) == true)
    {
      println("B WORKED");
    }
    else if(inPort.equals(cString) == true)
    {
      println("C WORKED");
    }
    else if(inPort.equals(dString) == true)
    {
      println("D WORKED");
    }
    else
    {
      println("NOPE");
    }
  }
}

and the following arduino code:

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);

}

void loop() {
  // put your main code here, to run repeatedly:
  Serial.println('A');
  delay(100);
  // Serial.println(random(1000, 7001)/100.0);
  Serial.println(10.0);
  delay(100);
  Serial.println(11.0);
  delay(100);
  Serial.println('B');
  delay(100);
  //Serial.println(random(1000, 7001)/100.0);
  Serial.println(20.0);
  delay(100);
  Serial.println(21.0);
  delay(10);
  Serial.println('C');
  delay(10);
  //Serial.println(random(1000, 7001)/100.0);
  Serial.println(30.0);
  delay(100);
  Serial.println(31.0);
  delay(10);
  Serial.println('D');
  delay(10);
  //Serial.println(random(1000, 7001)/100.0);
  Serial.println(40.0);
  delay(100);
  Serial.println(41.0);
  delay(10);
}

For testing and troubleshooting, and am unable to get it to recognize the specific inputs.

1 Like

Try comparing against trim(inPort). The string may still include “\n”. (my memory is a little fuzzy and I do not have an Arduino set up at the moment)

1 Like

Hello,

I am assisting with your existing code and troubleshooting efforts.
Once you get that working take the next step.

Your code with comments added:

void serialEvent(Serial p) {
  inPort = p.readStringUntil('\n');
  testString = inPort;
  if(inPort != null) //this check is the key to making code in draw work
  {
    println(trim(inPort));  
    if(testString.equals(aString) == true)  // glv You are comparing with testString and no trim()
    {
      println("A WORKED");
    }
    else if(inPort.equals(bString) == true) // glv You are comparing with inPort and no trim()

Give careful consideration to the variables used and the order that you are doing things.
My edit of your code:

void serialEvent(Serial p) 
  {
  inPort = p.readStringUntil('\n');
  if(inPort != null) //this check is the key to making code in draw work
    {
    testString = inPort.trim();
    print(testString);  
    if(testString.equals(aString) == true)
      {
      println(" A WORKED");
      }
    else if(testString.equals(bString) == true)

Outout:

:)

1 Like

@glv
Thank you so much, that works!

Now to figure out how to take following values and save them to other strings for use elsewhere.

Record of current attempts:

  • Using delay(#) to try and time things - Still trying, still failing
  • Tried just having the if loop directly save next values - Failed
  • Tried using a for loop to save next values - Failed
  • Try having if loop call function to save values directly - Failed
  • Try having called function save values into array - in progress
1 Like

Once I got the .equals() going, the split finally worked. Thanks. Will update once i’ve gone through and updated everything.

@noahbuddy
@glv

Got it sorted out, thanks for your help. Functional code below:

void serialEvent(Serial p)
{
  // capture serial info
  inPort = p.readStringUntil('\n');
  // clean out null values that break draw code
  if(inPort != null)
  {
    // remove unnecessary info from received data 
    inString = inPort.trim();
  
    // print for debugging
    //    most print commands within loops below removed for clarity
    println("INPORT");
    println(trim(inPort));
  
    // parse input in testString
    String[] parts = inPort.split(" ");
    //  parts[0] will be A/B/C/D keypress reference
    //  parts[1] will be entered value to be converted
    //  parts[2] will be resulting converted value
    
    //    D uses parts[1] for storing boolean state
    //      parts[2] duplicates parts[1] for D for consistency of info parsing
    
    // printing for debugging
    //println("INSTRING");
    //println(inString);
    //println("PARTS");
    //println(parts[0]);
    //println(parts[1]);
    //println(parts[2]);
  
    // react to and sort data into reference variables
    if(parts[0].equals(aString) == true)
    {
      // parse values out of string
      //    identical syntax and function for A, B, and C
      aVal1 = parts[1];
      aVal2 = parts[2];
      // set aUnits display to current conversion direction
      aUnits = conDis;
    }
    else if(parts[0].equals(bString) == true)
    {
      bVal1 = parts[1];
      bVal2 = parts[2];
      bUnits = conDis;
    }
    else if(parts[0].equals(cString) == true)
    {
      cVal1 = parts[1];
      cVal2 = parts[2];
      cUnits = conDis;
    }
    else if(parts[0].equals(dString) == true)
    {
      dVal1 = parts[1];
      
      //set conDis based on resulting dVal1 state
      if(dVal1.equals(dRef0) == true)
      {
        conDis = "M->I";
        //println("CONDIS M I");
      }
      else if(dVal1.equals(dRef1) == true)
      {
        conDis = "I->M";
        //println("CONDIS I M");
      }
    }
    else
    {
      // print for debugging
      //println("NOPE");
      // otherwise do nothing
    }
  }
}
2 Likes