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.
//
#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:
Sending "#L1", LED turns on as expected and the motor move.
Sending "#L0", LED turns off as expected and the motor move.
Sending "#S1", taking a snapshot and as long as the transfer of the photo goes the motors moving again.
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,
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 ?
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....