Controlling a Servo?

Hello all!

I need help and insight to design a way to control several servo's through the Arduino chip. I found this code and it's been quite useful to me. The code allows me to input numbers 0-9 through the Serial Monitor and moves the servo (unless I've completely misunderstood the code, which I most likely did :P). However it doesn't seem to allow me to control more than servo. What I'm aiming at is getting a setup that would control several servo's individually, but just like how the posted code did (Pressing 0-9 and moving the servo to a certain positions. My programming skills are horrifying (in the bad way), so any suggestions or help would be fantastic.

Thanks,

Frank

Additional notes:

  • I'm using Arduino Uno, software: Arduino 0022
  • I'm using a Futaba S3115 Micro Precision Servo
    Futaba S3115 Servo Specifications and Reviews
  • I'm currently using the Arduino's 5v port to power the Servo
  • I have tried to use an external power supply, but it makes the Servo unresponsive.
    The external power supply outputted about 5v as well
  • OS: Windows 7
/* Servo Motors
 * ------------
 *
 * This program controls 2 servo motors through sending commands over
 * the serial port. The motors will be connected to pins 2 and 3. It
 * motors will be controlled with a single byte. The first nibble will
 * control the motor, while the second will control the postion. Thus
 * each motor will have 16 positions.
 *
 *
 * (cleft) 2006 David Cuartielles for K3, Sweden
 * http://www.arduino.cc
 *
 * @idea: T. Igoe, J. Gray
 * @code: T. Igoe, J. Gray, D. Cuartielles
 * @PD patch: D. Cuartielles
 *
 */

int servoPinL = 2; // Control pin for servo motor - L
int servoPinR = 3; // Control pin for servo motor - R
int pulseL = 0; // Amount to pulse the servoL
int pulseR = 0; // Amount to pulse the servoR
int delayValueMax = 20000; // the 2 millisecond maxiumum pulse range for the servo
int delayValue = 20000; // the actual value the code should wait,  determined later
int analogValue = 0; // the value returned from the analog sensor
int analogPin = 0; // the analog pin that the sensor's on
char c, servoNumber, servoValue;

void setup(void)
{
  pinMode(servoPinL, OUTPUT); // Set servo pins as an output pins
  pinMode(servoPinR, OUTPUT);
  pulseL = 1000; // Set the motor position values to the minimum
  pulseR = 1000;
  Serial.begin(9600);
}

void loop(void)
{
  c = Serial.read();
  if (c != -1)
  {
    servoNumber = (c & 0xF0) >> 4; // servo ID is in high nibble
    servoValue = (c & 0x0F); // servo angle is in low nibble
    if (servoNumber%2 == 0) pulseL = (servoValue*62) + 1000; // make a pulse 1000-2000 us
    else if (servoNumber%2 == 1) pulseR = (servoValue*62) + 1000; //  make a pulse 1000-2000 us
    // print values on the screen
    // for a terminal window
    //printString("\n\r Numer: ");
    //printInteger(servoNumber%2);
    //printString(" - Value: ");
    //printInteger(servoValue);
    // print values on the screen
    // for debugging in PD
    Serial.write(c);
  }

  digitalWrite(servoPinL, HIGH); // Turn the L motor on
  delayMicroseconds(pulseL); // Length of the pulse sets the motor position
  digitalWrite(servoPinL, LOW); // Turn the L motor off

  digitalWrite(servoPinR, HIGH); // Turn the R motor on
  delayMicroseconds(pulseR); // Length of the pulse sets the motor  position
  digitalWrite(servoPinR, LOW); // Turn the R motor off

  delayValue = delayValueMax - pulseL - pulseR; // determine how   much time you have before the 20 ms is over...
  delayMicroseconds(delayValue); // 20 millisecond delay is needed between pulses to keep the servos in sync
}

Here's where I found the Code:

http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1149088829:

I have tried to use an external power supply, but it makes the Servo unresponsive.
The external power supply outputted about 5v as well

You need to connect the ground of the external supply to the ground of the arduino.

You need to send two numbers, the first one gives the servo number and the second the position.

Much obliged for the quick response Grumpy :wink:

You need to connect the ground of the external supply to the ground of the arduino.

Worked successfully

You need to send two numbers, the first one gives the servo number and the second the position.

Correct me if I'm wrong, but should I be using the Serial monitor to input the numbers? I've tried entering in two numbers on the same line like "39", "35", or with a space in between like "2 1", but both motors move into the last corresponding digit. For example when I input "38" both servos move to position 8.

False alarm on the fix (I removed the post) :~

The original code is posted now, and now only one motor is responding to commands (on PIN 3).

Franky that servo code is over five years old. The servo library that is distributed with Arduino can control up to 12 servos on a standard board. This is a test sketch you can use to control any of the servos attached:

/*
 * Servo serial tester
 *
 * Command a servo by entering a numeric value for the angle followed by a letter to identify the servo
 * where 'a' is the first servo, 'b' the second and so on
 * '*' commands all servos
 * '+' sweeps all servos in one direction and '-' sweeps then in the other direction
 */
 
#include <Servo.h> 

const int NBR_SERVOS = MAX_SERVOS;       // the number of servos, up to 48 for Mega, 12 for other boards
const int FIRST_SERVO_PIN = 2;

Servo Servos[NBR_SERVOS] ; // max servos is 48 for mega, 12 for other boards

void setup() 
{ 
  Serial.begin(9600); 
  for(int i=0; i < NBR_SERVOS; i++)  
    Servos[i].attach(FIRST_SERVO_PIN +i);  
    
  delay(2000);  
  Serial.print(" Initialized ");  
  Serial.print(NBR_SERVOS,DEC);      
  Serial.println(" Servos");
} 


void loop()
{
  static int pos = 0;

  if ( Serial.available())
  {
    char ch = Serial.read();

    if(ch >= '0' && ch <= '9')              // is ch a number?  
      pos = pos * 10 + ch - '0';           // yes, accumulate the value
    else if(ch >= 'a' && ch <= 'a'+  NBR_SERVOS) // is ch a letter for one of our servos?
    {
      Servos[ch - 'a'].write(pos);         // yes, save the position in the position array   
      pos = 0;
      int channel =  ch - 'a';
      int  angle = Servos[channel].read();
      Serial.print("Servo on pin "); 
      Serial.print(FIRST_SERVO_PIN + channel, DEC);
      Serial.print(": angle = ");  
      Serial.println(angle,DEC);  
    }
    else if (ch == '*')
    {
      // position all the servos
      for(int i=0; i < NBR_SERVOS; i++)
        Servos[i].write(pos);         
      pos = 0;      
    }
    else if (ch == '+')
    {
      // sweep all servos from 0 to 180
      for(int angle = 0;angle < 180; )
      {
        for(int i=0; i < NBR_SERVOS; i++)
        {
          Servos[i].write(angle);            
        }
        Serial.print("Angle = ");
        Serial.println(angle,DEC); 
        ++angle; 

        delay(20);
      }
      pos = 0;      
    }
    else if (ch == '-')
    {
      // sweep all servos from 180 to 0
      for(int angle = 180;angle >= 0; )
      {
        for(int i=0; i < NBR_SERVOS; i++)
        {
          Servos[i].write(angle);                
        }
        angle = Servos[0].read();   
        Serial.print("Angle = ");
        Serial.println(angle,DEC); 
        --angle; 
        delay(20);
      }
      pos = 0;      
    }
  }
}

If the servos don't work, check that you have the grounds connected correctly and are suppllying enough power for all the servos.

5 years old!? :astonished:

Your code worked perfectly mem, thank you so much! Is it possible to macro angle commands or write up something in your code that would allow me to macro angle positions for the servo's? Just like the sweep function that was included?

-Frank

you can use the writeMicroseconds() method to get greater precision. see Servo - Arduino Reference

Awesome, thank you very much mem

-Frank