Go Down

Topic: Maze solver "stop" method? (Read 942 times) previous topic - next topic

OllyR

Im upgrading my line follower (which rocks) to a maze solver. We have white floorboards here, so with a big roll of electrical tape i can make a pretty cool maze in the spare room. Im currently looking for ideas on how to make a "finish" for the maze. My two ideas are currently:

Count the distance across a box, ie: stop after x ms of no returned signals.

Or

Make the box a colour, and use an rgb sensor to detect the box. The problem here is i have run out of pins!

So assuming the count plan is a good idea, any suggestions as to how to say "if x &y&z are all low for more than x ms...", or at least the waiting part...


PeterH

How about putting an obstacle just past the exit that trips a physical switch mounted on the front? So the 'bot's goal would be to run into something without crossing a line.
I only provide help via the forum - please do not contact me for private consultancy.

PaulS

Quote
any suggestions as to how to say "if x &y&z are all low for more than x ms...",

You need to periodically check all values. If all are low, set the time that they went low (or, more accurately, the time they were detected to be low). If any goes high later, clear the time.

Periodically, see if the difference between now and then is greater than the interval of interest, when then is not 0. If so, stop.

OllyR

I'm struggling a bit here. Ive found the millis() function, bit not sure how to "call" it, and make any decisions based on it.
Can i reset the millis clock to zero with each change of state perhaps? Or is that not the way to go about it
I think i want it to run for 1 sec over all high, just to allow it to cross junctions, and account for flaws in my white floorboards.
Also to stop after 5 secs of white, and assume its lost..

Little help?

PeterH

You call it by putting the function name in your code followed by brackets:

Code: [Select]
unsigned long now = millis();



I suggest you look at the 'blink without delay' example sketch to see how you would use this to do things when a given time has passed.
I only provide help via the forum - please do not contact me for private consultancy.

OllyR

#5
Sep 06, 2012, 12:56 am Last Edit: Sep 06, 2012, 01:04 am by OllyR Reason: 1
So what i tried is this:

1: Create a "long" for "last known event" (last)
2: created a "long" for the delay (interval) although im not sure why i cant just refer to "2000" in the code where required, but that is how the blink tutorial did it so fine.

3: in the line following arguments, (for 000, 001, 010, 011, 100, 110) i have asked it to assign "last" with the current time. I HOPE this will update the "last" value every state change.

4: finally for argument 111:

