MG995 Contiuous Servo is doing my head in!!

Hi everyone. I don't usually post but I reeally need some advice regarding my MG995 continuous servo. I am building the chicken door opener, which uses photocell to control the servo to open and shut the door at the correct times. I have everything working by writing either 2000 or 1000 microseconds to Pin 7 to control the servo. The Servo will open and close the door without any problem. Then without any apparent reason the servo will decide to spin in the wrong direction. It seems completely random . Sometimes it will do it straight after a reset, other times it will work for a while then go random on me. I suppose my question is whether these servos cans go flaky like this or if there is something else going on. I have the servo powered by a 7805 regulator and the Ardunio is powered by a 7808. I have tested continuity on the GND from the supply right through the regulators, arduino and servo GND. They all buzz out ok.

I have attached my code too, so hopefully someone can see my error......or tell me to buy a new servo! Thanks in advance :)

// pin assignments

const int servoPin = 7;     //Servo connected to pin D7
Servo myServo;              // create servo object to control a servo 
 
// variables
 
 
 
// photocell variables
int photocellRawData;                            // analog reading of the photocel
int photocellLevel;                       // photocel reading levels (dark, twilight, light)
int lastPhotocellLevel;							// variable to hold previous light state for change detection 

unsigned long lastPhotocellRawDataTime = 0;		// photocell reading delay
unsigned long photocellRawDataDelay = 600000;   	//delay between reading sensor (normally 10mins = 600000ms)
 
// switches top and bottom of coop door
 
// top switch variables 
 
int topSwitchPinVal;                   // top switch var for reading the pin status
int topSwitchPinVal2;                  // top switch var for reading the pin delay/debounce status
int topSwitchState;                    // top switch var for to hold the switch state
 
// bottom switch variables
 
int bottomSwitchPinVal;                // bottom switch var for reading the pin status
int bottomSwitchPinVal2;               // bottom switch var for reading the pin delay/debounce status
int bottomSwitchState;                 // bottom switch var for to hold the switch state
 
// debounce delay
unsigned long lastDebounceTime = 0;			//delay to stop switch jitter when being read 
unsigned long debounceDelay = 100;
 
 
 
 
 
// ************************************** setup **************************************
 
void setup(void) {
 
  Serial.begin(9600); // initialize serial port hardware
 
 
  pinMode(servoPin, OUTPUT);                         //setup servo control pin as an output
  

  // coop door leds
  pinMode (coopDoorOpenLed, OUTPUT);                // enable coopDoorOpenLed = output
  pinMode (coopDoorClosedLed, OUTPUT);              // enable coopDoorClosedLed = output
  digitalWrite(coopDoorClosedLed, HIGH);
  digitalWrite(coopDoorOpenLed, HIGH);
 
  // coop door switches								//switches will read 1 when open, 0 when closed/activated 
  // bottom switch
  pinMode(bottomSwitchPin, INPUT);                  // set bottom switch pin as input
  digitalWrite(bottomSwitchPin, HIGH);              // activate bottom switch resistor
 
  // top switch
  pinMode(topSwitchPin, INPUT);                     // set top switch pin as input
  digitalWrite(topSwitchPin, HIGH);                 // activate top switch resistor

//initialise Door to find extremes of movement
 
 
// openCoopDoor();
// closeCoopDoor();
 Serial.println("########END OF MOTOR SETUP######");
Serial.println("Continuing normal operation............");
 
}
 
// operate the coop door
 
// photocell to read levels of exterior light
 
void readPhotocell() { // function to be called repeatedly - per coopPhotoCellTimer set in setup
 
  
 
  if ((unsigned long)(millis() - lastPhotocellRawDataTime) >= photocellRawDataDelay) {
    lastPhotocellRawDataTime = millis();
	photocellRawData = analogRead(photocellPin);
    //  set photocel threshholds
    if (photocellRawData >= 0 && photocellRawData <= 150) {
      photocellLevel = '1';
 
      //if (SerialDisplay) {
        Serial.println(" Photocell Reading Level:");
        Serial.println(" - Dark");
    //  }
    }
    else if (photocellRawData  >= 150 && photocellRawData <= 200) {
      photocellLevel = '2';
     // if (SerialDisplay) {
        Serial.println(" Photocell Reading Level:");
        Serial.println(" - Twilight");
     // }
    }
    else if (photocellRawData  >= 200 ) {
      photocellLevel = '3';
     // if (SerialDisplay) {
        Serial.println(" Photocell Reading Level:");
        Serial.println(" - Light");
     // }
    }
    //if (SerialDisplay) {
      Serial.println(" Photocell Analogue Reading = ");
      Serial.println(photocellRawData);
    //}
  }
}
 
 void checkIfLightChanged(){
 
 if (photocellLevel != lastPhotocellLevel) {
		lastPhotocellLevel = photocellLevel;
		actionCoopDoor();
		}
		 }
 
 // action the coop door
void actionCoopDoor() {
  if (photocellLevel  == '1') {              // if it's dark
    if (photocellLevel != '2') {             // if it's not twilight
      if (photocellLevel != '3') {           // if it's not light
          closeCoopDoor();                      // close the door
      }
    }
  }
  if (photocellLevel  == '3') {              // if it's light
    if (photocellLevel != '2') {             // if it's not twilight
      if (photocellLevel != '1') {           // if it's not dark
       
        openCoopDoor();                       // Open the door
      }
    }
  }
}
 
