Control Servo Speed with Ethernet problems

Hello all,

My goal: control 2 servos over ethernet and slow down their movement speed

Where am I:
I am working on getting 2 servos to work over ethernet which are controlled by Labview. I've gotten communications between Arduino and Labview working fine. I got servo control working without a load at the end of the servos. As soon as I put a load on the servos, I start to see an oscillating motion on the load. I went to check my servo pulse widths thinking that the pulse width must be changing which gives me the oscillating effect. I look at the servo pulse widths via serial communications and it is constant. I then notice that when I move slowly, I get less oscillation than when I do an abrupt movement with them. I then rework my move servo code to

side note: command() is a sent from Labview to Arduino and contains all the info about what I want the Arduino to do.

tempVar1 = servos[command[2]].readMicroseconds();
tempVar2 = (command[3] + (command[4]<<8));

if (tempVar1 >= TempVar2 + 3)
{
   while (tempVar1 >tempVar2)
   {
      tempVar1--;
      servos[comannd[2]].writeMicroseconds(tempVar1);
      delay(2);
   }
}
else if (tempVar1 <= TempVar2 - 3)
{
   while (tempVar1 < tempVar2)
   {
      tempVar1++;
      servos[comannd[2]].writeMicroseconds(tempVar1);
      delay(2);
   }
} 
client.write('0');

when I look at the error code from Labview, I get

Timeout expired before operation completed.

I looked into my labview code and saw that I only have a 20 ms delay between send the data and receive confirmation that everything is okay by the Arduino.

My thoughts: at the very best, if my code can be off by ~10 micro seconds or I will get a time out. if I changed delay to mills(); would that help get things to move faster in the Arduino code? Would using a for loop be faster than a while loop? I think I should make the delay for servo movement larger, but if I do that, I will make the rest of my Labview code slower. However, I can make a copy of the send/receive Labview code for the servo only which would only give servo a delay ~150 or so miliseconds.

Thank you in advance.
Matt

Making the servo move slower is a reasonable thing to do, although if it's only to prevent the servo from glitching you might find the behaviour is still problematic under the wrong conditions of load, speed, heat, humidity or whatever else effects the mechanical characteristics of the servo.

The code you posted adjusts the servo position in a blocking manner - the sketch stops and waits for the change to be completed before it does anything else.

A minimal change would be to send the acknowledgement immediately and then run your delay loop to update the servo. Note that this would mean the Arduino didn't respond to any other events until the change had completed.

A better approach would be to make the change asynchronously. The approach would be:

When you receive a command to move the servo, update a variable which holds the desired position of the servo. Have some other code which runs at regular intervals - the code to achieve that would be similar to the 'blink without delay' example. When it runs, compare the current and desired position of the servo and move the servo towards the required position. The servo speed would be determined by the interval you run the code at, and the size of the step. With this approach it is easy to add extra embellishments such as controlling the acceleration at the start and end of the travel, and nothing you do here slows down the Arduino's response to commands or prevents it from doing other things at the same time.

PeterH,

I'm not understanding the whole do two things at once from the BlinkWithoutDelay example. Do you mean something like this? Please excuse the psudeo code and code in the same code block.

unsigned long endtime=200;

case move servo
tempVar1 = servos[command[2]].readMicroseconds();
tempVar2 = (command[3] + (command[4]<<8));
client.write('0');  //sends the all clear back to Labview 

// start second thing to do that is not affected by the cleint.write('0'); and the arduino code continues like normal?

long current = millis();

if (current >= endtime)
{
    current=0;
   if (tempVar1 >= TempVar2 + 3)
   {
      while (tempVar1 >tempVar2)
      {
         tempVar1--;
         servos[comannd[2]].writeMicroseconds(tempVar1);
      }
   }
   else if (tempVar1 <= TempVar2 - 3)
   {
      while (tempVar1 < tempVar2)
      { 
         tempVar1++;
         servos[comannd[2]].writeMicroseconds(tempVar1);
      }
   } 
} 
break;

I merged the BlinkWithoutDelay and servo sweep together successfully. LED9 (im using arduino ethernet) blinks every ~1second and the servo goes from 0 to 90 degrees. Blow is my code

#include <Servo.h> 
Servo myservo;  // create servo object to control a servo 
                // a maximum of eight servo objects can be created 
 
const int ledPin =  9;      // the number of the LED pin
int pos = 0;    // variable to store the servo position 
 
// Variables will change:
int ledState = LOW;             // ledState used to set the LED
unsigned long previousMillis = 0;        // will store last time LED was updated



// the follow variables is a long because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long interval = 1000;           // interval at which to blink (milliseconds)

