How to add simple Servo code from a Tutorial?

Newcomer looking for debugging help from veterans: I'm adding a bit of servo code to an existing program and getting an error I don't understand.

I've got a simple Simon Says game up and running. Now I'd like it to 'unlock' a box by operating a servo after correct input. So I've taken code from Tutorial 12 (Knock Lock) and added it, but I get this error:

libraries/Tone/Tone.cpp.o (symbol from plugin): In function timer0_toggle_count': (.text+0x0): multiple definition of __vector_11'
libraries/Servo/avr/Servo.cpp.o (symbol from plugin):(.text+0x0): first defined here
collect2: error: ld returned 1 exit status
exit status 1

This is my first time importing two libraries. Is that allowed? The error seems to come from my adding this:

// import the library
#include <Servo.h>
// create an instance of the Servo library
Servo myServo;

Or is there a conflict between the Tone and Servo libraries, and if so, how should I go about fixing that?

The remaining code doesn't seem to be the problem, though I can't be sure since the above error keeps me from running it. Here's what I've added:

under void setup(), I added

// attach the servo to pin 9
myServo.attach(9);
// move the servo to the locked position
myServo.write(90);
// print status to the Serial Monitor
Serial.println("the box is locked!");

then under void loop(), if the correct sequence is entered, there's already a 'cheer' sound, and then I added

delay(5000);  // allow time for person to acually Open the door
     // move the servo to the unlocked position
  myServo.write(0);
  // print out status
  Serial.println("the box is unlocked!");
  
    // move the servo to the locked position, returning to its original state
  myServo.write(90);
  // print out status
  Serial.println("the box is locked!");

Is it the Library that's causing me trouble? Where should I debug?

Thanks!

That means that two different pieces of code are trying to use the same interrupt. In your case, the Tone function and the Servo library are both using the Timer1 hardware. You have to find an alternative for one or the other that DOESN'T use Timer1.

Thanks. Out of curiosity, how did you know that's a Timer1 problem?

And on a practical level, how do I change that? I don't see a Servo library file, probably because it comes with the main installation, but I do see in the .cpp file for Tone that there are references for Timer1 through Timer5.

Hmmm.... There are a lot of lines using timer1, and it may be beyond me at this time to edit them all without introducing new errors. Maybe there's a way to get a different Servo library? What else should I consider?

Because the same problem comes up here about once a week.

Many libraries that use timers, have a #define (preprocessor command) to select which timer to use. Have a look for that in both libraries, probably in the .h file.

I'm new and doing the best I can. I did search the forums, but I didn't spot relevant threads, despite the promising title of ones like these
https://forum.arduino.cc/t/exit-status-1-error-compiling-for-board-arduino-uno/881269
https://forum.arduino.cc/t/multiple-definition-of-vector11/868971

As for fixing the problem, I don't see Timer defined in the .h file for Tone, though I do see dozens of lines of code that use it in the .cpp (for Tone - I don't see the files for Servo). Is that something a beginner can fix, or is there another approach?

Servo.h is not part of the core. It's a built-in library so you will find it in one of the 'libraries' folders.

It's not your fault - resource allocation in this environment is mostly ad hoc. I'll have a look at those...

I'm curious about where they are where. My search results say on a Mac that they're in user/Documents/Arduino/libraries, but the only thing there is the Tone library I added. The default files don't seem to be hidden, so perhaps they're someplace else. Scanning my HD for 'Servo' and looking at the package contents of the Arduino application don't reveal the location.

Still, on a practical level, I still wouldn't know what to do with the the Servo.h file, or even if altering it is the way to go. As a complete beginner, I don't have the experience to know if I could or should rename the timer variables, or change a definition in the main code, or use a different library, or accomplish the same movement without the Servo library, or any other alternative.

I just want to add six lines of code from one program to another (opening, closing, and delaying servo movement), and I'm stumped by the library conflict. I simply don't have the experience to solve this particular problem. If you have any guidance on fixing it, I'd sure appreciate it.

