Servo twitching; arduino mega to power w/dfplayer and servos

I am trying to use an Arduino mega as a clock. When the time hits specific values, I want to either: have my dfplayer mini play an mp3 file, or actuate a servo. Right now, I am using the DFROBOT LCD Kepyad Shield for the LCD screen, plugged into the Arduino Mega. I have a 5V power supply board powering the two 5g servos, and I am using the Arguino Mega to power both the LCD, the dfplayer mini, and a small speaker. The code works for the most part: the mp3 file plays at the correct time, and the servos actuate at the correct time. However--sometimes, the servos will twitch/actuate sporadically, especially when the dfplayer mini is commanded and operating. I tried using a separate power supply for each servo, but no change/success. The servos are fairly small, and combined are pulling well under the max for the power supply board.

My initial suspicion is that perhaps I either 1) have a code issue where the servo is constantly reading off a PWM pin, and somehow in the code the arduino is using the same pin or channel for the dfplayer, or 2) I have the wiring messed up and there is a short somewhere.

I did also try (within each if loop for the servo) the sequence of: attaching the servo, writing to a position, and then detaching the servo...I thought the "detach" would fix the potential issue of a dueling pwm channel; However, when I did that, the servo did not respond/actuate at all.

Below is the code I'm using (pieced together based on various arduino forums): I would appreciate any assistance!

/*This software is provided in “AS IS” condition,NO WARRANTIES in any form apply to this software.
 picmicrolab.com 
***************************************************************************************************************
Digital Clock with 1602 LCD Shield Board for Arduino


SELECT - 3.0855 V - Adj Hours
LEFT - 1.9778 V - Adj Minutes
DOWN - 1.2446 V
UP - 0.4918 V
RIGHT - 0 V

*/
// include the library code:
#include <LiquidCrystal.h>
#include "DFRobotDFPlayerMini.h"
#include "SoftwareSerial.h"
 #include <Servo.h> 
// #include <VarSpeedServo.h> 

Servo Servo1; //rear landing gear
Servo Servo2; //front landing gear
// Servo Servo3; //bottom flap


// Use pins 11 and 12 to communicate with DFPlayer Mini
static const uint8_t PIN_MP3_TX = 11; // Connects to module's RX 
static const uint8_t PIN_MP3_RX = 12; // Connects to module's TX 
SoftwareSerial softwareSerial(PIN_MP3_RX, PIN_MP3_TX);

// Create the Player object
DFRobotDFPlayerMini player;

// initialize the library by associating any needed LCD interface pin
// with the arduino pin number it is connected to
const int rs = 8, en = 9, d4 = 4, d5 = 5, d6 = 6, d7 = 7;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
//----Time Var----------
int TimeHours10s =  0;
int TimeHours1s =  0;
int TimeMinutes10s =  0;
int TimeMinutes1s =  0;
int TimeSeconds10s =  0;
int TimeSeconds1s =  0;
//----------------------
//----Alarm Var---------
int AlarmHours10s =  0;
int AlarmHours1s =  0;
int AlarmMinutes10s =  0;
int AlarmMinutes1s =  0;
int AlarmSeconds10s =  0;
int AlarmSeconds1s =  0;
//----------------------

// ----------------------int steps for servo----------------------
int pos = 0; // current servo position
    int targetPos = 90; // target servo position
    int stepSize = 1; // increment for each step
    unsigned long lastMoveTime = 0;
    int delayBetweenSteps = 10; // milliseconds


void setup() 
{
  // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);

  // Init USB serial port for debugging
 // Serial.begin(9600);
  // Init serial port for DFPlayer Mini
  softwareSerial.begin(9600);
  player.begin(softwareSerial);
  delay(1500);
  Servo1.attach(22); 
  Servo1.write(0);
  delay(1500);
  Servo2.attach(45);
  Servo2.write(0);
  delay(1500);



}

void loop() 
{
CalculateTime();  
ShowTime();
//ShowAlarm();
delay(1000);



//-------------------------------------Adj Time Value--------------
while(analogRead(A0)* 4.88 < 4500)
{
CalculateTime();  
ShowTime();
if(analogRead(A0)* 4.88 > 10 && analogRead(A0)* 4.88 < 293) // right button,
{
TimeMinutes1s++;
delay(500);
CalculateTime();
}
if(analogRead(A0)* 4.88 > 300 && analogRead(A0)* 4.88 < 1465) // up button, inc hours
{
TimeHours1s++;
delay(500);
CalculateTime();
}
}
}

 void ShowTime()
  {
  //--------------------------------------------
  // Turn on the display
  lcd.display();
  lcd.setCursor(0, 0); // top left
  lcd.print("Time  ");//
  if(TimeHours10s == 0)
  lcd.print(" ");//
  else
  lcd.print(TimeHours10s);//
  lcd.print(TimeHours1s);//
  lcd.print(":");//
  lcd.print(TimeMinutes10s);//
  lcd.print(TimeMinutes1s);//
  lcd.print(":");//
  lcd.print(TimeSeconds10s);//
  lcd.print(TimeSeconds1s);//
  lcd.setCursor(0, 0); // top left
  }

 

