Servo "Chirping"

Hey everyone, I'm almost finished with a school project and I need some help...I have a thermocouple which acts as an input to control a servo. When the temperature of the thermocouple reaches 115 the servo turns 90deg. Two problems:

  1. The LCD keeps flashing rapidly during the loop. I know its because of the delay and the loop, but is there a way around this? The reason we put it inside the loop is because when the temperature exceeded 3-digits and went back down to 2-digits, it would leave the undesired last digit on the LCD. We wrote inside the loop to constantly "refresh" the temperature reading, but unfortunately its annoying me and isn't a desirable design.

  2. The servo keeps "chirping". I can't seem to find anything on the boards that is similar to what I need. Can someone explain why it would be chirping and jerking every second or so? My guess is that the servo isn't in steady state or something, and the loop is having some sort of effect on it. Any help with code would be greatly appreciated!

/* Valve Control System for Monitoring & Scald-Proofing Tap Water Outputs
Developed by: Dennis M. Burke & Chris Mroz

Wayne State University
Detroit, MI
ET4999: Senior Project
Winter 2010

Copyright 2010 by Dennis M. Burke & Chris Mroz
All Rights Reserved
*/

/********************************************************************************
LCD Pinout: LED Pinout: Servo Motor:
Digital I/O Pin 2: D7 Digital I/O Pin 7: Red LED Digital I/O Pin 9
Digital I/O Pin 3: D6 Digital I/O Pin 8: Green LED
Digital I/O Pin 4: D5
Digital I/O Pin 5: D4
Digital I/O Pin 11: Enable Thermocouple:
Digital I/O Pin 12: RS Analog I/O Pin 0
*********************************************************************************/

#include <Servo.h>
#include <LiquidCrystal.h>

int red = 7, green = 8, index = 0, total = 0, average = 0, TC = 0, q = 0;
const int numReadings = 5;
int readings[numReadings];

LiquidCrystal lcd(12, 11, 5, 4, 3, 2); //see LCD Pinout
Servo myservo; // declares servo

void setup()
{
pinMode(TC, INPUT);
pinMode(green, OUTPUT);
pinMode(red, OUTPUT);

myservo.attach(9);

digitalWrite(red, HIGH);
digitalWrite(green, LOW);

lcd.begin(20, 2);
lcd.print(" ET4999");
lcd.setCursor(0,1);
lcd.print(" Senior Project");
delay(1000);

for (int i = 0; i < 20; i++)
{
lcd.scrollDisplayLeft();
delay(50);
}

lcd.clear();
lcd.print(" Wayne State");
lcd.setCursor(0,1);
lcd.print(" University");
delay(1000);

for (int positionCounter = 0; positionCounter < 20; positionCounter++)
{
lcd.scrollDisplayRight();
delay(50);
}

lcd.clear();
lcd.print(" Scalding Water");
lcd.setCursor(0,1);
lcd.print(" Shutoff Device");
delay(3000);
lcd.clear();
lcd.print(" Developed by:");
delay(1000);
lcd.clear();
lcd.print(" Dennis Burke &");
lcd.setCursor(0,1);
lcd.print(" Chris Mroz");
delay(3000);
lcd.clear();
delay(500);

} //END VOID SETUP

void loop()
{
int raw = 0, celsius = 0, fahrenheit = 0;

digitalWrite(red, LOW);
digitalWrite(green, HIGH);

if (q<5) //initializing sequence
{
lcd.print("Initializing");

for (int j = 0; j<=5; j++)
{
total= total - readings[index]; // subtract the last reading.
readings[index] = analogRead(TC); // read from the sensor.
total= total + readings[index]; // add the reading to the total.
index = index + 1; // advance to the next position in the array.

if (index >= numReadings) // if at the end of the array, then go back to the beginning
index = 0;

average = total / numReadings; // calculate the average analog reading (0 - 1024)
}

for(int z = 0; z <= 8; z++)
{
lcd.print(".");
digitalWrite(green, HIGH);
delay(250);
digitalWrite(green, LOW);
delay(250);
}

lcd.clear();
q = 5;
}

else
{

total= total - readings[index]; //see above notes...
readings[index] = analogRead(TC);
total= total + readings[index];
index = index + 1;

if (index >= numReadings)
index = 0;

average = total / numReadings;

celsius = ( 5.0 * average * 100.0) / 1024.0;
fahrenheit = (((celsius * 9) / 5) + 32);

if (fahrenheit >= 115)
{
myservo.write(180); // close valve and turn on "warning" LED
digitalWrite(green, LOW);
digitalWrite(red, HIGH);
}

else
{
myservo.write(90); // open valve and turn on "okay" LED
digitalWrite(green, HIGH);
digitalWrite(red, LOW);
}

lcd.print("Fahrenheit:");
lcd.setCursor(14,0);
lcd.print(fahrenheit);
lcd.setCursor(0,1);
lcd.print("Celsius:");
lcd.setCursor(14,1);
lcd.print(celsius);
delay(250);
lcd.clear();

} //END ELSE STATEMENT

} //END VOID LOOP

