Servo motors unwanted movement

Hi everyone,

I'm doing this project of controlling a camera and servos via a cellular shield (SM5100B).
All look to work fine except of one problem, my servo motors move even when I don't send them any command.

For example:
When sending command to turn on the LED, both motors move a little ,
Or when taking a photo they shake until the photo fully transfered to the SD card.

How can I prevent this unwanted movement?

I have attached the circuit, and can attach the code if needed.

Try to power the devices by separate power sources. The 5V on-board regulator may be overloaded by so many consumers.
Also add capacitors to the consumers, to stabilize the supplied power.

You need an external power supply for the servos (6v is better than 5v) with the arduino and servo power supply grounds connected.

I tried to add separate power supply for the servos and it didn't helped, same behavior as before.

Is there any meaning in adding the capacitors for stabilization? (If I understand right it's to prevent power surges).

Maybe it's better to connect a capacitor in some way to the digital pin controlling the servo?

any more suggestions?

Post your code.

And describe in more detail what you mean by unwanted movement, including when it occurs.

...R

// 
#include <Adafruit_VC0706.h>
#include <SPI.h>
#include <SD.h>
#include <Servo.h> 
#include <SoftwareSerial.h>
#include <SerialGSM.h>

#define chipSelect 10

char inchar; //Will hold the incoming character from the Serial Port.
SoftwareSerial cell(2,3); //Create a 'fake' serial port. Pin 2 is the Rx pin, pin 3 is the Tx pin.
SoftwareSerial cameraconnection = SoftwareSerial(4, 5);  
//SerialGSM cell(2,3);

Servo servoUD; // Define Servos
Servo servoRL; // UD-Up/Down, RL-Right/Left 

Adafruit_VC0706 cam = Adafruit_VC0706(&cameraconnection);

int led1 = 7;

void setup()
{
  servoUD.attach(8); // servos on digital pins 8,9
  servoRL.attach(9);
  
 // prepare the digital output pins
 pinMode(led1, OUTPUT);
 digitalWrite(led1, LOW);

 // When using hardware SPI, the SS pin MUST be set to an
 // output (even if not connected or used).  If left as a
 // floating input w/SPI on, this can cause lockuppage.
#if !defined(SOFTWARE_SPI)
 if(chipSelect != 10) pinMode(10, OUTPUT); // SS on Uno, etc.
#endif

  Serial.begin(9600);
  
   // check if the SD card is present and can be initialized:
 if (!SD.begin(chipSelect)) {
   Serial.println("Card failed, or not present");
   // don't do anything more:
   return;
 }  

 // Locate the camera
 if (cam.begin()) {
    Serial.println("Camera Found:");
 } else {
   Serial.println("No camera found?");
   return;
 }

 // Set the picture size:
 //cam.setImageSize(VC0706_640x480);        // biggest
 cam.setImageSize(VC0706_320x240);        // medium
 //cam.setImageSize(VC0706_160x120);          // small
 
 //cell2.begin(9600);
 //delay(60000);
 
  //Initialize GSM module serial port for communication.
 cell.begin(9600);
 delay(30000); // give time for GSM module to register on network etc.
 cell.println("AT+CMGF=1"); // set SMS mode to text
 delay(200);
 cell.println("AT+CNMI=3,3,0,0"); // set module to send SMS data to serial out upon receipt 
 delay(200); 
 Serial.println("Servo,Camera and GSM Initialized");

 digitalWrite(led1, HIGH);  //ready to go
 delay(2000);
 digitalWrite(led1, LOW);
}

void loop() 
{
 //If a character comes in from the cellular module...
 if(cell.available() >0)
 {
   inchar=cell.read();
   Serial.print(inchar);
   if (inchar=='#')
   {
     delay(10);
     inchar=cell.read();
     switch (inchar)
     {
       case 'L':
         delay(10);
         Serial.print("L");
         inchar=cell.read();
         if (inchar=='0')
         {
           Serial.println("0- LED off");
           digitalWrite(led1, LOW);
         } 
         else if (inchar=='1')
         {
           Serial.println("1- LED on");
           digitalWrite(led1, HIGH);
         }
         break;
       
       case 'V':
         delay(10);
         Serial.print("V");
         inchar=cell.read();
         switch (inchar)
         {
            case '0':
              Serial.println("0- Go Down");
              servoUD.write(160);   // Go Down  
              break;
            case '1':
              Serial.println("1- Go Center");
              servoUD.write(100);     // Go Center
              break;
            case '2':
              Serial.println("2- Go Up");
              servoUD.write(40);     // Go Up
              break;
         }
         break;
       
       case 'H':
         delay(10);
         Serial.print("H");
         inchar=cell.read();
         switch (inchar)
         {
            case '0':
              Serial.println("0- Go Left");
              servoRL.write(20);   // Go Left
              break;
            
            case '1':
              Serial.println("1- Go Center");
              servoRL.write(90);     // Go Center
              break;
            
            case '2':
              Serial.println("2- Go Right");
              servoRL.write(160);     // Go Right
              break; 
         }
         break;
         
         case 'S':
             delay(10);
             Serial.print("S");
             inchar=cell.read();
     
             switch (inchar)
             {
                case '1':
                  Serial.println("1- Take Snapshot:");
                   cam.begin();
                   Serial.println("Snap in 2 sec...");
                   delay(1000);
                   
                   digitalWrite(led1, HIGH);  //ready to go
                   delay(1000);
                   digitalWrite(led1, LOW);
                   
                   if (! cam.takePicture()) 
                     Serial.println("Failed to snap!");
                   else 
                     Serial.println("Picture taken!");
                   
                   // Create an image with the name IMAGExx.JPG
                   char filename[13];
                   strcpy(filename, "IMAGE00.JPG");
                   for (int i = 0; i < 100; i++) {
                     filename[5] = '0' + i/10;
                     filename[6] = '0' + i%10;
                     // create if does not exist, do not open existing, write, sync after write
                     if (! SD.exists(filename)) {
                       break;
                     }
                   }
                   
                   // Open the file for writing
                   File imgFile = SD.open(filename, FILE_WRITE);
                 
                   // Get the size of the image (frame) taken  
                   uint16_t jpglen = cam.frameLength();
                   Serial.print("Storing ");
                   Serial.print(jpglen, DEC);
                   Serial.print(" byte image.");
                 
                   int32_t time = millis();
                   // Read all the data up to # bytes!
                   byte wCount = 0; // For counting # of writes
                   while (jpglen > 0) {
                     // read 32 bytes at a time;
                     uint8_t *buffer;
                     uint8_t bytesToRead = min(32, jpglen); // change 32 to 64 for a speedup but may not work with all setups!
                     buffer = cam.readPicture(bytesToRead);
                     imgFile.write(buffer, bytesToRead);
                     if(++wCount >= 64) { // Every 2K, give a little feedback so it doesn't appear locked up
                       Serial.print('.');
                       wCount = 0;
                     }
                     jpglen -= bytesToRead;
                   }
                   imgFile.close();
                 
                   time = millis() - time;
                   Serial.println("done!");
                   Serial.print(time); Serial.println(" ms elapsed");
                   
                   cam.resumeVideo();
                   
                   digitalWrite(led1, HIGH);  
                   delay(2000);
                   digitalWrite(led1, LOW); 
                   
                   cell.begin(9600);
                   break;
                 }     
             break;

     }
     cell.println("AT+CMGD=1,4"); // delete all SMS 
     Serial.println("SMS Deleted");
   }  
 }
}

I have uploaded a video to youtube showing what happens:

I'ts bad quality, but you can see there few examples:

  1. Sending "#L1", LED turns on as expected and the motor move.
  2. Sending "#L0", LED turns off as expected and the motor move.
  3. Sending "#S1", taking a snapshot and as long as the transfer of the photo goes the motors moving again.

Please --- read How to use the Forum and put your long code into code tags. Use the '</>' button.

Code should look like this

Help us to help you.

Almost certainly you want to get rid of the delay()s and use millis() to manage timing without blocking as illustrated in several things at a time.

...R

Simple servo test code you can try to see if the servo is stable with this code..

//zoomkat 7-30-10 serial servo test
//type servo position 0 to 180 in serial monitor
// Powering a servo from the arduino usually *DOES NOT WORK*.

String readString;
#include <Servo.h> 
Servo myservo;  // create servo object to control a servo 

void setup() {
  Serial.begin(9600);
  myservo.attach(9);
  Serial.println("servo-test"); // so I can keep track of what is loaded
}

void loop() {

  while (Serial.available()) {
    char c = Serial.read();  //gets one byte from serial buffer
    readString += c; //makes the String readString
    delay(2);  //slow looping to allow buffer to fill with next character
  }

  if (readString.length() >0) {
    Serial.println(readString);  //so you can see the captured String 
    int n = readString.toInt();  //convert readString into a number
    Serial.println(n); //so you can see the integer
    myservo.write(n);
    readString="";
  } 
}

Robin2:
Almost certainly you want to get rid of the delay()s and use millis() to manage timing without blocking as illustrated in several things at a time.

Robin2, Before I change all my code :), are you sure it's something that can help?
I think i'm asking just for one action at a time (depand on the case), and only when it finish I go back to the beggining of the loop to read another SMS.

