Need Help Writing AttachServo ()/ DetachServo() Functions For Servo Program

I am working on a Zumo Robot Project using an Uno.

The problem is that the motor library uses Timer1 and can not be changed.
The buzzer library uses Timer2.
The servo program below also uses timer2.

Based on the program below I want to add an AttachServo() function and an DetachServo() function similar to the one in the servo.h library.

My goal is to attach the servo, use it, the detach it, thus allowing the buzzer to work while the servo is not being used.

I do not have enough knowledge of the Arduino architecture to accomplish this myself.

Your help is greatly appreciated.

ZumoServoExample.ino

/** Arduino Uno Timer 2 Servo Example
This example code for the Arduino Uno shows how to use Timer 2 on
the ATmega328P to control a single servo.  This can be useful for
people who cannot use the Arduino IDE's Servo library.  For
example, the ZumoMotors library uses the same timer as the Servo
library (Timer 1), so the two libraries conflict.

The SERVO_PIN macro below specifies what pin to output the 
servo on.  This pin needs to be connected to the signal input
line of the servo.  The Arduino's GND needs to be connected to
the ground pin of the servo.  The servo's ground and power pins
need to be connected to an appropriate power supply.
*/

// This line specifies what pin we will use for sending the
// signal to the servo.  You can change this.
#define SERVO_PIN 11

// This is the time since the last rising edge in units of 0.5us.
uint16_t volatile servoTime = 0;

// This is the pulse width we want in units of 0.5us.
uint16_t volatile servoHighTime = 3000;

// This is true if the servo pin is currently high.
boolean volatile servoHigh = false;

void setup()
{
  servoInit();
}

void loop()
{
  servoSetPosition(1000);  // Send 1000us pulses.
  delay(1000);  
  servoSetPosition(2000);  // Send 2000us pulses.
  delay(1000);
}

// This ISR runs after Timer 2 reaches OCR2A and resets.
// In this ISR, we set OCR2A in order to schedule when the next
// interrupt will happen.
// Generally we will set OCR2A to 255 so that we have an
// interrupt every 128 us, but the first two interrupt intervals
// after the rising edge will be smaller so we can achieve
// the desired pulse width.
ISR(TIMER2_COMPA_vect)
{
  // The time that passed since the last interrupt is OCR2A + 1
  // because the timer value will equal OCR2A before going to 0.
  servoTime += OCR2A + 1;
  
  static uint16_t highTimeCopy = 3000;
  static uint8_t interruptCount = 0;
  
  if(servoHigh)
  {
    if(++interruptCount == 2)
    {
      OCR2A = 255;
    }

    // The servo pin is currently high.
    // Check to see if is time for a falling edge.
    // Note: We could == instead of >=.
    if(servoTime >= highTimeCopy)
    {
      // The pin has been high enough, so do a falling edge.
      digitalWrite(SERVO_PIN, LOW);
      servoHigh = false;
      interruptCount = 0;
    }
  } 
  else 
  {
    // The servo pin is currently low.
    
    if(servoTime >= 40000)
    {
      // We've hit the end of the period (20 ms),
      // so do a rising edge.
      highTimeCopy = servoHighTime;
      digitalWrite(SERVO_PIN, HIGH);
      servoHigh = true;
      servoTime = 0;
      interruptCount = 0;
      OCR2A = ((highTimeCopy % 256) + 256)/2 - 1;
    }
  }
}

void servoInit()
{
  digitalWrite(SERVO_PIN, LOW);
  pinMode(SERVO_PIN, OUTPUT);
  
  // Turn on CTC mode.  Timer 2 will count up to OCR2A, then
  // reset to 0 and cause an interrupt.
  TCCR2A = (1 << WGM21);
  // Set a 1:8 prescaler.  This gives us 0.5us resolution.
  TCCR2B = (1 << CS21);
  
  // Put the timer in a good default state.
  TCNT2 = 0;
  OCR2A = 255;
  
  TIMSK2 |= (1 << OCIE2A);  // Enable timer compare interrupt.
  sei();   // Enable interrupts.
}

