Help needed for code optimization

Dear all,

the following Arduino sketch isn't running fast enough but I'm not yet smart or experienced enough ( :wink: ) to make further improvements on it. The situation: The Arduino (it's not an NG version) receives two byte information snippets via USB in this pattern and sends their corresponding values to three servos, that are connected to digital pins:

E6 AA
or
F0 BB
or
FA CC

The first byte always represents the ID for the servo, like E6 (230 in DEC) is servo #1, F0 (240 in DEC) is servo #2 and FA (250 in DEC) is servo #3. The second byte carries the servo turning values.

My problem is, that the code itself runs very slow. And I don't have any clue what to do about it. Please help, any thoughts appreciated!

Thanks, Patrick

/*
  Servo control from vvvv via RS232 and a virtual COM port
 
 The minimum (minPulse) and maxiumum (maxPulse) values
 will be different depending on your specific servo motor.
 Ideally, it should be between 1 and 2 milliseconds, but in practice,
 0.5 - 2.5 milliseconds works well.
 
 Original Servo code by Tom Igoe, Carlyn Maw
 modified by milo (milo.digialsoul.org) and Patrick Raddatz (dingbatz.net)
 */

int servoPin;                    // control pin for servo motor
int minPulse = 500;              // minimum servo position
int maxPulse = 550;              // maximum servo position
int pulse = 2;                   // amount to pulse the servo

int incomingByte = 0;            // value returned from vvvv
int memoryPulse2 = 0;            // stores last pwm value of servo 1
int memoryPulse4 = 0;            // stores last pwm value of servo 2
int memoryPulse6 = 0;            // stores last pwm value of servo 3


void setup() {
  pinMode(2, OUTPUT);            // set servo 1 pin as an output pin
  pinMode(4, OUTPUT);            // set servo 2 pin as an output pin
  pinMode(6, OUTPUT);            // set servo 3 pin as an output pin
  pulse = minPulse;              // set the motor position value to the minimum
  Serial.begin(9600);            // begin serial readout
}

void loop() {
  incomingByte = Serial.read();  // read incoming serial data
  if (incomingByte > -1)         // do we get anything?
  {  
    if (incomingByte == 230)     // checks for servo 1 data
    {
      servoPin = 2;              // sets the corresponding pin
    }
    else if (incomingByte == 240) // checks for servo 2 data
    {
      servoPin = 4;               // sets the corresponding pin
    }  
    else if (incomingByte == 250) // checks for servo 3 data
    {
      servoPin = 6;               // sets the corresponding pin
    }    
    else 
    {
      pulse = (incomingByte * 8) + 500;   // convert the serial value to pwm value

      if (servoPin == 2)
      {
        memoryPulse2 = pulse;             // stores the pulse value
      }
      else  if (servoPin == 4)
      {
        memoryPulse4 = pulse;;            // stores the pulse value
      }
      else  if (servoPin == 6)
      {
        memoryPulse6 = pulse;;            // stores the pulse value
      }
    }
    //Serial.println(incomingByte);       // only for debugging
  }
  else {                                  // if there's no new data, send the last known value
    if (servoPin == 2)
    {
      pulse = memoryPulse2;
    }
    else  if (servoPin == 4)
    {
      pulse = memoryPulse4;
    }
    else  if (servoPin == 6)
    {
      pulse = memoryPulse6;
    }                           
  }     

  constrain(pulse,minPulse,maxPulse);     // constrain pwm values to a range between minPulse & maxPulse

    // pwm generation
  delay(50);                         // pulse the servo again after (50 ms) have passed
  digitalWrite(servoPin, HIGH);      // turn the motor on
  delayMicroseconds(pulse);          // length of the pulse sets the motor position
  digitalWrite(servoPin, LOW);       // turn the motor off
}

That "delay(50)" is your slowdown. Your code would be ok for 1 servo, but with three, and delaying 50ms on each one you are going to be looking at 6 updates per second.

I might be tempted to just store the desired value when the serial data comes in, then at the top of my loop check millis() and if it is at least 40ms since my last pusling, then pulse all three servos and not the time I did it.

That way your pulse interval would be indepentent (mostly) of the number of servos and as a side effect you wouldn't have to keep sending the same value from the host to keep the servos in place, they would stay in the last position if the host got busy with something else and delayed an update.

(Actually, I'd use a cool servo library, but I'm not done polishing so I haven't posted it.)

Looks like a sound concept, I'll try that next morning! I'm unsure though, what you say with 'then pulse all three servos and not the time I did it.' Do you mean 'the time you did it'?

Please tell me more about that servo lib of yours, could come in handy, wouldn't it? :slight_smile:

Well, there was no time left for me to try this, I had to fix some technical issues and the exhibition was only hours away ? luckily milo did work on my original code and this is the result:

/*
  Servo control from vvvv via RS232 and a virtual COM port

 The minimum (minPulse) and maxiumum (maxPulse) values
 will be different depending on your specific servo motor.
 Ideally, it should be between 1 and 2 milliseconds, but in practice,
 0.5 - 2.5 milliseconds works well.

 Original code by Tom Igoe, Carlyn Maw
 modified by milo (milo.digialsoul.org)
 */

int servoPin;                    // Control pin for servo motor
int minPulse = 500;                  // Minimum servo position
int maxPulse = 550;                 // Maximum servo position
int pulse = 2;                       // Amount to pulse the servo

int incomingByte = 0;                // value returned vvvv
int memoryPulse2 = 0;
int memoryPulse4 = 0;
int memoryPulse6 = 0;
int memoryPulseSend = 0;                 // stores last pwm value


void setup() {
  pinMode(2, OUTPUT);         // set servo pin as an output pin
  pinMode(4, OUTPUT);         // set servo pin as an output pin
  pinMode(6, OUTPUT);         // set servo pin as an output pin
  pulse = minPulse;                  // set the motor position value
  Serial.begin(115200);                // begin serial readout
}

void loop() {
  incomingByte = Serial.read();        // read serial data
 
  if (incomingByte > -1)
  {
    if (incomingByte == 230)
    {
      servoPin = 2; 
      
    }
    else if (incomingByte == 240)
    {
      servoPin = 4;
     
    }
    else if (incomingByte == 250)
    {
      servoPin = 6;
     
    }
    else
    {

      pulse = (incomingByte * 8) + 500; 
     
      if (servoPin == 2)
      {
        memoryPulse2 = pulse;
      }
      else  if (servoPin == 4)
      {
        memoryPulse4 = pulse;
      }
      else  if (servoPin == 6)
      {
        memoryPulse6 = pulse;
      }
           motor(servoPin);
    }
  }
  else {

    pulse = memoryPulse2;
    motor(2);
    pulse = memoryPulse4;
    motor(4);
    pulse = memoryPulse6;
    motor(6);
  }

}

void motor (int servo)
{
 if (pulse > 499 && pulse <2325)
 {
  //Serial.println(pulse);
  constrain(pulse,minPulse,maxPulse);     // constrain pwm value
  delay(5);                         // pulse the servo again after 5 ms
  digitalWrite(servo, HIGH);      // turn the motor on
  delayMicroseconds(pulse);          // length of the pulse sets the motor
  digitalWrite(servo, LOW);
  }
}

What I really don't get is the fact, that the servos wouldn't respond unless my MacBook Pro (running Win XP) was connected via Ethernet to a hub (even if the hub wasn't connected to anything else than it's power supply). Arduino was USB powered, the servos got their own power supply, so there wouldn't be any strain on it. This really did me in the night before setting it all up, until I accidentally connected it to the network and suddenly the servos finally began to respond as they've should.

Does anyone have a reasonable explanation for this kind of behaviour?

hi

all I can think of is that connecting your Macbook completed some kind of open ground circuit...

D

What else could be done to eliminate this, Daniel?

hi
If connecting your macbook completes the circuit, you should check the standalone Arduino circuitry, to see if everything connected has a ground path back to the Arduino. Check the power supplies and the servos to see that each one has the proper power connections, including ground.

D

Now I see ? thanks for explaining this issue!