About 3PI maze solve fabricated "s"

I use 3pi robot for a competition
the venue is black ground with white line
I look for the follow white line code on this forum
and I successed
BUT later,I want to make the robot turn faster
so I adjust the file “turn.c”
this is code:

#include <pololu/3pi.h>

// Turns according to the parameter dir, which should be 'L', 'R', 'S'
// (straight), or 'B' (back).
void turn(char dir)
{
	switch(dir)
	{
	case 'L':
		// Turn left.
		set_motors(-120,120);
		delay_ms(120);
		break;
	case 'R':
		// Turn right.
		set_motors(120,-120);
		delay_ms(120);
		break;
	case 'B':
		// Turn around.
		set_motors(120,-120);
		delay_ms(240);
		break;
	case 'S':
		// Don't do anything!
		break;
	}

Later when I try run
I found that the abbreviations on LCD(LRLS…) are mess
take an example
there is an intersection (left side)
the LCD display “LS” NOT “L”
It means that the robot multi-determination of a straight

Can you tell me why?I just adjust the motor speed

Sorry if you do not understand what I talking about,
I put these sentence in google translation :frowning:

Hello.

Does changing the turning speed back to the original value fix the problem? If it does, then I suspect that changing the turning speed is causing the 3pi to be misaligned with the line after it has finished turning, which could cause it to immediately detect the same intersection after it turns. You might try adding a non-blocking delay in follow_segment() before checking the sensors for an intersection. That should allow some time for the 3pi to correct itself and get back on the line. If you try adding this to your code and have trouble, you can post that section of your code, and I would be happy to take a look at it.

-Brandon

Thank you to answer my question :smiley:

Yes,changing the turning speed back to the original value can fix the problem.
But sorry I don’t know how to adding a non-blocking delay in follow_segment() before checking the sensors for an intersection…
here is my follow segment code
Can you tell me how to do it?

#include <pololu/3pi.h>

void follow_segment()
{
	int last_proportional = 0;
	long integral=0;

	while(1)
	{
		// Normally, we will be following a line.  The code below is
		// similar to the 3pi-linefollower-pid example, but the maximum
		// speed is turned down to 60 for reliability.

		// Get the position of the line.
		unsigned int sensors[5];
		unsigned int position = read_line_white(sensors,IR_EMITTERS_ON);

		// The "proportional" term should be 0 when we are on the line.
		int proportional = ((int)position) - 2000;

		// Compute the derivative (change) and integral (sum) of the
		// position.
		int derivative = proportional - last_proportional;
		integral += proportional;

		// Remember the last position.
		last_proportional = proportional;

		// Compute the difference between the two motor power settings,
		// m1 - m2.  If this is a positive number the robot will turn
		// to the left.  If it is a negative number, the robot will
		// turn to the right, and the magnitude of the number determines
		// the sharpness of the turn.
		int power_difference = proportional/10 + integral/20000 + derivative*5/2;

		// Compute the actual motor settings.  We never set either motor
		// to a negative value.
		const int max = 130; // the maximum speed
		if(power_difference > max)
			power_difference = max;
		if(power_difference < -max)
			power_difference = -max;
		
		if(power_difference < 0)
			set_motors(max+power_difference,max);
		else
			set_motors(max,max-power_difference);

		// We use the inner three sensors (1, 2, and 3) for
		// determining whether there is a line straight ahead, and the
		// sensors 0 and 4 for detecting lines going to the left and
		// right.

		if(sensors[1] > 900 && sensors[2] > 900 && sensors[3] > 900)
		{
			// There is no line visible ahead, and we didn't see any
			// intersection.  Must be a dead end.
			return;
		}
		else if(sensors[0] < 800 || sensors[4] < 800)
		{
			// Found an intersection.
			return;
		}

	}
}

Here is another question:
Can 3pi do straightly accelerating?
I mean that can 3pi robot accelerating when it pass a specific distance,like 200 cm or 400 cm ?
And How can I do this?
Thank you!

One way to add a non-blocking delay to your 3pi code is to use millis() to store the current millisecond counter value and see how much time has passed since the 3pi has started following the segment. You might try looking at this “Blink Without Delay” example on the Arduino website to get an idea of how it might look; the example uses the same method I described, but blinks an LED without using the blocking delays found in the typical “Blink” example sketch.

If you try adding this kind of delay to your code and have trouble, you can post what you have so far, and I would be happy to take a look.

As far as your question about accelerating, the 3pi does not have a way to do position tracking such as encoders, so it is not able to calculate exactly how far it has traveled; however, you could probably do something similar by using timing to determine the approximate distance traveled and have your code adjust your speed or acceleration based on that.

-Brandon

I’m sorry I don’t know where should I add the milli() in the code
Can you help me? Please

We recently hosted a non-looped and a looped maze solving competition as part of a local robotics club, and I used a 3pi robot for the looped maze solving competition. The code below shows the modifications I made to follow_segment() so that the 3pi can only detect a turn after following the segment for 250ms; I have added some comments to point out where I added the lines of code for the non-blocking delay:

void follow_segment()
{
	int last_proportional = 0;
	long integral=0;

	//This variable will store the time value to keep track of when follow_segment() began.
	unsigned long time_delay = millis();

	while(1)
	{
		unsigned int sensors[5];
		unsigned int position = read_line(sensors,IR_EMITTERS_ON);

		int proportional = ((int)position) - 2000;

		int derivative = proportional - last_proportional;
		integral += proportional;

		last_proportional = proportional;

		int power_difference = proportional/20 + integral/10000 + derivative*3/2;

		const int max = 130;

		if(power_difference > max)
			power_difference = max;
		if(power_difference < -max)
			power_difference = -max;
		
		if(power_difference < 0)
			set_motors(max+power_difference,max);
		else
			set_motors(max,max-power_difference);

		//The condition for the if statement below is only true when the 3pi has been following 
		//the segment for more than 250ms.
		//By putting the two if statements that break out of the loop inside of this if statement, the 3pi  
		//should not be able to detect a turn unless it has followed the line for longer than 250ms.
		if(get_ms() - time_delay > 250)
		{
			if(sensors[1] < 100 && sensors[2] < 100 && sensors[3] < 100)
			{
        				 // There is no line visible ahead, and we didn't see any
        				 // intersection.  Must be a dead end.
        				 return;
      			}
			else if(sensors[0] > 200 || sensors[4] > 200)
			{
         				// Found an intersection.
         				return;
    			}			
		}
	}
}

-Brandon

Thaks for your help! :smiley:

And your code solve my problem~
But
I have another question again.
How can I let the millis() function to do accelerating?
And where should I add the function in?

Hello.

To add acceleration to follow_segment() using the code from my previous post, you can use the same “time_delay” variable to calculate how long your 3pi has been following the line by subtracting it from get_ms() (which is also what we did to add the delay before the 3pi looks for a turn condition). Then, you can use this difference to adjust the “max” variable (which is the maximum straight speed setting). Depending on how you write it, this code will probably need to be just after the const int max = 130; line of code.

-Brandon

Hello
Thanks for your help~
I try to adjust the code:

int last_proportional = 0;
	long integral=0;
    unsigned long time_delay = millis();

	while(1)
	{
		// Normally, we will be following a line.  The code below is
		// similar to the 3pi-linefollower-pid example, but the maximum
		// speed is turned down to 60 for reliability.

		// Get the position of the line.
		unsigned int sensors[5];
		unsigned int position = read_line_white(sensors,IR_EMITTERS_ON);

		// The "proportional" term should be 0 when we are on the line.
		int proportional = ((int)position) - 2000;

		// Compute the derivative (change) and integral (sum) of the
		// position.
		int derivative = proportional - last_proportional;
		integral += proportional;

		// Remember the last position.
		last_proportional = proportional;

		// Compute the difference between the two motor power settings,
		// m1 - m2.  If this is a positive number the robot will turn
		// to the left.  If it is a negative number, the robot will
		// turn to the right, and the magnitude of the number determines
		// the sharpness of the turn.
		int power_difference = proportional/10 + integral/20000 + derivative*5/2;

		// Compute the actual motor settings.  We never set either motor
		// to a negative value.
		const int max = 130; // the maximum speed
   
		if(power_difference > max)
			power_difference = max;
		if(power_difference < -max)
			power_difference = -max;
		if(power_difference < 0)
			set_motors(max+power_difference,max);
		else
			set_motors(max,max-power_difference);
       if(get_ms() - time_delay > 200)
         {
	       if(sensors[1] > 800 && sensors[2] > 800 && sensors[3] > 800)
	     {
		// There is no line visible ahead, and we didn't see any
		// intersection.  Must be a dead end.
		  return;
	     }
	        else if(sensors[0] < 800 || sensors[4] < 800)
	     {
		// Found an intersection.
		  return;
	     }

 }
   if(get_ms()-time_delay >= 800)
    {
	 const int max = 200; // the maximum speed
	 
     if(power_difference > max)
	 power_difference = max;
	 if(power_difference < -max)
	 power_difference = -max;
	 if(power_difference < 0)
	 set_motors(max+power_difference,max);
	 else
	 set_motors(max,max-power_difference);
	}
 if(get_ms()-time_delay > 2000) 
	{ 
	  const int max = 130; // the maximum speed
	  
	  if(power_difference > max)
	  power_difference = max;
	  if(power_difference < -max)
	  power_difference = -max;
	  if(power_difference < 0)
	  set_motors(max+power_difference,max);
	  else
	  set_motors(max,max-power_difference);
	}
		// We use the inner three sensors (1, 2, and 3) for
		// determining whether there is a line straight ahead, and the
		// sensors 0 and 4 for detecting lines going to the left and
		// right.

 if(get_ms() - time_delay > 200)
 {
		if(sensors[1] > 800 && sensors[2] > 800 && sensors[3] > 800)
		{
			// There is no line visible ahead, and we didn't see any
			// intersection.  Must be a dead end.
			return;
		}
		else if(sensors[0] < 800 || sensors[4] < 800)
		{
			// Found an intersection.
			return;
		}

	}
}
}]