void servoSetPosition(uint16_t highTimeMicroseconds)
{
  TIMSK2 &= ~(1 << OCIE2A); // disable timer compare interrupt
  servoHighTime = highTimeMicroseconds * 2;
  TIMSK2 |= (1 << OCIE2A); // enable timer compare interrupt
}

There is almost never a valid reason to detach a servo in a running sketch. Servos are not designed to be powered up but with no control pulses being sent to them. The servo library will continue to output the last valid position command you send to a servo without you having to do anything else to the servo until you wish to command it to a new position.

I suggest that you need to find another way to solve your timer conflict.

Lefty

On Arduino Uno (Atmel 328) you have only three timers, 0, 1 and 2

On Arduino Mega you have others 3 timers (timer 3, 4 and 5)

You can look at "blink without delay" to run the servos and or the buzzer or look at software servo.

Mark

I have found that servos twitch while idle. On my internet laser pointer cat toy, I've found it beneficial to attach the servos when a client connects and detach them when they disconnect. Something like this:

if (client) {
  servoA.attach(3);
  servoB.attach(5);

  while(client.connected()){
   //do lots of stuff
  }
  servoA.detach();
  servoB.detach();
}

Works perfectly.

vulture2600:
I have found that servos twitch while idle. On my internet laser pointer cat toy, I've found it beneficial to attach the servos when a client connects and detach them when they disconnect. Something like this:

if (client) {

servoA.attach(3);
  servoB.attach(5);

while(client.connected()){
   //do lots of stuff
  }
  servoA.detach();
  servoB.detach();
}




Works perfectly.

Not saying that doesn't work for your application. Rather I suggest that is treating the symptom and not the root cause of servo twitching?

I dont know what the cause of the jitter was so this seemed to take care of it fine. The power is always connected, just no signal being sent seems to fix it.

vulture2600:
I dont know what the cause of the jitter was so this seemed to take care of it fine. The power is always connected, just no signal being sent seems to fix it.

One thing you lose using detach is that the servo wheel will then have no 'holding torque' so unless the servo load is balanced in all positions the servo wheel can move depending on the mechanical load. Again servo manufactures do not define how their servos will operate/respond to being powered up but with no valid control signal being refreshed every 20 millisecs or so. So while might work fine on your specific project, it might not be a good method for others to utilize in their projects. It's a hobby so there are no 'rules' one must follow, but it's always good to understand what is happening behind the curtains. :wink:

Good to know! In my application, there's no load on the servos while not in use but I could see how that would be bad in many other situations!

retrolefty:
There is almost never a valid reason to detach a servo in a running sketch. Servos are not designed to be powered up but with no control pulses being sent to them. The servo library will continue to output the last valid position command you send to a servo without you having to do anything else to the servo until you wish to command it to a new position.

I suggest that you need to find another way to solve your timer conflict.

Lefty

I have a valid reason.

The servo.h library accomplishes this easily with the Servo.Detach() function.

.

Two servos that I have immediately run to the end stop if powered up without a signal.

One solution may be to use a relay or transistor to cut the power to the servo before the signal is stopped. Of course this leaves the servo free to move if the load exceeds the internal friction.

...R

vulture2600:
I have found that servos twitch while idle. On my internet laser pointer cat toy, I've found it beneficial to attach the servos when a client connects and detach them when they disconnect. Something like this:

if (client) {

servoA.attach(3);
  servoB.attach(5);

while(client.connected()){
   //do lots of stuff
  }
  servoA.detach();
  servoB.detach();
}




Works perfectly.

As I stated earlier, there is no attach() / detach() function in the program example.
I need help writing these functions.

.

Robin2:
Two servos that I have immediately run to the end stop if powered up without a signal.

One solution may be to use a relay or transistor to cut the power to the servo before the signal is stopped. Of course this leaves the servo free to move if the load exceeds the internal friction.

