200 Servos and multiple arduino boards

Hi am fairly new to Arduino and I am using servos to control panels that rotate for architecture. I was wondering if anyone knew the issues associated with using multiple arduino mega boards with the same piece of code.

For example if I had 200 servos could I connect 4 arduino boards with 50 servos each through a serial port and have them all rotate on different intervals within one written piece of code?

Any information or examples on this topic would be very useful. Thanks very much!
-Charles

The number of servos connected to the arduino will be limited based on the hardware you use to put it all together. The arduino alone can only do 2 or 3 servos without the use of a shift register.

AS far as intercommunication between boards that will get quite complicated. You'll need to have a good understanding of the boards limitations in this area. This should be a good place to start on that. http://arduino.cc/en/Reference/Serial

The arduino alone can only do 2 or 3 servos without the use of a shift register.

Where did you get that fact? The Servo library says "12".

Be aware that 200 servos represents a [u]lot[/u] of current, even idle. Make sure your wiring and decoupling is up to scratch.

The arduino alone can only do 2 or 3 servos without the use of a shift register.

Where did you get that fact? The Servo library says "12".

It's from the old documentation.

The ability of the servo library to handle 12 servos is a relatively new development.

I don't know if the Mega is capable of handling 50, though...

and have them all rotate on different intervals within one written piece of code?

The code can be the same in all arduinos but I would consider it not to be the same piece as it is in four boards. I would say that is four pieces of identical code. If the code is written flexibly enough there is no reasion why you should not have it in different boards.

… if I had 200 servos could I connect 4 arduino boards with 50 servos each through a serial port and have them all rotate on different intervals

The Arduino servo library is designed to drive up to 48 servos on a Mega board (although I have to say that I have never had enough servos available to test that many).

It’s relatively easy to control the servos using serial commands. I would suggest using one board as a dedicated master controller and have the servos driven from other boards through serial commands.

Here is some code I use to control servos over the serial that gives an idea of what you can do. Send the position in degrees followed by a letter indicating the servo. 100A will write a value of 100 to the first servo. 90B writes 90 to the second servo etc. See an ascii chart for the 48 characters starting from ‘A’ . the characer ‘*’ writes the preceeding value to all servos.

#include <Servo.h> 

const int NBR_SERVOS = MAX_SERVOS;       // the number of servos, up to 48 for Mega, 12 for other boards
const int FIRST_SERVO_PIN  = 2;

Servo Servos[NBR_SERVOS] ; // max servos is 48 for mega, 12 for other boards

void setup() 
{ 
  Serial.begin(9600); 
  for(int i=0; i < NBR_SERVOS; i++)  
    Servos[i].attach(FIRST_SERVO_PIN +i);  
} 


void loop()
{
  static int pos = 0;

  if ( Serial.available())
  {
    char ch = Serial.read();

    if(ch >= '0' && ch <= '9')              // is ch a number?  
      pos = pos * 10 + ch - '0';           // yes, accumulate the value
    else if(ch >= 'A' && ch <= 'A'+  NBR_SERVOS) // is ch a letter for one of our servos?
    {
      Servos[ch - 'A'].write(pos);         // yes, save the position in the position array   
      pos = 0;
    }
    else if (ch == '*')
    {
      // position all the servos
      for(int i=0; i < NBR_SERVOS; i++)
        Servos[i].write(pos);         
      pos = 0;      
    }
  }
}

If I were doing a project on that scale, I'd seriously consider breaking it down into modules of, say, a dozen or 16 servos each, and using a chip like this one (or an Arduino like the RBBB) to control each module. Then I'd have a "master" Arduino (using either the SoftSerial library, or a decoder chip like the 74HC154 to fan out a single hardware UART) control the "peripheral" servo controllers.

That would significantly reduce the amount of wiring, and should ease the processes of building and repairing the system.

Ran

Just a note of warning on software serial, I would be not use it on the boards that are driving servos. Code such as newSoftSerial disables interrupts so will interfere with the servo pulse timing - using the Hardware serial port on the servo driving boards should not be a problem.