But there is a problem,
When I try run,
the 3pi is acceleration,this is true,
but it can not stop 3pi to turn right or turn left.
This is a big problem!
I think it is because 3pi do not slow down
But how can I slow down 3pi?

After that,I try to put in a condition that set 3pi acceleration in 800 ms~2000 ms
but after 2000 ms,3pi had stopped…
Where do I modify code wrong?
How can I solve this problem?

Can any one help me as soon as possible?
Sorry,I have a competition this weekend…

I noticed you were setting the speed of your motors in multiple places in your code, which in some cases would have resulted in your motors being commanded to change speeds twice each time the code executed. I modified the code you posted to show how you can make the time difference only change the max variable. The modified code also shows how you can combine your two time conditions into one if statement:

int last_proportional = 0;
long integral=0;
unsigned long time_delay = millis();
int max = 130;

while(1)
{
  // Normally, we will be following a line.  The code below is
  // similar to the 3pi-linefollower-pid example, but the maximum
  // speed is turned down to 60 for reliability.

  // Get the position of the line.
  unsigned int sensors[5];
  unsigned int position = read_line_white(sensors,IR_EMITTERS_ON);

  // The "proportional" term should be 0 when we are on the line.
  int proportional = ((int)position) - 2000;

  // Compute the derivative (change) and integral (sum) of the
  // position.
  int derivative = proportional - last_proportional;
  integral += proportional;

  // Remember the last position.
  last_proportional = proportional;

  // Compute the difference between the two motor power settings,
  // m1 - m2.  If this is a positive number the robot will turn
  // to the left.  If it is a negative number, the robot will
  // turn to the right, and the magnitude of the number determines
  // the sharpness of the turn.
  int power_difference = proportional/10 + integral/20000 + derivative*5/2;

  // Compute the actual motor settings.  We never set either motor
  // to a negative value.
  // the maximum speed
   
   
  //This if...else statement increases the max speed after 800ms and returns
  //it back to the original speed after 2000ms
  if((get_ms()-time_delay) >= 800 && (get_ms()-time_delay) < 2000)
    max = 200;
  else	
    max = 130;
  
  if(power_difference > max)
     power_difference = max;
  if(power_difference < -max)
     power_difference = -max;
  if(power_difference < 0)
     set_motors(max+power_difference,max);
  else
     set_motors(max,max-power_difference);

     // We use the inner three sensors (1, 2, and 3) for
     // determining whether there is a line straight ahead, and the
     // sensors 0 and 4 for detecting lines going to the left and
     // right.
  if(get_ms() - time_delay > 200)
     {
     if(sensors[1] > 800 && sensors[2] > 800 && sensors[3] > 800)
     {
     // There is no line visible ahead, and we didn't see any
     // intersection.  Must be a dead end.
     return;
     }
     else if(sensors[0] < 800 || sensors[4] < 800)
     {
     // Found an intersection.
     return;
     }
  }
}

