Without delay

So far I have seen the Blink without delay program and the water buckett program. I just cannot seem to wrap my mind around the concept. Or, how I can apply that to my individual situation. (Sorry for being so dense.)

If someone could give me another example. I have a set of brows on my robot. When I raise the brows, I leave them UP about 1-2 seconds and use a 1000 to 2000 delay. This is right in the middle of my PING and IR scan. So, it makes the whole robot run slow. But, the brows are really cool and I wish to keep them. Someone said that I could use this NO Delay technique in order to pause the brows without pausing the PING scan. I am hopelessly loss trying to understand this. If someone could be so kind to explain this concept to someone who has JUST begun to use 'c'. I finally understand how to do a subroutine, but that took me a week and a half and LOTS of advice.

The reason I activate these during the scan is so the BROWS can go UP when the PING or IR sees something. It is a really cool effect.

Thanks!

:wink:

Here is some quickly put together and untested code that should get you going.

#include <MegaServo.h>
   MegaServo myservo;
// Begin Robot Code
//int micVal;
//int cdsVal;
int irLval;  // Left IR
int irCval;  // Center IR
int irRval;  // Right IR
int i;   // Generic Counter
int x;  // Generic Counter
int PLval;  // Pulse Width for Left Servo
int PRval;  // Pulse Width for Right Servo
int cntr;  // Generic Counter Used for Determining amt. of Object Detections
int counter; // Generic Counter
int clrpth;  // amt. of Milliseconds Of Unobstructed Path
int objdet;  // Time an Object was Detected
int task;  // Routine to Follow for Clearest Path
int pwm;  // Pulse Width for Pan Servo
boolean add;  // Whether to Increment or Decrement PW Value for Pan Servo
int distance;  // Distance to Object Detected via Ultrasonic Ranger
int oldDistance;  // Previous Distance Value Read from Ultrasonic Ranger

float scale = 1.9866666666666666666666666666667;  // *Not Currently Used*

int LeftPin = 6;  // Left Servo
int RightPin = 9;  // Right Servo
int PingServoPin = 5;  // Pan Servo
int irLPin = 0;            // Analog 0; Left IR
int irCPin = 1;            // Analog 1; Center IR
int irRPin = 2;            // Analog 2; Right IR
int ultraSoundSignal = 7; // Ultrasound signal pin
int val = 0;              // Used for Ultrasonic Ranger
int ultrasoundValue = 0;  // Raw Distance Val
int oldUltrasoundValue;  // *Not used*
int pulseCount;        // Generic Counter
int timecount = 0; // Echo counter
int ledPin = 13; // LED connected to digital pin 13
int pos = 0;
int SPKR = 4;

long browTimer;
int browState;

#define BAUD 9600
#define CmConstant 1/29.034

