Assistance with parsing data

Hi Community,

I am transferring data from a Jetson Nano via pyserial to arduino. I can transfer the data no problem but having trouble parsing the data for motor control.

The data seems to be in a Char format but need it to be a string. I am sure this is a simple issue but it just cant seem to crack it. The data structure looks like this ('a',200). I can split the char and the integer and print them out in the serial monitor but cant seem to transfer the data to match the drive command. It has to do with the data type.

I would appreciate your assistance.

I want the data in the code below from 'messageFromPC' , which is a char like 'a' for example to connect in with the "if (Direction =="a"). The full version of the code is below this section.

void showParsedData() {
//    Serial.print("Message ");
//    Serial.println(messageFromPC);
//    Serial.print("Integer ");
//    Serial.println(integerFromPC);

}

    String Direction = messageFromPC; {
    Serial.print(Direction); 

    if (Direction == "a") {
       ADVANCE();
    }
    else if (Direction == "z") {
       STOP();
    }
    else if (Direction == "b") {
       RIGHT_1();
    }
    else if (Direction == "c") {
       RIGHT_2();
    }

This is the full code below:

//Motor Pins
#define PWMA 12    //Motor A Speed
#define DIRA1 34
#define DIRA2 35  //Motor A Direction
#define PWMB 8    //Motor B Speed
#define DIRB1 37
#define DIRB2 36  //Motor B Direction
#define PWMC 9   //Motor C Speed
#define DIRC1 43
#define DIRC2 42  //Motor C Direction
#define PWMD 5    //Motor D Speed
#define DIRD1 26
#define DIRD2 27  //Motor A Direction


int error = 0;
byte type = 0;
byte vibrate = 0;
String incomingByte;
String Direction;
int pwmint = 0;



// variables to hold the parsed data
const byte numChars = 11;
char receivedChars[numChars];
char tempChars[numChars];        // temporary array for use when parsing

      // variables to hold the parsed data
char messageFromPC[numChars] = {0};
int integerFromPC = 0;


boolean newData = false;
// Sets the character types for markers


void (* resetFunc) (void) = 0;

//Motor A
#define MOTORA_FORWARD(pwm)    do{digitalWrite(DIRA1,LOW); digitalWrite(DIRA2,HIGH);analogWrite(PWMA,pwm);}while(0)
#define MOTORA_STOP(x)         do{digitalWrite(DIRA1,LOW); digitalWrite(DIRA2,LOW); analogWrite(PWMA,0);}while(0)
#define MOTORA_BACKOFF(pwm)    do{digitalWrite(DIRA1,HIGH);digitalWrite(DIRA2,LOW); analogWrite(PWMA,pwm);}while(0)

//Motor B
#define MOTORB_FORWARD(pwm)    do{digitalWrite(DIRB1,HIGH); digitalWrite(DIRB2,LOW);analogWrite(PWMB,pwm);}while(0)
#define MOTORB_STOP(x)         do{digitalWrite(DIRB1,LOW); digitalWrite(DIRB2,LOW); analogWrite(PWMB,0);}while(0)
#define MOTORB_BACKOFF(pwm)    do{digitalWrite(DIRB1,LOW);digitalWrite(DIRB2,HIGH); analogWrite(PWMB,pwm);}while(0)

#define MAX_PWM   200
#define MIN_PWM   130
int Motor_PWM = 130;

//Controlling Motor Motion Macro Definition


//    ↑A-----B↑
//     |  ↑  |
//     |  |  |
//    ↑C-----D↑
void ADVANCE()
{
  MOTORA_FORWARD(Motor_PWM); MOTORB_FORWARD(Motor_PWM);
  MOTORC_FORWARD(Motor_PWM); MOTORD_FORWARD(Motor_PWM);
}

//    ↓A-----B↓
//     |  |  |
//     |  ↓  |
//    ↓C-----D↓
void BACK()
{
  MOTORA_BACKOFF(Motor_PWM); MOTORB_BACKOFF(Motor_PWM);
  MOTORC_BACKOFF(Motor_PWM); MOTORD_BACKOFF(Motor_PWM);
}
//    ↑A-----B=
//     |   ↖ |
//     | ↖   |
//    =C-----D↑
void LEFT_1()
{
  MOTORA_FORWARD(Motor_PWM); MOTORB_STOP(Motor_PWM);
  MOTORC_STOP(Motor_PWM); MOTORD_FORWARD(Motor_PWM);
}

//    ↓A-----B↑
//     |  ←  |
//     |  ←  |
//    ↑C-----D↓
void LEFT_2()
{
  MOTORA_BACKOFF(Motor_PWM); MOTORB_FORWARD(Motor_PWM);
  MOTORC_FORWARD(Motor_PWM); MOTORD_BACKOFF(Motor_PWM);
}
//    ↓A-----B=
//     | ↙   |
//     |   ↙ |
//    =C-----D↓
void LEFT_3()
{
  MOTORA_BACKOFF(Motor_PWM); MOTORB_STOP(Motor_PWM);
  MOTORC_STOP(Motor_PWM); MOTORD_BACKOFF(Motor_PWM);
}
//    ↓A-----B↑
//     |  ←  |
//     | ↓  ↑ |
//     |  →  |
//    ↓C-----D↑
void LEFT_4()
{
  MOTORA_BACKOFF(Motor_PWM); MOTORB_FORWARD(Motor_PWM);
  MOTORC_BACKOFF(Motor_PWM); MOTORD_FORWARD(Motor_PWM);
}
//    =A-----B↑
//     | ↗   |
//     |   ↗ |
//    ↑C-----D=
void RIGHT_1()
{
  MOTORA_STOP(Motor_PWM); MOTORB_FORWARD(Motor_PWM);
  MOTORC_FORWARD(Motor_PWM); MOTORD_STOP(Motor_PWM);
}
//    ↑A-----B↓
//     |  →  |
//     |  →  |
//    ↓C-----D↑
void RIGHT_2()
{
  MOTORA_FORWARD(Motor_PWM); MOTORB_BACKOFF(Motor_PWM);
  MOTORC_BACKOFF(Motor_PWM); MOTORD_FORWARD(Motor_PWM);
}
//    =A-----B↓
//     |   ↘ |
//     | ↘   |
//    ↓C-----D=
void RIGHT_3()
{
  MOTORA_STOP(Motor_PWM); MOTORB_BACKOFF(Motor_PWM);
  MOTORC_BACKOFF(Motor_PWM); MOTORD_STOP(Motor_PWM);
}
//    ↑A-----B↓
//     |  →  |
//     | ↑  ↓ |
//     |  ←  |
//    ↑C-----D↓
void RIGHT_4()
{
  MOTORA_FORWARD(Motor_PWM); MOTORB_BACKOFF(Motor_PWM);
  MOTORC_FORWARD(Motor_PWM); MOTORD_BACKOFF(Motor_PWM);
}
//    =A-----B=
//     |  =  |
//     |  =  |
//    =C-----D=
void STOP()
{
  MOTORA_STOP(Motor_PWM); MOTORB_STOP(Motor_PWM);
  MOTORC_STOP(Motor_PWM); MOTORD_STOP(Motor_PWM);
}

void IO_init()
{
  pinMode(PWMA, OUTPUT);
  pinMode(DIRA1, OUTPUT);
  pinMode(DIRA2, OUTPUT);
  pinMode(PWMB, OUTPUT);
  pinMode(DIRB1, OUTPUT);
  pinMode(DIRB2, OUTPUT);

  STOP();
}

//===========================

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


  Serial.println("<Arduino is ready>");

  IO_init();
}


