~~Dissect~~ Parsing Commands

Hi! I am making a program that will move a specified motor in a specified direction and degrees. A command looks like this:
a:+20
That is supposed to move motor A 20 degrees. I think I can do the part where it moves the motor. The command could also be
b:-176
That would move motor B back 176 degrees. Does somebody know how I can get the integer and the +/-? I have done some research and can't find a good solution. Another command would be something like this:
a:+20,b:145,c:-20,d:+34,e:90,f:45, 1000
That would move 6 different motors in different directions. b:145 means to just move it to that degree and not increase or decrease it. The "1000" at the end means to wait 1000 milliseconds.

Can somebody give me a script that would work? I don't know enough about Arduino to just go off random terminology. I am currently taking a class and having massive issues, which is why I want some way to accomplish that. I cannot change the commands.

(Don't think "dissect", think "parse")

Take a look at the Serial Input Basics tutorial, which gives an overview of parsing serial data.

There are a host of simple functions in the C/C++ <string.h> library that allow all sorts of manipulations.

I would suggest to study Serial Input Basics to handle getting the command line

then try something like this to extract and parse each token

char command[] = "a:+20,b:145,c:-20,d:+34,e:90,f:45, 1000";


bool parseCommand(char * c) {
  Serial.print("Parsing ["); Serial.print(c); Serial.println("]");

  char * commaPtr = strtok(c, ",");
  while (commaPtr != nullptr) {
    Serial.print("\tToken ["); Serial.print(commaPtr); Serial.print("] -> ");
    char * colonPtr = strchr(commaPtr, ':');
    if (colonPtr != nullptr) { // we have a label
      *colonPtr = '\0';
      Serial.print("Label is '"); Serial.print(commaPtr);
      long v = strtol(colonPtr + 1, nullptr, 10); // no fancy error detection but could be done
      Serial.print("' and value is "); Serial.println(v);
    } else { // we don't have a label, it's a duration
      long d = strtol(commaPtr, nullptr, 10); // no fancy error detection but could be done
      Serial.print("duration is "); Serial.print(d);
    }
    commaPtr = strtok(nullptr, ","); // go to next token
  }
}

void setup() {
  Serial.begin(115200);
  parseCommand(command); // this function call will modify the command
}

void loop() {}

you'll see

Parsing [a:+20,b:145,c:-20,d:+34,e:90,f:45, 1000]
	Token [a:+20] -> Label is 'a' and value is 20
	Token [b:145] -> Label is 'b' and value is 145
	Token [c:-20] -> Label is 'c' and value is -20
	Token [d:+34] -> Label is 'd' and value is 34
	Token [e:90]  -> Label is 'e' and value is 90
	Token [f:45]  -> Label is 'f' and value is 45
	Token [ 1000] -> duration is 1000

the strtol() function does the heavy lifting of parsing your value and takes care of the + or - and leading spaces as well

look this over

processCmd
  0:      0 a:+20
  1:      0 b:145
  2:      0 c:-20
  3:      0 d:+34
  4:      0 e:90
  5:      0 f:45
  6:   1000  1000

vars:
  0: a     20
  1: b    145
  2: c    -20
  3: d     34
  4: e     90
  5: f     45
  6: g      0
  7: h      0
  8: i      0
  9: j      0
 wait   1000
a:123,b:456,777
processCmd
  0:      0 a:123
  1:      0 b:456
  2:    777 777

vars:
  0: a    123
  1: b    456
  2: c    -20
  3: d     34
  4: e     90
  5: f     45
  6: g      0
  7: h      0
  8: i      0
  9: j      0
 wait    777

const int Nvars = 10;
int  vars [Nvars];
int  wait;

char command[] = "a:+20,b:145,c:-20,d:+34,e:90,f:45, 1000";

char s [80];

// -----------------------------------------------------------------------------
#define MAX_TOKS   10
static int    _nToks;
static char * _toks [MAX_TOKS];
static int    _vals [MAX_TOKS];

int
_tokenize (
    char *s,
    const char *sep )
{
    int n = 0;
    for (_toks [n] = strtok (s, sep); _toks [n]; ) {
        _vals [n] = atoi (_toks [n]);
     // printf ("   %2d: %6d %s\n", n, _vals [n], _toks [n]);
        _toks [++n] = strtok (NULL, sep);
    }

    return _nToks = n;
}

// -----------------------------------------------------------------------------
void
processCmd (
    const char *cmd )
{
    char buf [90];

    if (strlen (cmd) > sizeof(buf)-1)  {
        sprintf (s, "%s: cmd > %d", __func__, sizeof(buf)-1);
        Serial.println (s);
        return;
    }

    Serial.println (__func__);

    strcpy (buf, cmd);
    _tokenize (buf, ",");
    for (int n = 0; n < _nToks; n++)  {
        sprintf (s, " %2d: %6d %s", n, _vals [n], _toks [n]);
        Serial.println (s);

        if (strstr (_toks [n], ":"))  {
            char c;
            int  val;
            sscanf (_toks [n], "%c:%d", &c, &val);
            int  i = c - 'a';
            if (Nvars > i)
                vars [i] = val;
        }
        else if (n == (_nToks -1))
            wait = _vals [n];
    }

    Serial.println ("\nvars:");
    for (int n = 0; n < Nvars; n++)  {
        sprintf (s, " %2d: %c %6d", n, 'a' + n, vars [n]);
        Serial.println (s);
    }
    sprintf (s, " wait %6d", wait);
    Serial.println (s);
}

// -----------------------------------------------------------------------------
void
setup (void)
{
    Serial.begin (9600);
    processCmd (command);
}

void loop (void)
{
    if (Serial.available ())  {
        char buf [80];
        int  n = Serial.readBytesUntil ('\n', buf, sizeof(buf)-1);
        buf [n] = '\0';

        Serial.println (buf);
        processCmd (buf);
    }
}

Thank You! That's pretty much exactly what I needed. Didn't expect such a quick response though.

Glad if it helps, make sure you understand what’ it does.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.