Looks like here's your problem:

if (fahrenheit >= 115)
{
myservo.write(180); // close valve and turn on "warning" LED
digitalWrite(green, LOW);
digitalWrite(red, HIGH);
}

else
{
myservo.write(90); // open valve and turn on "okay" LED
digitalWrite(green, HIGH);
digitalWrite(red, LOW);
}

Every time you loop, you're rewriting the servo position. Even if it isn't technically a different position, the servo must be trying to make sure it's exactly there. What you need to do is this:

if (fahrenheit >= 115)
        {
          myservo.write(180);              // close valve and turn on "warning" LED
          digitalWrite(green, LOW);
          digitalWrite(red, HIGH);
        }
       
      else
        {
[glow]if (myservo.read() != 90) {[/glow]
          myservo.write(90);              // open valve and turn on "okay" LED
          digitalWrite(green, HIGH);
          digitalWrite(red, LOW);
[glow]}[/glow]
        }

The highlighted section will test to see if the last written value was 90, and if it was, there's no need to change anything.

Let me know if that works.

Thanks for the idea, but unfortunately that doesn't work either...

I did upload this code and it showed me that my servo has a hum just from power. Take a look:

#include <Servo.h>

Servo myservo;

void setup()
{
myservo.attach(9); // attaches the servo on pin 9 to the servo object
}

void loop()
{

}

No idea why. Someone at school had mentioned adding a filtering circuit? I don't want to design one if there is an easier solution. Any ideas would be really helpful.

In the Servo.h file, located in /libraries/Servo, there are a couple of parameters you can play with; stick with your "simple attach" example as you adjust the parameters, then try your regular code.

In this file, the parameters are:

#define DEFAULT_PULSE_WIDTH  1500     // default pulse width when servo is attached
#define REFRESH_INTERVAL    20000     // minumim time to refresh servos in microseconds

I would first try lowering the REFRESH_INTERVAL to something like 19500 or 19000; I am not sure how low you can go, but if you don't notice any changes by 15000, revert it back to 20000, and try changing the DEFAULT_PULSE_WIDTH - by making it a little wider (increase the value) or narrower (decrease the value). I have a feeling your "dead band" is a little smaller than what the library is set up for; I am not sure why you can't change this with the attach command, but it isn't set up that way (you can only change the minimum and maximum pulse widths)?

Make a backup of the file (just in case), then use a text editor to alter the file and re-save it, then re-upload/compile your sketch in the Arduino IDE.

Hope this helps!

:slight_smile:

The servo will chirp due to the liquid crstal library. I think it's the interrupts or something... You can detach the servo servo.detach(); when you are not using it but you can only use this for some situations as it then allows the servo to move from its position.

Mowcius

To add to Mowcius' statement, this is most certainly manifestation of bug #146.
http://code.google.com/p/arduino/issues/detail?id=146&sort=-id

There is some discussion on this thread:
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1266553734/21
Moving the servos to other pins can reduce the frequency of the glitches.

to add to vinceherman's statement, try attaching the servo to one of the analog input pins (for example, analog input pin 0 is digital pin 14). if that solves the problem then it was due to bug #146.

if you are using arduino version 0017 or earlier, you will also need to upgrade to 0018 as there are other issues with the earlier versions that can affect servo operation with LiquidCrystal.

Thanks everyone, I really appreciate it...I will try using your suggestions soon and keep you posted.

-DB

Another problem...but some background first. The servo is attached to a water valve. 90deg is open and 180deg is closed. When the temperature of the water is 115degF the servo goes to closed position. The problem we are having is that n the servo goes crazy by opening and closing when the temperature is very close to 115F. I want to write something that says the following:

if temperature<=115

within the if statement I want to turn servo to closed position until the temperature reaches 110 (so the valve isn't opening and shutting rapidly).

The programming is blowing my mind, but I think its a very simple nested if statement. I just don't have the skills to write it yet!

I think this stabilizes the system and its called hysterisis or something.

try this:

      if (fahrenheit >= 115)
        {
          myservo.write(180);              // close valve and turn on "warning" LED
          digitalWrite(green, LOW);
          digitalWrite(red, HIGH);
        }
        
      if (fahrenheit <= 110)
        {
          myservo.write(90);              // open valve and turn on "okay" LED
          digitalWrite(green, HIGH);
          digitalWrite(red, LOW);
        }