Go Down

Topic: Servo Sweep with conditions (Read 995 times) previous topic - next topic

eclipsear

hello, this part of the code doesn't work and i dont get why.
threshold2 is 70
Simple Servo sweep code

int analogValue2 = dht_dat[0];
                if (analogValue2 > threshold2) {
                for(pos = 0; pos < 180; pos += 1)  // goes from 0 degrees to 180 degrees
                {                                  // in steps of 1 degree
                  myservo.write(pos);              // tell servo to go to position in variable 'pos'
                  delay(15);                       // waits 15ms for the servo to reach the position
                }
                }
                else {
                for(pos = 180; pos>=1; pos-=1)     // goes from 180 degrees to 0 degrees
                {                               
                myservo.write(pos);              // tell servo to go to position in variable 'pos'
                delay(15);                       // waits 15ms for the servo to reach the position
                  }
               }

Im trying to compare AnalogValue2 and when is over 70 it SHOULD made the servo move from 0 to 180 and when is LOWER than 70 return to 0. What im doing wrong?




rgallant

Not enough code, where do you set dht_dat[0] ?   Are you sure it is set? toss some debug print outs in your code right above
Quote
int analogValue2 = dht_dat[0];
.   It is a simple if statement they only fail when the conditions are not met, which leads back to my 1st question.

eclipsear

#2
Nov 23, 2012, 05:20 pm Last Edit: Nov 24, 2012, 02:14 pm by eclipsear Reason: 1
Code: [Select]
#define dht_dpin 14
#define LIGHT_SENSOR_PIN 1
#include <LiquidCrystal.h>

LiquidCrystal lcd(0, 1, 2, 3, 4, 5);

byte bGlobalErr; //for passing error code back from complex functions.
byte dht_dat[4]; //Array to hold the bytes sent from sensor.
int light_intensity = 0;
unsigned int flip = 0;

const int ledPin = 12;       // RELE    pin that the LED is attached to
const int threshold = 400;   // an arbitrary threshold level that's in the range of the analog input

const int threshold2 = 70;   // SERVO    an arbitrary threshold level that's in the range of the analog input

#include <Servo.h>
Servo myservo;  // create servo object to control a servo
               // a maximum of eight servo objects can be created
int pos = 0;

void setup(){
       myservo.attach(9);
       pinMode(ledPin, OUTPUT);
       pinMode(13, OUTPUT);
       lcd.begin(16, 2);
       lcd.print("MTC cia ltda");
       InitDHT(); //Do what's necessary to prepare for reading DHT
       //Serial.begin(9600);
       delay(300); //Let system settle
       //Serial.println("Humidity and temperature\n\n");
       delay(700); //Wait rest of 1000ms recommended delay before
       //accessing sensor
} //end "setup()"