//debounce bottom reed switch
 
void debounceBottomReedSwitch() {
 
  //debounce bottom reed switch
  bottomSwitchPinVal = digitalRead(bottomSwitchPin);       // read input value and store it in bottomSwitchPinVal
 
  if ((unsigned long)(millis() - lastDebounceTime) > debounceDelay) {    // delay 10ms for consistent readings
 
    bottomSwitchPinVal2 = digitalRead(bottomSwitchPin);    // read input value again to check or bounce
 
    if (bottomSwitchPinVal == bottomSwitchPinVal2) {       // make sure we have 2 consistant readings
      if (bottomSwitchPinVal != bottomSwitchState) {       // the switch state has changed!
        bottomSwitchState = bottomSwitchPinVal;
      }
      //if (SerialDisplay) {
        Serial.print (" Bottom Switch Value: ");           // display "Bottom Switch Value:"
        Serial.println(digitalRead(bottomSwitchPin));      // display current value of bottom switch;
      //}
    }
  }
}
 
 
 
// debounce top reed switch
void debounceTopReedSwitch() {
 
  topSwitchPinVal = digitalRead(topSwitchPin);             // read input value and store it in val
 
  if ((unsigned long)(millis() - lastDebounceTime) > debounceDelay) {     // delay 10ms for consistent readings
 
    topSwitchPinVal2 = digitalRead(topSwitchPin);          // read input value again to check or bounce
 
    if (topSwitchPinVal == topSwitchPinVal2) {             // make sure we have 2 consistant readings
      if (topSwitchPinVal != topSwitchState) {             // the button state has changed!
        topSwitchState = topSwitchPinVal;
      }
      //if (SerialDisplay) {
        Serial.print (" Top Switch Value: ");              // display "Bottom Switch Value:"
        Serial.println(digitalRead(topSwitchPin));         // display current value of bottom switch;
      //}
    }
  }
}
 
 
 

void closeCoopDoor() {
	//debounceTopReedSwitch();                    // read and debounce the switches
    myServo.attach(servoPin);
	delay(15);
	debounceBottomReedSwitch();
    while (bottomSwitchState != 0)
    {
    myServo.writeMicroseconds(1000);  
    delay(15);
	debounceBottomReedSwitch();
    }
  
   
   //if (bottomSwitchPinVal == 0) {                         // if bottom reed switch circuit is closed
    stopCoopDoorServo();
	digitalWrite(coopDoorClosedLed, HIGH);
    digitalWrite(coopDoorOpenLed, LOW);
    //if (SerialDisplay) {
      Serial.println("Coop Door Closed"); 
   // }
  }
 
 
 
// open the coop door 
void openCoopDoor() {
   myServo.attach(servoPin);
   delay(15);
   debounceTopReedSwitch();                    // read and debounce the switches
   //debounceBottomReedSwitch();
   while (topSwitchState != 0)
   {
    myServo.writeMicroseconds(2000);  
    delay(15);
	debounceTopReedSwitch();
   }
	stopCoopDoorServo();
	digitalWrite(coopDoorOpenLed, HIGH);
    digitalWrite(coopDoorClosedLed, LOW);
    //if (SerialDisplay) {
      Serial.println(" Coop Door open!");
    //}
}

 // stop the coop door motor
void stopCoopDoorServo() {
  delay(15);
   //myServo.writeMicroseconds(1500);
   //delay(15);
   myServo.detach();
   delay(15);
  
}

 
void loop() {
  
  readPhotocell();
  checkIfLightChanged(); 
}

You are very generous giving your chickens all that code.

I see several servo.attach() statements. Why not just do that once in setup() ? Servos can misbehave when they are not attached.

Are you sure you are not getting unwanted / unexpected light readings.

...R

Hi Robin, Thanks for your reply. I have thrown a load of serial debugging lines in there to see what is going on. It seems to be calling the correct functions depending on the light level. I have also put in a twilight zone, to make the gap between light and dark even greater where it does not call any further door action. The top and bottom door limit switches also detach the motor as required and hopefully that should only work if it has been called by the correct door action function.

I will be running this whole thing on a car battery so I didnt want the servo continually powered, draining the battery. I thought by detaching the servo after every movement it would save the battery?

I'm so tempted to get this, but am hoping my code or circuit is wrong so i dont have to spend another £15!

http://www.ebay.co.uk/itm/Adafruit-Continuous-Rotation-Servo-/161362104047?pt=LH_DefaultDomain_3&hash=item2591ee4eef

Before spending money make sure that the detach is actually causing the problem. If that was my project I would write a much shorter version just with the minimum necessary to exercise the servo.

If the detach is the problem it may be worth connecting a 4700 ohm resistor between the servo signal wire and GND.

...R

The top and bottom door limit switches also detach the motor as required and hopefully that should only work if it has been called by the correct door action function.

If you are switching the power to the servo on the servo ground wire, the servo may become unstable and possibly internally damaged.

Thanks, Robin, I'll definately try pulling the code out and testing seperately, along with the 4.7K resistor. I am at work but will try later this evening.

Zoomkat. thanks for your reply. The top and bottom limit switched are not directly controlling power to the servo. They are connected to other digital input pins, which are tested seperately while the servo is in action. Once either of the switches is activated the program drops out of the loop and then calls the stopCoopDoorServo(). This then detaches then servo.