…R

The servo I am using simply stops when the PWM signal is stopped.
The servo is not load bearing so it does not need to hold its position when turned off.

.
Based on the program sample in the first post.
I am asking for your help in writing a ServoDetach() and a ServoAttach() function.
Or a point in the right direction.
Your help is appreciated

.

nid69ita:
On Arduino Uno (Atmel 328) you have only three timers, 0, 1 and 2

On Arduino Mega you have others 3 timers (timer 3, 4 and 5)

For form factor reasons I am limited to either an Uno or a Leonardo.
Using the Leonardo presents other problems, and besides, I don't have one.

Don't you read the documentation?

Mark

I made the below test code for use with continuous rotation servos. Sometimes the pot settings will start to drift causing a very slow rotation when they are supposed to be stopped at the 1500us command. The code below should detach the servo and stop the slow rotation drift when the 1500us command is received.

// zoomkat 10-14-11 serial servo test
// type servo position 500 to 2500 in serial monitor
// type in number 1500 to detach servo
// for IDE 0022 and later
// Powering a servo from the arduino usually DOES NOT WORK.

String readString;
#include <Servo.h> 
Servo myservo;  // create servo object to control a servo 

void setup() {
  Serial.begin(9600);
  myservo.writeMicroseconds(1500); //set initial servo position if desired
  myservo.attach(7);  //the pin for the servo control 
  Serial.println("servo-test-22"); // so I can keep track of what is loaded
}

void loop() {
  while (Serial.available()) {
    char c = Serial.read();  //gets one byte from serial buffer
    readString += c; //makes the string readString
    delay(2);  // allow buffer to fill with next character
    }

  if (readString.length() >0) {
    Serial.println(readString);  //so you can see the captured string 
    int n = readString.toInt();
    
    if (n == 1500) {
      myservo.detach(); 
    }
    else {
       myservo.attach(7);
       myservo.writeMicroseconds(n); //convert readString to number for servo
    }
    readString=""; //empty for next input
  } 
}

It sounds to me (forgive the pun) that you could do without the buzzer until you have everything else working and then find some other way to make noise if it is essential.

I'm not sure if you have looked at the ServoTimer2 library Digital Modellbahn - Browse /Arduino (v1.0) libaries at SourceForge.net

...R

holmes4:
Don't you read the documentation?

Mark

Don't you read the initial posts before you reply?

.

zoomkat:
I made the below test code for use with continuous rotation servos. Sometimes the pot settings will start to drift causing a very slow rotation when they are supposed to be stopped at the 1500us command. The code below should detach the servo and stop the slow rotation drift when the 1500us command is received.

// zoomkat 10-14-11 serial servo test

// type servo position 500 to 2500 in serial monitor
// type in number 1500 to detach servo
// for IDE 0022 and later
// Powering a servo from the arduino usually DOES NOT WORK.

String readString;
#include <Servo.h>
Servo myservo;  // create servo object to control a servo

void setup() {
  Serial.begin(9600);
  myservo.writeMicroseconds(1500); //set initial servo position if desired
  myservo.attach(7);  //the pin for the servo control
  Serial.println(“servo-test-22”); // so I can keep track of what is loaded
}

void loop() {
  while (Serial.available()) {
    char c = Serial.read();  //gets one byte from serial buffer
    readString += c; //makes the string readString
    delay(2);  // allow buffer to fill with next character
    }

if (readString.length() >0) {
    Serial.println(readString);  //so you can see the captured string
    int n = readString.toInt();
   
    if (n == 1500) {
      myservo.detach();
    }
    else {
       myservo.attach(7);
       myservo.writeMicroseconds(n); //convert readString to number for servo
    }
    readString=""; //empty for next input
  }
}

The servo.h library uses Timer1, so this will not work for this application.

I posted a program for servo control using Timer2 in the initial post.
It is this program that I need to write the functions for.

Thanks for trying.