void CalculateTime()
{
 TimeSeconds1s++;
  if(TimeSeconds1s == 10)
  {
  TimeSeconds1s = 0;
  TimeSeconds10s++;
  }
  if(TimeSeconds10s == 6)
  {
  TimeSeconds10s = 0;
  TimeSeconds1s = 0;
  TimeMinutes1s++;
  }
  if(TimeMinutes1s == 10)
  {
  TimeMinutes1s = 0;
  TimeSeconds10s = 0;
  TimeSeconds1s = 0;
  TimeMinutes10s++;
  }
  if(TimeMinutes10s == 6)
  {
  TimeMinutes10s = 0;
  TimeMinutes1s = 0;
  TimeSeconds10s = 0;
  TimeSeconds1s = 0;
  TimeHours1s++;
  }
  if(TimeHours1s == 10) 
  {
  TimeHours1s=0;
  TimeMinutes10s = 0;
  TimeMinutes1s = 0;
  TimeSeconds10s = 0;
  TimeSeconds1s = 0;
  TimeHours10s++;
  }
  if(TimeHours10s == 2 && TimeHours1s == 4) 
  {
  TimeHours10s=0; 
  TimeHours1s=0;
  TimeMinutes10s = 0;
  TimeMinutes1s = 0;
  TimeSeconds10s = 0;
  TimeSeconds1s = 0;
 
  } 

if (TimeMinutes10s == 0 && TimeMinutes1s == 0 && TimeSeconds10s == 0 && TimeSeconds1s == 0) // top of hour:  takeoff, gear down
{

    player.volume(20);
    player.play(1);
    
  }

 

if (TimeMinutes10s == 0 && TimeMinutes1s == 7 && TimeSeconds10s == 0 && TimeSeconds1s == 0) // halfway to 15:  gear up
  {

    Servo1.write(90);
    Servo2.write(90);
 
  }

  

if (TimeMinutes10s == 1 && TimeMinutes1s == 5 && TimeSeconds10s == 0 && TimeSeconds1s == 0 ) //10k ft, at 15min
{
    player.volume(25);
    player.play(2);

}


if (TimeMinutes10s == 3 && TimeMinutes1s == 0 && TimeSeconds10s == 0 && TimeSeconds1s == 0 ) // 30mins:  10k ft descending
{
    player.volume(25);
    player.play(3);

}


if (TimeMinutes10s == 3 && TimeMinutes1s == 7 && TimeSeconds10s == 0 && TimeSeconds1s == 0) // halfway to 45, gear down
{

    Servo1.write(0);
    Servo2.write(0);

  }

 

if (TimeMinutes10s == 4 && TimeMinutes1s == 5 && TimeSeconds10s == 0 && TimeSeconds1s == 0 )
{
    player.volume(25);
    player.play(4);

}  
} 

What do you suppose your servos are doing while all those delays are delaying in your loop() function?

Servo twitching comes up nearly every day on the forum, and it is almost always due to an inadequate servo power supply.

For two servos, the servo power supply should be rated for 4.8 to 6V at 2 Amperes. A 4XAA battery pack is OK, but a "breadboard" power supply module is not. Don't forget to connect the grounds.

The servo library has some issue with the dfplayer library. I think they use the same timers. I get twitching servos even if the dfplayer isn’t powered but I send to request to play a sound.

That is easy enough to check, which I did. The source code is here: dfPlayer/libraries/DFRobotDFPlayerMini at master · roberttidey/dfPlayer · GitHub

The only reference I could find to a "timer" is millis(), which does not interfere with the timer used in the servo library.

There may be some other problem, but the servo power supply capability should be checked.

Below is the code I'm using (pieced together based on various arduino forums):

You got some bad advice, namely this:

SoftwareSerial softwareSerial(PIN_MP3_RX, PIN_MP3_TX);

Software serial could interfere with servo timers, and there is absolutely no point in using it on a Mega, which has four hardware serial ports. Use Serial1, Serial2 or Serial3 instead.

1 Like

Please provide more details on exactly what you expect your sketch to do. For example, at what times does stepper1 move its arm, to what position does it rotate, at what speed, etc? My LCDs are I2C so for now I've stripped all that code to focus on the DFR and servos, but need a fuller description.