//==========================
// Receiving data from Python

//============

void loop() {
    recvWithStartEndMarkers();
    if (newData == true) {
        strcpy(tempChars, receivedChars);
            // this temporary copy is necessary to protect the original data
            //   because strtok() used in parseData() replaces the commas with \0
        parseData();
        showParsedData();
        newData = false;
    }
}

//============

void recvWithStartEndMarkers() {
    static boolean recvInProgress = false;
    static byte ndx = 0;
    char startMarker = '<';
    char endMarker = '>';
    char rc;

    while (Serial.available() > 0 && newData == false) {
        rc = Serial.read();

        if (recvInProgress == true) {
            if (rc != endMarker) {
                receivedChars[ndx] = rc;
                ndx++;
                if (ndx >= numChars) {
                    ndx = numChars - 1;
                }
            }
            else {
                receivedChars[ndx] = '\0'; // terminate the string
                recvInProgress = false;
                ndx = 0;
                newData = true;
            }
        }

        else if (rc == startMarker) {
            recvInProgress = true;
        }
    }
}

//============

void parseData() {      // split the data into its parts

    char * strtokIndx; // this is used by strtok() as an index

    strtokIndx = strtok(tempChars,",");      // get the first part - the string
    strcpy(messageFromPC, strtokIndx); // copy it to messageFromPC
 
    strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
    integerFromPC = atoi(strtokIndx);     // convert this part to an integer

}

//============

void showParsedData() {
//    Serial.print("Message ");
//    Serial.println(messageFromPC);
//    Serial.print("Integer ");
//    Serial.println(integerFromPC);

}

    String Direction = messageFromPC; {
    Serial.print(Direction); 

    if (Direction == "a") {
       ADVANCE();
    }
    else if (Direction == "z") {
       STOP();
    }
    else if (Direction == "b") {
       RIGHT_1();
    }
    else if (Direction == "c") {
       RIGHT_2();
    }
    else if (Direction == "d") {
       RIGHT_3();
    }
    else if (Direction == "e") {
       BACK();
    }
    else if (Direction == "f") {
       LEFT_3();
    }
    else if (Direction == "g") {
       LEFT_2();
    }
    else if (Direction == "h") {
       LEFT_1();
    }
    else if (Direction == "i") {
       RIGHT_4();
    

}
    else if (Direction == "j") {
       LEFT_4();
    }
    
    else {
       Serial.write("invalid");
    }
  }
//============================

I really appreciate your assistance.

Can you please clarify the exact format of the data being received ?

When you say it is ('a',200) are the brackets and single quotes part of the message ?

Take a look at Serial input basics - updated for ideas

presumably you understand that a character is a byte containing an ASCII encoded value and that an array of characters with a null (0) as the last character is a string which can be compared to other string using strcmp()

a "String" data type is a struct. to access its value as an array of characters you need to use the c_str() method.

regardless of approach, comparing a string (lower case) to a string constant (e.g. "a") isn't done using "==".

however, if the string is "a200", you can compare the first character of the string to a specific character :

if (s [0] == 'a')

anticipating your next question, you can convert the numeric string value to an integer using atoi() and locating the numeric portion of the string - int val = atoi(& s[1]);

a "String" data type is a struct

A "String" data type is a class.
It's a subtle difference, but important.

@UKHeliBob,

The data being sent from python looks like this in the output including the brackets:

('e', 210)

I actually don't know why it comes out like that because all i wanted is a,210. In the process of adding end markers, it attached the brackets and comma.

@gcjr thank you for your info, i will explore your comments. I had the code working with a PS2 controller connected into the arduino via uart to drive it. No connected computer. i want to remove that function and control the vehicle by a Jetson Nano commanding the arduino. Once i have this step sorted it should pave the way for automation control.

I really appreciate your comments.

ardunio serial monitor output.png

Data from PC.png

If that's what your strings look like, you can extract the data you want without String objects or strtok.

For direction, all you want is a single char and it's always in the same position:

char direction= receivedChars[2];

Getting the number is scarcely more taxing:

int num=atoi(&receivedChars[5]);

Personally, I believe it is wise to ALWAYS parse the whole thing, as validation. If you just assume you have valid data, and parse a piece of it, you may be accepting garbage. Parse and validate the whole message, and you'll know if you receive a corrupted or mal-formed message, and can then ignore it. With such a short, simple message, full parsing has near zero overhead...

Regards,
Ray L.

If you capture the characters in a String, then it would be fairly straight forward to extract the data you want. You probably could get your data using the indexOf() and substring() functions from the captured character String.

Late to the party, but you can easily communicate between Arduinos and Python with the libraries SerialTransfer.h and pySerialTransfer. They were developed to be compatible, non-blocking, robust, and efficient data transfer libraries. See the libraries' readme files for more info.

SerialTransfer.h is installable through the Arduino IDE's Libraries Manager and pySerialTransfer is pip-installable.

Example Python:

from time import sleep
from pySerialTransfer import pySerialTransfer as txfer

if __name__ == '__main__':
    try:
        link = txfer.SerialTransfer('COM13')
        
        link.open()
        sleep(2) # allow some time for the Arduino to completely reset
    
        link.txBuff[0] = 'h'
        link.txBuff[1] = 'i'
        link.txBuff[2] = '\n'
        
        link.send(3)
        
        while not link.available():
            if link.status < 0:
                print('ERROR: {}'.format(link.status))
            
        print('Response received:')
        
        response = ''
        for index in range(link.bytesRead):
            response += chr(link.rxBuff[index])
        
        print(response)
        link.close()
        
    except KeyboardInterrupt:
        link.close()

Example Arduino:

#include "SerialTransfer.h"

SerialTransfer myTransfer;

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

void loop()
{
  myTransfer.txBuff[0] = 'h';
  myTransfer.txBuff[1] = 'i';
  myTransfer.txBuff[2] = '\n';
  
  myTransfer.sendData(3);
  delay(100);

  if(myTransfer.available())
  {
    Serial.println("New Data");
    for(byte i = 0; i < myTransfer.bytesRead; i++)
      Serial.write(myTransfer.rxBuff[i]);
    Serial.println();
  }
  else if(myTransfer.status < 0)
  {
    Serial.print("ERROR: ");
    Serial.println(myTransfer.status);
  }
}