Thanks allot for all the input everyone. I think I could have done a better job explaining how im doing what im doing. I am actually in the field of architecture and I am currently using a visual programming software called grasshopper. That software has a built in VB.net editor that allows me to write code. So currently I have all the logic that controls the servos in grasshopper with the vb.net code sending information through the serial port to arduino, thus far I have six servos and it runs flawlessly. I would like to add 48 with the mega plus at lease one more board(additional 48)

It sounds like it would be smart to add a board thats a controller than attach boards to that board, personally I have no idea how I would do this. It also seems smart to have a controller because my grasshopper code asks me for the serial port and I don’t think I can use multiple serial ports in my code the way I currently have it written. Here is my arduio code if anyone would like to take a look and give feedback.

Again this is working great with 5 servos, I just want to scale this as big as possible.

/*This demo receives a comma separated string over the serial port
from the Grasshopper plugin for Rhino, which ultimately controls a 
pan/tilt servo.


 */

#include <Servo.h>

#include <Wire.h>

 

#define BAUDRATE 19200

#define BUFFSIZE  1600   

char buffer[BUFFSIZE];  

uint8_t bufferidx = 0;

uint16_t Servo1Degrees, Servo2Degrees, Servo3Degrees, Servo4Degrees, Servo5Degrees;

 

Servo Robot_one;  // create variable object to control the Pan servo
Servo Robot_two;  // create variable object to control the Tilt servo
Servo Robot_three; 
Servo Robot_four;
Servo Robot_five;

char *parseptr;

char buffidx;

 

void setup()          

{

  Robot_one.attach(9);  // attaches the servo on pin 9 to the servo object
  Robot_two.attach(10);  // attaches the servo on pin 10 to the servo object
  Robot_three.attach(11);
  Robot_four.attach(12);
  Robot_five.attach(13);
  
  Serial.begin(BAUDRATE);

 

}

 

void loop()                    

{

  char c;    // holds one character from the serial port

  if (Serial.available()) {

    c = Serial.read();      // read one character

    buffer[bufferidx] = c;  // add to buffer

    Serial.print(c);//write raw data to serial for testing

   

    if (c == '\n') {   

      buffer[bufferidx+1] = 0; // terminate it

      Serial.println(" eol");    // debug marker

 

      parseptr = buffer;    // offload the buffer into temp variable

 

      Servo1Degrees = parsedecimal(parseptr);    // parse out the first number, and offload to variable
      parseptr = strchr(parseptr, ',')+1;  // move past the ","

 

      Servo2Degrees = parsedecimal(parseptr);    // parse the second number
      parseptr = strchr(parseptr, ',')+1;    // move past the ","
      
     
      Servo3Degrees = parsedecimal(parseptr); // parse the third number
      parseptr = strchr(parseptr, ',')+1;    // move past the ","
      
      Servo4Degrees = parsedecimal(parseptr); // parse the third number
      parseptr = strchr(parseptr, ',')+1;    // move past the ","
      
      Servo5Degrees = parsedecimal(parseptr); // parse the third number
  
      
      
      
      
      
      
    

 

      Robot_one.write(Servo1Degrees); // tell Pan servo to go to position in variable 'Servo1Degrees'

      Robot_two.write(Servo2Degrees); // tell Tilt servo to go to position in variable 'Servo2Degrees'

      Robot_three.write(Servo3Degrees);  // tell Tilt servo to go to position in variable 'Servo3Degrees'
      
      Robot_four.write(Servo4Degrees);  // tell Tilt servo to go to position in variable 'Servo4Degrees'

      Robot_four.write(Servo5Degrees);  // tell Tilt servo to go to position in variable 'Servo5Degrees'

     
     
      bufferidx = 0;      // reset the buffer for the next read

      return;        //return so that we don't trigger the index increment below

    }

  

       

        // didn't get newline, need to read more from the buffer

    bufferidx++;    // increment the index for the next character

    if (bufferidx == BUFFSIZE-1) {  //if we get to the end of the buffer reset for safety

      Serial.print('!', BYTE);

      bufferidx = 0;

    }

  }

}

 