void setup() {
  // set the digital pin as output:
  pinMode(ledPin, OUTPUT);      
  myservo.attach(7);  // attaches the servo on pin 7 to the servo object 
  Serial.begin(9600);
}

void loop()
{
    // here is where you'd put code that needs to be running all the time.
  for(pos = 0; pos < 90; pos += 1)  // goes from 0 degrees to 180 degrees 
  {                                  // in steps of 1 degree 
    myservo.write(pos);              // tell servo to go to position in variable 'pos' 
    delay(15);                       // waits 15ms for the servo to reach the position 
   previousMillis= switchLED(previousMillis, interval);  
  } 
  for(pos = 90; pos>=1; pos-=1)     // goes from 180 degrees to 0 degrees 
  {                                
    myservo.write(pos);              // tell servo to go to position in variable 'pos' 
    delay(15);                       // waits 15ms for the servo to reach the position 
   previousMillis= switchLED(previousMillis, interval);  
  } 
  
   // check to see if it's time to blink the LED; that is, if the 
  // difference between the current time and last time you blinked 
  // the LED is bigger than the interval at which you want to 
  // blink the LED.

 
}

unsigned long switchLED(unsigned long previousMillis, int interval)
{
  unsigned long currentMillis = millis();
  Serial.print("previousMillis: ");
  Serial.print(previousMillis);
  Serial.print(" currentMillis: ");
  Serial.println(currentMillis);
    
  if(currentMillis - previousMillis > interval) 
  {
    // save the last time you blinked the LED 
    previousMillis = currentMillis;   

    // if the LED is off turn it on and vice-versa:
    if (ledState == LOW)
      ledState = HIGH;
    else
      ledState = LOW;

    // set the LED with the ledState of the variable:
    digitalWrite(ledPin, ledState); 
  }
  return previousMillis;
}

Can I use milli(200) to create a 200 millisecond delay in my code while other things are working? Or do I need to create the interval and check to see if the difference is larger than a certain time.

For example, when I get to the move servo section, i say milli(200) and then move servo. Meanwhile the other parts of my code are working and unaffected by the servo

That's not really what I had in mind.

The LED blinking code is along the right lines, but there's a technique you can use to simplify it a bit:

void blinkLed()
{
  const unsigned long interval = 1000;
  static unsigned long previousMillis = millis();
  static int ledState = LOW;

  if(millis() - previousMillis > interval) 
  {
    // save the last time you blinked the LED 
    previousMillis += interval;   

    // if the LED is off turn it on and vice-versa:
    if (ledState == LOW)
      ledState = HIGH;
    else
      ledState = LOW;

    // set the LED with the ledState of the variable:
    digitalWrite(ledPin, ledState); 
}

There are several variables and constants that you want to retain their value between calls to blinkLed() but don't need to be accessed from anywhere else. You can define these as static variables and constants within the function. That keeps the function nicely self-contained. As long as you call it reasonably often the LED will keep blinking.

The servo updating code can be done in a similar way. Write a function similar to blinkLed() which runs some logic at regular intervals. The logic will be to decide whether the servo needs to be moved, and if so move it. This will replace the blocking code in loop() which is moving the servo a little bit, waiting until it is time for the next movement, moving it again, and so on. Let's suppose you called your new function moveServo(); your loop() now just needs to call blinkLed() and moveServo(). If you wanted your sketch to do anything else at the same time, such as reading and writing to the Serial port, you would approach that in the same way. As long as long of your code blocks for any significant time and none of it takes very long to execute, you can do lots of activities independently and each activity can be implemented independently (no need to make your servo-moving loops call the LED blinking code, etc).

Yes, if the blink-without-delay scheme is used properly, you should be removing all
delay() calls from your code.

Servo speed control stuff.

http://forum.arduino.cc/index.php/topic,61586.30.html

Thank you all for your help! I'm going to try out using badji's code and if i can get that working, I'll use the library.

Hopefully next post will be my success story :smiley:

Matt

Great news, got everything working servos. They are incremented or decremented every 10 milliseconds to give a smooth look. A bit slow, but I can modify that later.

However, I thought that slowing down how fast they change would stop the oscillations in my servos from happening. They are not. Any tips to get these to stop oscillating so much?

I am currently using HS-M7990TH High Voltage, Mega Torque, Magnetic Encoder Ultra Premium Servo | HITEC RCD USA. My thought is that the circuitry inside is too precise thus giving me the jittering. From my understanding, it thinks it is .0001 off and tries to correct that and over shoots, then under shoots, over shoots, under shoots, etc.

Thanks,
Matt

I am using servos controlled via Arduino for controlling a pan tilt head. To avoid the jitter, I have detach of the servos incorporated in the code.