Do you mean, "more guidance"? Thing is, it is what it is. Here is where the Servo library chooses a timer:
https://github.com/arduino-libraries/Servo/blob/master/src/avr/ServoTimers.h
Tone may use multiple timers because different timers are physically associated with different pins.

There is a topic that introduced ServoTimer2 as a countermeasure to use Timer1 with two libraries a while ago, so I will link it.

1 Like

The original libraries are inside the Arduino app. Control-click on the app and select "Show Package Contents". Then Contents/Java/libraries/Servo.

I keep the "Java" folder in my Finder sidebar, along with Documents/Arduino (the sketchbook) and Documents/Arduino/libraries (the 3rd-party libraries I've installed).

If you install an update, some libraries are found in:
/Users/username/Library/Arduino15/packages/arduino/hardware/avr/1.8.3/libraries

For different (non AVR) platforms the libraries will be found under the platform, like /Users/username/Library/Arduino15/packages/esp32/hardware/esp32/1.0.6/libraries

Thanks. Glad to know where it is.

Whoa.

Ah, that's great - thanks. I'll see if I can get that running.

It has frustrated me before, too. Anyone who has played around with a great enough variety of peripherals will encounter it soon. But it is sort of "baked" into the paradigm now so it's hard to fix retroactively (in a way that old sketches would still work). It happens that many sketches like yours have no technical reason not to run, the CPU and Compiler have no problem with it. It's because the libraries are not coordinated. They've been written by thousands of people. System resources have often been a best guess usually based on a standard architecture, the AVR. To be fair, how can so many people coordinate on resources when there is no particular standard or built in resource allocation system (beyond simple stuff like maybe refusing to open a serial port that is in use? IDK).

I've seen systems (OS9 to reveal my age) that keep resources like serial ports, timers, whatevers in a table, and allow tasks to obtain and release ownership of them. Not only that, but dynamically, i.e. in real time. Theoretically for the Arduino it might be possible to use a similar allocation table, so that application B can use any resources that application A did not request and use up, for example. So in this case, Tone and Servo could share a pool of timers along with every other library. It could be just first come, first served for simplicity. Locked in at compile time as well, so there is no run time resource allocation code. But the entire thing is hypothetical, there is a lot of horizontal integration in the Arduino core, but there is almost no resource allocation, flexible and easy at least. Not for this common situation. One obstacle to such an approach is making it processor independent. That implies a possible need for a HAL, hardware abstraction layer. But there is always a trade off in Arduino between something effective, but technically complex or verbose, and something simple and easy to understand and use. That is because it is meant to encourage beginners.

It's also community behaviour because so much library code is written by third party developers. Perhaps because either there are people who can really figure out how to do it by analyzing the code and docs, or because there are other solutions like using two processors, the problem hasn't been really front burner. I know this may seem unhelpful, but it's hard to solve. In fairness, many library authors try to add provisions for co-existence with unknown second processes, for example the IR library I looked at, had one line that chooses a timer to use. Very easy to adapt.

I might be getting there. I'm a little fried - this has been a lot of hours, starting well before I posted here - and maybe I'm overlooking something simple.

The ServoTimer2 library that Chris linked lets the program upload - yay! But the Servo doesn't move.

Since I can get it to move using the Example code in the ServoTimer2 library, it looks like a problem in the code, rather than a mechanical problem. The strange thing is that I can get that same code to work in the alternative route I took before Chris posted that link, a Silent Simon Says game: I took out the Tone library and speaker instructions, so the game runs only with lights. The servo then works fine with the original Servo library.

That same code does nothing in the new version with the Tone and ServoTimer2 libraries. So either it isn't really the same, meaning I missed something despite checking it line by line, or the ServoTimer2 library changes the way instructions should be given to the servo.

I wondered if the time scale is different for ServoTimer2, and that was previously a 4s delay was now crazy long, but dropping the delay to 10 didn't change anything. I then tried comparing the Servo and ServoTimer2 libraries, but the differences are beyond me at this stage.

It's not that many lines of code that I've added, and they're straight from the Arduino Tutorial:

// import the library
#include <ServoTimer2.h>
// create an instance of the Servo library
ServoTimer2 myServo;

void setup()
{
   // attach the servo to pin 9
  myServo.attach(9);
 // move the servo to the locked position
  myServo.write(100);

  // print status to the Serial Monitor
  Serial.println("the box is locked!");

void loop()  // This 'loop' is automatically ran repeatedly
{
    if (turn==OPEN_CNT) {
      Serial.println("\n Simon Says Open the Lock ");
      playCheer();
      delay(500);  //  short gap between victory display and door opening

         // move the servo to the unlocked position
      myServo.write(0);
      delay(4000);  // allow time for person to actually Open the door
    
      // print out status
      Serial.println("the box is unlocked!");

        // move the servo to the locked position
      myServo.write(100);

      // print out status
      Serial.println("the box is locked!");
      

Is that enough to spot an error? I'm just trying to add five lines of code! (That's three server instructions and two timer delays, not counting loading the library files and the Print instructions copied from the Tutorial).

If I need to understand every line in the library files, it may be quite awhile before I'm able to do this. I'm really trying to do a beginner project, and this sure looked simpler than it turned out to be.

Did you read all the content of that topic?

Especially in the latter half.

I did, but I didn't catch the significance of the second part. Thanks for pointing me to the right spot.

For any other newcomers struggling with this, see Chris' 8th post in that thread, which reads

That info isn't in the documentation with the Servo2 library, at least not that I've found, and I hope it helps anyone else using this.

But my servo still doesn't move.

It does move when I use my 'Silent' program (no Tone library or speaker, Servo1 library), so the servo motor and connection appear good. I'm using the code Chris posted, with the change of Servo1 to myServo (matching the term in the tutorial):

#include <ServoTimer2.h>
// create an instance of the Servo library
ServoTimer2 myServo;

and, under void setup

   // attach the servo to pin 9
  myServo.attach(9);
 // move the servo to the locked position
  myServo.write(map(0, 0, 180, MIN_PULSE_WIDTH, MAX_PULSE_WIDTH));
  delay(500);

and under void loop

      myServo.write(map(90, 0, 180, MIN_PULSE_WIDTH, MAX_PULSE_WIDTH));
      delay(4000);  // allow time for person to actually Open the door

I've tried 180 under the map function, and different delay times, and I keep going over the code, but I don't see what causes the trouble. What am I missing?

I’m gonna assume you meant OS-9, the one that came between OS/9 and OS 9. :expressionless:

a7

I can't tell what you're doing from tiny code fragments but ServoTimer2 write() uses microseconds NOT angles. So the equivalent of 0-180 is 544-2400.

Steve

I'll put the whole code below. I thought it would be easier if I posted the parts giving me trouble, but in case I missed something, it's all below.

As I read Chris' code, using the map function as listed converts to microseconds, but in case there was something there I misunderstood, I tried doing it with your figures (though other threads suggest 1000 and 2000 for 0 and 180?). Now the servo moves for the first step to 'lock.' Thanks!

So where I'm stuck is the second servo movement, to 'unlock.' Is there a mistake in my code?

if (turn==OPEN_CNT) {
      // CODE FOR SERVO OPEN
      Serial.println("\n Simon Says Open the Lock ");
      playCheer();

         // move the servo to the unlocked position
      myServo.write(2000);
      delay(4000);  // allow time for person to actually Open the door
    
      // print out status
      Serial.println("the box is unlocked!");

      
      // CODE FOR SERVO RETURN TO NORMAL STATE
        // move the servo to the locked position
      myServo.write(1000);
       delay(500);

      // print out status
      Serial.println("the box is locked!");
      
      Serial.println(" Re-Close ");
      wait4nextBtn = true;
    }

Full code here:

#include "Tone.h"

const int OPEN_CNT = 4;
Tone speaker;
byte speakerPin = 8; // D14 is aka A0, speaker was on pin 13
int starttune[] = {NOTE_C4, NOTE_F4, NOTE_C4, NOTE_F4, NOTE_C4, NOTE_F4, NOTE_C4, NOTE_F4, NOTE_G4, NOTE_F4, NOTE_E4, NOTE_F4, NOTE_G4};
int duration2[] = {100, 200, 100, 200, 100, 400, 100, 100, 100, 100, 200, 100, 500};
int cheer[] = {NOTE_C4, NOTE_C4, NOTE_G4, NOTE_C5, NOTE_G4, NOTE_C5};
int btnNote[] = {NOTE_G3, NOTE_A3, NOTE_B3, NOTE_C4};
int duration[] = {100, 100, 100, 300, 100, 300};
//boolean button[] = {2, 3, 4, 5}; //The four button input pins
//boolean ledpin[] = {8, 9, 10, 11};  // LED pins
int button[] = {15, 16, 17, 18}; //The four button input pins
int ledpin[] = {2, 3, 4, 5};  // LED pins
int turn = 0;  // turn counter
int buttonstate = 0;  // button state checker
int randomArray[100]; //Intentionally long to store up to 100 inputs (doubtful anyone will get this far)
int inputArray[100];
bool wait4nextBtn = true;

// import the library
#include <ServoTimer2.h>
// create an instance of the Servo library
ServoTimer2 myServo;

// ===================================================
void setup()
{
  int note;
  Serial.begin(9600);
  speaker.begin(speakerPin);

  // SERVO SETUP
   // attach the servo to pin 9
  myServo.attach(9);
  // INITIALIZATION SERVO TO CLOSED
 // move the servo to the locked position
  myServo.write(1000);
  delay(500);

  // print status to the Serial Monitor
  Serial.println("the box is locked!");

  for (int x = 0; x < 4; x++) // LED pins are outputs
  {
    pinMode(ledpin[x], OUTPUT);
    pinMode(button[x], INPUT);  // button pins are inputs
    digitalWrite(button[x], HIGH);  // enable internal pullup; buttons start in high position; logic reversed
  }

  randomSeed(analogRead(0)); //Added to generate "more randomness" with the randomArray for the output function
  for (int thisNote = 6; thisNote < 11; thisNote ++) {
    // play the next note:
    note = starttune[thisNote];
    speaker.play(note);
    if (note == NOTE_C4)      digitalWrite(ledpin[0], HIGH);
    else if (note == NOTE_F4) digitalWrite(ledpin[1], HIGH);
    else if (note == NOTE_G4) digitalWrite(ledpin[2], HIGH);
    else if (note == NOTE_E4) digitalWrite(ledpin[3], HIGH);

    // hold the note:
    delay(duration2[thisNote]);
    // stop for the next note:
    speaker.stop();
    allLEDs(LOW);
    delay(25);
  }
  delay(1000);
}

// ========================================================
void loop()  // This 'loop' is automatically run repeatedly
{
  for (int level = 0; level <= 99; level++)
  {
    allLEDs(LOW);
    
    Serial.print("\n Turn: ");   // Some serial output to follow along
    Serial.print(turn);

    if (turn==OPEN_CNT) {
      // CODE FOR SERVO OPEN
      Serial.println("\n Simon Says Open the Lock ");
      playCheer();
      delay(500);  // brief pause before unlocking


       // move the servo to the unlocked position
  myServo.write(1800);
  delay(10);
    
      // print out status
      Serial.println("The box is unlocked!");
      delay(5000);  // allow time for person to actually Open the door
      
      // CODE FOR SERVO RETURN TO NORMAL STATE
        // move the servo to the locked position
      myServo.write(1000);

      // print out status
      Serial.println("The box is locked!");
  
      wait4nextBtn = true;
    }
    
    if (wait4nextBtn) {
      wait4nextBtn = false;
      bool btnPushed = false;
      while (! btnPushed) { // wait for a key-press before starting all over
        for (int y = 0; y < 4; y++)
        { if (digitalRead(button[y]) == LOW) //Checking for button push
          btnPushed = true; 
        }
      }
      turn = -1; //Reset turn value so the game starts over
      exit;
    }
    
    // fill up the array to be matched by the player
    randomArray[turn] = random(1, 5); //Assigning a random number (1-4) to the randomArray[turn count]
    Serial.print("  Rand#: ");
    Serial.println(randomArray[turn]);

    for (int x = 0; x <= turn; x++)
    {
      Serial.print(randomArray[x]);
      byte btn = randomArray[x];  // logical button/led # (1-4)
      digitalWrite(ledpin[btn - 1], HIGH);
      speaker.play(btnNote[btn - 1], 100);
      delay(400);
      digitalWrite(ledpin[btn - 1], LOW);
      delay(100);
    }
    input();
  }
}

// ===================================================
//            local functions

void input() { //Function for allowing user input and checking input against the generated array
  bool btnPushed;

  for (int x = 0; x <= turn; x++)
  { // for each one in the current sequence wait for a button to be pushed 
    // if it is the correct one we keep looping through the sequence

    btnPushed = false;
    while (! btnPushed) {
      for (int y = 0; y < 4; y++)
      {
        buttonstate = digitalRead(button[y]);
        byte btn = y + 1; // logical button # (1-4)

        if (buttonstate == LOW)  //Checking for button push
        {
          btnPushed = true;
          digitalWrite(ledpin[y], HIGH);
          speaker.play(btnNote[btn - 1], 100);
          delay(100);  // insures minimum LED illumination
          inputArray[x] = btn;
          Serial.print("  btn pushed: ");
          Serial.print(btn);
// was a poor way to allow for button release:         delay(250);
          wait_BtnRelease();  // much better this way
          digitalWrite(ledpin[y], LOW);
          if (inputArray[x] != randomArray[x]) { //Checks value input by user and checks it against
            fail();                              //the value in the same spot on the generated array
            //The fail function is called if it does not match
            exit;
          }
        }
      }
    }  // end while
  }
  delay(500);
  turn++; //Increments the turn count, also the last action before starting the output function over again
}

// ------------------------------------------------------
void playCheer() { //Function used if the player fails to match the sequence
    allLEDs(HIGH);

    for (int thisNote = 0; thisNote < 6; thisNote ++) {
      // play the next note:
      speaker.play(cheer[thisNote]);
      // hold the note:
      delay(duration[thisNote]);
      // stop for the next note:
      speaker.stop();
      delay(25);
    }

    allLEDs(LOW);
    delay(1000);
}

void fail() { //Function used if the player fails to match the sequence

  for (int y = 0; y <= 2; y++)
  { //Flashes lights for failure
    allLEDs(HIGH);
    speaker.play(NOTE_G3, 300);
    delay(200);
    allLEDs(LOW);
    speaker.play(NOTE_C3, 300);
    delay(200);
          // print out status
  }
       Serial.println("\n Oops!");
  delay(500);
  turn = -1; //Resets turn value so the game starts over without need for a reset button
}

// ------------------------------------------------------
void allLEDs(byte state) {
  digitalWrite(ledpin[0], state);
  digitalWrite(ledpin[1], state);
  digitalWrite(ledpin[2], state);
  digitalWrite(ledpin[3], state);
}

void wait_BtnRelease() {
  bool btnStillDown;
  int debounce=0; // need depends on button used. mine caused some double trips
    while (debounce<2) {
      delay(5);
      btnStillDown = false;
      for (int y = 0; y < 4; y++)
      {
        buttonstate = digitalRead(button[y]);
        if (buttonstate == LOW)  //Checking for button push
          btnStillDown = true;
      }
      if (btnStillDown) debounce=0;
      else debounce++;
    }
}

Servo.write() takes 0 to 180. Servo.writeMicroseconds() takes 1000 to 2000.