zoomkat:
Simple servo test code you can try to see if the servo is stable with this code..

The servos are stable. I have checked each part separately before i combined them.

MaxGrin:
Robin2, Before I change all my code :), are you sure it's something that can help?

I did not mean that it was the cause of (or solution to) your problem. But it is not good practice to use delay() because it blocks the Arduino from doing anything else during the delay period.

It may be that the Adafruit library interferes with the Servo library - unfortunately that is not uncommon in the Arduino world. For example the Servo library does not work alongside SoftwareSerial. You might like to try the ServoTimer2 library - but note that it does everything in microseconds,

...R

I tried using the ServoTimer2 library, the servos behave different but still move unfortunately.

I thought of few possible solutions:

  • Using Arduino Mega (maybe another timer, more pins to move the camera/servos to)
  • Somehow to define the Servos just before using them and then to undifine. (if possible).

Please let me know what you think.

You could certainly try detach()ing the servo - but then it may wiggle when you attach() it again

I don't know whether the extra resources in a Mega could make a difference. Maybe you could rewrite the SevoTimer2 library to use a different Timer.

You have a lot of libraries and you will have to find a solution where they all work nicely together. Perhaps you can modify your code in a series of steps to see which of them does not agree with ServoTimer2 ?

Post your latest code.

...R

Hi,

I tried to add separate power supply for the servos and it didn't helped, same behavior as before.

So you have gone back to using the arduino supply for the servos have you?

As said earlier they draw more current than the arduino 5V regulator or USB supply can maintain.

So before you do anything else, have you got your servos on their own supply and are the servo supply and arduino gnds connected together?

Tom...... :slight_smile:

I don't know if detaching is the smartest move, but it simple and it worked.
(and of course a separate power supply).

Big thank you to everyone who helped!

An attached servo receives the last position command every 20ms as a consequence of the way the library works, and that's the common way to control a servo. The purpose of that is to hold a loaded servo in the right position. The attached pic shows a 'scope trace for a servo commanded to 1500ms (nominally 90 degrees).

If it was moving while attached, that to me means that the load on the servo was moving it away from the commanded position, and the next pulse pulled it back.

If it's now detached, there's nothing to hold the servo in the desired position....

servo attached.jpg