Does Software serial still conflict with the Servo library?

jboyton:
I know how to download a zip file and expand it. It just seems like a long ways to go to find out what you meant.

Hang on a mo... You are not the OP!

If the OP wanted the library how else would he get it?

...R

Robin2:
Hang on a mo... You are not the OP!

No, I'm the guy who said that there are alternatives to SoftwareSerial that don't have the problem MarkT described. You're the guy who said that your previous post already pointed that out.

So how does that other servo library solve the problem?

jboyton:
So how does that other servo library solve the problem?

It doesn't.

Had to use an older IDE to get ServoTimer2 to compile and have the same problem. When sending data using software serial and using a servo at the same time, the servo jumps around.

Anybody have any further ideas or suggestions?

What about ServoTimer2 + AltSoftSerial?

I thought the point bringing up ServoTimer2 was that AltSoftSerial would do the job but used up timer 1.

Delta_G:
What about ServoTimer2 + AltSoftSerial?

I thought the point bringing up ServoTimer2 was that AltSoftSerial would do the job but used up timer 1.

Now that makes sense.

Alternatively one could use Servotimer1 and use software serial code that uses timer 2. It's also possible to use only timer 0 for soft serial without affecting millis/micros/delay.

MartynC:
It doesn't.

Had to use an older IDE to get ServoTimer2 to compile and have the same problem. When sending data using software serial and using a servo at the same time, the servo jumps around.

Anybody have any further ideas or suggestions?

I am surprised that there is still a problem. Post the code that demonstrates the problem.

...R

In the below sketch, every time data is sent via software serial (BTserial) the servo jumps.

#include <SoftwareSerial.h>
SoftwareSerial BTserial(2,3); // RX | TX

#include <Servo.h>
Servo myservo;  // create a servo object 



void setup()  
{

    Serial.begin(9600);
    Serial.println("servoTest_01");
    Serial.println(" ");
    
    myservo.attach(5);
    myservo.write(0); 
    pinMode(13, OUTPUT); 
    digitalWrite(13,LOW);
    BTserial.begin(9600); 

} 


void loop()  
{

    digitalWrite(13,HIGH);
    BTserial.print("<START>");                // Start marker
    BTserial.print("<P05000170000>");         // Initialize pin 9 for PWM. min=0, max=175, start val=0
    BTserial.print("<ND05Servo Pos>");        // Set the name for D9 to Servo Pos
    BTserial.print("<C2>");                   // number of commands not including itself.
    BTserial.print("<END>");    
    delay(100);
    digitalWrite(13,LOW);   
    delay(900);
}

I get the same results when I change the pin and also when I use ServoTimer2

You could get a Mega, for the extra hardware serial ports. Decent clones are pretty cheap.

Alternatively, will your finished project use a hardware serial connection back to a PC? Could you do away with that, and use the hardware serial for the stuff Software Serial does now?
If hardware serial is only used for debugging during development, you could flash a LED for debugging purposes, or even use an I2C LCD module if it's important enough.
I usually work well away from the PC, so rarely use hardware serial for debugging.

OldSteve:
You could get a Mega, for the extra hardware serial ports. Decent clones are pretty cheap.

Alternatively, will your finished project use a hardware serial connection back to a PC? Could you do away with that, and use the hardware serial for the stuff Software Serial does now?
If hardware serial is only used for debugging during development, you could flash a LED for debugging purposes, or even use an I2C LCD module if it's important enough.
I usually work well away from the PC, so rarely use hardware serial for debugging.

For now I will switch to hardware serial which works fine. I will also continue to look for a solution that uses some kind of software serial or an alternative servo library.

MartynC:
I will also continue to look for a solution that uses some kind of software serial or an alternative servo library.

Why not try what Delta_G suggested?

MartynC:
I get the same results when I change the pin and also when I use ServoTimer2

If you post the code that uses ServoTimer2 I will try it on my Arduino.

...R

I am away from home until the weekend. When I get back I will try Delta_G's suggestion (I some how missed it) and also post more code.

This morning I have tried a few different set ups:

Hardware serial + Servo works ok.
The servo movment is smooth and as expected

SoftwareSerial + Servo.
The Servo jumps whenever software serial is sending or receiving data

AltSoftSerial + Servo
Complie error
Servo\avr\Servo.cpp.o: In function __vector_11': D:\__A163\libraries\Servo\src\avr/Servo.cpp:81: multiple definition of __vector_11'
AltSoftSerial_V1.2\AltSoftSerial.cpp.o:D:__A163\libraries\AltSoftSerial_V1.2/AltSoftSerial.cpp:131: first defined here
collect2.exe: error: ld returned 1 exit status
Error compiling.

