Need help detaching servo then re-attaching.

So a brief into to what this code does.

Takes an analog thermistor reading, converts it to F.
Averages out that reading over 10 measurements.
Use if statement to check if averaged temp is greater than or less than a variable value to open servo or close servo.

This will be attached to an air handler in the attic, so it will be running non stop 24/7. I don’t want the servo to burn up pre-maturely. The servo is constantly “buzzing” a tiny bit. Probably because I’m using a Futaba S9650 digital servo (what I had, used to be into R/C Helis)

I’d like to detach the servo, and then re-attach it but I’ve run into two problems:

One, the if is looped every second, so if I put the servo.attach command in there, it’s still going to attach every second. Still better than running constantly but not ideal

Two, It seems really buggy, I can’t get the code right. Either the servo detached, and never re-attaches or it never detaches at all.

The code is below. Please forgive me if it is confusing, hard to understand, or just not done right. I’ve only had my arduino for a few days, and am brand new to it and programming. The code is alot of copy/paste from examples on the web with some tweaking here and there.

So what should I do to move the servo to the desired position (openpos or closedpos) and have it detach after that, UNTIL the temp has changed to the opentemp or closedtemp.

#include <math.h>
#include <Servo.h>
#define ThermistorPIN 0                                                                          // Define the Thermistor Input Pin
Servo servo1;
int servo1Pin = 5;                                                                               // Define Servo 1 Signal Pin (Digital)
int openTemp = 78;                                                                               // Temperature to open butterfly valve
int closeTemp = 73;                                                                              // Temperature to close butterfly valve
int openpos = 180;                                                                               // Define servo1 OPEN position to 180 degrees
int closepos = 90;                                                                               // Define servo1 CLOSED position to 0 degrees
const int numReadings = 10;                                                                      // Number of temperature readings to averageTemp out. 10 to 20 works best. 
int readings[numReadings];                                                                       // the readings from the analog input
int readIndex = 0;                                                                               // the index of the current reading
int total = 0;                                                                                   // the running total
int averageTemp = 0;                                                                             // setting up the averageTemp
float tempResistor = 9550;                                                                       // Thermistor Pull Up/Down Resistor Value in ohms
float Thermistor(int RawADC) {
  long Resistance;  
  float Temp;                                                                                    // Dual-Purpose variable to save space.
  Resistance=tempResistor / 4 * ((1024.0 / RawADC) - 1);                                         // Original code did not divide by 4 and I got incorrect readings. If your readings are off take out the " / 4 "
  Temp = log(Resistance);                                                                        // Saving the Log(resistance) so not to calculate  it 4 times later
  Temp = 1 / (0.001129148 + (0.000234125 * Temp) + (0.0000000876741 * Temp * Temp * Temp));      // Convert resistance to Kelvin
  Temp = Temp - 273.15;                                                                          // Convert Kelvin to Celsius                      
  return Temp;                                                                                   // Return the Temperature
}

void setup() {
  Serial.begin(9600);                                                                            // Define baud rate for serial interface output
  servo1.attach(servo1Pin, 785, 2180);                                                           // Define Servo Output Pin, Min Sweep uSec, Max Sweep uSec
  for (int thisReading = 0; thisReading < numReadings; thisReading++) {
  readings[thisReading] = 0;
 }
}