void loop(){
       
       Serial.print("Moisture Sensor Value:");
  Serial.println(analogRead(2));  
  delay(100);
if ( flip & 1 )
       {
               digitalWrite(13, HIGH);
       } else {
               digitalWrite(13, LOW);
       }

       flip++;

       light_intensity=analogRead(LIGHT_SENSOR_PIN);

       ReadDHT();
       switch (bGlobalErr) {
       case 0:
               lcd.setCursor(0, 0);
               // Serial.print("humdity = ");
               lcd.print("T Aire =       ");
               lcd.setCursor(9, 0);
               lcd.print( dht_dat[2], DEC);
               lcd.setCursor(0, 1);
               //Every 7 out of 15 times we show humidity, rest temp
               if ((flip % 15) > 7 )
               {
                       lcd.print("H Aire =      ");
                       lcd.setCursor(9, 1);
                       lcd.print( dht_dat[0], DEC);
                       lcd.setCursor (11,1);
                       lcd.print("%");
               } else {
                       lcd.print("H Suelo =      ");
                       lcd.setCursor(10, 1);
                       lcd.print( analogRead(2), DEC);
                       lcd.setCursor(12,1);
                       lcd.print("%");
               }
               //Serial.print("temperature = ");
               //Serial.print(dht_dat[2], DEC);
               //Serial.print(".");
               //Serial.print(dht_dat[3], DEC);
               //Serial.println("C  ");
               break;
               
       case 1:
               //Serial.println("Error 1: DHT start condition 1 not met.");
               break;
       case 2:
               //Serial.println("Error 2: DHT start condition 2 not met.");
               break;
       case 3:
               //Serial.println("Error 3: DHT checksum error.");
               break;
       default:
               //Serial.println("Error: Unrecognized code encountered.");
               break;
       } //end "switch"
       
       
       int analogValue = analogRead(2);
               // if the analog value is high enough, turn on the LED:
               if (analogValue > threshold) {
               digitalWrite(ledPin, LOW);
               }
               else {
               digitalWrite(ledPin,HIGH);
               }
               
        int analogValue2 = dht_dat[0];
               if (analogValue2 > threshold2) {
               for(pos = 0; pos < 180; pos += 1)  // goes from 0 degrees to 180 degrees
               {                                  // in steps of 1 degree
                 myservo.write(pos);              // tell servo to go to position in variable 'pos'
                 delay(15);                       // waits 15ms for the servo to reach the position
               }
               }
               else {
               for(pos = 180; pos>=1; pos-=1)     // goes from 180 degrees to 0 degrees
               {                                
               myservo.write(pos);              // tell servo to go to position in variable 'pos'
               delay(15);                       // waits 15ms for the servo to reach the position
                 }
              }


       delay(800); //Don't try to access too frequently... in theory
       //should be once per two seconds, fastest,
       //but seems to work after 0.8 second.
       
} // end loop()

/*Below here: Only "black box" elements which can just be plugged unchanged
  unchanged into programs. Provide InitDHT() and ReadDHT(), and a function
  one of them uses.*/

void InitDHT(){
       //DDRC |= _BV(dht_PIN);//set data pin... for now... as output
       //DDRC is data direction register for pins A0-5 are on
       //PORTC |= _BV(dht_PIN);//Set line high
       //PORTC relates to the pins A0-5 are on.
       //Alternative code...
//        if (dht_dpin-14 != dht_PIN){Serial.println("ERROR- dht_dpin must be 14 more than dht_PIN");};//end InitDHT
       pinMode(dht_dpin,OUTPUT); // replaces DDRC... as long as dht_dpin=14->19
       digitalWrite(dht_dpin,HIGH); //Replaces PORTC |= if dht_pin=14->19
} //end InitDHT

void ReadDHT(){
/*Uses global variables dht_dat[0-4], and bGlobalErr to pass
  "answer" back. bGlobalErr=0 if read went okay.
  Depends on global dht_PIN for where to look for sensor.*/
       bGlobalErr=0;
       byte dht_in;
       byte i;
       // Send "start read and report" command to sensor....
       // First: pull-down i/o pin for 18ms
       digitalWrite(dht_dpin,LOW); //Was: PORTC &= ~_BV(dht_PIN);
       delay(18);
       delayMicroseconds(600);//TKB, frm Quine at Arduino forum
/*aosong.com datasheet for DHT22 says pin should be low at least
  500us. I infer it can be low longer without any]
  penalty apart from making "read sensor" process take
  longer. */
//Next line: Brings line high again,
//   second step in giving "start read..." command
       digitalWrite(dht_dpin,HIGH); //Was: PORTC |= _BV(dht_PIN);
       delayMicroseconds(40); //DHT22 datasheet says host should
       //keep line high 20-40us, then watch for sensor taking line
       //low. That low should last 80us. Acknowledges "start read
       //and report" command.

//Next: Change Arduino pin to an input, to
//watch for the 80us low explained a moment ago.
       pinMode(dht_dpin,INPUT); //Was: DDRC &= ~_BV(dht_PIN);
       delayMicroseconds(40);

       dht_in=digitalRead(dht_dpin); //Was: dht_in = PINC & _BV(dht_PIN);

       if(dht_in) {
               bGlobalErr=1; //Was: Serial.println("dht11 start condition 1 not met");
               return;
       } //end "if..."
       delayMicroseconds(80);

       dht_in=digitalRead(dht_dpin); //Was: dht_in = PINC & _BV(dht_PIN);

       if(!dht_in) {
               bGlobalErr=2; //Was: Serial.println("dht11 start condition 2 not met");
               return;
       } //end "if..."

/*After 80us low, the line should be taken high for 80us by the
  sensor. The low following that high is the start of the first
  bit of the forty to come. The routine "read_dht_dat()"
  expects to be called with the system already into this low.*/
       delayMicroseconds(70);
//now ready for data reception... pick up the 5 bytes coming from
//   the sensor
       for (i=0; i<5; i++)
               dht_dat[i] = read_dht_dat();

//Next: restore pin to output duties
       pinMode(dht_dpin,OUTPUT); //Was: DDRC |= _BV(dht_PIN);
//N.B.: Using DDRC put restrictions on value of dht_pin

//Next: Make data line high again, as output from Arduino
       digitalWrite(dht_dpin,HIGH); //Was: PORTC |= _BV(dht_PIN);
//N.B.: Using PORTC put restrictions on value of dht_pin

//Next see if data received consistent with checksum received
       byte dht_check_sum =
               dht_dat[0]+dht_dat[1]+dht_dat[2]+dht_dat[3];
/*Condition in following "if" says "if fifth byte from sensor
      not the same as the sum of the first four..."*/
       if(dht_dat[4]!= dht_check_sum)
       {bGlobalErr=3; } //Was: Serial.println("DHT11 checksum error");
}; //end ReadDHT()