softwareSerial + ServoTimer2
The Servo jumps whenever software serial is sending or receiving data

AltSoftSerial + ServoTimer2
Works OK but need to use pulse rather than degrees

When using ServoTimer2 I am mapping the degree value (0 to 170) to pulse (500 to 2500).
I am not getting the same range of movement from ServoTimer2 as I get with Servo. Pulses below 7xx and above 22xx don't have any effect. I haven't looked in to this yet.

I am controlling the Servo from an Android app and the Arduino is using variations of the below sketch.

/*
*
* Sketch: serial_Servo_002_SoftwareSerial_Servo
*
* Servo jumps when data is received/sent by software serial
*
* The example uses the following pins
* D2 - software serial RX
* D3 - software serial TX
* D5 - servo
*
*/

// The Bluetooth module is connected to pin D2 and D3 and uses software serial
#include <SoftwareSerial.h>
SoftwareSerial BTserial(2,3); // RX | TX


#include <Servo.h>
Servo myservo;  // create a servo object 


// Change DEBUG to true to output debug information to the serial monitor
const boolean DEBUG = true;


char rc = ' ';
const byte maxDataLength = 20;
char receivedChars[21] ;
boolean newData = false;


void setup()  
{
    if (DEBUG)
    {
        // open serial communication for debugging
        Serial.begin(9600);
        while (!Serial);
        Serial.println("serial_Servo_002_SSoftwareSerial_Servo");
        Serial.println(" ");
    }  
  
    myservo.attach(5);
    myservo.write(0); 
    if (DEBUG)  {  Serial.println("Servo attached to pin 5"); }
  
    // Use the LED on pin 13 to show status 
    // Flashing means sending initialization commands and waiting for a reply
    // On means the Android app has replied correctly
    pinMode(13, OUTPUT); 
    digitalWrite(13,LOW);
    

    //  open software serial connection to the bluetooth module
    BTserial.begin(9600); 
    if (DEBUG)  {  Serial.println("BTserial started at 9600");  }
    
    // Send initialization commands and the wait for an "OK"   
    boolean LEDisON = false;
    boolean done = false;
    byte count = 0;
    boolean sendInitCodes = true;
      
    newData = false;
    int refreshRate = 250;
    unsigned long startTime = millis();
    while (!done)
    {
        // This bit flashes the LED on pin 13. 
        if ( millis()-refreshRate > startTime)
        {
            startTime = millis();
            if (LEDisON) { LEDisON = false;  digitalWrite(13,LOW);   }
            else         { LEDisON = true;   digitalWrite(13,HIGH);  } 
            count++; 
            // if reply is not received within 3 seconds resend the commands
            if (count==12) { count = 0; sendInitCodes = true;         }
        }
        
        
        // Keep sending the initialization commands until the "OK" reply is received.
        if (sendInitCodes == true)   
        { 
            sendInitCodes = false; 
            BTserial.print("<START>");                // Start marker
            BTserial.print("<P05000170000>");         // Initialize pin 9 for PWM. min=0, max=170, start val=0
            BTserial.print("<ND05Servo Pos>");        // Set the name for D5 to Servo Pos
            BTserial.print("<C2>");                   // number of commands not including itself.
            BTserial.print("<END>");                  // End marker
            if (DEBUG) { Serial.println("Sent init commands. Waiting for reply"); }
        }

        
        recvWithStartEndMarkers(); // check for new data from the Bluetooth module
        if (newData)
        {
            // The Android app receives the commands and sends an "OK" back.            
            if (DEBUG) { Serial.print("Data received = ");      Serial.println(receivedChars);         }
            if (  (receivedChars[0] == 'O') & (receivedChars[1] == 'K')  )
            { done = true;  }
            else 
            {newData = false; }            
        }
        
    } // while (!done) 

  
    // Turn on the built in LED to show the app has received the initialization codes
    digitalWrite(13,HIGH); 
    if (DEBUG)  {  Serial.println("OK received from the app");  } 

    newData = false; 
    receivedChars[0] = '\0';
  
} // void setup()



void loop()  
{
    recvWithStartEndMarkers();          // check to see if we have received any new commands
    if (newData) { processCommand(); }  // if we have a new command set the Arduino pin accordingly
    delay(5);
}