void loop() {
  float temp;
  temp=Thermistor(analogRead(ThermistorPIN));                                                    // read ADC and convert it to Celsius
  temp = (temp * 9.0)/ 5.0 + 32.0;                                                               // converts to  Fahrenheit
  total = total - readings[readIndex];                                                           // subtract the last reading:
  readings[readIndex] = temp;                                                                    // read from the sensor:
  total = total + readings[readIndex];                                                           // add the reading to the total:
  readIndex = readIndex + 1;                                                                     // advance to the next position in the array:
  if (readIndex >= numReadings) {                                                                // if we're at the end of the array...
    readIndex = 0;                                                                               // ...wrap around to the beginning:
  }
  averageTemp = total / numReadings;                                                             // calculate the averageTemp:
  // ------------------------------------
  Serial.print("Temp: "); 
  Serial.print(averageTemp);                                                                     // Outputs "smoothed" thermistor integer value
  Serial.print(" F");
  // ------------------------------------
  Serial.print("    Raw Data : ");
  Serial.print(temp,1);                                                                          // Outputs raw temp in F for comparison
  Serial.println("");
  // ------------------------------------
  delay(1000);                                                                                   // delay in between reads for stability

  if (averageTemp >= openTemp) {                                                                 // Compares the average temp to the temp to open valve   
    
    digitalWrite(13, HIGH);                                                                      // Turns on LED to indicate 
    servo1.write(openpos);                                                                       // Move servo1 to open position 
    //servo2.write(openpos);
    //servo3.write(openpos);
  }    
                                                                        
  if (averageTemp <= closeTemp) {                                                                // Compares the average temp to the temp to close valve
    digitalWrite(13, LOW);                                                                       // Turns off LED to indicate closed valve
    servo1.write(closepos);                                                                      // Move servo1 to closed position
    //servo2.write(closedpos);
    //servo3.write(closedpos);
  }
}

Your sketch never detaches the servo.

Be sure to allow time for the servo1.write() to move the servo before detaching the servo. Detaching causes the servo library to stop sensing positioning pulses to that pin. If you detach before the servo has completed the move it is likely the servo will stop wherever it is.

You should keep track of the last set position of the servo. If the servo is already in the desired position there is no need to attach the servo, write to it, delay, and detach the servo.

Hi thanks for the reply.
I’m aware there is no detach. This is how the code is currently running. It is working this way, the issue is the servo is a very high resolution digital servo meant for cyclic controls on a helicopter. The motor is buzzing when at a set position. I’m quite sure this is because the arduino’s output is nowhere near as clean as a receiver would be sending to the servo.

It is not locked, stalled, or anythng like that, it is more like “hunting” a fraction of a mm. not visible to the naked eye.

Here’s how I was trying the code to detach and attach. The issue is the whole script is being looped every second. A downfall I’ve not anticipated with the arduino.

I want it to take a temperature measurement every second, but not write the servo’s position every second. Seems no matter where I put the 1000ms delay it affects the temperature reading.

  if (averageTemp >= openTemp) {                                                                 // Compares the average temp to the temp to open valve   
    
    digitalWrite(13, HIGH);                                                                      // Turns on LED to indicate 
    servo1.attach(servo1Pin, 785, 2180);
    servo1.write(openpos);                                                                       // Move servo1 to open position 
    servo1.detach();
  }    
                                                                        
  if (averageTemp <= closeTemp) {                                                                // Compares the average temp to the temp to close valve
    digitalWrite(13, LOW);                                                                       // Turns off LED to indicate closed valve
    servo1.attach(servo1Pin, 785, 2180);
    servo1.write(closepos);                                                                      // Move servo1 to closed position
    servo1.detach();
  }

This was how I was trying it, but it seems to not function as anticipated. Since this whole if statement is looped every second, along with the temp readings it’s still writing every second. Also when the temperature does go up to the point where the servo is triggered to move and LED comes on, but doesn’t seem to go back to the original position. I’ll have to re-upload it this way and try some stuff out to make sure I have that correct.

What I’d like to do if possible is have the temperature measurement and averaging take place every 1000ms, but unless the outcome changes, no servo writing or anything should be happening. Instead it seems the greater than/less than servo write and digital write for the led is happenning with every loop as well.

I hope I’ve explained that correctly. Make sense?

poor_red_neck:
What I'd like to do if possible is have the temperature measurement and averaging take place every 1000ms, but unless the outcome changes, no servo writing or anything should be happening.

That sounds like a sensible thing to do. The "BlinkWithoutDelay" example should help you do the temperature sensing every 1000mS.

