Help with multiple servos



  • I'm hoping someone can nudge me in the right direction. I'm struggling to understand how to make the servo controller sketch control multiple servos, individually. I have added 'for' loops - modeled after the "relay controller" sketch - to get the controller to see the different servos. The node and gw are communicating, and the controller (Domoticz) sees and wants to command 3 servos, but only 1 pin responds.

    I'm sure its the 'void receive' part of the code but I'm stuck trying to get the myservo.attach(?????) part right.

    Any help is greatly appreciated! Heres the sketch:

    / Enable debug prints to serial monitor
    #define MY_DEBUG 
    #define MY_RF24_CE_PIN 49
    #define MY_RF24_CS_PIN 53
    #define MY_RF24_IRQ_PIN 2
    #define MY_RF24_PA_LEVEL RF24_PA_LOW
    // Enable and select radio type attached
    #define MY_RADIO_RF24
    //#define MY_RADIO_RFM69
    
    #include <MySensors.h>
    #include <Servo.h> 
    
    #define SERVO_DIGITAL_OUT_PIN 39
    #define NUMBER_OF_SERVOS 3 
    #define SERVO_MIN 0 // Fine tune your servos min. 0-180
    #define SERVO_MAX 180  // Fine tune your servos max. 0-180
    #define DETACH_DELAY 900 // Tune this to let your movement finish before detaching the servo
    #define CHILD_ID 13   // Id of the sensor child
    MyMessage msg(CHILD_ID, V_DIMMER);
    Servo myservo;  // create servo object to control a servo 
                    // a maximum of eight servo objects can be created Sensor gw(9,10);
    unsigned long timeOfLastChange = 0;
    bool attachedServo = false;
    
    void before()
    {
      for (int sensor=1, pin=SERVO_DIGITAL_OUT_PIN; sensor<=NUMBER_OF_SERVOS; sensor++, pin++) {
        // Then set relay pins in output mode
        pinMode(pin, OUTPUT);
      }
    }
    void setup() 
    { 
      for (int sensor=1, pin=SERVO_DIGITAL_OUT_PIN; sensor<=NUMBER_OF_SERVOS; sensor++, pin++) {
      // Request last servo state at startup
      request(CHILD_ID, V_DIMMER);
      }
    } 
    
    void presentation()  {
      // Send the sketch version information to the gateway and Controller
      sendSketchInfo("Servo", "1.0");
    for (int sensor=1, pin=SERVO_DIGITAL_OUT_PIN; sensor<=NUMBER_OF_SERVOS; sensor++, pin++) {
      // Register all sensors to gw (they will be created as child devices)
      present(CHILD_ID, S_COVER);
    }
    }
    
    void loop() 
    { 
      if (attachedServo && millis() - timeOfLastChange > DETACH_DELAY) {
         myservo.detach();
         attachedServo = false;
      }
    } 
    
    void receive(const MyMessage &message) {
      myservo.attach(SERVO_DIGITAL_OUT_PIN);
      attachedServo = true;
    
      if (message.type==V_DIMMER) { // This could be M_ACK_VARIABLE or M_SET_VARIABLE
         int val = message.getInt();
         myservo.write(SERVO_MAX + (SERVO_MIN-SERVO_MAX)/100 * val); // sets the servo position 0-180
         // Write some debug info
         Serial.print("Servo changed. new state: ");
         Serial.println(val);
       } else if (message.type==V_UP) {
         Serial.println("Servo UP command");
         myservo.write(SERVO_MIN);
         send(msg.set(100));
       } else if (message.type==V_DOWN) {
         Serial.println("Servo DOWN command");
         myservo.write(SERVO_MAX); 
         send(msg.set(0));
       } else if (message.type==V_STOP) {
         Serial.println("Servo STOP command");
         myservo.detach();
         attachedServo = false;
    
       }
       timeOfLastChange = millis();
    }
    

  • Hardware Contributor

    @bsmtdweller said in Help with multiple servos:

    myservo.attach(SERVO_DIGITAL_OUT_PIN);
    

    Hello, isn't the problem on this line ? You need to change the pin that will control the wanted servo based on the sensor id in the message.



  • @bsmtdweller

    @Nca78 Has this nailed I think. You need a separate output pin for each servo.

    Also, you need a separate power supply for the servos with the ground connected to the arduio ground. Arduino can not supply enough power from its pins and interference will be an issue if you don't.



  • Thanks @Nca78! Thats exactly it! But how? I dug through the messages.h and found a "getSensor()" command. Prior to discovering that, I went through and re-wrote the code with no arrays hoping that it would simplify my understanding of whats going on. The new code is below. I feel it is close, but I'm still missing something - when a command is received all three servo pins respond, so while I think I have the root of the problem identified I'm struggling with syntax to make it work properly.

    Also thanks to @skywatch for chiming in - I was reading through his 2019 topic with @mfalkvidd - which seems applicable too regarding formatting the 'void receive' function. With such a jumbled, non-array-simplified code, my next step was to try and put chunks together in a separate function and then combine that into the void receive function. My gut tells me that won't help and I better get a more thorough understanding of simplifying with arrays first!

    Another question - I read somewhere that in order to accurately test this, there needs to be physical servos connected? My project where I have the servos installed, it out in the shop, far away from my computer -- so I've been simply testing the output of the pins with my voltmeter during this preliminary testing.

    Heres the non-array written code:

    #define MY_DEBUG
    #define MY_RF24_CE_PIN 49
    #define MY_RF24_CS_PIN 53
    #define MY_RF24_IRQ_PIN 2
    #define MY_RF24_PA_LEVEL RF24_PA_LOW
    // Enable and select radio type attached
    #define MY_RADIO_RF24
    //#define MY_RADIO_RFM69
    
    #include <MySensors.h>
    #include <Servo.h>
    
    #define SERVO_MIN 0
    #define SERVO_MAX 180
    #define DETACH_DELAY 900
    #define CHILD_ID1  13
    #define CHILD_ID2  14
    #define CHILD_ID3  15
    Servo servos1;
    Servo servos2;
    Servo servos3;
    #define servoPin1  39
    #define servoPin2  40
    #define servoPin3  41
    
    MyMessage msg1(CHILD_ID1, V_DIMMER);
    MyMessage msg2(CHILD_ID2, V_DIMMER);
    MyMessage msg3(CHILD_ID3, V_DIMMER);
    
    unsigned long timeOfLastChange = 0;
    bool attachedServo = false;
    
    
    void setup()
    {
      // Request last servo state at startup
    
      request(CHILD_ID1, V_DIMMER);
      request(CHILD_ID2, V_DIMMER);
      request(CHILD_ID3, V_DIMMER);
    
    
    }
    
    
    void presentation()  {
      // Send the sketch version information to the gateway and Controller
      sendSketchInfo("Servo", "1.0");
    
      // Register all sensors to gw (they will be created as child devices)
    
      present(CHILD_ID1, S_COVER);
      present(CHILD_ID2, S_COVER);
      present(CHILD_ID3, S_COVER);
    }
    
    
    void loop()
    {
    
      if (attachedServo && millis() - timeOfLastChange > DETACH_DELAY) {
        servos1.detach();
        servos2.detach();
        servos3.detach();
        attachedServo = false;
    
      }
    }
    
    void receive(const MyMessage &message) {
      Serial.println("   This is the Id of the Message     ");
      Serial.println(message.getSensor());
    
    
      if (message.type == V_DIMMER && message.getSensor() == CHILD_ID1) { // This could be M_ACK_VARIABLE or M_SET_VARIABLE
        servos1.attach(servoPin1);
        int val = message.getInt();
        servos1.write(SERVO_MAX + (SERVO_MIN - SERVO_MAX) / 100 * val); // sets the servo position 0-180
        // Write some debug info
        Serial.print("Servo changed. new state: ");
        Serial.println(val);
      } else if (message.type == V_UP) {
        Serial.println("Servo UP command");
        servos1.write(SERVO_MIN);
        send(msg1.set(100));
      } else if (message.type == V_DOWN) {
        Serial.println("Servo DOWN command");
        servos1.write(SERVO_MAX);
        send(msg1.set(0));
      } else if (message.type == V_STOP) {
        Serial.println("Servo STOP command");
        servos1.detach();
        attachedServo = false;
      }
    
      if (message.type == V_DIMMER && message.getSensor() == CHILD_ID2) { // This could be M_ACK_VARIABLE or M_SET_VARIABLE
        servos2.attach(servoPin2);
        int val = message.getInt();
        servos2.write(SERVO_MAX + (SERVO_MIN - SERVO_MAX) / 100 * val); // sets the servo position 0-180
        // Write some debug info
        Serial.print("Servo changed. new state: ");
        Serial.println(val);
      } else if (message.type == V_UP) {
        Serial.println("Servo UP command");
        servos2.write(SERVO_MIN);
        send(msg2.set(100));
      } else if (message.type == V_DOWN) {
        Serial.println("Servo DOWN command");
        servos2.write(SERVO_MAX);
        send(msg2.set(0));
      } else if (message.type == V_STOP) {
        Serial.println("Servo STOP command");
        servos2.detach();
        attachedServo = false;
      }
    
      if (message.type == V_DIMMER && message.getSensor() == CHILD_ID3) { // This could be M_ACK_VARIABLE or M_SET_VARIABLE
        servos3.attach(servoPin3);
        int val = message.getInt();
        servos3.write(SERVO_MAX + (SERVO_MIN - SERVO_MAX) / 100 * val); // sets the servo position 0-180
        // Write some debug info
        Serial.print("Servo changed. new state: ");
        Serial.println(val);
      } else if (message.type == V_UP) {
        Serial.println("Servo UP command");
        servos3.write(SERVO_MIN);
        send(msg3.set(100));
      } else if (message.type == V_DOWN) {
        Serial.println("Servo DOWN command");
        servos3.write(SERVO_MAX);
        send(msg3.set(0));
      } else if (message.type == V_STOP) {
        Serial.println("Servo STOP command");
        servos3.detach();
        attachedServo = false;
      }
    
      timeOfLastChange = millis();
    
    
    }
    

  • Mod

    @bsmtdweller an alternative to voltmeter could be to hook up a led (with matching resistor) to each servo pin. The led will then light up proportional to the servo signal.



  • Hi @mfalkvidd - thanks! That definitely makes it more fun! I set it up without resistors as the voltages produced on the servo pins are millivolts (hopefully not enough to burn an led). I'm re-working the code again with some arrays and will hopefully be able to report back with success😬



  • I finally got it!! Staring me in the face the whole time! Forgetting the arrays portion, because I still can't figure that out with multiple servos and messages.

    My problem was that in the void receive 'if' conditions, I needed to specify from which child ID - right, we knew that part - but I ALSO needed to add the child ID conditional statement to ALL the 'else if' statements!

    Thanks to everyone for their help!!



  • @bsmtdweller Yay! - You got there - well done and thanks for sharing the knowledge.


Log in to reply
 

Suggested Topics

  • 3
  • 10
  • 4
  • 24
  • 2
  • 3

24
Online

11.2k
Users

11.1k
Topics

112.5k
Posts