/*
****************************************
* Function processCommand
* parses data commands contained in receivedChars[]
* receivedChars[] has not been checked for errors
* 
* Passed:
*
* Returns:
*  
* Global: 
*       receivedChars[]
*       newData
*          
* Sets/Changes:
*       newData
*
*/
void processCommand()
{
    newData = false;
    byte pin = ((receivedChars[1]-48) *10 ) + receivedChars[2]-48;

    // PWM pin
    if ( receivedChars[0] == 'P')
    {
        if (DEBUG) { Serial.print("PWN command = ");  Serial.println(receivedChars); }
        byte val = ((receivedChars[3]-48) *100 ) + ((receivedChars[4]-48) * 10)  + (receivedChars[5]-48)   ;
        myservo.write(val);  
    }  
}





// function recvWithStartEndMarkers by Robin2 of the Arduino forums
// See  http://forum.arduino.cc/index.php?topic=288234.0
/*
****************************************
* Function recvWithStartEndMarkers
* reads serial data and returns the content between a start marker and an end marker.
* 
* Passed:
*
* Returns:
*  
* Global: 
*       receivedChars[]
*       newData
*
* Sets/Changes:
*       newData
*       receivedChars
*
*/
void recvWithStartEndMarkers() 
{
    static boolean recvInProgress = false;
    static byte ndx = 0;
    char startMarker = '<';
    char endMarker = '>';
    if (BTserial.available() > 0) 
    {
          rc = BTserial.read();
          if (recvInProgress == true) 
          {
               if (rc != endMarker) 
               {
                    receivedChars[ndx] = rc;
                    ndx++;
                    if (ndx > maxDataLength) { ndx = maxDataLength; }
               }
               else 
               {
                     receivedChars[ndx] = '\0'; // terminate the string
                     recvInProgress = false;
                     ndx = 0;
                     newData = true;
               }
          }
          else if (rc == startMarker) { recvInProgress = true; }
    }
}

Attached is the AltSoftSerial and ServoTimer2 sketch

serial_Servo_005_AltSoftSerial_ServoTimer2.ino (6.05 KB)

Thanks, good research, and a good thread to bookmark.

Just tried the PWMservo library and it works fine with software serial (Arduino Nano). PWMservo is the old servo library that uses PWM. It does not conflict/share resources with software serial.

The only caveat is that it can only be used with 2 servos and they must be on pins 9 and 10. You also need to change #include <Wiring.h> to #include <Arduino.h> in the library cpp file.

MartynC:
Just tried the PWMservo library and it works fine with software serial (Arduino Nano). PWMservo is the old servo library that uses PWM. It does not conflict/share resources with software serial.

The only caveat is that it can only be used with 2 servos and they must be on pins 9 and 10. You also need to change #include <Wiring.h> to #include <Arduino.h> in the library cpp file.

Glad you found a solution... at least for two servos.

MartynC:
AltSoftSerial + ServoTimer2
Works OK but need to use pulse rather than degrees

Why was this unsatisfactory? Is converting from pulse width to degrees too complicated?

jboyton:
Why was this unsatisfactory? Is converting from pulse width to degrees too complicated?

I never got the same range of movement with ServoTimer2 as I did with Servo. I didn't do much in the way of testing though and and didn't look in to it.

I only tried PWMservo because I saw it mentioned while reading something unrelated.

MartynC:
I never got the same range of movement with ServoTimer2 as I did with Servo. I didn't do much in the way of testing though and and didn't look in to it.

I only tried PWMservo because I saw it mentioned while reading something unrelated.

I see. You don't get the same resolution because ServoTimer2 uses an 8-bit timer instead of a 16-bit timer. And you can't use AltSoftSerial with the regular Servo library because they both use timer 1.

What you really need, at least to support more than two servos, is to use the regular Servo library coupled with an implementation of software serial that uses timer 2. This exists in a very rough form (Robin's "sss" serial), but it isn't a drop-in replacement for SoftwareSerial. Some more work needs to be done for it be a seamless replacement.

But if all you have are two servos then it sounds like you're set.

edit:
I've attached a version of software serial that uses timer 2. It's based on Robin's original code.

It only works at 9600 baud and is limited in many ways. It would be interesting to see if it worked in an environment with several servos. If the time taking by the servo interrupts is great enough it could cause the software serial to fail.

For what it's worth.

sSoftSerial.cpp (6.96 KB)

sSoftSerial.h (780 Bytes)

jboyton:
I've attached a version of software serial that uses timer 2. It's based on Robin's original code.

Great stuff. I was never going to do that. I have bookmarked this Post.

...R

Hello!

I've solved this problem with AltSoftSerial and ServoTimer2.

In ServoTimer2 it is necessary to comment the line typedef uint8_t boolean;