void setup() {
  myservo.attach(11);
  pos = 40;
  myservo.write(pos);
  delay(150);
  myservo.detach();
  Serial.begin(9600);
  pinMode(SPKR, OUTPUT);
  pinMode(ledPin, OUTPUT);
  pinMode(LeftPin, OUTPUT);
  pinMode(RightPin, OUTPUT);
  pinMode(PingServoPin, OUTPUT);
  pinMode(irLPin, INPUT);
  pinMode(irCPin, INPUT);
  pinMode(irRPin, INPUT);
    // Beep!
  {
    for (int i = 0; i<500; i++) {  // generate a 1KHz tone for 1/2 second
      digitalWrite(SPKR, HIGH);
      delayMicroseconds(400);
      digitalWrite(SPKR, LOW);
      delayMicroseconds(400);
    }
  for(i = 0; i < 20; i++) {
    digitalWrite(PingServoPin, HIGH);
    delayMicroseconds(655 * 2);
    digitalWrite(PingServoPin, LOW);
    delay(20);
  }
  ultrasoundValue = 600;
  i = 0;
}
}
void loop()
{
  Look();
  Go();
  checkBrow();
}
void Look() {
  irLval = analogRead(irLPin);
  irCval = analogRead(irCPin);
  irRval = analogRead(irRPin);
  if(irLval > 200) {
    BrowUP();
     PLval = 850;
    PRval = 820;
    x = 5;
    cntr = cntr + 1;
    clrpth = 0;
    objdet = millis();
  }
  else if(irCval > 200) {
    BrowUP();
    PLval = 850;
    PRval = 820;
    x = 10;
    cntr = cntr + 1;
    clrpth = 0;
    objdet = millis();
  }
  else if(irRval > 200) {
    BrowUP();
    PLval = 650;
    PRval = 620;
    x = 5;
    cntr = cntr + 1;
    clrpth = 0;
    objdet = millis();
  }
  else {
    x = 1;
    PLval = 850;
    PRval = 620;
    counter = counter + 1;
    clrpth = (millis() - objdet);
    if(add == true) {
      pwm = pwm + 50;
    }
    else if(add == false) {
      pwm = pwm - 50;
    }
    if(pwm < 400) {
      pwm = 400;
      add = true;
    }
    if(pwm > 950) {
      pwm = 950;
      add = false;
    }
    digitalWrite(PingServoPin, HIGH);
    delayMicroseconds(pwm * 2);
    digitalWrite(PingServoPin, LOW);
    delay(20);
    readPing();
    if(ultrasoundValue < 150) { // this value is the closeness of PING will get.
      cntr = cntr + 1;
      switch(pwm) {
      case 400:
        x = 7;
        PLval = 650;
        PRval = 650;
        Go();
        break;
      case 500:
        x = 10;
        PLval = 650;
        PRval = 650;
        Go();
        break;
      case 600:
        x = 14;
        PLval = 850;
        PRval = 850;
        Go();
        break;
      case 700:
        x = 10;
        PLval = 850;
        PRval = 850;
        Go();
        break;
      case 950:
        x = 7;
        PLval = 850;
        PRval = 850;
        Go();
        break;
      }
    }
  }
  if(cntr > 25 && clrpth < 2000) {
    clrpth = 0;
    cntr = 0;
    Scan();
  }
}
void Go() {
  for(i = 0; i < x; i++) {
    digitalWrite(LeftPin, HIGH);
    delayMicroseconds(PLval * 2);
    digitalWrite(LeftPin, LOW);
    digitalWrite(RightPin, HIGH);
    delayMicroseconds(PRval * 2);
    digitalWrite(RightPin, LOW);
    delay(20);
  }
}
void readPing() {  // Get Distance from Ultrasonic Ranger
  timecount = 0;
  val = 0;
  pinMode(ultraSoundSignal, OUTPUT); // Switch signalpin to output
  digitalWrite(ultraSoundSignal, LOW); // Send low pulse
  delayMicroseconds(2); // Wait for 2 microseconds
  digitalWrite(ultraSoundSignal, HIGH); // Send high pulse
  delayMicroseconds(5); // Wait for 5 microseconds
  digitalWrite(ultraSoundSignal, LOW); // Holdoff
  pinMode(ultraSoundSignal, INPUT); // Switch signalpin to input
  val = digitalRead(ultraSoundSignal); // Append signal value to val
  while(val == LOW) { // Loop until pin reads a high value
    val = digitalRead(ultraSoundSignal);
  }
  while(val == HIGH) { // Loop until pin reads a high value
    val = digitalRead(ultraSoundSignal);
    timecount = timecount +1;            // Count echo pulse time
  }
  ultrasoundValue = timecount; // Append echo pulse time to ultrasoundValue
  // Lite up LED if any value is passed by the echo pulse
   if(timecount > 0){
    digitalWrite(ledPin, HIGH);
  }
}
void Scan() {   // Scan for the Clearest Path
  oldDistance = 30;
  task = 0;
  for(i = 1; i < 5; i++) {
    switch(i) {
    case 1:
      //Serial.println("Pos. 1");
      pwm = 1125;    ///  incr. by 100 from 1085
      break;
    case 2:
      //Serial.println("Pos. 2");
      pwm = 850; //// increased by 100 from 850
      break;
    case 3:
      //Serial.println("Pos. 3");
      pwm = 400;
      break;
    case 4:
      //Serial.println("Pos. 4");
      pwm = 235;
      break;
    }
    for(pulseCount = 0; pulseCount < 20; pulseCount++) {  // Adjust Pan Servo and Read USR
      digitalWrite(PingServoPin, HIGH);
      delayMicroseconds(pwm * 2);
      digitalWrite(PingServoPin, LOW);
      readPing();
      delay(20);
    }
    distance = ((float)ultrasoundValue * CmConstant);   // Calculate Distance in Cm
    if(distance > oldDistance) {  // If the Newest distance is longer, replace previous reading with it
      oldDistance = distance;
      task = i;   // Set task equal to Pan Servo Position
    }
  }
  distance = 50;  // Prevents Scan from Looping
  switch(task) {   // Determine which task should be carried out
  case 0:  // Center was clearest
    x = 28;
    PLval = (850);
    PRval = (850);
    Go();
    break;
  case 1:  // 90 degrees Left was Clearest
    x = 14;
    PLval = (650);
    PRval = (650);
    Go();
    break;
  case 2:  // 45 degrees left
    x = 7;
    PLval = (650);
    PRval = (650);
    Go();
    break;
  case 3:  // 45 degrees right
    x = 7;
    PLval = (850);
    PRval = (850);
    Go();
    break;
  case 4:  // 90 degrees right
    x = 14;
    PLval = (850);
    PRval = (850);
    Go();
    break;
  }
}