byte read_dht_dat(){

       byte i = 0;
       byte result=0;
       for(i=0; i< 8; i++) {
               delayMicroseconds(30);

               
               if (digitalRead(dht_dpin)==HIGH) //Was: if(PINC & _BV(dht_PIN))
                       result |=(1<<(7-i));  // "add" (not just addition) the 1
               while (digitalRead(dht_dpin)==HIGH) ;  //Was: while((PINC & _BV(dht_PIN)));
               
               
       }
       return result;
}


AWOL

...and if you think we're being picky, ask yourself "Did I really write my source with italics?"
"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

eclipsear

well i said the servo need to move from 0 degree to 180 when the Air humidity is over 70% (dht_dat[0]) and return from 180 or stay in 0...  This mean actually a "Window opening because the humidity is too high"

AWOL

OK, we're still missing a few things here.
The first is [font=Verdana][[/font]code] [font=Verdana][[/font]/code] tags, and another is a list of your observations and the output from your debug prints.
"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

eclipsear

#7
Nov 24, 2012, 01:10 pm Last Edit: Nov 24, 2012, 01:42 pm by eclipsear Reason: 1
Hey everyone, i have this soil sensor OBSoil + sweep servo. In this code the servo should be acting when Analogread(2) > 400 making the servo move from 0 degree to 180 degree and when is lower (else) return from 180 to 0 degree or just stay in 0 degree. (acting like a window)

When I try this code the servo it just acting back and forth.. i think its something with the FOR line in the servo, i tried to make the comparation there but it doesnt work.

This is the basic sweep servo code but im pretty sure its something with the FOR of the servo and the IF that im trying to put there.

Code: [Select]
//OB SOIL
//# the sensor value description
//  # 0  ~300      dry soil
//  # 300~700     humid soil
//  # 700~950     in water
#include <Servo.h>
Servo myservo;
const int number = 400;
int pos = 0;

void setup(){
       Serial.begin(9600);
       myservo.attach(9);
}

void loop(){
        Serial.print("Moisture Sensor Value:");
        Serial.println(analogRead(2));  
        delay(100);
        int analogValue2 = analogRead(2);
               if (analogValue2 > number) {
               for(pos = 0; pos < 180; pos += 1)  
               {                                  
                 myservo.write(pos);              
                 delay(15);                      
               }
               }
               else {
               for(pos = 180; pos>=1; pos-=1)    
               {                                
               myservo.write(pos);              
               delay(15);                        
                 }
              }
}

MarkT

You need hysteresis in your code to prevent noise being amplified like this.

You use two threshold values that are far enough apart that sensor noise won't trigger changes.

Lets imagine your sensor has +/-10 counts or so of noise, you might choose thresholds of 390 an 410.

I the value goes above 410 then you move the servo, but only move it back if it falls below 390,