And a schematic please, ideally after you've changed to using hw serial instead of software serial, as recommended.

Can't find this in the code. Perhaps you meant "servo1"?

Indeed I did, thanks! Actually 'Servo1' :slightly_smiling_face:

1 Like

Could you investigate and post the results? After correcting the power supply situation, your observations might help the OP (and me).

Will do

1 Like

Ok so, my issue is that I am using the SoftwareSerial library to communicate with the DFPlayer. I am doing this because I am using a NRF24_Nano and it only has the one UART, which I use for debugging and so I need to use the SoftwareSerial library; And as we know the SoftwareSerial and Servo library have issues with their timers. As fo the OP, he may be seeing the same thing if the code hasn't already been changed to use the other available UART ports.


Thanks everyone for all of the help and suggestions! Below is the updated code. The servos are still sporadically twitching, although they DID stop actuating each time the dfplayer mini is commanded to operate...here are the things I have done:
-- Switched from softwareserial to serial.
-- Attached each servo to their own individual power supply (power supply each rated for 3.3 and 5V outputs with <700mA, and each 5g servo operating voltage of 4.8-6V, with a 20mA standby current and no-load current of <110mA).

I see on other forums that perhaps a capacitor should be used? I want to make sure I have not messed up the code somehow, to where signals are being interrupted. But--since the servo twitching seems more sporadic now, I'm wondering if it is either a wiring issue, or simply a current issue or electrical noise?

/*This software is provided in “AS IS” condition,NO WARRANTIES in any form apply to this software.
 picmicrolab.com 
***************************************************************************************************************
Digital Clock with 1602 LCD Shield Board for Arduino


SELECT - 3.0855 V - Adj Hours
LEFT - 1.9778 V - Adj Minutes
DOWN - 1.2446 V
UP - 0.4918 V
RIGHT - 0 V

*/
// include the library code:
#include <LiquidCrystal.h>
#include "DFRobotDFPlayerMini.h"
// #include "SoftwareSerial.h"
// #include <Servo.h> 
#include <VarSpeedServo.h> 

VarSpeedServo Servo1; //rear landing gear
VarSpeedServo Servo2; //front landing gear
// Servo Servo3; //bottom flap


// Use pins 11 and 12 to communicate with DFPlayer Mini
// static const uint8_t PIN_MP3_TX = 11; // Connects to module's RX 
// static const uint8_t PIN_MP3_RX = 12; // Connects to module's TX 
// SoftwareSerial softwareSerial(PIN_MP3_RX, PIN_MP3_TX);

// Create the Player object
DFRobotDFPlayerMini player;

// initialize the library by associating any needed LCD interface pin
// with the arduino pin number it is connected to
const int rs = 8, en = 9, d4 = 4, d5 = 5, d6 = 6, d7 = 7;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
//----Time Var----------
int TimeHours10s =  0;
int TimeHours1s =  0;
int TimeMinutes10s =  0;
int TimeMinutes1s =  0;
int TimeSeconds10s =  0;
int TimeSeconds1s =  0;
//----------------------
//----Alarm Var---------
int AlarmHours10s =  0;
int AlarmHours1s =  0;
int AlarmMinutes10s =  0;
int AlarmMinutes1s =  0;
int AlarmSeconds10s =  0;
int AlarmSeconds1s =  0;
//----------------------

// ----------------------int steps for servo----------------------
int pos = 0; // current servo position
    int targetPos = 90; // target servo position
    int stepSize = 1; // increment for each step
    unsigned long lastMoveTime = 0;
    int delayBetweenSteps = 10; // milliseconds


void setup() 
{
  // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);

  // Init USB serial port for debugging
 // Serial.begin(9600);
  // Init serial port for DFPlayer Mini
  Serial.begin(9600); // TX & RX ports, arduino using to speak to computer
  Serial2.begin(9600); // TX 16 and RX 17, to communicate with DFPlayer mini
  player.begin(Serial2); // attach DFPlayer mini to serial
  Servo1.attach(22); 
  Servo1.write(0,30,true);
  Servo2.attach(45);
  Servo2.write(0, 30, true);
  delay(1000);

}