void checkBrow()
{
  switch (browState)
  {
    case 1: //Brow Up
      if ((millis() - browTimer) > 500)
      {
        BrowDown();
      }
      break;
    case 2: //Brow Down Waiting to Detach Servo
      if ((millis() - browTimer) > 120)
      {
        myservo.detach();
        browState = 0;
      }
      break;
    default:
      break;
  }
}

void BrowUP()
{
  browTimer = millis();
  myservo.attach(11);
  pos = 0;
  myservo.write(pos);
  browState = 1;
}

void BrowDOWN()
{
  browTimer = millis();
  myservo.attach(11);
  pos = 40;
  myservo.write(pos);
  browState = 2;
}

// End Robot Code

Imagine you get a ping. You raise the eyebrows and look at the clock. The time is 8:45:16. You want to keep the brows up for 2 seconds, or until 8:45:18. So everytime you go through Loop, you look at the clock. If it's not time yet, you continue on and do whatever. But if it is time, then you lower the eyebrows.

HTH.

Thank You Guys, I will try it. This forum Rocks~!

I got this error message:

In function 'void checkBrow()':
error: 'BrowDown' was not declared in this scope

which I do not know what it means.

But, at least I have it in place in the program and an example of a starting place that I can work with to study. I feel we have made a step forward. This is Great!

You call "BrowDown" in "checkBrow", but you've defined "BrowDOWN".

C/C++ is case-sensitive.

You are Right! It works now!

You Guys are sooo GOOD!

:wink:

I'm not sure why you've got attach/detach calls in the brow routines. Unless you're re-purposing the servo pin, I can't really see the point of this.

Just plain Ignorance of the 'c' language. I figured that I would save battery life and not wear out the servo from having it stay there so solidly.

rather than checking directly in the loop function which action to perform accordingly to the time, you could also delegate the responsability to run to the "action" themself. proto-thread like system seems really good for this kind of problems...

http://www.sics.se/~adam/pt/

Thanks, Elwing, this looks interesting. How would I unzip this in windows? It looks like it is made for the Mac which I dearly love but cannot afford right now.

.tar.gz is just a tar archive inside a gz archive, there are many option to open theses kind of archive, winzip does it just well. the version directly in this website seem quite old, it is simplier, but there is a sourceforge project containing a reimplementation (protothread - Browse Files at SourceForge.net also inside a .tar.gz...) that also contain the scheduler part.

depending on what you want to do you might prefer the version without a scheduler that is too complex for your application... it is up to you...

I usually use winrar, winace, or winzip, or 7zip. I did not know that it would work. Thanks! I actually prefer the mac platform, but mine is down.