Code: [Select]
if now - last < interval { carry  on!}
if now - last > interval {all stop!}
(I would like this to declare the end to the code, but it isn't necessary, as once it has stopped, it wont be changing states on the sensors.

i have enclosed this last section between two lines of asterixes ************************** near the bottom of the sketch.

in practice as soon as the argument 111 is reached, it stops.
i want it to carry on for 2000 ms, and then if the argument is not changed within the 2000 ms, THEN stop.

if anyone could point out what ive missed it would be greatly appreciated.

Thanks all, sorry if im being thick.

Code: [Select]
#include <AFMotor.h>

AF_DCMotor motorL(3, MOTOR12_1KHZ);  
AF_DCMotor motorR(2, MOTOR12_1KHZ);

// These constants won't change:
const int LeftPR = A1;    // pin that the sensor is attached to
const int CentrePR = A2;    // pin that the sensor is attached to
const int RightPR = A3;    // pin that the sensor is attached to
const int IndicatorL = 10;        // pin that the LED is attached to
const int IndicatorC = 9;        // pin that the LED is attached to
const int IndicatorR = 19;        // pin that the LED is attached to
const int button = 18;

// finish line timing
long last= 0;
long interval = 2000; // delay time

// variables:
int LeftValue = 0;         // the sensor value
int LeftMin = 1023;        // minimum sensor value
int LeftMax = 0;           // maximum sensor value

int CentreValue = 0;         // the sensor value
int CentreMin = 1023;        // minimum sensor value
int CentreMax = 0;           // maximum sensor value

int RightValue = 0;         // the sensor value
int RightMin = 1023;        // minimum sensor value
int RightMax = 0;           // maximum sensor value


void setup() {

 // Serial monitor
 Serial.begin(9600);           // set up Serial library at 9600 bps

 //Motors
 //set the speed to 200 of 255 of "motorL".
 //Note that 0 is stop, 255 is full speed:
 motorL.setSpeed(200);    
 // set the speed to 200 of 255 of "motorR":
 motorR.setSpeed(200);

 //Calibraton

 // turn on LEDs to signal the start of the calibration period:
 pinMode(IndicatorL,OUTPUT);
 pinMode(IndicatorC,OUTPUT);
 pinMode(IndicatorR,OUTPUT);

 digitalWrite(IndicatorL, HIGH);
 digitalWrite(IndicatorC, HIGH);
 digitalWrite(IndicatorR, HIGH);

 // calibrate during the first 5 seconds
 {  
   while (millis() < 5000) {

     //Spin on the spot
     motorL.run(FORWARD);      // turn it on going forward
     motorR.run(BACKWARD);  // motor 2 goes forward as well

     //Calibrate
     LeftValue = analogRead(LeftPR);
     // record the maximum sensor value
     if (LeftValue > LeftMax) {
       LeftMax = LeftValue;
     }
     // record the minimum sensor value
     if (LeftValue < LeftMin) {
       LeftMin = LeftValue;
     }
     CentreValue = analogRead(CentrePR);
     // record the maximum sensor value
     if (CentreValue > CentreMax) {
       CentreMax = CentreValue;
     }
     // record the minimum sensor value
     if (CentreValue < CentreMin) {
       CentreMin = CentreValue;
     }
     RightValue = analogRead(RightPR);
     // record the maximum sensor value
     if (RightValue > RightMax) {
       RightMax = RightValue;
     }
     // record the minimum sensor value
     if (RightValue < RightMin) {
       RightMin = RightValue;
     }
   }


   motorL.run(RELEASE);      // turn it on going forward
   motorR.run(RELEASE);  // motor 2 goes forward as well

   // signal the end of the calibration period
   digitalWrite(IndicatorL, LOW);
   digitalWrite(IndicatorC, LOW);
   digitalWrite(IndicatorR, LOW);
   delay(1000);
   digitalWrite(IndicatorC, HIGH);
   delay(100);
   digitalWrite(IndicatorC, LOW);
   delay(100);
   digitalWrite(IndicatorC, HIGH);
   delay(100);
   digitalWrite(IndicatorC, LOW);
   delay(100);
   digitalWrite(IndicatorC, HIGH);
   delay(100);
   digitalWrite(IndicatorL, LOW);
   digitalWrite(IndicatorC, LOW);
   digitalWrite(IndicatorR, LOW);

 }
 //hold
 while (digitalRead (button) == HIGH){
   // stops script. Its waiting for a button press (LOW on "button")
 }
}

void loop() {
 {
   //LEFT SENSOR
   LeftValue = analogRead(LeftPR);
   // apply the calibration to the sensor reading
   LeftValue = map(LeftValue, LeftMin, LeftMax, 0, 100);
   LeftValue = constrain(LeftValue, 0, 200);

   // in case the sensor value is outside the range seen during calibration
   if (LeftValue > 100) {
     digitalWrite (IndicatorL, HIGH);
   }
   if (LeftValue < 100) {
     digitalWrite (IndicatorL, LOW);
   }

   //CENTRE SENSOR
   CentreValue = analogRead(CentrePR);
   // apply the calibration to the sensor reading
   CentreValue = map(CentreValue, CentreMin, CentreMax, 0, 100);
   CentreValue = constrain(CentreValue, 0, 200);

   // in case the sensor value is outside the range seen during calibration
   if (CentreValue > 100) {
     digitalWrite (IndicatorC, HIGH);
   }
   if (CentreValue < 100) {
     digitalWrite (IndicatorC, LOW);
   }

   // RIGHT SENSOR
   RightValue = analogRead(RightPR);
   // apply the calibration to the sensor reading
   RightValue = map(RightValue, RightMin, RightMax, 0, 100);
   RightValue = constrain(RightValue, 0, 200);

   // in case the sensor value is outside the range seen during calibration
   if (RightValue > 100) {
     digitalWrite (IndicatorR, HIGH);
   }
   if (RightValue < 100) {
     digitalWrite (IndicatorR, LOW);
   }
 }


 // Line following arguments
 // Forward 010, 000 (000 to be set to 5 second time limit once ive worked out how to handle millis)

 if ((digitalRead(IndicatorL) == LOW && digitalRead(IndicatorC) == LOW && digitalRead(IndicatorR) == LOW)||
   (digitalRead(IndicatorL) == LOW && digitalRead(IndicatorC) == HIGH && digitalRead(IndicatorR) == LOW)){
   motorL.run(FORWARD);  
   motorR.run(FORWARD);  
   unsigned long last = millis();
 }

 //Turn right: 001, 011
 if ((digitalRead(IndicatorL) == LOW && digitalRead(IndicatorC) == LOW && digitalRead(IndicatorR) == HIGH)||
   (digitalRead(IndicatorL) == LOW && digitalRead(IndicatorC) == HIGH && digitalRead(IndicatorR) == HIGH)){
   motorL.run(FORWARD);  
   motorR.run(RELEASE);  
   unsigned long last = millis();
 }

 //Turn Left: 100, 110
 if ((digitalRead(IndicatorL) == HIGH && digitalRead(IndicatorC) == LOW && digitalRead(IndicatorR) == LOW)||
   (digitalRead(IndicatorL) == HIGH && digitalRead(IndicatorC) == HIGH && digitalRead(IndicatorR) == LOW)){
   motorL.run(RELEASE);    
   motorR.run(FORWARD);
   unsigned long last = millis();
 }

 // finish box or cross roads decision **************************************

 unsigned long now = millis();


 if (digitalRead(IndicatorL) == HIGH && digitalRead(IndicatorC) == HIGH && digitalRead(IndicatorR) == HIGH && (now - last < interval)){
   motorL.run(FORWARD);  
   motorR.run(FORWARD);

 }
 else  if (digitalRead(IndicatorL) == HIGH && digitalRead(IndicatorC) == HIGH && digitalRead(IndicatorR) == HIGH && (now - last > interval))  {
   motorL.run(RELEASE);  
   motorR.run(RELEASE);  
 }



 //***********************************************



 Serial.print("Left:");
 Serial.print(LeftValue);
 Serial.print(" Centre:");
 Serial.print(CentreValue);
 Serial.print(" Right:");
 Serial.print(RightValue);
 Serial.println();

}


PeterH

Code: [Select]

long last= 0;
long interval = 2000; // delay time


These need to be unsigned long not just long.

There are several places where you put this line in your code:

Code: [Select]

   unsigned long last = millis();

I assume the intent is to update the global variable. Because you included the type in this statement, it actually declares a new local variable within that block of code, which is updated with the return value from millis() and them immediately thrown away as you leave that code block.

If you want to update a variable which has already been declared, you would need to change that code to:

Code: [Select]

   last = millis();


Code: [Select]
 if (digitalRead(IndicatorL) == HIGH && digitalRead(IndicatorC) == HIGH && digitalRead(IndicatorR) == HIGH && (now - last < interval)){
   motorL.run(FORWARD);  
   motorR.run(FORWARD);

 }
 else  if (digitalRead(IndicatorL) == HIGH && digitalRead(IndicatorC) == HIGH && digitalRead(IndicatorR) == HIGH && (now - last > interval))  {
   motorL.run(RELEASE);  
   motorR.run(RELEASE);  
 }

These conditions can be written more concisely:
Code: [Select]
 
if (digitalRead(IndicatorL) == HIGH && digitalRead(IndicatorC) == HIGH && digitalRead(IndicatorR) == HIGH)
{
   if(millis() - last < interval)
   {
       // timeout has not expired, keep going
       motorL.run(FORWARD);  
       motorR.run(FORWARD);
   }
   else
   {
       // timeout has expired, assume we have reached the end
       motorL.run(RELEASE);  
       motorR.run(RELEASE);  
   }
}
I only provide help via the forum - please do not contact me for private consultancy.

OllyR

Thats got it!

thanks for your help guys, its really appreciated.
funny how these things are easy when you know how, and its the details that make the difference.

Don't forget to handle the case where millis() rolls back over to 0 just like an odometer in a car. That is sure to throw you for a loop down the road

;)

PeterH


Don't forget to handle the case where millis() rolls back over to 0 just like an odometer in a car. That is sure to throw you for a loop down the road


If you code it properly as shown in the code fragment I posted, the rollover behaves correctly. If you find you need to explicitly deal with the rollover case, you're doing it wrong.
I only provide help via the forum - please do not contact me for private consultancy.

Go Up