MeArm gripper servo stops working after a while

Hi,
I connected the four MeArm (Turnigy TG9e) servos to the Arduino board using pins 6, 9, 10, and 11 as shown in the MeArm instructions.
The Arduino board is powered by USB and the servos are powered using a 6V power supply with 3A.

I wrote a program to generate smooth position profiles to output to the servos. The Arduino main program (mearm.ino) connects the USB serial I/O and the servo output to the rest of the code:

#include <Servo.h>
#include "../calibration.hh"
#include "../controller.hh"
#include "../curve.hh"

class Controller: public ControllerBase
{
public:
  Controller(void) {}
  void setup(void) {
    for (int drive=0; drive<DRIVES; drive++)
      m_servo[drive].attach(SERVOPIN[drive]);
  }
  int offset(int drive) { return OFFSET[drive]; }
  float resolution(int drive) { return RESOLUTION[drive]; }
  int lower(int drive) { return MIN[drive]; }
  int upper(int drive) { return MAX[drive]; }
  void reportTime(void) {
    Serial.print(millis());
    Serial.write("\r\n");
  }
  void reportAngle(float angle) {
    Serial.print(angle);
    Serial.write("\r\n");
  }
  void reportPWM(float pwm) {
    Serial.print(round(pwm));
    Serial.write("\r\n");
  }
  void writePWM(int drive, int pwm) {
    m_servo[drive].writeMicroseconds(pwm);
  }
protected:
  Servo m_servo[DRIVES];
};

unsigned long t0;

Controller controller;

void setup() {
  controller.setup();
  Serial.begin(9600);
  t0 = millis();
}

void loop() {
  int dt = millis() - t0;
  if (Serial.available())
    controller.parseChar(Serial.read());
  if (dt >= 20) {
    controller.update(dt);
    t0 += dt;
  };
}

Each call to the method "controller.update(dt)" causes the "writePWM" method to be called once for each servo. The servo to pin mappings and calibration values are specified in calibration.hh:

// BASE, SHOULDER, ELBOW, GRIPPER
const int SERVOPIN[] = {11, 9, 10, 6};
const int OFFSET[] = {1380, 1357, 1589, 1327};// normally around 1500

const int MIN[] = {544, 856, 544, 544};// must not be below 544
const int MAX[] = {2400, 2246, 1786, 2022};// must not be above 2400

const float RESOLUTION[] = {11.12222, 11.12222, 9.8888, 15.44444};
const float BOUND = 0.000015;

The other files (controller.hh and curve.hh) only contain platform-independent code for parsing user input and interpolating curves for the servos.

Everything works fine except after some time (ca. 15 minutes) the gripper servo will suddenly jerk and stop moving (not shown in the video above). The other servos continue to work. After power cycling the Arduino board, controlling the gripper works again. I wonder whether anybody can help? Has anybody experienced similar issues?

The full source code repository is here: GitHub - wedesoft/arduino-mearm: Arduino MeArm USB-serial terminal using Vim-like shortcuts.

arduino-mearm.zip (13 KB)

To get people to look at your code, try posting it per #7 below:

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

Ok, I have added the relevant part of the code. Maybe it's also worth mentioning that I am using an Arduino Diecimila.

Another thing: I am using the Debian Jessie "arduino-core" package and it looks like Servo.cpp has changed quite a bit since then. Maybe I should try a more recent version of the Arduino software?

What version of Arduino is it? We're up to v 1.6.6 (I recommend 1.6.5r5, 1.6.6 has a few new regressions), and there really are some significant changes since the 1.0.x versions. Make sure whatever version you're using, everyone knows which version of the servo library you're using - otherwise we will incorrectly diagnose the problem.

Debian Jessie comes with (patched) Arduino version 1.0.5.
The content of Servo.cpp file matches this one: https://raw.githubusercontent.com/arduino/Arduino/1.0.5/libraries/Servo/Servo.cpp.

Actually the AVR version of Servo.cpp only seems to have minor changes.
The 1.6.5r5 version looks almost exactly the same: Arduino/Servo.cpp at 1.6.5-r5 · arduino/Arduino · GitHub

Another thing I could try is using another pin for the gripper servo.

Ok, I have added the relevant part of the code.

If you don't know where/what the problem is, then how do you know that what you posted contains the issue? Most likely a memory issue in the code somewhere.

Well, I have attached all the files. It's not a big project. The logic is tested using GoogleTest. Also the serial USB feedback shows that the values passed to the servo library are correct. If I would know more, I probably wouldn't need to ask for help in this forum :wink:

Why couldn't you post the sketch like you were asked - not many people are going to
fiddle with .zip files.

One obvious fault is here:

unsigned long t0;

...

void loop() {
  int dt = millis() - t0;
  if (Serial.available())
    controller.parseChar(Serial.read());
  if (dt >= 20) {
    controller.update(dt);
    t0 += dt;
  };
}

Your handling of timestamps is all whacky. t0 is 32 bit and t1 is 16 bit, so after a while the comparison
can never succeed.

What are you trying to do? Run a task every 20ms? If so this is the correct way:

unsigned long last_time = millis () ;
unsigned long last_actual_time = last_time ;

...
void loop ()
{
  if (Serial.available())
    controller.parseChar(Serial.read());
  unsigned long now = millis () ;
  if (now - last_time >= 20)   // always subtract two times before compare
  {
    controller.update (now - last_actual_time) ;  // pass in the dt value
    last_actual_time = now ;
    last_time += 20 ;    // schedule at fixed intervals
  }
}

I updated my initial post with the sketch (instead of replying).
I installed Arduino 1.6.5-r5 and I'll let you know if I encounter issues again. So far the robot was working 20 minutes without problem. Regarding using "unsigned long" variables for the time, I didn't manage to create a failing test.