bask185
bask185

Reputation: 397

Arduino servo object does not work within my own library

I have written a libary for somebody else to slowly sweep servo's from one position to another. It did not work like I intented and I had to remove the servo objects from the library. Instead I let the new version calculate the servo positions and return those values instead. Yet I really like to know why it is not working.

The header file with the private Servo objects

#include <Arduino.h>
#include <Servo.h>

class ServoSweep {

public:
    ServoSweep( byte _servoPin, byte _min, byte _max, byte _speed  ) ;        // constructor 1
    ServoSweep( byte _servoPin, byte _min, byte _max, byte _speed, byte _relayPin ) ;  // constructor 2
    void sweep( );
    void setState( uint8_t _state );

private:
    Servo servo ;
    unsigned long timeToRun ;
    byte pos ;
    byte state ;
    byte prevPos;
    byte servoPin ;
    byte servoSpeed ;
    byte servoMin ;
    byte servoMax  ;
    byte middlePosition ;
    byte relayPresent ;
    byte relayPin ;

} ;

And the source file:

#include "ServoSweep.h"

ServoSweep::ServoSweep( byte _servoPin, byte _min, byte _max, byte _speed ) {                   // constructor 1
    
    servoPin = _servoPin ;
    servoSpeed = _speed ;
    servoMin = _min ;
    servoMax = _max ;
   
    middlePosition = ( (long)servoMax - (long)servoMin ) / (long)2 + (long)servoMin ;               // start with middle position

    pos = middlePosition ;

    servo.write( pos ) ;
    servo.attach( servoPin ) ;
}

ServoSweep::ServoSweep( byte _servoPin, byte _min, byte _max, byte _speed, byte _relayPin ) {      // constructor 2
    
    servoPin = _servoPin ;
    servoSpeed = _speed ;
    servoMin = _min ;
    servoMax = _max ;

    middlePosition = ( (long)servoMax - (long)servoMin ) / (long)2 + (long)servoMin ;

    pos = middlePosition ;

    servo.write( pos ) ;
    servo.attach( servoPin ) ;

    relayPresent = 1;
    relayPin = _relayPin ;
    pinMode( relayPin, OUTPUT ) ;

}


void ServoSweep::sweep () {

    if( millis() > timeToRun ) {
        timeToRun = millis() + servoSpeed ;

        if( state ) {
            if( pos < servoMax ) pos ++ ;
        }
        else {
            if( pos > servoMin ) pos -- ;
        }

        if( prevPos != pos ) {
            prevPos  = pos ;

            if( relayPresent == 1 ) {
                if( pos < middlePosition ) digitalWrite( relayPin,  LOW ) ;
                else                       digitalWrite( relayPin, HIGH ) ;
            }
            servo.write( pos ) ;
        }
    }
}

void ServoSweep::setState( uint8_t _state ) {
    state = _state ;
}

The servo signal was complete jitter caused by the arduino. The example sketch I used:


#include "ServoSweep.h"

const int inputButton = 12 ;
const int servoPin1 = 2 ;
const int servoPin2 = 3 ;

unsigned long prev ;
byte state ;

//                   pin   min max speed (bigger speed = slower movement ;
ServoSweep servo1(servoPin1, 10, 30, 50) ; 
ServoSweep servo2(servoPin2, 10, 30, 50) ; 

void setup() {
    pinMode( inputButton, INPUT_PULLUP ) ;
}

void loop() {
 
    servo1.sweep();
    servo2.sweep();

    if( digitalRead( inputButton ) ) servo1.setState( 1 ) ; 
    else                             servo1.setState( 0 ) ;

    if( digitalRead( inputButton ) ) servo2.setState( 0 ) ; 
    else                             servo2.setState( 1 ) ;
 
}

Even I comment out al code inside the loop, the jitter is there. The jitter starts as soon as I construct the ServoSweep objects.

What did I wrong with the servo objects? I assume this has to be possible.

Upvotes: 0

Views: 322

Answers (1)

Delta_G
Delta_G

Reputation: 3243

The problem is most likely in your constructor. These lines:

servo.write( pos ) ;
servo.attach( servoPin ) ;

in the constructor are trying to work with hardware that may not be ready yet. You are calling the constructor at global scope, so these things may be happening before init() runs and sets up the hardware. So when init() does run, it is probably overwriting values that the servo library had written to timer 1.

This is a common issue and a common newbie trap. Constructors should initialize variables and set up values and things, but they are not for handling hardware. For that you need a begin() or init() method that you can call from setup. Think about how the servo library has the attach function that you have to call from setup. If it were possible to do that in the constructor, they would have had the constructor take the pin number and do it. Think about the begin method that you have to call for Serial to work. That's the same story, there's hardware to setup and you need to be able to control when that happens.

So make one more method:

void ServoSweep::begin()  {
   servo.write( pos ) ;
   servo.attach( servoPin ) ;
}

And call that from setup for each object and remove those lines from the constructor.

Upvotes: 1

Related Questions