Problem using servo and pcm sound

Hi,
I'm building a 'robot bird' project. The robot moves, using an Sg-90 servo, using the Servo.h library, on D5, and makes an audible birdcall. To do the latter I am reading a wav file from an SD reader and then playing it via D9 which connects to a powered speaker using the TMRpcm library. Both the routines work fine alone, but when I try to use both the servo routine fails (it just does nothing). I'm probably doing something stupid and would be grateful for any help.

Best wishes
Chris.

This is the code: (if I comment out the tmrpcm audio calls then the servo works, but when I uncomment them the audio works and the servo does not).

#include <Servo.h>
#include "SD.h"
#include "TMRpcm.h"
#include "SPI.h"
#define SD_ChipSelectPin 10 //connect pin 10 of arduino to cs pin of sd card
int servoPin = 5; //PWM pin that is connected to the servo
int speaker = 9;
int crowData = 0;
int servoAngle = 0;
Servo Servo1;
TMRpcm tmrpcm;

void setup()
{
Servo1.attach(servoPin); //create a servo object
digitalWrite(2, HIGH); // sets LED Green eye ON
Servo1.write(0); //move servo to zero angle
tmrpcm.speakerPin = 9;
Serial.begin(9600);
if (!SD.begin(SD_ChipSelectPin)) // returns 1 if the card is present
{
Serial.println("SD fail");
return;
};
tmrpcm.setVolume(6); //
}
// End of setup

// Main program loop
void loop() {
if (random(1,80) == 1)
{
birdMove();
}
if (random(1,8) == 1)
{
birdblink();
}
if (random(1,50) == 1)
{
birdcall();
}
delay(1000);
}
// End of main program

void birdMove()
{
// Some code to ensure servo is moving - I'll code the real movement later.
// Make servo go to 0 degrees
Servo1.write(0);
delay(1000);
// Make servo go to 90 degrees
Servo1.write(90);
delay(1000);
// Make servo go to 180 degrees
Servo1.write(180);
delay(1000);
}

void birdblink()
{
digitalWrite(2, LOW);
delay(1000);
digitalWrite(2, HIGH);
delay(500);
}

void birdcall()
{
digitalWrite(2, LOW);
digitalWrite(3, HIGH);
tmrpcm.setVolume(6); //
tmrpcm.play("crow1.wav");
delay(1000);
digitalWrite(3, LOW);
digitalWrite(2, HIGH);
}

Both the TMRpcm library and the Servo library use Timer1.

Please Servo library change to the ServoTimer2 library.
Since the servo will be controlled using Timer2, so Timer1 can be use with the TMRpcm library.

Brilliant - that solved the problem.
Many thanks for that - I was getting frustrated :slight_smile:

I spoke too soon.
When I use ServoTimer2.h the servo sets to zero (as instructed in the setup) but it doesn't move after that. The audio works fine.
I just copied the ServoTimer2-master directory to the libraries subdirectory in Arduino - is that how I should have installed it?
Do I need to uninstall the servo library?

Is it possible to paste the latest code after modifying the library here?
Select all of your code in the IDE and select Copy to Forums from the right-click menu.
Code tags are automatically added to make it easier to see.
Many respondents don't read code posted without code tags, like the first post.

Sure - thanks for the heads-up.
Here is the code..

#include <ServoTimer2.h>
#include "SD.h"
#include "TMRpcm.h"
#include "SPI.h"
#define SD_ChipSelectPin 10 //connect pin 4 of arduino to cs pin of sd card
int servoPin = 5; //PWM pin that is connected to the servo 
int speaker = 9;
int crowData = 0;
int servoAngle = 0;
ServoTimer2 Servo1; 
TMRpcm tmrpcm;

void setup() 
{ 
Servo1.attach(servoPin);      //create a servo object
digitalWrite(2, HIGH);  // sets LED Green eye ON
Servo1.write(0);  
tmrpcm.speakerPin = 9;  
Serial.begin(9600);
 if (!SD.begin(SD_ChipSelectPin)) // returns 1 if the card is present
 {
 Serial.println("SD fail");
 return;
 };
tmrpcm.setVolume(6); //
tmrpcm.play("crow1.wav");
}

void loop() { 
if (random(1,8) == 1)
 {
    birdMove();
 }
  if (random(1,8) == 1)
  {
    birdblink();
  }
  if (random(1,50) == 1)
  {
    birdcall();
  }
  delay(1000);
}

