How do I repeatedly take multiple sequential serial inputs

I am setting up a two motor stepper control program using an Arduino Mega 2560, and am using USB serial connection from a Raspberry Pi. When I run my code, I would like it so that there are two sequential inputs, to begin with a multiplier for revolution of the stepper motors and then a command to move a specific way. These inputs can then be used multiple times to allow for different revolution multipliers and commands.

I currently have code to take the input for the multiplier with start and end markers, e.g <7.4>, and then the move command, e.g 1. This should then loop once the commands have been executed and take the multiplier and commands again.

An example input would be <7.4> and then 1. This should update y and x to be what you have entered (in x’s case without the <>).

float steps;
int x;
const byte numChars = 32;
char recievedChars[numChars];
boolean newData = false;

void setup() {
  Serial.begin(9600);
  if(Serial.available() > 0){
    Serial.read();
  }
}

void loop() {
  recvWithStartEndMarkers();
  if(Serial.available() > 0) {
    x = Serial.read() - '0';
    Serial.println(x);
    float y = atof(recievedChars);
    steps = stepsPerRevolution * y;
    Serial.println(steps);
    // choice(); // This leads to the commands that run the steppers.
  }
}

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) {
        recievedChars[ndx] = rc;
        ndx++;
        if (ndx >= numChars) {
          ndx = numChars -1;
        }
      }
      else {
        recievedChars[ndx] = '\0';
        recvInProgress = false;
        ndx = 0;
        newData = true;
      }
    }
    else if (rc == startMarker) {
      recvInProgress = true;
    }
  } 
}

This is the minimal code for what I am trying to do, and doesn’t include actual motor control just serial inputs.

From this, it is expected that I would be able to input a multiplier, and then a command, however when running I cannot input a second multiplier after both the command even when I format it as ‘<‘x’>’ (would not let me use the symbols so the ’ are not normally there) the program just seems to read x as a the command not a multiplier.

As well as this, occasionally upon running the program will not take any inputs until three or 4 numbers have been entered, or will take the multiplier as the multiplier and the command (so an input of <3.4> would take the three as the multiplier, and 4 as the command).

What can i do to make this serial reading more reliable so that it works every time, and more repeatable so that I can use it more than once per upload to the Mega?

Thanks!

What’s this supposed to do in setup() if(Serial.available() > 0){
Serial.read();
}?

void fReceiveSerial_LIDAR( void * parameters )
{
bool BeginSentence = false;
char OneChar;
char *str;
str = (char *)ps_calloc(300, sizeof(char) ); //use PSRAM for the str buffer
// log_i(“Free PSRAM: %d”, ESP.getFreePsram());
for ( ;; )
{
EventBits_t xbit = xEventGroupWaitBits (eg, evtReceiveSerial_LIDAR, pdTRUE, pdTRUE, portMAX_DELAY);
if ( LIDARSerial.available() >= 1 )
{
while ( LIDARSerial.available() )
{
OneChar = LIDARSerial.read();
if ( BeginSentence )
{
if ( OneChar == ‘>’)
{
if ( xSemaphoreTake( sema_ParseLIDAR_ReceivedSerial, xSemaphoreTicksToWait10 ) == pdTRUE )
{
xQueueOverwrite( xQ_LIDAR_Display_INFO, ( void * ) &str );
xEventGroupSetBits( eg, evtParseLIDAR_ReceivedSerial );
//
}
BeginSentence = false;
break;
}
strncat( str, &OneChar, 1 );
}
else
{
if ( OneChar == ‘<’ )
{
strcpy( str, “”); // clear string buffer
BeginSentence = true; // found beginning of sentence
}
}
} // while ( LIDARSerial.available() )
} //if ( LIDARSerial.available() >= 1 )
xSemaphoreGive( sema_ReceiveSerial_LIDAR );
// Serial.print( "fReceiveSerial_LIDAR " );
// Serial.print(uxTaskGetStackHighWaterMark( NULL ));
// Serial.println();
// Serial.flush();
}
free(str);
vTaskDelete( NULL );
} //void fParseSerial( void * parameters )

Here is some code that I use on an ESP32, the principle is the same I’d use with an Uno.

I think you make life difficult by using different approaches for the reading.

I would suggest to send <7.4,1>. Robin’s examples demonstrate parsing.

Alternatively send something like <m=7.4> (where m indicates multiplier) followed by e.g.<s=1> (where s indicates start); feel free to choose different letters.

If you want to do it the way you intend (and probably with the above alternative), you will need a state machine to keep track of what you have received.

The code I posted does keep track of the received info. The start of receiving is done by the
if ( OneChar == ‘<’ )
{
strcpy( str, “”); // clear string buffer
BeginSentence = true; // found beginning of sentence
}
If the complete message was not received during a pass of this task the data received up to the point of the task going out of focus will be kept until if ( OneChar == ‘<’ )
{
strcpy( str, “”); // clear string buffer
BeginSentence = true; // found beginning of sentence
}
or a new ‘<’ is received.