Friday, February 3, 2012

Can I Control More Than X Servos With An Arduino ? Follow Up Results

The servo library can be uses a single Arduino Timer to control upto 12 Servos.

See here for a detailed overview and sample code - How To Control X Servos and MultiSweep Example

To achieve this the library attaches an interrupt service route to the timer which is called around 50 times per second for each connected servo. In the case of 12 Servos, this is 600 times per second.

Within the timer service routine, there are array access operations, function calls and also a few calculations are performed. It is reasonable to expect that repeating these operations 600 times per second may have a performance impact on the Arduino.

To measure the impact I have modified the multi sweep sketch to run a busy loop and a hardware timer. When the timer counts down to 0, the loop exits and prints the number of loops completed during the countdown. The countdown period is approximately 3.8 seconds.

With no servos attached, the busy loop is executed 219,744 times per countdown. We will consider this bench mark as equivalent to 100% available processing power.

With 12 Servos attached, the busy loop is executed 217,719 times per second, based on the no servo bench mark this is equivalent to 99% meaning that to drive 12 servos, only 1% of available processing power is required.

If my logic and calculations are correct, thats very Impressive.

Try it for yourself -

// Multi Servo Benchmark
// The loop tests the base load for the Arduino Servo
// library to maintain positions on upto 12 connected servos
// to change the number of servos change the CONNECTED_SERVOS value

#include <Servo.h>
// Sample sketch for driving 12 Servos from an Arduino UNO, servos are attached to digital pins 2,3,4,5,6,7,8,9,10,11,12,13

#define CONNECTED_SERVOS 12

// macro just adds two - the first servo is attached to digital pin 2, this gives us upto 12 servos - digital 2 to 13
#define SERVO_TO_PIN(x) (x+2)

Servo myServos[CONNECTED_SERVOS];

#define COUNT_DOWN -1
#define COUNT_UP +1
#define INCREMENT 10 // move in steps of 10 milliseconds

int nPulseWidth = DEFAULT_PULSE_WIDTH ; // 1500, defined in servo.h
int nDirection = COUNT_UP;

volatile unsigned long ulStart = 0;
volatile unsigned long ulStartToEnd = 0;


#define CLICK_START 255

volatile short sClicks = CLICK_START;
volatile unsigned long ulAnother = 0;

ISR(TIMER2_OVF_vect)
{
  if(sClicks)
  {
    sClicks--;
  }
};

void setup()
{
  TCCR2A = 0;
  TCCR2B = (1<<CS02|1<<CS01|1<<CS00);
  TIMSK2 = 1<<TOIE2;
 
  Serial.begin(9600);

  // attach the servos
  for(int nServo = 0;nServo < CONNECTED_SERVOS;nServo++)
  {
    myServos[nServo].attach(SERVO_TO_PIN(nServo));
  }
 
  pinMode(13,OUTPUT);
 
  digitalWrite(13,LOW);
}

void loop()
{
   unsigned int uiOuter = 0;
   unsigned int uiInner = 0;
  
   for(;sClicks && uiOuter < 0xFFFF;uiOuter++)
   {
    uiInner = 0;
    for(;sClicks && uiInner < 0xFFFF;uiInner++)
    {
     int nTemp = uiInner%10;
     ulAnother = uiOuter/nTemp;
    }
   }
  
   Serial.println(uiOuter);
   Serial.println(uiInner);
  
   sClicks = CLICK_START;
}



Duane B.

No comments:

Post a Comment