Ethercard and Servo wobble strangeness

Hi all,

I’ve got 4 servos hooked up to my Uno and a ENC28J60 ethernet module, sending messages to the servos over UDP, and I am getting some strange twitching of the servos, at different intervals, when they are not receiving any values. Here is a video of one of them http://tinypic.com/r/zb7yv/8 (bit out of focus, but you hear it at least). The twitching also often happens if I send messages to other servos…!

I have boiled it down to being a problem with the code or Ethercard/Servo library (see below for the things I have ruled out as being the issue).

When I comment out:
ether.packetLoop(ether.packetReceive());
in void loop() the problem disappears, but it also does not read any UDP packets anymore.

Also, strangely, when I comment out some of the servos, to leave me with just two, the twitching is reduced, but not gone, and it increases with more servos added in the code.

#include <EtherCard.h>
#include <IPAddress.h>
#include <Servo.h> 

// ethernet interface ip address
static byte myip[] = { 172,16,1,152 };
// gateway ip address
static byte gwip[] = { 172,16,1,2 };
// mac
static byte mymac[] = { 0x70,0x69,0x69,0x2D,0x30,0x03 };

byte Ethernet::buffer[500]; // send and receive buffer

// initialization of the servos - pin 10 is used by the Ethernetshield
Servo Servo1;  // Servo 1 on pin 3
Servo Servo2;  // Servo 2 on Pin 4  
Servo Servo3;  // Servo 3 on Pin 5
Servo Servo4;  // Servo 4 on Pin 6


//callback that prints received packets to the serial port
void udpSerialPrint(word port, byte ip[4], const char *data, word len) {
  
  char command[4];      // commandstring
  unsigned int vnumber; // the value as integer
  
  if (len > 0) {
        
          command[0]=data[0];
          command[1]=data[1];
          command[2]=data[2];
          command[3]='\0';
          
          vnumber = atoi(&data[3]); // convert to integer
    
    // this part converts the command to hardware
    if (String(command) == "SR1")
    {
      Servo1.write(vnumber);
    }

    if (String(command) == "SR2")
    {
      Servo2.write(vnumber);
    }

    if (String(command) == "SR3")
    {
      Servo3.write(vnumber);
    }
    
    if (String(command) == "SR4")
    {
      Servo4.write(vnumber);
    }

  }
}

void setup(){
  Serial.begin(9600);
  Serial.println("\n[backSoon]");

  if (ether.begin(sizeof Ethernet::buffer, mymac, 10) == 0)
    {Serial.println( "Failed to access Ethernet controller"); };

  Serial.println("ether begin ok");

  ether.staticSetup(myip, gwip);

  Serial.println("static ip set");

  //register udpSerialPrint() to port 8888
  ether.udpServerListenOnPort(&udpSerialPrint, 8888);
  
  Servo1.attach(3);  // Servo 1 on pin 3
  Servo2.attach(4);  // Servo 2 on Pin 4
  Servo3.attach(5);  // Servo 3 on Pin 5
  Servo4.attach(6);  // Servo 4 on Pin 6
  Servo1.write(65);
  Servo2.write(65);
  Servo3.write(65);
  Servo4.write(65);

  Serial.println("setup ok");
}

void loop(){
  //this must be called for ethercard functions to work.
  ether.packetLoop(ether.packetReceive());
}

Other things I have tried:

  • using different servos (so it’s not the servo)
  • using a pro mini board (so it’s not the uno board)
  • different ENC28J60 modules (so it’s not the module)
  • powering from a 9v power adapter
  • powering from USB only from the laptop running on batteries (so it’s not unstable current or something)
  • using the servos with plain example code for servos.

Any insight or tips of other things I can try to pinpoint this is greatly appreciated! I am hoping something is obvious in my code, as I’m not a very experienced coder…

Cheers!

Hi gorgon

How are you supplying power to the servos?

Regards

Ray

Hackscribble: How are you supplying power to the servos?

Hi Ray,

With the Pro Mini I power them from a 5v, 1A power supply, which also powers the Pro Mini. The issue is still there when only one servo is connected. I have measured the ampere pull and it is sufficient.

With the Uno I power just one servo from the 5v pin on the board.

    // this part converts the command to hardware
    if (String(command) == "SR1")

The comment should say // This part pisses away resources unnecessarily

Quit pissing away resources:

if(strcmp(command, "SR1") == 0)

PaulS: The comment should say // This part pisses away resources unnecessarily

Haha! Thanks, I made the change (to the code, not the comment ;)), but it did not change the behavior though :/

  if (len > 0) {
        
          command[0]=data[0];
          command[1]=data[1];
          command[2]=data[2];
          command[3]='\0';
          
          vnumber = atoi(&data[3]); // convert to integer

If the array was NULL terminated, it wouldn't be necessary to pass the length. If the array is not NULL terminated, you should not be using atoi() to process (part of) it.

Suppose len is 2. What are you doing with this code, then? Is that reasonable?

Hi Paul,

hm, you suggested using atoi in this context in this thread http://forum.arduino.cc/index.php?topic=235019.msg1691170#msg1691170. My knowledge on this is limited, what should I use to process the incoming UPD packet instead of atoi? Do you think that this could be the problem?

I have now boiled down the code to the only necessary parts, and only one servo:

#include <EtherCard.h>
#include <IPAddress.h>
#include <Servo.h>

static byte myip[] = { 172,16,1,153 };
static byte mymac[] = { 0x70,0x69,0x69,0x2D,0x30,0x04 };
// gateway ip
static byte gwip[] = { 172,16,1,2 };

byte Ethernet::buffer[500]; // tcp/ip send and receive buffer

Servo Servo1;

//callback that prints received packets to the serial port
void udpSerialPrint(word port, byte ip[4], const char *data, word len) {

}

void setup(){
  ether.begin(sizeof Ethernet::buffer, mymac, 10);
  ether.staticSetup(myip, gwip);
  //register udpSerialPrint() to port 8888
  ether.udpServerListenOnPort(&udpSerialPrint, 8888);
  
  Servo1.attach(3);  // Servo 1 on pin 3
  Servo1.write(62);

}

void loop(){
  //this must be called for ethercard functions to work.
  ether.packetLoop(ether.packetReceive());
}
  • The servo twitches when sending any values to the ip address.
  • When set to of these values (7, 18, 26, 37, 54, 62, 68, 73, 81, 92, 103, 111, 117, 122, 147, 153, 158, 166) the servo will stay twitching even when not receiving any packets over UDP. On other values it remains still unless I send it any values.

Edit: and still if I comment out
ether.packetLoop(ether.packetReceive());
in void loop(), the twitching stops.

After reading this topic http://forum.arduino.cc/index.php?topic=235765.0 it seems probable that the Ethercard library is obstructing the Servo lib from updating the servo, or that there is a fault in the Servo library.

Any ideas? Am I asking in the right forum?

cheers,
g

After more research I started to suspect that the Ethercard library was using the same timer as the Servo library so I tried the ServoTimer2 library which uses a different timer, but the twitch was still there.

Then I tried the UIPEthernet library and the problem was not there. So this is for sure something with the Ethercard lib.

I have a problem with dropouts, latency and loosing connection with the UIPEthernet lib, so I would much prefer to use Ethercard. Anyone know where to go from here?