void birdMove()
{ 
   // Make servo go to 0 degrees 
  Servo1.write(0); 
   delay(1000); 
   // Make servo go to 90 degrees 
  Servo1.write(90); 
   delay(1000); 
   // Make servo go to 180 degrees 
  Servo1.write(180); 
   delay(1000); 
}

 void birdblink()
 {
  digitalWrite(2, LOW);
  delay(1000);
  digitalWrite(2, HIGH);
  delay(500);
}

void birdcall()
{
  digitalWrite(2, LOW);
  digitalWrite(3, HIGH);
  tmrpcm.setVolume(6); //
  tmrpcm.play("crow1.wav");
  delay(1000);
  digitalWrite(3, LOW);
  digitalWrite(2, HIGH);
}

Updated version with comments

#include <ServoTimer2.h>
#include "SD.h"
#include "TMRpcm.h"
#include "SPI.h"
#define SD_ChipSelectPin 10 //connect pin 10 of arduino to cs pin of sd card
int servoPin = 5; //PWM pin that is connected to the servo 
int speaker = 9;
int crowData = 0;
int servoAngle = 0;
ServoTimer2 Servo1; 
TMRpcm tmrpcm;

// Bird Red eye LED on D3 and Green eye LED on D2

void setup() 
{ 
Servo1.attach(servoPin);      //create a servo object
digitalWrite(2, HIGH);  // sets LED Green eye ON
Servo1.write(0);  //initialise Servo
tmrpcm.speakerPin = speaker;  
Serial.begin(9600);
 if (!SD.begin(SD_ChipSelectPin)) // returns 1 if the card is present
 {
 Serial.println("SD fail");
 return;
 };
tmrpcm.setVolume(6); // Play crow call to make sure code is working
tmrpcm.play("crow1.wav");
}

void loop() { 
  // use random numbers to generate 3 behaviour - blinking, moving, calling
if (random(1,50) == 1)
 {
    birdMove();
 }
  if (random(1,10) == 1)
  {
    birdblink();
  }
  if (random(1,100) == 1)
  {
    birdcall();
  }
  delay(1000);
}

void birdMove()
{ 
  //Placeholder code to make sure servo is working - I'll write the real code later.
   // Make servo go to 0 degrees 
  Servo1.write(0); 
   delay(1000); 
   // Make servo go to 90 degrees 
  Servo1.write(90); 
   delay(1000); 
   // Make servo go to 180 degrees 
  Servo1.write(180); 
   delay(1000); 
}

 void birdblink()
 {
  digitalWrite(2, LOW);
  delay(1000);
  digitalWrite(2, HIGH);
  delay(500);
}

void birdcall()
{
  digitalWrite(2, LOW);
  digitalWrite(3, HIGH);
  tmrpcm.setVolume(6); //
  tmrpcm.play("crow1.wav");
  delay(1000);
  digitalWrite(3, LOW);
  digitalWrite(2, HIGH);
}

The ServoTimer2 library requires the write() function argument in microseconds of the pulse, not the angle.

It is also possible to convert with the map function.

// Make servo go to 0 degrees
Servo1.write(map(0, 0, 180, MIN_PULSE_WIDTH, MAX_PULSE_WIDTH));
delay(1000);
// Make servo go to 90 degrees
Servo1.write(map(90, 0, 180, MIN_PULSE_WIDTH, MAX_PULSE_WIDTH));
delay(1000);
// Make servo go to 180 degrees
Servo1.write(map(180, 0, 180, MIN_PULSE_WIDTH, MAX_PULSE_WIDTH));
delay(1000);

Enter the angle in the first parameter of the map() function. Other value is fixed.
 


 

Also, if the servo doesn't move 180 degrees and only about 160 degrees, open the library folder ServoTimer2.h and edit the following line.

Default

#define MIN_PULSE_WIDTH       750        // the shortest pulse sent to a servo

#define MAX_PULSE_WIDTH      2250        // the longest pulse sent to a servo

to Modified

#define MIN_PULSE_WIDTH       550        // the shortest pulse sent to a servo
 
#define MAX_PULSE_WIDTH      2450        // the longest pulse sent to a servo
1 Like

Once again, many thanks. I assumed it took the same arguments as the standard Servo library and would never have found the error.
Just tried it and all is well....Now I can get on to the final part - making a bluetooth interface and phone app to control it.
('It' is a 3D printed crow, standing about 18 inches. The servo spins the head via a joint at the neck.).

Once again, many thanks, and your song will be sung :slight_smile:

I'm glad to solve it.
If you like, please :white_check_mark: the "solution" at any post.
It will be easier for people with the same problem to find it.

That sounds like a very cool project.
Good luck. :wink: