Bug using NewSoftSerial & Servo.h together

Hello,
I spent my whole day trying to get around a bug I got when using the NewSoftSerial library from Arduinana and the Servo Library (Servo.h Version 017) together: One of my two servo motors is going crazy all the time as long as the sensor read by the NewSoftSerial library is connected to the Arduino. One user also reported this problem on the Arduinana website, but there is no fix yet apart from using the previous version of the Servo library (from 016), but there's the writeMicroseconds method missing without my project doesnt work :-[
Can anybody help me ? I would be very happy about any suggestions :slight_smile:

It might be useful to know which Arduino you have, and what pins you are connecting the servos to, as well as which pins you are using for NewSoftSerial.

I am using the Arduino Duemilanove together with the ladyada motor shield, but the problem also exists without it. My sensor, a Parallax MLX90614 is connected to the 5V and two digital Pins. I changed both the sensor and the servo pins, so it's not depending on the pins. I even tried it with the ServoTimer2 library which also has a write(Milliseconds) function, but theres the same problem :-[

On this page: http://buildsomething.net/Projectblog/?p=37 someone has the same issue.. It obviously has to do something with the interrupts but I don't not what that means..

Hi all--

I can officially confirm that NewSoftSerial (and really any software serial library) is incompatible with the new Servo library that ships with Arduino 0017. The problem is that the new Servo library, which is really quite cool, depends on reliable interrupts, where software serial solutions require interrupts to be disabled -- at least for short periods of time. I discovered this issue when I was trying to upgrade my Reverse Geocache box to 0017, and the only workaround I could come up with was to downgrade the Servo library back to 0016.

I wonder if it would be possible to retain both libraries in 0018?

Mikal

I opened an issue for this: Google Code Archive - Long-term storage for Google Code Project Hosting.. Not really sure what to do about it. I don't want to include two Servo library, but maybe we could have this one work differently if you're only using Servo motors on pins 9 and 10?

Hello all, I am having the same problem described. Can someone please tell me where I can get the servo 0016 library? I can't seem to find it anywhere. Thanks a lot!

Can someone please tell me where I can get the servo 0016 library? I can't seem to find it anywhere

David, I suggest that you put the old servo library as a standalone download for those that have a problem with code such as NewSoftSerial.

Perhaps add a note in the Servo documentation that code such as NewSoftSerial that disables interrupts for relatively long periods of time will not work with the interrupt driven servo library or other libraries that require reliable interrupts.

( a single character at 2400 baud is a very long time from the perspective of a servo pulse)

Mikal, have you tested NSS with the new Tone function in 0018?

No, I haven't, mem. But you're right that there would almost certainly be a conflict.

I added an end() method in NewSoftSerial 10 (now in beta) that allows for you to turn off a NewSoftSerial interrupt stream. (Previously, interrupts were enabled forever.)

Could someone test this with Servo and Tone, i.e. start a NewSoftSerial stream, turn it off with end(), run a Servo, play a Tone, then turn NSS back on with begin(...)?

http://arduiniana.org

Mikal

Mikal,

I did a very quick test using tone with 12 servos and a single instance of NSS.

Without nss sending or receiving, the tone frequency and servo pulse widths are within 0.1 % of the expected periods (as measured on a logic analyzer). The mark/space ratio of the tone output very occasionally changes from 50/50 to 66/33 if the start of servo pulse exactly coincides with the end of a tone pulse, but the frequency of the tone does not change.

When NSS is sending data the servo pulse width increase by 50% and the tone period varies by plus minus 100 % (1khz tone sometime is 2khz, sometimes 500hz)

I have not tested receiving using nss or turning NSS off, but when data is not being sent by NSS the tone and servo periods are correct.
The sketch used is as follows.

#include <NewSoftSerial.h>

// tone servo test & nss test

#include <Servo.h>

NewSoftSerial mySerial(2, 3);

const int spkrPin = 4;
const int firstServoPin = 5;
const int NBR_SERVOS = 12;

Servo myServos[12];

void setup() 
{ 
  for(int i=0; i < NBR_SERVOS; i++)
    myServos[i].attach(firstServoPin + i); 
 
  Serial.begin(57600);
  Serial.println("Goodnight moon!");

  // set the data rate for the NewSoftSerial port
  mySerial.begin(4800);
  mySerial.println("Hello, world?");
  tone(spkrPin, 1000);
}    
    


void loop()
{
  static unsigned long pos = 0;

  if ( Serial.available())
  {
    char ch = Serial.read();
    mySerial.print((char)Serial.read());
  }
}

hey maxbot,

have u got your mlx90614 to work with motor even with the 0016?. i'm having huge issue with that still. sensors just stop reading (motor stop too) after motor first loop, here's my code:

#include <Servo.h> 
#include <SoftwareSerial.h>

Servo myservo;  // create servo object to control a servo 
                // a maximum of eight servo objects can be created 
SoftwareSerial Temp10(2, 3);

int pos = 0;    // variable to store the servo position 
int prev_temp =0;
void setup() 
{ 
  pinMode(2,OUTPUT);
  pinMode(3,OUTPUT);
  myservo.attach(9);  // attaches the servo on pin 9 to the servo object 
  Serial.begin(115200);
  Temp10.begin(2400);
  delay(100);
  Temp10.print(0,BYTE);
  Temp10.print("!TEMc");
  Temp10.print(0x5A,BYTE);
  Temp10.print(7,BYTE);
  
  pinMode(2,INPUT);
  pinMode(3,INPUT);
} 
 
 
void loop() 
{ 
  for(pos = 0; pos < 180; pos += 1)  // goes from 0 degrees to 180 degrees 
  {                                // in steps of 1 degree 
    prev_temp = Acqu_Temp();
    Serial.print("Temperature= ");
    Serial.print(prev_temp,DEC);
    Serial.println(" Degrees Celsius");
    myservo.write(pos);              // tell servo to go to position in variable 'pos' 
    delay(15);                       // waits 15ms for the servo to reach the position 
  } 
  for(pos = 180; pos>=1; pos-=1)     // goes from 180 degrees to 0 degrees 
  {                                
//    prev_temp = Acqu_Temp();
//    Serial.print("Temperature= ");
//    Serial.print(prev_temp,DEC);
//    Serial.println(" Degrees Celsius");
    myservo.write(pos);              // tell servo to go to position in variable 'pos' 
    delay(15);                       // waits 15ms for the servo to reach the position 
  } 
} 


int Acqu_Temp()
{
 static char rByte[10];
 char rChar;
 int Temp1, Temp2, Temp3;

   rChar = Temp10.read();
   if (rChar == 'T') {
     rByte[0]=rChar;
     rChar=Temp10.read();
     if(rChar=='E')
     {
         rByte[1]=rChar;
         rChar=Temp10.read();
         if(rChar=='M')
         {
           rByte[2]=rChar;
           rByte[3]=Temp10.read();
           rByte[4]=Temp10.read();
           rByte[5]=Temp10.read();
           Temp1 = rByte[4] + rByte[5]*256;           
           Temp3 = (Temp1/100*2)-273;
         }
     }
   }

 return(Temp3);
}

Thanks

minhtue86,

I think your problem almost certainly stems from dropped characters from your sensor. You should migrate to NewSoftSerial or Serial. SoftwareSerial RX and delay() do not play well together. Every time you do a delay(15), you are missing whatever important data arrived from your sensor.

Mikal

Hi Mikal,

Thank you very much for the reply.

I tried to switch to newsoftserial. The motor seems to work now(rotate as intended), but the sensors still seem not work, it wont print out the temperature on the serial command window like i wanted (without servo write command it would work). I even try to control the motor manually by sending pulses (the commented code in the void loop()) but result still the same

Do you have any more idea where I could do things wrong?

Thank you so much

#include <NewSoftSerial.h>
#include <Servo.h> 

NewSoftSerial Temp10(2, 3);

int RESET = 12;
int lastPulse = 0;

Servo myservo;
int pos = 0;

void setup() 
{ 
  pinMode(RESET,OUTPUT);
  digitalWrite(RESET,LOW);
  delay(10);
  pinMode(RESET,INPUT);

  myservo.attach(9);
//  pinMode(9,OUTPUT);
  Temp10.begin(4800);
  Serial.begin(115200);
  delay(100); 
  
  Temp10.print(0,BYTE);
  Temp10.print("!TEMc");
  Temp10.print(0x5A,BYTE);
  Temp10.print(7,BYTE);
  delay(1000);
  pinMode(3,INPUT);
  
} 
 
void loop() 
{ 
    checkTemp();
    myservo.write(pos);
//    if ((millis() - lastPulse >= 20)) {
//      digitalWrite(9, HIGH);   // start the pulse
//      delayMicroseconds(1000);  // pulse width
//      digitalWrite(9, LOW);    // stop the pulse
//      lastPulse = millis();           // save the time of the last pulse
//    }
} 

int checkTemp()
{
  static char rByte[10] ;
  char rChar;
  static int Read = 0;
  static int rcount=0;
  int Temp1;
  int Temp2;
  int Temp3;
  while (Temp10.available() > 0) {
    rChar = Temp10.read();
    if (rChar == 'T') {
      Read = 1;
      rcount = 0;
    }
    if (Read == 1) {
      rByte[rcount] = rChar;
      rcount++;
    }
  }
  
  if (rcount >= 6) {
    if ((rByte[0] == 'T') && (rByte[1] == 'E') && (rByte[2] == 'M')) {
      Temp1 = rByte[4] + rByte[5]*256;
      Temp2 = (Temp1/100);
      if (Temp1*2 < 27315) {
        Temp3 = ((27315-(Temp1*2))/100);
      }
      else
      {
        Temp3 = (Temp1/100*2)-273;
      }
       Serial.print("Temperature= ");
       Serial.print(Temp3,DEC);
       Serial.println(" Degrees Celsius");
      
      rcount = 0;
      Read = 0;
    }
  }
}

Try putting a delayMicroseconds(1) after the read from the NewSoftSerial, that solved the issue for me.

i have the same problem but none of the tips above helped
i.e servo library 16

any other tips?

@diamantamtch, there is a response to your post on this topic in this thread:
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=127250160