servo positioning

Hello everyone - I'm new here so first I'd like to introduce myself.

My name is Nick - I'm an architecture graduate student using physical computing to investigate interactive spaces and responsive materials and how they apply to architectural concepts and future construction methods.

Ok my question - I'm building a little prototype and will eventually need 18 servos running independently responding to various analog input -

right now I just need to move one, or two motors to three specific locations - min, middle , and max. I'm using a simple potentiometer and 180 degree servos.
I've gotten the servo to run alongside of the potentiometer, but I'd rather see it only move when specific values are hit (eg, potentiometer is at midway - the servo runs from min to mid rotation and stops)

heres some code that doesn't seem to work.... nothing moves! I was hoping you guys could share some insight to maybe illuminate things I may be doing incorrectly - as well as possibly offer places to get some source code that works so I could manipulate it and learn more of arduino coding - I'm new to the platform! Cheers and thanks in advance!

int servoPin = 12; // Control pin for servo motor
int minPulse = 500; // Minimum servo position
int maxPulse = 2500; // Maximum servo position
int pulse = 0; // Amount to pulse the servo
int analogValue = 0;
int analogPin = 2;
int myVar = 0;

void newline(void);
void pulsout( int servoPin, int pulse);
void turnServo(int angle);

void setup() {
pinMode(servoPin, OUTPUT); // Set servo pin as an output pin
pulse = minPulse; // Set the motor position value to the minimum
beginSerial(9600);
}

void loop() {

// read analog input from 'analogPin'
analogValue = analogRead(analogPin);
// calculate the input relative to the input range and angle range
myVar = (analogValue * 180)/1023;
// change the analog reading to the wanted range (between 500 to 2500)
//myVar = minPulse + (analogValue * 2);
turnServo( myVar );
// turn servo to the 50 degrees mark

turnServo(50);
delay(500);
turnServo(5);
delay(500);
turnServo(150);
delay(500);
turnServo(5);
delay(500);
turnServo(20);
delay(500);
turnServo(90);
delay(500);

}

// brings servo motor to the wanted angle (between 0 to 180 degrees)
void turnServo(int angle) {
int i;

// this loop is done in order to turn the servo motor to the wanted angle
for( i=1; i;)

pulse = (i*2500)/180;

pulse += 500+((2000/180)*i);

pulsout( servoPin, pulse);

}

void pulsout( int servoPin, int pulse) {

digitalWrite(servoPin, HIGH); // Turn the motor on
delayMicroseconds(pulse); // Length of the pulse sets the motor position
digitalWrite(servoPin, LOW); // Turn the motor off
delay(20); // 20 millisecond delay is needed between pulses

}

// newline function -> prints out new line (\n) as well as a carriage return (\c);
void newline() {
printNewline();
printByte(13);
}

// this loop is done in order to turn the servo motor to the wanted angle 

for( i=1; i;)

pulse = (i*2500)/180;

pulse += 500+((2000/180)*i);

pulsout( servoPin, pulse);

Not sure what you are trying to do here, but if my math is correct, no matter what the inputs to this function your pulsewidth will be 525. IIRC, that's a bit low - I think my 180degree servos are centered at 2000, with extremes at about 1500 and 2500. Someone with more servo experience can jump in here and correct me if I'm wrong.

That for loop doesn't really do anything = replace it with i = 1; and you'll accomplish the same thing.

Servos don't have to be "walked" to the correct position; if you want it to go to a particular position, just send the appropriate pulsewidth until it gets there.

Here is some code I wrote when learning about servos. It starts out trying to roughly center the servo, then reads + and - characters from the serial port, and adjusts the servo in increments up or down accordingly.

#define SERVO 2
#define MIN_PULSE 1000
#define MAX_PULSE 2500
#define DELTA 10

void setup()
{
  int i;
  pinMode(SERVO, OUTPUT);
  digitalWrite(SERVO, LOW);
  Serial.begin(9600);
  for (i=0; i<300; i++)
  {
    digitalWrite(SERVO, HIGH);
    delayMicroseconds((MIN_PULSE + MAX_PULSE)/2);
    digitalWrite(SERVO, LOW);
    delay(10);
  }
  Serial.println("servo should be at center");

  delay(100);
}

void loop()
{
  int i, c;
  static int pulse_width = (MIN_PULSE + MAX_PULSE)/2;

  if (Serial.available())
  {
      c = Serial.read();
      if ((c == '+') || (c == '='))
      {
        pulse_width+=DELTA;
        if (pulse_width > MAX_PULSE) pulse_width = MAX_PULSE;
        Serial.print('+', BYTE);
        Serial.println(pulse_width, DEC);
      }
      else if (c == '-')
      {
        pulse_width-=DELTA;
        if (pulse_width < MIN_PULSE) pulse_width = MIN_PULSE;
        Serial.print(c, BYTE);
        Serial.println(pulse_width, DEC);
      }
      else
      {
        Serial.print("Error: ");
        Serial.println(c, BYTE);
      }

  }
  
  for (i=0; i<10; i++)
  {
      digitalWrite(SERVO, HIGH);
      delayMicroseconds(pulse_width);
      digitalWrite(SERVO, LOW);
      delay(10);
  }
}

As far as running 18 servos, The arduino only has 13 digital pins (and two of those are used for the serial port). If you only need to run one at a time you can use a multiplexer to select which servo you're driving, then send the output pulses. It would be a bit more work to interleave the pulses to various servos.

hope this helps. It'll at least give you something to read until the servo experts show up. :slight_smile:

-j

great reply - I really appreciate it.

I'll dig a bit deeper into the code you supplied to see if I can get something started - thanks again for the info!

ok so the much easier way to do what I needed to do was to simply send a specific pulse to determine the servo location - I now know its pretty easy to translate that into degrees that servo is moving.

the code - slightly modified version of Tom Igoe's
pretty simple stuff

int servoPin = 13;     
//int servoPin1 = 12;
int minPulse = 500;   
int maxPulse = 2500;  
int pulse = 0;       

// the time in milliseconds of last pulse
int lastPulse = 0;   
int refreshTime = 20; 

int analogValue = 0;  
int analogPin = 2;    

void setup() {
  pinMode(servoPin, OUTPUT);  
//  pinMode(servoPin1, OUTPUT);
  pulse = minPulse;           
  Serial.begin(9600);
}

void loop() {
  analogValue = analogRead(analogPin);   
  
  // length of pulse determines the servo position
  if (analogValue <= 50) pulse = minPulse;
  //if (analogValue >= 21 && analogValue <= 499) pulse = 0;
  if (analogValue >= 500 && analogValue <= 550) pulse = 1500;
  //if (analogValue >= 551 && analogValue <= 999) pulse = 0;
  if (analogValue >= 1000 && analogValue <= 1023) pulse = maxPulse;
  
  // for continuous motion alongside of potentiomter
  //pulse = (analogValue / 10) * 19 + 500;

  //Serial.print(minPulse, DEC);
  //Serial.print(maxPulse, DEC);
  Serial.println(analogValue, DEC);  
  

  // pulse the servo again if rhe refresh time (20 ms) have passed:
  if (millis() - lastPulse >= refreshTime) {
    digitalWrite(servoPin, HIGH);   
    digitalWrite(servoPin1, HIGH);
    delayMicroseconds(pulse);      
    digitalWrite(servoPin, LOW);    
    digitalWrite(servoPin1, LOW);
    // save the time of the last pulse
    lastPulse = millis();          
  }
}