Also you can reduce the noise with low-pass filtering (soil doesn't change very fast does it?).  Keep a running average of the sensor values over a timescale of a minute or so - this should average away most of the noise and allow much more narrow hysteresis limits.
[ I won't respond to messages, use the forum please ]

holmes4

Your servo is being told to go to pos 0 and then move step by step to pos 180
Code: [Select]

              for(pos = 0; pos < 180; pos += 1)  
               {                                  
                 myservo.write(pos);              
                 delay(15);                      
               }
           


this tells your servo to go to pos 180 and then move step by step to pos 0

Code: [Select]
               for(pos = 180; pos>=1; pos-=1)    
               {                                
               myservo.write(pos);              
               delay(15);                        
                 }


So what ever reading you get it just move back forth!


Mark

eclipsear


So what ever reading you get it just move back forth!

Thank you, thats the big problem for me.. what i should change for making to act like a window? the for should i change it for some other sentence?

PaulS

Quote
Your servo is being told to go to pos 0 and then move step by step to pos 180

Which happens in a if block.

Quote
this tells your servo to go to pos 180 and then move step by step to pos 0

Which happens in the else block.

Quote
So what ever reading you get it just move back forth!

Not true.

@OP:
You need to put each { on a new line, and use Tools + Auto Format to properly/consistently indent your code. Then, you need to add some Serial.print() and Serial.println() statements to print out the values read from the sensor.

Code: [Select]
         Serial.println(analogRead(2)); 
         delay(100);
         int analogValue2 = analogRead(2);

The value that you are printing is NOT the value that you are acting on. While they should be relatively close to the same value, that is true only if your sensor is working correctly. Why not make life easy, though, and print the value that you make decisions on?

Also, you are the only one that can see the output you are getting now, so you are the only one that can solve the problem. Share the output (after you fix it) and the modified code if you want us to help.

eclipsear

ok i added the auto format and the }. The problem is when the sensor is lower than 400 is making the servo act like the IF but it should be Else (lower than 400) .. from 0 to 180 degree step by step, returning to 0 fast and going to 0 to 180 degree step by step again and again.

Serial says this and its fine because is not in the soil (making the condition Else < 400 BUT acting like the IF)
Moisture Sensor Value: 0
Moisture Sensor Value: 0
Moisture Sensor Value: 7
Moisture Sensor Value: 7
Moisture Sensor Value: 11
Moisture Sensor Value: 7
Moisture Sensor Value: 0


Code: [Select]
//OB SOIL
//# the sensor value description
//  # 0  ~300      dry soil
//  # 300~700     humid soil
//  # 700~950     in water
#include <Servo.h>
Servo myservo;
const int number = 400;
int pos = 0;

void setup()
{
  Serial.begin(9600);
  myservo.attach(9);
}

void loop()
{
  Serial.print("Moisture Sensor Value:");
  Serial.println(analogRead(2)); 
  delay(100);
  if (analogRead(2) > number)
  {
    for(pos = 0; pos < 180; pos += 1) 
    {                                   
      myservo.write(pos);             
      delay(15);                       
    }
  }
  else
  {
    for(pos = 180; pos>=1; pos-=1)     
    {                               
      myservo.write(pos);               
      delay(15);                       
    }
  }
}

PaulS

Quote
The problem is when the sensor is lower than 400 is making the servo act like the IF but it should be Else (lower than 400) .. from 0 to 180 degree step by step, returning to 0 fast and going to 0 to 180 degree step by step again and again.

When the value is less than 400, as it always appears to be, you tell the servo to move from 180 to 0 slowly. But, the servo is not at 180, so, first, it need to go there. Then, it can go to 0 slowly.

Add two more print() statements, one in the if block, and one in the else block.
Code: [Select]
Serial.println("Soil is wet"); // in the if block
Serial.println("Soil is dry"); // in the else block


Does the correct message get printed, matching the sensor value? If so, the correct block is being executed.

eclipsear

umm yeah i think is not the sweep servo i should be using.. i just need to move from position 0 to 1 and from 1 to 0 with conditions

Code: [Select]
pos1 = 180 degree
pos0 = 0 degree

if Analogread(2) > 400
move the servo to pos1
else
move the servo to pos0


i need a hand for this.. it would be simple as that

Go Up