Multiple servos attached to one pin

Hi
Just a quick question.
I am wondering if it is ok to have more than one servo attached to the same pin at thte same time as long as only one servo is trying to read or write to the servo.
Reason being is that in my sketch I have a calibration area to set end pionts of all my servos and what I have done is make a servo object called CalibrationServo so that I can attach and detach it to differant pins, this allows me to save a lot on code since you cannot have a servo object that has a variable name (or at least that I know)
So I was wondering if I would need to detach all my servos when I entered the calibration mode (other than CalibrationServo) and then detach CalibrationServo and reattach all other servos at the start of my void loop with something like

void loop(){
if(digitalRead(Setup)==LOW){  //Callibration mode not entered
  CalibrationServo.detach();  //detach the servo object used for Calibration
  //attach all other servos here
}
while{(digitalRead(Setup)==HIGH){  
//Detach all servos
//attach CalibrationServo
//Callibration code here
(digitalRead(Setup);
} 
}

Or if this is not needed.
The calibration area is a while loop so no servo other than CalibrationServo is active here.

Hope the question makes sense.

grantastley:
Hope the question makes sense.

Not without posting your code, it doesn't. And a diagram showing how you are connecting your servos to your board.

Simple question is can I have more than one servo object attached to one output pin at a time without having any negative effects?
ie

servo1.attach(3);
servo2.attach(3);

Servos are attached to the board on all available pwm pins and there is one extra servo object in the sketch CalibrationServo which only exists in the code and attaches itself to which ever servo is being calibrateds pin.

If I cant then I will detach all of them then reattch all of them when entering and exiting the while loop.

Thought it was a bit of a generic question which does not really relate to my code.

I will work on cutting and pasting relevant code when I get home. Then will past it here.

Here is the code

//**************************
//         Liberies
//**************************
#include <Servo.h>  //include servo libery
#include <EEPROM.h> //Allow to read and write to EEPROM 

//Include liberies for LCD screen
#include <Wire.h> 
#include <LiquidCrystal_I2C.h>
    LiquidCrystal_I2C lcd(0x27,20,4);  //Set LCD address to 0x27 for 20 chars and 4 lines
//**************************


//**************************
//   Set Servos Objects
//**************************
//Landing gear
Servo RightGear;      //Pin 6
Servo LeftGear;       //Pin 7
Servo RightDoor;      //Pin 8
Servo LeftDoor;       //Pin 9
Servo TailGear;       //Pin 10
Servo TailDoor;       //Pin 11
Servo Brake;          //Pin 12

//WingFold
Servo WingFoldLeft;   //Pin 2
Servo WingFoldRight;  //Pin 3
Servo WingLock;       //Pin 4
Servo Canopy;         //Pin 5

//Thermo
Servo Cowl;           //Pin 13
Servo OilCooler;      //Pin 44

//Engine
Servo Imob;           //Pin 45
Servo Choke;          //Pin 46
//**************************

void setup(){
//********Servos**********
RightGear.attach(6);      //Pin 6
LeftGear.attach(7);       //Pin 7
RightDoor.attach(8);      //Pin 8
LeftDoor.attach(9);       //Pin 9
TailGear.attach(10);      //Pin 10
TailDoor.attach(11);      //Pin 11
Brake.attach(12);         //Pin 12
//WingFold
WingFoldLeft.attach(2);   //Pin 2
WingFoldRight.attach(3);  //Pin 3
WingLock.attach(4);       //Pin 4
//Thermo
Cowl.attach(13);           //Pin 13
OilCooler.attach(44);      //Pin 44
//Engine
Imob.attach(45);           //Pin 45
Choke.attach(46);          //Pin 46
//Canopy
Canopy.attach(5);         //Pin 5
}

void loop(){
if(digitalRead(Setup)==HIGH) Callibrate();
}

void Callibrate(){
  SetupVal=digitalRead(Setup);
  
//Set other variables
unsigned long  AcceptTimer=0;
const unsigned long AcceptTimerVal=3000; //Set timer to 3 seconds

boolean FirstAccept=true;
boolean FirstLowMap=true;
boolean FirstUpperMap=true;
boolean FirstTime=true;

int InitialTrimVal=0;
int LowerMap=0;
int UpperMap=0;

String Title1;
String Title2;

int Val;
int ValE;
int Pin;

Servo CallibrationServo;  //"Virtual" Callibration Servo
  
  while(SetupVal==HIGH){
    digitalWrite(CallibrateLED, HIGH);  //Turn on callibratiomnm LED

//Wing Fold
// Setup left wing lower end limit variables
if(WingFoldSetupVal==HIGH&&digitalRead(SetTrim1)==HIGH){
  Pin=digitalRead(SetTrim1);
  Val=LeftLowerTrimVal;
  ValE=LeftLowerTrimValE;
  CallibrationServo.detach();
  CallibrationServo.attach(2);
  Title1="  Wing Fold Setup   ";
  Title2="Left wing lower lim ";  
}

// Setup left wing upper end limit variables
if(WingFoldSetupVal==HIGH&&digitalRead(SetTrim2)==HIGH){
  Pin=digitalRead(SetTrim2);
  Val=LeftUpperTrimVal;
  ValE=LeftUpperTrimValE;
  CallibrationServo.detach();
  CallibrationServo.attach(2);  
  Title1="  Wing Fold Setup   ";
  Title2="Left wing upper lim ";
}

while(Pin==HIGH){
  
  //LCD Screen prints
  lcd.setCursor(0,0);
  lcd.print(Title2);
  lcd.setCursor(0,1);
  lcd.print("Current value = ");
  lcd.setCursor(17,1);
  lcd.print(ValE);
  lcd.setCursor(0,2);
  lcd.print("New value     = ");
  // value set at upper and lowwer maps
  lcd.setCursor(0,3);
  lcd.print("Press OK to Accept  ");
  
  //Timer
  if((millis()-AcceptTimer)>=AcceptTimerVal){   //reset timer once accept is pressed (AcceptTimer=milis())
    if(FirstAccept==true){       //Accept button pressed
      FirstLowMap=true;          //Reset FirstLowMap
      FirstUpperMap=true;        //Reset FirstUpperMap
      InitialTrimVal=TrimVal;    //Setup something to compare values to
      CallibrationServo.write(Val);          //write servo to current lower trim value stored in EEPROM
      FirstAccept=false;         //reset FirstAccept when accept button is pressed.
    }
  }
  
  AcceptVal=digitalRead(Accept);  //Read the digital input 9 - Accept  
  TrimVal=analogRead(Trims);      //Read the trim pot value
  Val=EEPROM.read(ValE);          //Read the EEPROM value for a particular servo end point

  //Only allow to happen once.
  if(FirstTime==true){
    InitialTrimVal=TrimVal;        //Setup something to compare values to
    CallibrationServo.write(Val);  //write servo to current lower trim value stored in EEPROM
    FirstTime=false;               //prevent initial trim and servo write from happening again
  }
  
  LowerMap=map(TrimVal, 0,InitialTrimVal, 0, Val);      //Map from 0 to the current trim pot value and current servo location (Lower end)
  LowerMap=constrain(LowerMap, 0, 90);                  //Constrain the mapped value
  
  UpperMap=map(TrimVal, InitialTrimVal, 1023, Val, 90); //Map from 90 to the curretn trim pot value and current servo location (Upper end)
  UpperMap=constrain(UpperMap, 0, 90);                  //Constrain the mapped value

  //use the lower map if the initial trim value is larger then the current trim value (pot has been turnd down and input is less)
  if (InitialTrimVal>TrimVal&&FirstLowMap==true){  
    CallibrationServo.write(LowerMap);    //Move servo to current LowerMaped position
    lcd.setCursor(17,2);
    lcd.print(LowerMap);
    
    //need to only happen once
    if(FirstLowMap==true){              //FirstLowMap has happened 
      if(AcceptVal==HIGH){              //Accept button pressed
        
        lcd.clear();
        lcd.setCursor(0,0);
        lcd.print(Title2);
        lcd.setCursor(0,1);
        lcd.print("Value changed       ");
        lcd.setCursor(0,2);
        lcd.print("New value = ");
        lcd.setCursor(13,2);
        lcd.print(LowerMap);
        
        EEPROM.write(ValE, LowerMap);   //Store new value in EEPROM
        FirstLowMap=false;              //Block FirstLowMap
        FirstAccept=true;               //Reset FirstAccept flag
        AcceptTimer=millis();           //Reset AcceptTimer
        
        delay(2000); //Allow time to read LCD screen
      }
    }
  }
  
  //use the upper map if the initial trim value is less then the current trim value (pot has been turnd up and input is more)
  if (InitialTrimVal<TrimVal&&FirstUpperMap==true){ 
    CallibrationServo.write(UpperMap);    //Move servo to current UpperMap location
    lcd.setCursor(17,2);
    lcd.print(UpperMap);
    
    //need to only happen once 
    if(FirstUpperMap==true){              //FirstUperMap has happened
      if(AcceptVal==HIGH){                //Accept button pressed
        
        lcd.clear();
        lcd.setCursor(0,0);
        lcd.print(Title2);
        lcd.setCursor(0,1);
        lcd.print("Value changed       ");
        lcd.setCursor(0,2);
        lcd.print("New value = ");
        lcd.setCursor(13,2);
        lcd.print(UpperMap);
        
        EEPROM.write(ValE, UpperMap);     //Store new value in EEPROM
        FirstUpperMap=false;              //Block FristUpperMap
        FirstAccept=true;                 //Reset FirstAccept flag
        AcceptTimer=millis();             //Reset AcceptTimer
        
        delay(2000);    //Allow time to read LCD screen
      }
    }
  }

Pin;        //Check to see if setup selections conditions have changed
delay(500); //allow time for servo to move to new location
}//End of Common trim setup
SetupVal=digitalRead(Setup);
}//End of Setup
}//End of Void Callibrate

The only issue I can foresee is if the two software objects fight each other, in their code, for control of the physical servo. This has nothing to do with a calibration servo object and 'ordinary' servo object, just as your most recent example shows.

Say, in the loop() servo1 is trying to send the servo to one end of its travel and then servo2 is trying to send it to the other...

Given that you have to write the code once for a calibrating function perhaps you could add that has a method to the servo object and then any servo object can be set into calibration 'mode/function'.

This strikes me as the more expected interpretation of a requirements analysis of your system... same object but with additional functionality and hence a new method. Deriving a CalibrationServo class from Servo still wouldn't be the best decision (in this case) because how to link it to the servo has to be made in your code and then your code would/could become clumsy dealing with the differences when looping through all servos.

It looks like your approach is to use a 'manager object'. This is valid but once again the only issue would be to ensure that the software objects don't fight over the physical object's control.

I would consider having calibration method in the servo object and the 'Calibration Manager' orchestrating the calibration activity but letting the servo object(s) actually do the calibrating.

the only issue would be to ensure that the software objects don't fight over the physical object's control.

I would have thought that this could not happen as the Calibration is done inside a while loop and hence all other code stops until the loop ends.
However in this code if SetTim1 was set high and SetTrim2 was accidently set high there would be a problem I think. Is there a way to "interlock" inputs (only allow one input out of a range of inputs to be high at a time) with code?

I would consider having calibration method in the servo object and the 'Calibration Manager' orchestrating the calibration activity but letting the servo object(s) actually do the calibrating.

Not quiet sure how to do this?

The only issue I can foresee is if the two software objects fight each other, in their code, for control of the physical servo. This has nothing to do with a calibration servo object and 'ordinary' servo object, just as your most recent example shows.

That is what I thought, so what I am doing should work?

Code wise I think it should work. Note I have not studied every inch of your code.

The suggestions I make are more for elegance and subsequent support (probably by yourself!). Perhaps the difference between getting a system running on a breadboard with jumpers and then moving to a PCB solution.

If you want to find out more about object oriented design and implementation you can find books that deal with this subject but you have to look further than C++ coding... that's the equivalent of thinking that because you know the alphabet you know the words... and the stories...

"Patterns" is a good keyword to use with "object orientation" for searching

Thank you for your help. I will study up on object orientated design, however it does seem like it may be a bit over my head at the moment. I am always willing and wanting to learn more though :slight_smile:
I think I will finish the code with the current direction do some tests and then go from there.

I would have thought that this could not happen as the Calibration is done inside a while loop and hence all other code stops until the loop ends.

Behind the scenes, the servo library is sending commands to any attached servo every 20ms. In consequence, your calibration servo will be fighting with any servo it's sharing a pin with.

wildbill:

I would have thought that this could not happen as the Calibration is done inside a while loop and hence all other code stops until the loop ends.

Behind the scenes, the servo library is sending commands to any attached servo every 20ms. In consequence, your calibration servo will be fighting with any servo it's sharing a pin with.

If that's the case then you may have to reappraise your use of objects and this code.

Interesting looking inside the servo library as it appears to be using timers... and I bet you thought like I did that something simpler was going on. Great the way objects can hide so much complexity but of course its a double edged sword :frowning:

Also the SoftwareServo library has that magic 20ms in it Arduino Playground - HomePage

This may shed some light on what the timer code in the Servo library is doing. http://blog.zipwhip.com/2012/03/28/manual-control-of-a-servo-on-the-arduino-for-the-zipwhip-textspresso-machine/ in addition to some background reading on servos in general as opposed to the Arduino based stuff which is nearly all based on the supplied servo library. I've found it very interesting

Doing it all yourself would be a hard hack so I suggest working with the Servo library. Perhaps make your own class up that embeds a servo object for each of your own objects or derive from Servo and avoid having two sources of command for the same servo.