uint32_t parsedecimal(char *str) 

{

  uint32_t d = 0;

 

  while (str[0] != 0) {

    if ((str[0] > '9') || (str[0] < '0'))

      return d;

    d *= 10;

    d += str[0] - '0';

    str++;

  }

  return d;

}

 
[code]

I am using a laptop for this which is crazy, at any rate it only has two USB serial ports so I dont know how to add more boards. I have all the logic controlling the servos done, no problem. What I need help with from this great community is how to scale this project as big ass possible. FYI I am doing this just for fun its not a commission or anything like that. Also given my lack of programing experience it might be nice to create a loop to call each pin and variable vs call them out individually which is what I have now. Thanks so much everyone!

I'd off load the servo work to a servo controller like the ssc-32. Seven of these would handle 224 servos. Then use a board like the Arduino to be the master controller for the ssc-32 boards. Use a multiplex chip to distribute the serial commands from the Arduino board out to the desired ssc-32 board. Never done that, but that is where I'd start looking.

You don’t need that big buffer for the serial data. The Arduino serial code has a 128 byte buffer that holds incoming data and if the data is coming in faster than the arduino can process it then it will be lost before it gets to the buffer in your sketch. You can process the data as it comes in without any additional buffer, the example code below is not tested but shows how you can do this.

#include <Servo.h>

#define BAUDRATE 19200
#define ROBOT_COUNT  5
#define FIRST_ROBOT_PIN 9

Servo Robots[ROBOT_COUNT];  // create an array of servos

void setup()          
{
  for(int i=0; i < ROBOT_COUNT;i++)  
    Robots[i].attach(FIRST_ROBOT_PIN + i);  // attaches the servo to the servo object
  Serial.begin(BAUDRATE);
}


// these values store commands from the serial port
// the loop logic assumes the command format is:  servNbr,servoValue\n 

int value = 0; 
int servoNbr = 0; 

void loop()                    
{
  char c;    // holds one character from the serial port

  if (Serial.available()) {
    c = Serial.read();      // read one character

    Serial.print(c);//write raw data to serial for testing

    if(c >= '0' && c <= '9'){              // is ch a number?  
      value = value * 10 + c - '0';           // yes, accumulate the value   
    }
    else if (c == ',') {    // if its comma then the preceeding value is the servo number
      servoNbr = value;
      Serial.println(servoNbr);  // for debug
      value = 0;
    }
    else if (c == '\n') {   //is it the end of message marker
      servoNbr--;  // the servo array starts at 0, use this if you send the first servo as number 1 
      if(servoNbr >= 0 && servoNbr <  ROBOT_COUNT){
        Robots[servoNbr].write(value);
        Serial.println(value);  // for debug
      }
      else {
        Serial.print(" got message for invalid servo number " );  // for debug         
        Serial.println(servoNbr);
      }
      value = 0;   
      Serial.println(" eol");    // debug marker
    }
  }
}

the code assumes your command forma is : ss,aaa\n
where ss are digits indicating the servo number (with the first servo as 1) and aaa are digits indicating the angle

This should scale to 48 without changing any of the logic. To scale larger you would need to modify the code so that it retransmitted the commands to slave boards that had the servos.
I would suggest that with lots of servos you should use a binary message format to reduce the amount of serial data that needs to be processed. Perhaps send a header byte followed by a byte indicating the servo number followed by a byte with the angle. A header value of 255 would not conflict with your servo numbers or servo values.

You could use SSC-32 for the slave boards but with the number of slaves you need, you may be better of with a board that can use i2c. I would think that 4 mega boards as slaves would to the trick.

Is the below similar to what you want to do?

http://www.youtube.com/watch?v=i-G54kVrhbE