void loop() 
{
CalculateTime();  
ShowTime();
//ShowAlarm();
delay(1000);



//-------------------------------------Adj Time Value--------------
while(analogRead(A0)* 4.88 < 4500)
{
CalculateTime();  
ShowTime();
if(analogRead(A0)* 4.88 > 10 && analogRead(A0)* 4.88 < 293) // right button,
{
TimeMinutes1s++;
delay(500);
CalculateTime();
}
if(analogRead(A0)* 4.88 > 300 && analogRead(A0)* 4.88 < 1465) // up button, inc hours
{
TimeHours1s++;
delay(500);
CalculateTime();
}
}
}

 void ShowTime()
  {
  //--------------------------------------------
  // Turn on the display
  lcd.display();
  lcd.setCursor(0, 0); // top left
  lcd.print("Time  ");//
  if(TimeHours10s == 0)
  lcd.print(" ");//
  else
  lcd.print(TimeHours10s);//
  lcd.print(TimeHours1s);//
  lcd.print(":");//
  lcd.print(TimeMinutes10s);//
  lcd.print(TimeMinutes1s);//
  lcd.print(":");//
  lcd.print(TimeSeconds10s);//
  lcd.print(TimeSeconds1s);//
  lcd.setCursor(0, 0); // top left
  }

 

void CalculateTime()
{
 TimeSeconds1s++;
  if(TimeSeconds1s == 10)
  {
  TimeSeconds1s = 0;
  TimeSeconds10s++;
  }
  if(TimeSeconds10s == 6)
  {
  TimeSeconds10s = 0;
  TimeSeconds1s = 0;
  TimeMinutes1s++;
  }
  if(TimeMinutes1s == 10)
  {
  TimeMinutes1s = 0;
  TimeSeconds10s = 0;
  TimeSeconds1s = 0;
  TimeMinutes10s++;
  }
  if(TimeMinutes10s == 6)
  {
  TimeMinutes10s = 0;
  TimeMinutes1s = 0;
  TimeSeconds10s = 0;
  TimeSeconds1s = 0;
  TimeHours1s++;
  }
  if(TimeHours1s == 10) 
  {
  TimeHours1s=0;
  TimeMinutes10s = 0;
  TimeMinutes1s = 0;
  TimeSeconds10s = 0;
  TimeSeconds1s = 0;
  TimeHours10s++;
  }
  if(TimeHours10s == 2 && TimeHours1s == 4) 
  {
  TimeHours10s=0; 
  TimeHours1s=0;
  TimeMinutes10s = 0;
  TimeMinutes1s = 0;
  TimeSeconds10s = 0;
  TimeSeconds1s = 0;
 
  } 

if (TimeMinutes10s == 0 && TimeMinutes1s == 0 && TimeSeconds10s == 0 && TimeSeconds1s == 0) // top of hour:  takeoff, gear down
{

    player.volume(20);
    player.play(1);
    
  }

 

if (TimeMinutes10s == 0 && TimeMinutes1s == 7 && TimeSeconds10s == 0 && TimeSeconds1s == 0) // halfway to 15:  gear up
  {

    Servo1.write(90, 30, true);
    Servo2.write(90, 30, true);
 
  }

  

if (TimeMinutes10s == 1 && TimeMinutes1s == 5 && TimeSeconds10s == 0 && TimeSeconds1s == 0 ) //10k ft, at 15min
{
    player.volume(25);
    player.play(2);

}


if (TimeMinutes10s == 3 && TimeMinutes1s == 0 && TimeSeconds10s == 0 && TimeSeconds1s == 0 ) // 30mins:  10k ft descending
{
    player.volume(25);
    player.play(3);

}


if (TimeMinutes10s == 3 && TimeMinutes1s == 7 && TimeSeconds10s == 0 && TimeSeconds1s == 0) // halfway to 45, gear down
{

    Servo1.write(0, 30, true);
    Servo2.write(0, 30, true);

  }

 

if (TimeMinutes10s == 4 && TimeMinutes1s == 5 && TimeSeconds10s == 0 && TimeSeconds1s == 0 )
{
    player.volume(25);
    player.play(4);

}  
} 

That is not good enough. The "5g" servos can draw up to 900 mA each, every time they start moving. Plan on 1 Ampere per servo, absolute minimum.

If you want your project to run, the very least you can do is give it an adequate power supply.

Finally, keep in mind that breadboards are intended for temporary experiments with low power logic circuits. They are not designed to handle the current required by motors and servos, and the tracks will burn.

Connections between motors or servos and the power supply should be soldered or made with suitable high current connectors, not through a breadboard.

Will try to reproduce your project later today but couple of points meanwhile.

A schematic should show what you are physically now using. Especially power supply here as that's been a major discussion topic. You shouldn't be expecting us to take account of the modification/improvements you've written about.

It's good practice to use red for +ve wires and black for 0V wires. And for critical adjacent connections (such as TX & RX here) to use different colours.

You were using Servo but I note you have changed to VarSpeedServo. Why?

EDIT (8 hours later)
No reply to questions I asked in post 7 yesterday, but I did take a look at your latest sketch.
Were you able to even compile it? I could not.
The error implicated a file called WProgram.h. That is referenced in the VarSpeedServo library. Seems to be ancient. Is your source also very old?

Anyway, good luck.