By the way, I also noticed that your program had duplicate instances of code that was checking the sensors for a turn condition, so I removed one of them.

-Brandon

Thanks for your help very much! :smiley:

But the code you gave me still let the 3pi stop after acceleration!
I want let 3pi continue solving the maze

And the LCD display "solved"
But is not because the sensor
I think it is because the code is end,
but why it happened?

After I adjust the “2000” to 10000(10s)
the stop problem had solve
but 3pi can not Slow Down

How can I slow down the 3pi?
Can anyone help me?
thanks~

Hello.

Since the LCD is displaying “solved”, the code has exited the follow_segment() function properly, so I do not think the error is caused by the delay time. I suspect there are some minor errors or, since it looks like you are using a white line with a black background, left over code from the example maze solving program that causes the 3pi to think it has reached the end of the maze. You might try looking at your program to see when your code displays “solved” on the LCD and working backwards from there.

When the 3pi stops and displays “solved”, are its middle three sensors directly over the intersection? If they are, the problem might also be caused by the speed of the 3pi when it reaches the intersection since that could change where it is when the code exits the follow_segment() loop. In the example maze solving code, after the 3pi finds an intersection, it characterizes the intersection by moving forward briefly, checking its sensors, moving forward again, and checking its sensors again. If the 3pi is confusing an intersection with the end of the maze, you might try adjusting how far the 3pi moves forward when it characterizes the intersection.

-Brandon

Sorry I am too busy to reply you :frowning:
And I found the problem is because when 3pi stop acceleration,
It will incline too much.
After I let it slow down lightly,the problem was solve~
Thank you so much~