SoftwareSerial and servo conflict

Hi!

I am building a simple Arduino robot using Arduino Uno, Adafruit Motor Shield v2.3, BlueSMiRF bluetooth shield and two servos connected to the motor shield. I'm controlling the robot via bluetooth. I thought I got everything to work but I ran into a slight snag. I noticed that bluetooth input to the robot caused servos to jitter a bit. Google told me that SoftwareSerial communication between the Arduino and the bluetooth shield interferes with the interrupts for servo control. If I understood correctly, SoftwareSerial disables interrupts for the time it takes to transmit data and this causes the problem.

Is there a way around this? For the moment I chose to go with hardware serial on pins 0 and 1 of my Arduino but I would be interested to know if this can be solved otherwise so that I could use SoftwareSerial for other devices/shields. If there is a way around this, what possible drawbacks may there be to it?

This is a common problem. Try the ServoTimer2 library. And if that does not solve the problem you might try my yet another software serial

...R

Robin2:
This is a common problem. Try the ServoTimer2 library. And if that does not solve the problem you might try my yet another software serial

…R

For the benefit of others, I tried Robin’s suggested ServoTimer2.h library to replace the standard Servo.h library. It did not solve the problem of a conflict between SoftwareSerial and Servo library for me. I still had the annoying twitching on the servo due to communications over the serial. (Basically, every few seconds, when a bluetooth module connected to the serial would send data, the servo would make a small little jump, moving degree by degree over time).

I looked at Robin’s “another software serial” post, but it was over my head technically. I suppose I could have powered through it and figured it out eventually, but laziness won out. :wink:

I then tried a different servo library called Servo2. Can’t remember where I downloaded it from, but it is google-able. When I first tried to compile my sketch (with the “#include Servo2.h”), i got an error related to wiring.h in a file called Servo2.cpp. (Not to be confused with another file called Servo2.h)

After a little google research, it appears that “#include <wiring.h>” needs to be changed to “#include <wiring_private.h>” inside this file. So I searched in the appropriate folder on my computer and found the file Servo2.cpp, opened it up with a simple text editor, and replaced “#include <wiring.h>” with “#include <wiring_private.h>”.

I then compiled and uploaded the sketch again (no error this time!) and everything worked great. The annoying twitch of the servo caused by serial communications totally went away. Woo hoo!

Zimbu: I then compiled and uploaded the sketch again (no error this time!) and everything worked great. The annoying twitch of the servo caused by serial communications totally went away. Woo hoo!

It would be a great help if you can post a link to the website where you got the servo library that works for you.

The standard SoftwareSerial library is a bit of a dog. There is also AltSoftSerial and NeoSWserial (hope I have the names right).

...R

Robin2:
It would be a great help if you can post a link to the website where you got the servo library that works for you.

…R

For some reason, I can’t find the website from which I downloaded the Servo2.zip file. I was really googling up a storm yesterday and have about 200 links in my browsing history, but can’t seem to figure out the right one now.

I googled today for Servo2, and found numerous sites BUT when I checked the contents of the .h and .cpp files, they were slightly different or sometimes very different from the files I used yesterday.

This one is very close but it doesn’t even include the wiring.h line that I had to comment out. Not sure if that is good news or bad news.

Anyhooo, long story short, here are the two exact files I used including the change I made on the wiring.h line (with my comments on the side):

Servo2.cpp

#include <avr/interrupt.h>
//#include <wiring.h>
#include <wiring_private.h> //Zimbu added this line and commented out wiring.h based on internet advice to prevent error when compiling
#include <Servo2.h>

/*
  Servo2.cpp - 2 Servo hardware timer Library
  Author: Jim Studt, jim@federated.com
  Modified for Mega Pins by Michael Margolis 
  Copyright (c) 2007 David A. Mellis.  All right reserved.
  
  This is the Servo library distributed with Arduino 0016 and earlier.
  It can drive up to two servos using pins 9 and 10 on a standard board
  or 11 and 12 on a Mega. Other pins wont work.
    
  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

#if defined(__AVR_ATmega1280__)
// Mega uses pins 11 and 12 for timer 1
const uint8_t servoAPin = 11;
const uint8_t servoBPin = 12;
#else
// Pins 9 and 10 for Standard Arduino (ATmega168/328
const uint8_t servoAPin = 9;
const uint8_t servoBPin = 10;
#endif

uint8_t Servo::attachedA = 0;
uint8_t Servo::attachedB = 0;

void Servo::seizeTimer1()
{
  uint8_t oldSREG = SREG;

  cli();
  TCCR1A = _BV(WGM11); /* Fast PWM, ICR1 is top */
  TCCR1B = _BV(WGM13) | _BV(WGM12) /* Fast PWM, ICR1 is top */
  | _BV(CS11) /* div 8 clock prescaler */
  ;
  OCR1A = 3000;
  OCR1B = 3000;
  ICR1 = clockCyclesPerMicrosecond()*(20000L/8);  // 20000 uS is a bit fast for the refresh, 20ms, but 
                                                  // it keeps us from overflowing ICR1 at 20MHz clocks
                                                  // That "/8" at the end is the prescaler.
#if defined(__AVR_ATmega8__)
  TIMSK &= ~(_BV(TICIE1) | _BV(OCIE1A) | _BV(OCIE1B) | _BV(TOIE1) );
#else
  TIMSK1 &=  ~(_BV(OCIE1A) | _BV(OCIE1B) | _BV(TOIE1) );
#endif

  SREG = oldSREG;  // undo cli()    
}

