I think this will do what you want the SafeStringReader from using my SafeString library
//https://forum.arduino.cc/t/sending-code-to-stepper-motors/887236
// Bluetooth
// download and install the SafeString library from
// www.forward.com.au/pfod/ArduinoProgramming/SafeString/index.html
#include "SafeString.h"
#include "SafeStringStream.h"
#include "SafeStringReader.h"
#include <SoftwareSerial.h>
SoftwareSerial mySerial(2, 3);
#define TEST_DATA
#ifdef TEST_DATA
// P-xx.xx\Yxx.xx\R-xx.xx\P-xx.xx\Yxx.xx\R-xx.xx...
// e.g. P-101.33\Y33.55\R-34.55
const char testData[] = "P-101.33\\Y33.55\\R-34.55\\P-201.33\\Y133.55\\R-234.55\\P-1.33\\Y-3.55\\R-4.55\\P21.33\\Y53.55\\R4.55\\";
// note the delimiting \ at the end
createSafeString(sfTestData, 100); // test data in a safeString
cSF(sfRxBuffer,64); // create a SafeString to use for an Rx buffer for sfStream, default rx buffer is only 8 bytes
SafeStringStream sfStream(sfTestData,sfRxBuffer); // set a 64byte RX buffer
#define dataSerial sfStream
#else
#define dataSerial mySerial
#endif
// create an sfReader instance of SafeStringReader class
// that will handle commands upto 11 chars long
// delimited by \ or CarrageReturn or NewLine
// the createSafeStringReader( ) macro creates both the SafeStringReader (sfReader) and the necessary SafeString that holds input chars until a delimiter is found
// args are (ReaderInstanceName, expectedMaxCmdLength, delimiters)
createSafeStringReader(sfReader, 12, "\\\r\n"); // allow for 11 char + delimiter
float phoneYaw, phonePitch, phoneRoll;
float currentPYR [3], DCM [3][3], EulerPYR [3], rotPYR [3], stepPYR [3];
void setup() {
// put your setup code here, to run once:
Serial.begin(115200); // make this fast
for (int i = 10; i > 0; i--) { // pause a little to give you time to open the Arduino monitor
Serial.print(i); Serial.print(' '); delay(500);
}
Serial.println();
SafeString::setOutput(Serial); // enable error messages and SafeString.debug() output to be sent to Serial
#ifdef TEST_DATA
sfTestData = testData;
sfReader.echoOn(); // echo back all input, by default echo is off
#endif
dataSerial.begin(9600);
sfReader.connect(dataSerial); // where SafeStringReader will read from
//sfReader.flushInput(); // use this to skip any partial data upto the first delimiter (or timeout)
}
void loop() {
if (sfReader.read()) {
// pick up the number
cSF(token, 12);
sfReader.substring(token, 1); // get the data after the P,Y,R
float num = 0.0;
if (!token.toFloat(num)) {
Serial.print(F("Invalid data - ")); Serial.println(sfReader);
} else {
// have a valid number
if (sfReader.startsWith('P')) {
phonePitch = num;
Serial.print(F("Pitch:")); Serial.println(phonePitch);
} else if (sfReader.startsWith('Y')) {
phoneYaw = num;
Serial.print(F(" Yaw:")); Serial.println(phoneYaw);
} else if (sfReader.startsWith('R')) {
phoneRoll = num;
Serial.print(F(" Roll:")); Serial.println(phoneRoll);
} else {
Serial.print(F("Unrecognized data - ")); Serial.println(sfReader);
}
}
}
// if have all three values then...
// EulerYPR_to_DCM(phoneYaw, phonePitch, phoneRoll, DCM);
// DCM_to_EulerPYR(DCM, EulerPYR);
// for (int i = 0; i < 3; i++) {
// rotPYR[i] = EulerPYR[i] - currentPYR[i];
// stepPYR[i] = rotPYR[i] / 1.8;
// currentPYR[i] = stepPYR[i] * 1.8;
// }
}
void EulerYPR_to_DCM(float phoneYaw, float phonePitch, float phoneRoll, float DCM [3][3]) {
float phoneRoll_rad = phoneRoll * PI / 180;
float phonePitch_rad = phonePitch * PI / 180;
float phoneYaw_rad = phoneYaw * PI / 180;
DCM[1][1] = cos(phonePitch_rad) * cos(phoneYaw_rad);
DCM[2][1] = cos(phonePitch_rad) * sin(phoneYaw_rad);
DCM[3][1] = -sin(phonePitch_rad);
DCM[1][2] = -cos(phoneRoll_rad) * sin(phoneYaw_rad) + sin(phoneRoll_rad) * sin(phonePitch_rad) * cos(phoneYaw_rad);
DCM[2][2] = cos(phoneRoll_rad) * cos(phoneYaw_rad) + sin(phoneRoll_rad) * sin(phonePitch_rad) * sin(phoneYaw_rad);
DCM[3][2] = sin(phoneRoll_rad) * cos(phonePitch_rad);
DCM[1][3] = sin(phoneRoll_rad) * sin(phoneYaw_rad) + cos(phoneRoll_rad) * sin(phonePitch_rad) * cos(phoneYaw_rad);
DCM[2][3] = -sin(phoneRoll_rad) * cos(phoneYaw_rad) + cos(phoneRoll_rad) * sin(phonePitch_rad) * sin(phoneYaw_rad);
DCM[3][3] = cos(phoneRoll_rad) * cos(phonePitch_rad);
}
void DCM_to_EulerPYR(float DCM[3][3], float EulerPYR [3]) {
float Pitch, Yaw, Roll;
if (DCM[2][1] < -0.99987) {
Yaw = -90;
Roll = 0;
Pitch = (atan2(DCM[1][3], DCM[3][3])) * 180 / PI;
}
else if (DCM[2][1] > 0.99987) {
Yaw = 90;
Roll = 0;
Pitch = (atan2(DCM[1][3], DCM[3][3])) * 180 / PI;
}
else {
Pitch = (atan2(-DCM[3][1], DCM[1][1])) * 180 / PI;
Yaw = (asin(DCM[2][1])) * 180 / PI;
Roll = (atan2(-DCM[2][3], DCM[2][2])) * 180 / PI;
}
EulerPYR[0] = Pitch;
EulerPYR[1] = Yaw;
EulerPYR[2] = Roll;
}
The output from the test data is
Pitch:-101.33
Yaw:33.55
Roll:-34.55
Pitch:-201.33
Yaw:133.55
Roll:-234.55
Pitch:-1.33
Yaw:-3.55
Roll:-4.55
Pitch:21.33
Yaw:53.55
Roll:4.55
Pitch:-101.33
Yaw:33.55
Roll:-34.55
Pitch:-201.33
Yaw:133.55
Roll:-234.55
Pitch:-1.33
Yaw:-3.55
Roll:-4.55
Pitch:21.33
Yaw:53.55
Roll:4.55
\\... for ever
Some important points to note
i) SafeStringReader tokenizes on one of the specified delimiters SO.. the last entry must be followed by a delimiter. Alternatively you can specify a timeout to return the last un-delimited entry
ii) SafeStringReader has a flushInput() method to clear the input until a delimiter is read or it timesout.
Not sure is you need the triples as a group, if so then need to sync to the next 'P' entry after flushing.
Edit -- with SafeStringReader.echoOn() the data read is put back on the input to be read again so the data goes on for ever.
For real data input comment out
#define TEST_DATA
Edit -- added 64 byte buffer to sfStream and increased Serial to 115200, otherwise error msgs cause input to be skipped due to rx buffer being full.
See Arduino Serial I/O for the Real World for how to add a non-blocking serial print to avoid this problem.