Servo Control Via Serial and Arrays

This post aims to answer 3 major questions I have:
**A)Can Serial.read() read an array printed into the Serial terminal? If not, how can I read and assign arrays from Serial? **(port, terminal, console?? I am unaware of the exact terminology)
B)Is a servo controller that uses arrays for servo positions a feasible idea?
Specifically{

  1. A python program on my PC prints an Array into Serial: Starg{time until target pos is reached, servo 1 target, servo 2, etc...}
  2. Arduino updates Array containing servo targets (Starg)
    Starg{120,90,80,120,30}
    Skey{null,45,47,49,51}
  3. Arduino writes each pwm to their corresponding servo pin according to parallel array. (Skey)
    time until target pos will be used when an additional function similar to that of the Sweep example is added
    }
    C) Is there a significantly easier way to control servos from a PC program through an Arduino?

The board I'm using while being powerful, wont be able to process or store the data that I am intending to compute using my pc; Facial tracking, speech recognition, and TTS an Arduino can do individually, but would find significant trouble doing all at once.
I also want to give direct command and/or use programs similar to Visual Show Automation for routines.

Also, if someone could point out some resources/forums for Python I would much appreciate.

Hardware: Elegoo 2560, Arduino motor driver shield, Adjustable power supply unit (7.5v preferred), 3 Airtronix servos (1990s era), 1 electric motor with gearbox)

Take a look into Arduino reference for how Serial.read() works.

A. Not directly. Serial read will get you a single character at a time - it's up to you to parse them and put them in your array.

B. Certainly

C. If all servos are independent, it might be easier to send their instructions over serial for each servo as needed, even if that data still ends up in the arrays you were planning to use.

Thanks, I'll look over the Serial.read example. It's almost exactly what im looking for.

Better yet, ready this tutorial Serial Input Basics - updated

Here is some code using Arduino Strings that does most of what you want.
Using start and end markers is an unnecessary complication.
Just send your data in CSV form terminated by ‘\n’ (or ‘\r’ ‘\n’). That makes it easier to check the number of fields are correct and to parse the results.
If you PC sends a partial line while the Arduino board is resetting, the field count will detect it and reject it.

If you want to use fixed size char instead of Strings, you can use my SafeString library that provides the same functionality as Arduino Strings but using fixed sized char's for storage.

Nothing wrong with using Arduino Strings. They are much easier to program with then low level c-string/char. It is extremely difficult to crash your Arduino board using Arduino Strings (or SafeStrings) see my tutorial on Taming Arduino Strings On the other hand it is trivial to crash Arduino using c-string methods and char.

Sample output. Here the ‘null’ is parsed as 0, which is probably OK for your purposes.

ServoControl.ino
Sample data lines (terminated by '\n', Arduino monitor NewLine ending)
Starg,120,90,80,120,30
Skey,null,45,47,49,51
 got a line of input 'Starg,120,90,80,120,30'
 Servo name:Starg {120,90,80,120,30}
 got a line of input 'Skey,null,45,47,49,51'
 Servo name:Skey {0,45,47,49,51}
 got a line of input 'Skey,null,45,47,49'
 Corrupted input 'Skey,null,45,47,49'
 got a line of input ''
 Corrupted input ''
 Corrupted input 'Starg,120,90,80,120,30 Skey,nu'
 got a line of input 'll,45,47,49,51'
 Corrupted input 'll,45,47,49,51'

The last input line was missing a ‘\n’ i.e.
Starg,120,90,80,120,30 Skey,null,45,47,49,51

// https://forum.arduino.cc/?topic=731916#msg4925286
// example inputs
// Starg{120,90,80,120,30}
// Skey{null,45,47,49,51}
// a better format would be on one line terminated by '\n'
// Skey,null,45,47,49,51
// the { } just complicate things

String input;
String servoName;
int servoData[5];

void setup() {
  Serial.begin(9600);
  for (int i = 10; i > 0; i--) {
    Serial.print(' '); Serial.print(i);
    delay(500);
  }
  Serial.println();
  Serial.println(F("ServoControl.ino"));
  Serial.println(F("Sample data lines (terminated by '\\n', Arduino monitor NewLine ending)"));
  Serial.println(F("Starg,120,90,80,120,30"));
  Serial.println(F("Skey,null,45,47,49,51"));
  input.reserve(30); // expected line size
  servoName.reserve(10); // expected name size
}

// read Serial until until_c char found or limit char read, returns true when found/limited else false
// non-blocking, until_c is returned as last char in String, updates input String with chars read
bool readStringUntil(String& input, char until_c, size_t char_limit) {
  while (Serial.available()) {
    char c = Serial.read();
    input += c;
    if (c == until_c) {
      return true;
    }
    if (input.length() >= char_limit) {
      return true;
    }
  }
  return false;
}

int countFields(String& input) {
  if (input.length() == 0) {
    return 0;
  }
  int count = 0; // always one field if input not empty
  int idx = -1; // not found
  do {
    idx = input.indexOf(',', idx + 1); // step over last field, -1 + 1 => 0 to start with
    count++;
  } while (idx >= 0);
  return count;
}

bool processInput(String& input, String& servoName, int *dataArray) {
  input.trim(); //
  if (input.length() == 0) {
    return false; // nothing in this line
  }
  int numberOfFields = countFields(input);
  if (numberOfFields != 6) {
    return false;
  }
  // ok got valid number of fields
  int startIdx = 0;
  int endIdx = input.indexOf(',', startIdx);
  servoName = input.substring(startIdx, endIdx);
  // add check here for valid servoName !!
  for (size_t i = 0; i < 5; i++) {
    startIdx = endIdx + 1; // step over ,
    endIdx = input.indexOf(',', startIdx);
    dataArray[i] = input.substring(startIdx, endIdx).toInt();
    // NOTE: this will return 0 for the null entry
    // could do more checks here for valid numbers
  }
  return true;
}


char terminatingChar = '\n';
void loop() {
  if (readStringUntil(input, terminatingChar, 30)) { // read until find newline or have read 30 chars
    if (input.lastIndexOf(terminatingChar) >= 0) {   // input terminated by '\n'
      input.trim();
      Serial.print(F(" got a line of input '")); Serial.print(input); Serial.println("'");
      if (!processInput(input, servoName, servoData)) {
        Serial.print(F(" Corrupted input '")); Serial.print(input); Serial.println("'");
      } else {
        Serial.print(F(" Servo name:")); Serial.print(servoName);
        Serial.print(F(" {"));
        for (size_t i = 0; i < 5; i++) {
          Serial.print(servoData[i]);
          if (i != 4) {
            Serial.print(",");
          }
        }
        Serial.println("}");
      }
    } else {
      Serial.print(F(" Corrupted input '")); Serial.print(input); Serial.println("'");
    }
    input = ""; // clear after processing for next line
  }
}

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