void Servo::releaseTimer1() {}

#define NO_ANGLE (0xff)

Servo::Servo() : pin(0), angle(NO_ANGLE) {}

uint8_t Servo::attach(int pinArg)
{
  return attach(pinArg, 544, 2400);
}

uint8_t Servo::attach(int pinArg, int min, int max)
{
  if (pinArg != servoAPin && pinArg != servoBPin) return 0;
  
  min16 = min / 16;
  max16 = max / 16;

  pin = pinArg;
  angle = NO_ANGLE;
  digitalWrite(pin, LOW);
  pinMode(pin, OUTPUT);

  if (!attachedA && !attachedB) seizeTimer1();

  if (pin == servoAPin) {
    attachedA = 1;
    TCCR1A = (TCCR1A & ~_BV(COM1A0)) | _BV(COM1A1);
  }
  
  if (pin == servoBPin) {
    attachedB = 1;
    TCCR1A = (TCCR1A & ~_BV(COM1B0)) | _BV(COM1B1);
  }
  return 1;
}

void Servo::detach()
{
  // muck with timer flags
  if (pin == servoAPin) {
    attachedA = 0;
    TCCR1A = TCCR1A & ~_BV(COM1A0) & ~_BV(COM1A1);
    pinMode(pin, INPUT);
  } 
  
  if (pin == servoBPin) {
    attachedB = 0;
    TCCR1A = TCCR1A & ~_BV(COM1B0) & ~_BV(COM1B1);
    pinMode(pin, INPUT);
  }

  if (!attachedA && !attachedB) releaseTimer1();
}

void Servo::write(int angleArg)
{
  uint16_t p;

  if (angleArg < 0) angleArg = 0;
  if (angleArg > 180) angleArg = 180;
  angle = angleArg;

  // bleh, have to use longs to prevent overflow, could be tricky if always a 16MHz clock, but not true
  // That 8L on the end is the TCNT1 prescaler, it will need to change if the clock's prescaler changes,
  // but then there will likely be an overflow problem, so it will have to be handled by a human.
  p = (min16*16L*clockCyclesPerMicrosecond() + (max16-min16)*(16L*clockCyclesPerMicrosecond())*angle/180L)/8L;
  if (pin == servoAPin) OCR1A = p;
  if (pin == servoBPin) OCR1B = p;
}

uint8_t Servo::read()
{
  return angle;
}

uint8_t Servo::attached()
{
  if (pin == servoAPin && attachedA) return 1;
  if (pin == servoBPin && attachedB) return 1;
  return 0;
}

Servo2.h

#ifndef Servo_h
#define Servo_h

/*
  Servo2.h - 2 Servo hardware timer Library
  Author: Jim Studt, jim@federated.com
  Modified for Mega Pins by Michael Margolis 
  Copyright (c) 2007 David A. Mellis.  All right reserved.
  
  This is the Servo library distributed with Arduino 0016 and earlier.
  It can drive up to two servos using pins 9 and 10 on a standard board
  or 11 and 12 on a Mega. Other pins wont work.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include <inttypes.h>

class Servo
{
  private:
    uint8_t pin;
    uint8_t angle;       // in degrees
    uint8_t min16;       // minimum pulse, 16uS units  (default is 34)
    uint8_t max16;       // maximum pulse, 16uS units, 0-4ms range (default is 150)
    static void seizeTimer1();
    static void releaseTimer1();
    static uint8_t attachedA;
    static uint8_t attachedB;
  public:
    Servo();
    uint8_t attach(int);
                             // pulse length for 0 degrees in microseconds, 544uS default
                             // pulse length for 180 degrees in microseconds, 2400uS default
    uint8_t attach(int, int, int);
                             // attach to a pin, sets pinMode, returns 0 on failure, won't
                             // position the servo until a subsequent write() happens
                             // Only works for 9 and 10.
    void detach();
    void write(int);         // specify the angle in degrees, 0 to 180
    uint8_t read();
    uint8_t attached();
};

#endif

Oops. Just noticed there is also a keywords.txt file included in the zip file I used yesterday.

Here is the keywords.txt file content:

#######################################
# Syntax Coloring Map Servo
#######################################

#######################################
# Datatypes (KEYWORD1)
#######################################

Servo  KEYWORD1

#######################################
# Methods and Functions (KEYWORD2)
#######################################
attach KEYWORD2
detach KEYWORD2
write KEYWORD2
read KEYWORD2
attached KEYWORD2

#######################################
# Constants (LITERAL1)
#######################################

Also here is how i used this library in the code:

#include <SoftwareSerial.h>
#include <Servo2.h> // Include the Servo2 library (non standard library since regular servo library conflicted with software serial causing twitching when HM-10 data was sent over serial)

SoftwareSerial HM10(2, 3);

// Variables and objects for servo motor
int servoPin = 10; // Declare the Servo pin 
Servo myServo; // Create a servo object. NOTICE IT'S NOT "SERVO2"...which actually would have made more sense!

void setup()
{
  Serial.begin(57600);  
  HM10.begin(57600);  
  myServo.attach(servoPin); //attaches the servo to the variable servoPin
}

void loop()
{
  (put your own code here. Moving the servo is done the same way as when you use Servo.h instead of Servo2.h)
}

Thanks for all that. I am taking a copy of the files and will have a look at them when I have some spare time.

...R