SSC-32 Serial Command Structure

Okay, my computer keeps crashing and I’ve lost the paragraph or so post I wrote, so I have to keep this short.

I pass serial data in a format #(pinnumber)P(PWM)T(Time) to an SSC-32 servo controller to get the servos to move.

However when I use a for loop to individually pass the setup arguments
(The servo controller only executes when it receives T(timetoexecute)
to the 12 individual servos, the servo controller freaks out, servos move randomly and don’t go to the correct place. I’ve decided this is some kind of weird error attributed to the buffer of serial data created before the execute command

Example:
#1P1500 T100 moves pin 1 to 1500 taking 100 ms to complete
#1P1500#2P1500 T100 moves both 1 and 2 to 1500 taking both exactly 100ms (speed and load control)

Currently my code loops through a simple for statement assigning pins and their associated values and then sends one execute command (this causes unpredictable movement)

They all work fine with individual execute commands, this is however unacceptable as all 12 servos need to move simultaneously.

The power supply is a 6v 20 Amp (120W) wall wart of which the system only draws 36W. Not a power issue.

I believe that if I were able to pre-write the command string and send it all at once instead of individual Serial.prints that my problem would be solved. I however have a very limited arduino vocabulary and am at a loss of how to create (what I believe to necessitate) a String containing the data for twelve individual iterations of:

for(int pin = 0; pin <=11; pin++){ // all 12 servos (0-11)
int Pulse = 1500; //or any value I need
    Serial.print("#");
    Serial.print(pin);
    Serial.print(" P");
    Serial.print(Pulse);
    
  if(final==1){ // is this the last servo? yes? Execute.
    Serial.print(" T");
    Serial.println(100);
    delay(100);
}

This is just sample code, my real structure is a little bit more complex, but this should give a general idea.

Please help, how do I create a string with multiple variables and such?

Please help, how do I create a string with multiple variables and such?

You could use strcat() to build a string and send it with one Serial.print() but that is not likely to be the problem.

Your sample code is sending a mixture of string constants and values. What format is the servo controller expecting. Please provide a link to the device.

Here is a link to the user manual.

As I specified before, the SSC-32 expects either an ASCII stream or some kind of hex/binary structure.

The control stream I send it works fine up until it's used to "multi control" all of the 12 servos.

If I want control of 3 servos at once I print (# 1 P1700 #2 P1300 #3 P 1500)(control codes) T150(execute code)

This part works, I just need a more elegant solution to pass data as I believe there's a little bit of data corruption happening when I pass the controller 12 separate control codes and 1 execute. The servo controller is built to do this, but it's not working with dynamic variables.

(It works if I were to send all 12 servo setup codes in one serial.print with hardcoded values)

Below is some ssc-32 test code from a long time back. This was used to make a way to send control positions from a web page GET request and change what was in the request to the ssc-32 command format.

//#include "WString.h"

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

 #define maxLength 100
 String url = String(maxLength);
 String teststring = String(maxLength);
 String finalstring = String(maxLength);
 
 int ind1 = 0;
 int ind2 = 0;
 int pos = 0;

  url=("GET /?-0p1500t1000-1p2200s1000-2p1500-3p500 HTTP/1.1");
  //url.append("GET /?-0p1500t1000-1p2200s1000-2p1500-3p500 HTTP/1.1");
  Serial.print("url before replace: ");
  Serial.print(url);
  Serial.print("\n");

  url.replace('-', '#');
  Serial.print("url after replace: ");
  Serial.print(url);
  Serial.print("\n");

  Serial.print("URL length: ");
  Serial.println(url.length());
  
  pos = url.length();
  
  ind1 = url.indexOf('#');
  Serial.print("location of first #: ");
  Serial.print(ind1); Serial.print("\n");
  
  teststring = url.substring(ind1, pos);
  Serial.print("intermediate teststring: "); Serial.print("\n");
  Serial.print(teststring);  Serial.print("\n");
  
  ind2 = teststring.indexOf(' ');
  Serial.print("location of space: ");
  Serial.print(ind2); Serial.print("\n");
 
  finalstring = url.substring(ind1, ind2+ind1);

  Serial.print("finalstring: ");
  Serial.print(finalstring);  Serial.print("\n");

}
void loop() {}

Okay, frustrated and confused; I come seeking answers.

I have a servo controller, it takes commands that I have to update constantly

I want to represent the following:

#1 P1500 #2 P1700 #3 1834 etc...

With one single Serial.print statement using the least amount of variables, strings, memory, etc.

Currently I have to write:

Serial.print("#");
Serial.print(pin);
Serial.print(" P");
Serial.print(Pulse);

For every single servo, this ties up my UART pretty heavily and often results in glitches and unexpected movement. I want a way to concatenate all of this data into one string and print that string only once.

How EXACTLY do I go about doing this?

Have you used sprintf() ?

I'm not familiar with the sprintf() function, no

My biggest concern is cross-compatibility, I have a number of different controllers (arduino clones) that all hook modularly into this specific robot. Most of the clones can't handle ANY external libraries, and I haven't the slightest inclination on how to edit them to work properly.

I did some searching and found some posts where the general method is to write something like:

String text1 = "#"
String text2 = "P"
Serial.print(text1 + Pin# + text2+ PWM);

But this, in my opinion is ridiculous and just plain stupid.

Why wont the compiler just let me write Serial.print("YO" + 15 + variable64 + 'dog'); ?!

Then again my main problem is looping the code 12 times (number of servos to control) and collecting all of that information in 1 string...

HELP!

For every single servo, this ties up my UART pretty heavily

It make no difference to the UART if you use many prints or just one big one.

often results in glitches and unexpected movement

Wrong again, This is why you are told to post ALL your code!

My biggest concern is cross-compatibility, I have a number of different controllers (arduino clones) that all hook modularly into this specific robot. Most of the clones can't handle ANY external libraries, and I haven't the slightest inclination on how to edit them to work properly.

Again Wrong Wrong Wrong. Its the IDE that deals with the libs it is nothing to do with the "clone".

Mark

Being told I’m wrong is such a lovely thing to hear.

The fact of the matter is: despite some of my mis-wording, I’m not.

I don’t post my entire code anymore because everyone always gets hung up on the stupid little details.

Sending 1 properly constructed servo move example results in a proper servo movement.
Sending a block of properly (manually) constructed moves, results in proper movement

Sending a
(for int i=0; int i<12;I++){ // this is purely made-up example code
ServoMove(i,PWM);
}
ServoExecute;

results in wildly unpredictable movements, if I send it twice or three times, the servos sometimes move properly.

My clones don’t use the same IDE, so therefore they are IDE dependent.

Okay (and I, for your enjoyment, will include my entire length of unmodified code)

To Recap:

#1 The amount data sent over my TX lines seems to directly influence the amount of “Glitching” that my servo controller applies. No it’s not my code, that I can assure you is sound. The only variable in the equation is the MULTI line vs PREFAB line of code I send.

#2 My clones have different IDE’s, are different boards altogether, and are in no way, shape, or form library compatible.

Honestly coming to the forums is always my last resort. You guys always seem to find a way to point a finger or tell me how I’m an idiot. I don’t come claiming to be a genius in English or Coding.

Is it possible to keep this thread going instead of getting hung up on the details and killing it?

CONCATENATION is my issue.

This is my main file, I don’t know if It still works, but it contained the gist of my code

//                 ONYX
//                  __
//Rear Right:4 |   |SC|   |Rear Left:2           
//             |___|32|___|
//                  ||
//              __|wMPU|__
//             |          |
//Front Right:3|          |Front Left:1
//
//Servo Groups:
//  Group Name (HIP,KNEE,ANKLE):GROUP #
//  Front Left (0,1,2):1
//   Rear Left (12,13,14):2
// Front Right (16,17,18):3
//  Rear Right (28,29,30):4


//---Servos: 12 x HS-5645MG (~750us - ~2200us)------
int ServoList[12] =           {0,    1,    2,    12,   13,   14,   16,   17,   18,   28,   29,   30};
int ServoCenters[12] =        {1800, 1900, 1250, 1200, 1100, 1750, 1200, 1100, 1750, 1800, 1900, 1250};
int ServoCenterPM[12] =       {667,  80,   633,  400,  0,    310,  640,  0,    310,  429,  0,    344};
int Servo_IN_DOWN_Limit[12] = {1000, 2000, 2200, 1500, 1100, 2200, 2000, 1100, 2200, 1500, 1900, 750};
int Servo_OUT_UP_Limit[12] =  {2200, 750,  700,  750,  200,  750,  750,  2200, 750,  2200, 750,  2200};
int ServoGroup[12] =          {1,    1,    1,    2,    2,    2,    3,    3,    3,    4,    4,    4,};
int InversionBit[12] =        {0,    1,    1,    1,    1,    1,    1,    0,    1,    0,    1,    0,}; //If 1: Counts from 2200 down to 750 (Inverted) ||| If 0: Counts from 750 up to 2200 (Non-Inverted)
//Limits:
// #  (OUT/UP, IN/DOWN) (CENTER)
// 0  (O2200, I1000) (1800)
// 1  (U750, D2000)  (1900)-
// 2  (U700, D2200)  (1250)

// 12 (O750, I1500)  (1200)
// 13 (U2200, D1100) (1100)-
// 14 (U750, D2200)  (1750)

// 16 (O750, I2000)  (1200)
// 17 (U2200, D1100) (1100)-
// 18 (U750, D2200)  (1750)

// 28 (O2200, I1500) (1800)
// 29 (U750, D1900)  (1900)-
// 30 (U2200, D750)  (1250)

//Modes (Set in initialize function):
//1 --- Autonomous
//2 --- Single Servo Control (Cycle Servos)
//3 --- Inverse Kinematic Leg Test (Cycle Legs)
#include "math.h"

const float pi = 3.14159;
int pm = 500;
void setup() {
   initialize(1, 9600);
   
}

void loop() {
raiseLeg(1,1,1);
}
  
  

void initialize(int mode, int baud){ //takes mode # and communication baud rate to begin and control following movements
    Serial.begin(baud);
    if(mode == 1){
        for(int i = 0; i < 12; i++){
            groupSet(ServoList[i], ServoCenters[i]);
            groupMove(100);
        }
           
        delay(1000);
    }
}


void raiseLeg(int group,int factor, int cor){ //Raises and lowers legs, takes group number, rasies it by a factor(255-full down---->0-full rasied, can be used to control single group(cor=0) or the corresponding walking group(cor=1)
  
}

 pulsetoPermille(int pulse,int pin){
  int maxLimit = Servo_OUT_UP_Limit[pin];
  int minLimit = Servo_IN_DOWN_Limit[pin];
return((-1000*pulse-minLimit)/(minLimit-maxLimit)); 
}

void servoMove(int pin, int permille, int final){
  int center = ServoCenters[pin];
  int maxLimit = Servo_OUT_UP_Limit[pin];
  int minLimit = Servo_IN_DOWN_Limit[pin];
  int group = ServoGroup[pin];
  int invert = InversionBit[pin];
  float Pulse;

  if(permille>1000)pm=1000;
  if(permille<0)pm=0;
  
    Pulse = ((minLimit-maxLimit)/(0-1000)*permille) + minLimit;
      Serial.print("#");
      Serial.print(pin);
      Serial.print(" P");
      Serial.print(Pulse);
      
    if(final==1){
      Serial.print(" T");
      Serial.println(100);
      delay(100);  
    }
  
  }

void groupSet(int servo, int position) { //Sets servo group move values, but does not execute the move; use groupMove to execute synced move
    Serial.print("#");
    Serial.print(servo);
    Serial.print(" P");
    Serial.print(position);
   
}

void groupMove(int time){ //Execute group move set by groupSet
    Serial.print(" T");
    Serial.println(time);
    delay(time);
}

void IK(float x, float y, float l1, float l2){ //Inverse Kinematic equation

float c2, s2, k1, k2;
c2=(x*x+y*y-l1*l1-l2*l2)/(2*l1*l2);
s2=sqrt(1-c2*c2);
k1=l1+l2*c2;
k2=l2*s2;
float theta1=atan2(y,x)-atan2(k2,k1);
float theta2=atan2(s2,c2);
    float deg1=theta1*180/pi; //conversion to degrees using new variable
    float deg2=theta2*180/pi;
   
   
    Serial.println(" ");
    Serial.println(" ");
    Serial.println(" ");
    Serial.print("T1=");
    Serial.println(theta1);
    Serial.print("Deg1=");
    Serial.println(deg1);
    Serial.print("T2=");
    Serial.println(theta2);
    Serial.print("Deg2=");
    Serial.println(deg2);
   
}

ONYX_Control_ManualSerial_Dudenofuckingclue.pde (4.23 KB)

This is my current project, I built a test controller to cycle through legs and servos, it’s built using similar code, and is based on a MEGA ADK (Which is why I’m including the LiquidCrystal library for readout)

#include "math.h"
#include <LiquidCrystal.h>


//                 ONYX
//                  __
//Rear Right:4 |   |SC|   |Rear Left:2           
//             |___|32|___|
//                  ||
//              __|wMPU|__
//             |          |
//Front Right:3|          |Front Left:1
//
//Servo Groups:
//  Group Name (HIP,KNEE,ANKLE):GROUP #
//  Front Left (0,1,2):1
//   Rear Left (12,13,14):2
// Front Right (16,17,18):3
//  Rear Right (28,29,30):4


//---Servos: 12 x HS-5645MG (~750us - ~2200us)------
int ServoList[12] =           {0,    1,    2,    12,   13,   14,   16,   17,   18,   28,   29,   30};
int ServoCenters[12] =        {1800, 1900, 1250, 1200, 1100, 1750, 1200, 1100, 1750, 1800, 1900, 1250};
int ServoCenterPM[12] =       {667,  80,   366,  400,  0,    310,  640,  0,    310,  429,  0,    344};
int Servo_IN_DOWN_Limit[12] = {1000, 2000, 700,  1500, 1100, 2200, 2000, 1100, 2200, 1500, 1900, 750};
int Servo_OUT_UP_Limit[12] =  {2200, 750,  2200, 750,  200, 750,  750,  2200, 750,  2200, 750,  2200};
int ServoGroup[12] =          {1,    1,    1,    2,    2,    2,    3,    3,    3,    4,    4,    4,};

int ServoValue[12] = {};

//Limits:
// #  (OUT/UP, IN/DOWN) (CENTER)
// 0  (O2200, I1000) (1800)
// 1  (U750, D2000)  (1900)-
// 2  (U700, D2200)  (1250)

// 12 (O750, I1500)  (1200)
// 13 (U2200, D1100) (1100)-
// 14 (U750, D2200)  (1750)

// 16 (O750, I2000)  (1200)
// 17 (U2200, D1100) (1100)-
// 18 (U750, D2200)  (1750)

// 28 (O2200, I1500) (1800)
// 29 (U750, D1900)  (1900)-
// 30 (U2200, D750)  (1250)

//Modes (Set in initialize function):
//1 --- Autonomous
//2 --- Single Servo Control (Cycle Servos)
//3 --- Inverse Kinematic Leg Test (Cycle Legs)

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
int legN = 1;
unsigned long oldTime = 0;
int mode = 1;


void setup() {
  Serial.begin(9600);
  LCDSTARTUP(1);
}


void loop() {
 ServoControl(mode);
  
  if(Serial.available()>0){
    int inbyte=Serial.read();
    switch(inbyte){
    case 'w' :
    legN +=1;
    break;
    case 's' :
    legN -=1;
    break;
     case 'd' :
    mode +=1;
    lcd.clear();
    break;
    case 'a' :
    mode -=1;
    lcd.clear();
    break;
  }
  }
}





void servoMove(int list, int permille, int time){
  
 // int s1=ServoList[0]; int s2=ServoList[1]; int s3=ServoList[2]; int s4=ServoList[3]; int s5=ServoList[4]; int s6=ServoList[5];
 // int s7=ServoList[6]; int s8=ServoList[7]; int s9=ServoList[8]; int s10=ServoList[9]; int s11=ServoList[10]; int s12=ServoList[11];
  
  int pin = ServoList[list];
  int center = ServoCenters[list];
  int maxLimit = Servo_OUT_UP_Limit[list];
  int minLimit = Servo_IN_DOWN_Limit[list];
  int group = ServoGroup[list];
  int Pulse;

  if(permille>1000)permille=1000;
  if(permille<0)permille=0;
  
  Pulse = map(permille, 0, 1000, minLimit, maxLimit);
  //String k = "#";
  //String l = "P";
 // String servoCommand = k + pin + l + Pulse;
  
      Serial.print(servoCommand + "hello");
     // Serial.print(pin);
     // Serial.print(" P");
      //Serial.print(Pulse);
      
    if(time>0)Serial.println(); 
  }
  
void refresh(){
  unsigned long time = millis();
  if(time - oldTime > 2500){
  lcd.clear();
  oldTime=time;
  }
}


void LCDSTARTUP(int mode){
  lcd.begin(20, 4);
      pinMode(6,OUTPUT);
      pinMode(7,OUTPUT); 
      pinMode(8,OUTPUT);  
  lcd.setCursor(0, 1);
    lcd.print("Manual Servo Control");
  lcd.setCursor(5, 2);
    lcd.print("Test V1.0");
 
     for(int i=0;i<12;i++){
     servoMove(i,ServoCenterPM[i],1); 
     }
     
 delay(2800);
 lcd.clear();
   lcd.setCursor(6, 0);
     lcd.print("Warning:");
   lcd.setCursor(2, 2);
     lcd.print("User Control in:");
     lcd.print("3");
    delay(1000);
   lcd.setCursor(18, 2);
     lcd.print("2");
    delay(1000);
     lcd.setCursor(18, 2);
     lcd.print("1");
    delay(1000);
     lcd.clear();  
}

void ServoControl(int mode){
 
  if(mode==1){
    int x,y,z;
        if(legN<1)legN=1;
        if(legN>4)legN=4;
          digitalWrite(6,1); 
          digitalWrite(7,1); 
          digitalWrite(8,1);
      lcd.setCursor(0, 0);
        lcd.print("Leg Control: Leg #");
        lcd.print(legN);
      lcd.setCursor(0, 1);
        lcd.print("H ");lcd.print(ServoList[3*legN-3]);lcd.print(":");
          x=map(analogRead(A6),0,1023,0,1000);
        lcd.print(x);lcd.print("  ");lcd.print("uS:");lcd.print(map(analogRead(A6),0,1023,Servo_IN_DOWN_Limit[3*legN-3],Servo_OUT_UP_Limit[3*legN-3]));
          servoMove(3*legN-3,x,0);
      
      lcd.setCursor(0, 2);
        lcd.print("K ");lcd.print(ServoList[3*legN-2]);lcd.print(":");
          y=map(analogRead(A7),0,1023,0,1000);
        lcd.print(y);lcd.print("  ");lcd.print("uS:");lcd.print(map(analogRead(A7),0,1023,Servo_IN_DOWN_Limit[3*legN-2],Servo_OUT_UP_Limit[3*legN-2]));
          servoMove(3*legN-2,y,0);
      
      lcd.setCursor(0, 3);
        lcd.print("A ");lcd.print(ServoList[3*legN-1]);lcd.print(":");
          z=map(analogRead(A8),0,1023,0,1000);
        lcd.print(z);lcd.print("  ");lcd.print("uS:");lcd.print(map(analogRead(A8),0,1023,Servo_IN_DOWN_Limit[3*legN-1],Servo_OUT_UP_Limit[3*legN-1]));
          servoMove(3*legN-1,z,100);
      refresh();
    
  }
  if(mode==2){
    if(legN<0)legN=0;
    if(legN>11)legN=11;
    refresh();
    digitalWrite(6,1); 
    digitalWrite(7,0); 
    digitalWrite(8,0);
  lcd.setCursor(0, 0);  
    lcd.print("Servo Control: ");
    lcd.print(ServoList[legN]);
  lcd.setCursor(0, 1);
    lcd.print("Min   Center   Max");
    //x=map(analogRead(A6),0,1023,0,1000);
  }
  
  
}

ControllerTestCode.ino (5.11 KB)

int ServoList[12] =           {0,    1,    2,    12,   13,   14,   16,   17,   18,   28,   29,   30};

If this is the list of pins the servos are hooked to then its your first problem as pin 0 and 1 are used by Serial which you are using!

Why are you still using a .pde and not an .ino?

Mark

To do what you are asking for, you would do something like:

char buffer[50];
char *p = buffer;
for (int i=0; i <servoPins; i++) {
   p += snprintf(p, p-buffer, "#%d P%d", i, servopos[i]);
}
Serial.write(buffer, p-buffer);

However, as holmes4 says, your understanding of the problem is likely to be incomplete. Serial.print() essentially has logic very similar to this internally, and using it multiple times should not result in “glitchy” traffic.

In fact, your problem may be way back here:

[the servo controller] takes commands that I have to update constantly

Most serial servo controllers do NOT require continuous updating; it’s part of THEIR job function to continuously output the PWM servo signal based on the most recent serial command. If you send serial commands to the servo controller too often (every time through loop(), for example), the serial data (useless, repetitive, servo commands) will get buffered due to the relatively slow rate of serial communications, and and actual change will get delayed. You probably only want to send serial commands when there is actually a change in the servo positions.

Why are you still using a .pde and not an .ino?

I see what he means about posting all his code results in getting "hung up on details."

My clones have different IDE's, are different boards altogether, and are in no way, shape, or form library compatible.

OTOH, this is a very frustrating statement. What clones are you talking about? Usually I reserve the term 'clone' for very closely-compatible boards. That's what 'clone' means. A Launchpad, maple, or chipKit is not an arduino clone.

I would be extremely surprised if there was any Arduino-like board (energia or mpide based, for example) that would compile your arduino sketch but not support sprintf(). sprintf() is a unix/posix/C standard thing that is MUCH more common than serial.Print().

Do you have a pointer to the documentation for your servo controller?

No it's not my code, that I can assure you is sound.

That is pretty bold. Are you using an ssc-32? What is feeding your code and how is it being used to generate the commands? Have you considered that the math and LCD libraries are potential problems or cause conflicts?

Sending a block of properly (manually) constructed moves, results in proper movement

Do you have an example of a manually constructed block?

The only variable in the equation is the MULTI line vs PREFAB line of code I send.

You're speaking metaphorically, right? I didn't see an "MULTI" or "PREFAB" variables in the code.

CONCATENATION is my issue.

So you say. And yet "we software experts" keep saying "allowing the Serial.print() code to concatenate the data should produce identical results to concatenating as a separate step."

One possibility:

I want to represent the following:

#1 P1500 #2 P1700 #3 1834 etc...

But the code you've posted doesn't include a terminator after each command, or a separator. It will produce:
"#1 P1500#2 P1700#3 P1834"
Are you sure that will work?

westfw:
I see what he means about posting all his code results in getting "hung up on details."

OTOH, it does suggest that the most up-to-date IDE is not being used.
That could be relevant.

  char k = "#";
  char l = "P";

Oops.

I’m going to cry… I wrote a multi-page response that encompassed your questions and concerns.
I, however, took too long to write my response and the board directed me to a time-out message and a white screen.

So here we go again…

I am writing this as a control code for a Quadruped that has an SSC-32 taking commands over a correctly configured 9600 BAUD Serial communication line. This line receives data from an arduino Cradle controller that test individual servo limits and overall leg functionality. When the robot is disconnected, a WIFI-enabled Spark Core turns on and controls the SSC-32(SPARK IDE). This can also be manually connected through a PIC32(MPIDE). That’s how it’s supposed to work anyway.

All of these following problems have been examined, tested, and repeated on each of the three devices.

When I send the SSC-32 a large volume of changing data (say move all 12 servos 90 degrees) the servos sometimes jerk or shake (sometimes in Palsy-style jumps to the correct angle, and sometimes in seemingly random directions. A couple joints, alternating moves, or individual control of servos does not lead to this problem. I am supplying the controllers with adequate voltage and the servos with rated voltage and above maximum power draw (about 36W of a 600W PSU). This is why I assumed it to be data corruption (which I know the least about).

I was extremely frustrated in coming here, my “char k = “#”; char l = “P”;” an example of that.

edit I found the drafts function of the forum, totally hidden.

I wasn’t trying to say I’m completely correct but I was frustrated as all hell. This project has just beat me left and right and every question I’ve asked has been shut down.

I’ve been hacking away at this robotfor a while now and have started to actually gain ground. It’s a Quadruped with a SSC-32 Controller. I have to pass it Serial commands in the form #(servo)P(Pulse).
What I’ve been doing is listed in the ServoMove() function, with a simple Serial.println(). as the
So far it’s worked great, I send it “#0P1500 (new line)” and the arduino (or FemtoDuino (MPIDE), or Spark Core(SPARK IDE), or arduino MEGA/UNO (arduino IDE) clones handle the communication while the SSC-32 moves that servo (being supplied with a more-than adequate power supply) on the SSC’s pin 0 (a valid pin) to a 1500 uS pulse.

Whenever I pass it a large number of commands the board just freaks out, servos go haywire and jump unpredictably. Sometimes it will happen almost predictably though. If I pass a ton of update info to the right leg, then the rear right leg will twitch. Same with left on left. This is what led me to conclude it was an intermittent error introduced by data corruption (not a totally wild guess in my opinion)

edit

I don’t have to update the values to the board constantly, but I do have to update the new angles according to the Pots or code. This is what I meant by updated constantly. I can’t just have three moves that make the entire leg cycle, its hundreds of values.

The Servo manual can be found here

As far as I can see, the "time" parameter to servoMove either allows or prevent the termination of the command - why?

I can pass a time value at the end of a group move and all of the servos are supposed to use that specified time (right now it just acts as my execute button). I had some issues with it so I made it work with my existing code but work without a time value

But what happens in the servo controller to all the incomplete commands?