This is what it is currently doing. Taking a reading every 1000ms.

What I'm trying to accomplish that I haven't found an example of is NOT writing to the servo every 1000ms.

I just wan the comparison of averagetemp and opentem (or closedtemp) to be done along with the temp reading, but ONLY writing to the servo when there is a change.

So if the averagetemp is greater than or equal to 78, then write to the servo ONCE to move it. Otherwise don't continue doing a servo write every 1000ms and detach the servo.

Once the averagetemp is equal or less than 72, open the vent (do a servo write once) then do nothing & detach the servo.

I've tried various ways of doing that, and no matter what I do it either moves, disconnects, but never re-connects. Or it fails to disconnect and continues in the loop. Or I somehow break the whole thing and get a movement one time, but nothing after that (if the temp goes above 78 it will move once, stay connected, but then won't move once the temp drops at or below 72.

I don't know how to search for an example of this, and I've read code until my eyes hurt but it's just not clicking.

I think another way of explaining my intended purpose is for the if x >= z generates a true or false return. Then if the result is true, do the servo write. If the next result is also true, detach the servo as it won’t need to move again. It will continue doing this check, then doing nothing because it has been receiving true returns each time. Once the if y <= z then it will return a true statement, move the servo, then if the next result is also true it will not do anything but detach the servo.

Since I have a 5 degree variance in there between x and y, if either one of those return a false statement it should also do nothing.

So let’s say the temp climbs to 79, the servo will open. The temp starts to fall and will go below 78. Let’s say 75. I don’t the servo to do anything. It will stay in that position until the temp reaches 73. At which point the servo will close. Once the temp starts to rise to 75 again, I still do not want the servo to move. Not until it reaches 78 again.

Without attempting to detach the servo, this is how the script currently works. The script in my original post is doing this perfectly. The issue is writing to the servo one time until it either raises above or falls below the two variables: opentemp, closed temp.

Perhaps if you picked one of your attempts and showed it we might be able to suggest changes.

poor_red_neck:

Here’s how I was trying the code to detach and attach. The issue is the whole script is being looped every second. A downfall I’ve not anticipated with the arduino.

I want it to take a temperature measurement every second, but not write the servo’s position every second. Seems no matter where I put the 1000ms delay it affects the temperature reading.

  if (averageTemp >= openTemp) {                                                                 // Compares the average temp to the temp to open valve   

digitalWrite(13, HIGH);                                                                      // Turns on LED to indicate
    servo1.attach(servo1Pin, 785, 2180);
    servo1.write(openpos);                                                                      // Move servo1 to open position
    servo1.detach();
  }   
                                                                       
  if (averageTemp <= closeTemp) {                                                                // Compares the average temp to the temp to close valve
    digitalWrite(13, LOW);                                                                      // Turns off LED to indicate closed valve
    servo1.attach(servo1Pin, 785, 2180);
    servo1.write(closepos);                                                                      // Move servo1 to closed position
    servo1.detach();
  }





This was how I was trying it, but it seems to not function as anticipated. Since this whole if statement is looped every second, along with the temp readings it's still writing every second. Also when the temperature does go up to the point where the servo is triggered to move and LED comes on, but doesn't seem to go back to the original position. I'll have to re-upload it this way and try some stuff out to make sure I have that correct.

This is what I posted earlier, my attempt at detaching and attaching. Problem is this whole part is looped every 1000ms along with the temp reading.

Here’s the entire script with the quoted above attempt:

#include <math.h>
#include <Servo.h>
#define ThermistorPIN 0                                                                          // Define the Thermistor Input Pin
Servo servo1;
int servo1Pin = 5;                                                                               // Define Servo 1 Signal Pin (Digital)
int openTemp = 78;                                                                               // Temperature to open butterfly valve
int closeTemp = 73;                                                                              // Temperature to close butterfly valve
int openpos = 180;                                                                               // Define servo1 OPEN position to 180 degrees
int closepos = 90;                                                                               // Define servo1 CLOSED position to 0 degrees
const int numReadings = 10;                                                                      // Number of temperature readings to averageTemp out. 10 to 20 works best. 
int readings[numReadings];                                                                       // the readings from the analog input
int readIndex = 0;                                                                               // the index of the current reading
int total = 0;                                                                                   // the running total
int averageTemp = 0;                                                                             // setting up the averageTemp
float tempResistor = 9550;                                                                       // Thermistor Pull Up/Down Resistor Value in ohms
float Thermistor(int RawADC) {
  long Resistance;  
  float Temp;                                                                                    // Dual-Purpose variable to save space.
  Resistance=tempResistor / 4 * ((1024.0 / RawADC) - 1);                                         // Original code did not divide by 4 and I got incorrect readings. If your readings are off take out the " / 4 "
  Temp = log(Resistance);                                                                        // Saving the Log(resistance) so not to calculate  it 4 times later
  Temp = 1 / (0.001129148 + (0.000234125 * Temp) + (0.0000000876741 * Temp * Temp * Temp));      // Convert resistance to Kelvin
  Temp = Temp - 273.15;                                                                          // Convert Kelvin to Celsius                      
  return Temp;                                                                                   // Return the Temperature
}

void setup() {
  Serial.begin(9600);                                                                            // Define baud rate for serial interface output
  //servo1.attach(servo1Pin, 785, 2180);     // Took this line out since the servo is attached below
  for (int thisReading = 0; thisReading < numReadings; thisReading++) {
  readings[thisReading] = 0;
 }
}

void loop() {
  float temp;
  temp=Thermistor(analogRead(ThermistorPIN));                                                    // read ADC and convert it to Celsius
  temp = (temp * 9.0)/ 5.0 + 32.0;                                                               // converts to  Fahrenheit
  total = total - readings[readIndex];                                                           // subtract the last reading:
  readings[readIndex] = temp;                                                                    // read from the sensor:
  total = total + readings[readIndex];                                                           // add the reading to the total:
  readIndex = readIndex + 1;                                                                     // advance to the next position in the array:
  if (readIndex >= numReadings) {                                                                // if we're at the end of the array...
    readIndex = 0;                                                                               // ...wrap around to the beginning:
  }
  averageTemp = total / numReadings;                                                             // calculate the averageTemp:
  // ------------------------------------
  Serial.print("Temp: "); 
  Serial.print(averageTemp);                                                                     // Outputs "smoothed" thermistor integer value
  Serial.print(" F");
  // ------------------------------------
  Serial.print("    Raw Data : ");
  Serial.print(temp,1);                                                                          // Outputs raw temp in F for comparison
  Serial.println("");
  // ------------------------------------
  delay(1000);                                                                                   // delay in between reads for stability

  if (averageTemp >= openTemp) {                                                                 // Compares the average temp to the temp to open valve   
    
    digitalWrite(13, HIGH);                                                                      // Turns on LED to indicate 
    servo1.attach(servo1Pin, 785, 2180);
    servo1.write(openpos);                                                                       // Move servo1 to open position 
    servo1.detach();
  }    
                                                                        
  if (averageTemp <= closeTemp) {                                                                // Compares the average temp to the temp to close valve
    digitalWrite(13, LOW);                                                                       // Turns off LED to indicate closed valve
    servo1.attach(servo1Pin, 785, 2180);
    servo1.write(closepos);                                                                      // Move servo1 to closed position
    servo1.detach();
  }
}

I think you probably want to do something like this:

#include <math.h>
#include <Servo.h>
const int ThermistorPIN = A0;                                                                          // Define the Thermistor Input Pin
Servo servo1;
const int servo1Pin = 5;                                                                               // Define Servo 1 Signal Pin (Digital)
const int openTemp = 78;                                                                               // Temperature to open butterfly valve
const int closeTemp = 73;                                                                              // Temperature to close butterfly valve
const int openpos = 180;                                                                               // Define servo1 OPEN position to 180 degrees
const int closepos = 90;                                                                               // Define servo1 CLOSED position to 0 degrees
const unsigned long SampleInterval = 1000;  // Sample every second
const int numReadings = 10; // Average over 10 intervals
int readings[numReadings];                                                                       // the readings from the analog input
int readIndex = 0;                                                                               // the index of the current reading
int total = 0;                                                                                   // the running total                                                                           // setting up the averageTemp
const float tempResistor = 9550.0;                                                                       // Thermistor Pull Up/Down Resistor Value in ohms

float Thermistor(int RawADC) {
  long Resistance;
  float Temp;                                                                                    // Dual-Purpose variable to save space.
  Resistance = tempResistor / 4 * ((1024.0 / RawADC) - 1);                                       // Original code did not divide by 4 and I got incorrect readings. If your readings are off take out the " / 4 "
  Temp = log(Resistance);                                                                        // Saving the Log(resistance) so not to calculate  it 4 times later
  Temp = 1 / (0.001129148 + (0.000234125 * Temp) + (0.0000000876741 * Temp * Temp * Temp));      // Convert resistance to Kelvin
  Temp = Temp - 273.15;                                                                          // Convert Kelvin to Celsius
  return (Temp * 9.0) / 5.0 + 32.0;                                                              // Return the Temperature
}

void MoveTo(int position) {
  static int lastPosition = -1;
  if (position != lastPosition) {  // Position changing
    servo1.attach(servo1Pin, 785, 2180);  // Set limits of pulse width in microseconds
    servo1.write(position);
    delay(100);  // Give the servo time to move to the new position
    servo1.detach();  // Stop sending pulses to the servo to prevent jitter noise
    lastPosition = position;
  }
}

void setup() {
  Serial.begin(9600);                                                                            // Define baud rate for serial interface output
  total = 0;
  int temperature = Thermistor(analogRead(ThermistorPIN));
  for (int thisReading = 0; thisReading < numReadings; thisReading++) {
    readings[thisReading] = temperature;
    total += temperature;
  }
}

void loop() {
  static unsigned long lastSampleTime = 0;
  unsigned long currentTime = millis();
  if (currentTime - lastSampleTime >= SampleInterval) {
    lastSampleTime = currentTime;
    float temp;
    temp = Thermistor(analogRead(ThermistorPIN));                                                  // read ADC and convert it to Celsius
    // converts to  Fahrenheit
    total = total - readings[readIndex];                                                           // subtract the last reading:
    readings[readIndex] = temp;                                                                    // read from the sensor:
    total = total + readings[readIndex];                                                           // add the reading to the total:
    readIndex = (readIndex + 1) % numReadings;                                                     // advance to the next position in the array:
    int averageTemp = total / numReadings;                                                             // calculate the averageTemp:
    // ------------------------------------
    Serial.print("Temp: ");
    Serial.print(averageTemp);                                                                     // Outputs "smoothed" thermistor integer value
    Serial.print(" F");
    // ------------------------------------
    Serial.print("    Raw Data : ");
    Serial.println(temp, 1);                                                                         // Outputs raw temp in F for comparison
    // ------------------------------------

    if (averageTemp >= openTemp) {                                                                 // Compares the average temp to the temp to open valve
      digitalWrite(13, HIGH);                                                                      // Turns on LED to indicate
      MoveTo(openpos);                                                                       // Move servo1 to open position
    }

    if (averageTemp <= closeTemp) {                                                                // Compares the average temp to the temp to close valve
      digitalWrite(13, LOW);                                                                       // Turns off LED to indicate closed valve
      MoveTo(closepos);                                                                      // Move servo1 to closed position
    }
  }
}

Thank you!! This works perfectly. Only thing I needed to do was adjust the delay for allowing the servo time to move.

I will now try and understand what you did. Having a working model to "reverse engineer" will definitely allow me to learn.

Thank you again.