3pi turning off alone

Good night, thanks for the tip and sorry for the mistake. I did not know I had this command.

What I would like my 3 pi to do was read the line more accurately, using PID in the case. But still detecting when there was a fault in the track, because when I tested it on the track of the school, which is not totally straight, because I was not using PID I noticed that for it to stay centralized it stays moving at all times during the path.
That’s because I’m using the code:

		else if(position < 1100)
		{
			set_motors(-70,90);
			reto = 0;
		}
		else
		{
			set_motors(90,-70);
			reto = 0;
		}

I have already tried to change the values, of both the readings and the engines, but he continues to “difficulties” to make the turns, and I noticed that he loses more time than necessary. This would not happen if I used the PID because it makes the way with the least possible error. But I tried to increment the white-detect code, but I could not.
This code:

int main()
{
	unsigned int sensors[5];
	unsigned char reto;
	unsigned int last_proportional=0;
	long integral=0;

	initialize();
	reto = 0;

	while(1)
	{
		unsigned int position = read_line(sensors,IR_EMITTERS_ON);
		if(sensors[0] < 400 && sensors[1] < 400 && sensors[2] < 400 && sensors[3] < 400 && sensors[4] < 400 && reto)
		{
			set_motors(100,100);
		}

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

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

		last_proportional = proportional;

		int power_difference = proportional/10 + integral/55000 + derivative*1/1;

		const int max = 80;
		if(power_difference > max)
		power_difference = max;
		else if(power_difference < -max)
		power_difference = -max;
				
		else if(power_difference <0)
		{
		set_motors(max+power_difference, max);
		reto = 1;
		}
		else
		{
		set_motors(max, max-power_difference);
		reto = 0;
		}
		
	}

}

From what I know, the PID uses a value of proportion, so there would have to be an exception in this code so that even with PID, the 3pi would know what to do when there was no more line.

Thank You!

Some additional information…

I wanted to implement PID in my robot because, when I change the values of the sensors, it does not make the way with perfection, it is taking small pauses to stay straight from the line. That makes him lose a lot of time, and with the wheel adaptation I made on him, if he’s not well centered with the line, he can not move up the ramp of the challenge

Look: https://www.youtube.com/watch?v=_pLk9teHSsk

Thanks for using code tags. The main issue with your code was that after it was checking for a break in the line, it was immediately executing the PID line following part of your code. So, any motor speed set in response to recognizing a break in the line would be immediately overwritten by the PID code. To fix that, you can add an else after your code checks for a break in the line. I edited your code to include that change and pasted it below. In addition to what I just mentioned, I removed an unnecessary else that was changing the logic of the program and causing the 3pi to occasionally miss turns, and removed reto, since it is no longer needed. This should be fine unless your 3pi begins to have trouble with sharp turns. If that happens, let me know and I might be able to help you handle that better.

int main()
{
	unsigned int sensors[5];
	unsigned char reto;
	unsigned int last_proportional=0;
	long integral=0;

	initialize();

	while(1)
	{
		unsigned int position = read_line(sensors,IR_EMITTERS_ON);
		if(sensors[0] < 400 && sensors[1] < 400 && sensors[2] < 400 && sensors[3] < 400 && sensors[4] < 400)
		{
			set_motors(80,80);
		}

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

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

			last_proportional = proportional;
			int power_difference = proportional/10 + integral/55000 + derivative*1/1;

			const int max = 80;
			if(power_difference > max)
				power_difference = max;
			else if(power_difference < -max)
				power_difference = -max;
	
			if(power_difference <0)
			{
				set_motors(max+power_difference, max);
			}
			else
			{
				set_motors(max, max-power_difference);
			}
		}

		
	}

}

Why did you add that “wheel adaptation”? (I ran the code I wrote above on a stock 3pi, so I expect it to work for you.)

-Jon

Thank you so much for helping me, tomorrow I will test your program! (I should have gone to sleep already)

The reason for the adaptation is the following, because the 3pi is tiny, and that the incline angle of the ramp of the challenge is very accentuated, I had to do this, so that with the momentum he has on the straight he can go on the ramp, without causing damage to 3pi!
Before the adaptation, the robot hit the front of the ramp and braked, Like this: https://www.youtube.com/watch?v=tPxCXCGVod4

Good morning Jon, I did the tests on the track of my school, unfortunately he had problems with 90 ° curves. I did this test with a speed of 190, it’s a good speed, climbed the ramp no problem (using the wheel adaptation), But had problems with 90 ° curves. See the videos:

This first video shows the function of the front wheel. It works perfectly, even more with PID! What happens during the video is happens in fractions of seconds, so I recommend seeing at speed 0.25

In this other video I show his circuit complete on the test track (Sorry for having recorded vertically.)

Unfortunately, it is beyond the scope of our direct technical support to keep helping you make specific changes to your code. Some other forum members might be interested in helping you out, or you might be able to find someone who can help you in person. However, I recommend that you read through the program carefully to understand how its logic operates and exactly what it is doing, then try to identify where it is not behaving the way you want.

For example, it looks like the robot is failing to make that sharp turn because it is losing the line before it can turn enough. You might try slowing it down to see if it doesn’t overshoot the turn so badly, or you could think about how to add the goingStraight or reto check back in so that the robot only continues straight after losing the line if it was going straight before (which probably means it is at a break in the line), not if it was trying to turn (which probably means it is at a sharp turn). (Note that your previous program was not correctly assigning a useful value to reto; you’ll have to think about how the robot should decide whether it is trying to go straight or not).

-Jon

What a pity, that made me a bit confused, but okay …

But anyway, thank you so much for what you have helped me until up here!

I just want to make it clear then what happened. I changed the programming by adding the “reto”, but when the 3pi makes the way counterclockwise he go normal, but clockwise it gets lost… And I could not figure out why.

And I unfortunately do not understand what you mean in the last paragraph :confused:

In case of doubt, here is the code:

int main()
{
	unsigned int sensors[5];
	unsigned char reto;
	unsigned int last_proportional=0;
	long integral=0;

	initialize();
	reto = 0;
	
	while(1)
	{
		unsigned int position = read_line(sensors,IR_EMITTERS_ON);
		if(sensors[0] < 300 && sensors[1] < 300 && sensors[2] < 300 && sensors[3] < 300 && sensors[4] < 300 && reto)
		{
			set_motors(100,100);
		}
		else
		{
			int proportional = ((int)position) - 2000;

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

			last_proportional = proportional;
			int power_difference = proportional/3 + integral/50000 + derivative*4/1;

			const int max = 200;

			if(power_difference > max)
			power_difference = max;
			else if(power_difference < -max)
			power_difference = -max;

			if(power_difference <0)
			{
				set_motors(max+power_difference, max);
				reto = 0;
			}
			else
			{
				set_motors(max, max-power_difference);
				reto = 1;
			}
		}

		
	}

}

To be clear, we can answer questions about your code and help you with specific problems that you run into, but we cannot keep writing all of your code for you. As for your current issue, you should try to think about what power_difference represents and understand why it doesn’t make sense to set reto based on whether power_difference is less than or greater than 0.

-Jon

Good evening!

Right. I’ll try to sort out some doubts then.

The command power_diference is defined by the formula int power_difference = proportional/X + integral/Y + derivative*Z; right?

In these two engine commands, why must power_diference be less than 0?

if(power_difference <0)
			{
				set_motors(max+power_difference, max);
				reto = 0;
			}
			else
			{
				set_motors(max, max-power_difference);
				reto = 1;
			}

The max constant is the speed I want it to have, but what defines when it’s going to be this speed will be the maximum (for straight lines) or less (for curves)?

And because in PID it only uses two commands for motors, instead of 3 as in the basic control?

Thank you

The segment of code you are referring to uses the power_difference value to set the speeds of each motor in order to adjust how strongly the 3pi reacts (i.e. turns) for a given deviation from the line. It does so by setting one motor to full speed, the value of max, and setting the other to a speed that is slower by the amount of power_difference.

The sign of power_difference represents how much the left motor speed should differ from the right motor speed, so it indicates which way the robot will be turning to drive back to the line. So, if power_difference is less than zero, power_difference is a negative number and it is added to max to set the left motor speed less than max, causing the left motor to run slower and the robot to turn to the left. If power_difference is greater than zero, then power_difference is positive and is subtracted from max to set the right motor speed less than max, causing the right motor to run slower and the robot to turn to the right.

We could have written the code to handle a third condition where power_difference is equal to zero (when the robot is trying to drive straight):

if (power_difference < 0)
{
  // turn left
  set_motors(max+power_difference, max);
}
else if (power_difference > 0)
{
  // turn right
  set_motors(max, max-power_difference);
}
else // power_difference is 0
{
  // go straight
  set_motors(max, max);
}

But if you think about what happens when power_difference is zero, there is actually nothing special that needs to be done in that case; it would work the same way even if we treated it the same as one of the other two cases. In other words, set_motors(max+power_difference, max) and set_motors(max, max-power_difference) both do the same thing as set_motors(max, max) if power_difference is zero. Therefore, we optimized the code a little bit by removing the third condition and changing the else if in the second condition to be just else (so that its code block executes whenever power_difference is greater than or equal to zero).

-Jon

Good evening, I did the tests with this code above, but I not did get what I expected, even putting a value for when I’m going straight.

Even after you said it made no sense to put a value of “straight” based on whether power_difference is less than or greater than 0, I tried to do tests with this variable, even altering the code, he continued on this, or worsened. And he only makes the turns clockwise, counterclockwise he gets lost.

The first code I made was this one:

int main()
{
	unsigned int sensors[5];
	unsigned char reto;
	unsigned int last_proportional=0;
	long integral=0;

	initialize();
	reto = 0;
	
	while(1)
	{
		unsigned int position = read_line(sensors,IR_EMITTERS_ON);
		if(sensors[0] < 300 && sensors[1] < 300 && sensors[2] < 300 && sensors[3] < 300 && sensors[4] < 300 && reto)
		{
			set_motors(150,150);
		}
		else
		{
			int proportional = ((int)position) - 2000;

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

			last_proportional = proportional;
			int power_difference = proportional/10 + integral/30000 + derivative*4/1;

			const int max = 220;

			if(power_difference && reto > max)
			power_difference = max;
			else if(power_difference && reto < -max)
			power_difference = -max;

			if(power_difference <0)
			{
				set_motors(max+power_difference && reto, max);
				reto = 0;
			}
			else
			{
				set_motors(max, max-power_difference);
				reto = 1;
			}
		}
		
	}

And, trying to fix the error of the 90 ° curves, I tried to adapt it here:

int main()
{
	unsigned int sensors[5];
	unsigned char reto;
	unsigned int last_proportional=0;
	long integral=0;

	initialize();
	reto = 0;
	
	while(1)
	{
		unsigned int position = read_line(sensors,IR_EMITTERS_ON);
		if(sensors[0] < 300 && sensors[1] < 300 && sensors[2] < 300 && sensors[3] < 300 && sensors[4] < 300 && reto)
		{
			set_motors(150,150);
		}
		else if(sensors[0] < 300 && sensors[1] < 300 && sensors[2] > 2200 && sensors[3] > 2800 && sensors[4] > 2800)
		{
			set_motors(70,-70);
		}
		else if(sensors[0] > 2800 && sensors[1] > 2800 && sensors[2] > 2200 && sensors[3] < 300 && sensors[4] < 300)
		{
			set_motors(-70,70);
		}
		else
		{
			int proportional = ((int)position) - 2000;

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

			last_proportional = proportional;
			int power_difference = proportional/8 + integral/30000 + derivative*4/1;

			const int max = 190;

			if(power_difference && reto > max)
			power_difference = max;
			else if(power_difference && reto < -max)
			power_difference = -max;

			if(power_difference <0)
			{
				set_motors(max+power_difference && reto, max);
				reto = 0;
			}
			else
			{
				set_motors(max, max-power_difference);
				reto = 1;
			}
		}
	}
}

But I believe that he runs away from the 90 ° curves by a logic error, or order in the code. But I made about 25 more changes, and I can not find the problem. By the flowchart everything is ok, but I believe it is in the order of the code. Could you help me in this or is it infeasible?

It sounds like you are trying to improve your 3pi’s ability to follow the line by adding reto and && reto in various places in your code and then running your 3pi to see if its behavior gets any closer to what you want. It also sounds like you might be making many changes at once and keeping them, regardless of whether or not they helped make your 3pi’s behavior any better. I think you should leave reto out of the following lines of code:

if(power_difference > max)
power_difference = max;
else if(power_difference < -max)
power_difference = -max;

if(power_difference <0)
{
	set_motors(max+power_difference, max);
}
else
{	
	set_motors(max, max-power_difference);
}

Instead, you should think about what it means for the 3pi to be going straight. The sign of power_difference (< 0 or > 0) indicates the direction the robot is turning. The magnitude of power_difference indicates how much the robot is turning. So a small magnitude should mean that the robot is going close to straight. Try adding a separate conditional check for the value of abs(power_difference) and setting reto appropriately based on that.

-Jon

What does abs (power_difference) mean?

But then if I should leave that part of the code without the “straight” variable, should I put it in another part of it?
Because it is strange, without the fault code reading on the track it makes the normal curves, with with the fault detection code, it gets lost in the 90 ° curves. And I can not understand why, Why does the fault reading part occur separate from the program that controls the curves.

This only happens with high speeds, I tested with speed of 110 and he does without errors

I’m already freaking out with this (but my teacher said it’s normal), because are missing 3 days FOR THE FINAL CHALLENGE.
Hat I tried to do was the following. I added this code next to the main program, and tried to add values in the engines, but he walked straight or just making turns:

			else if(power_difference > reto)
			power_difference = max;
			else if(power_difference < reto)
			power_difference = max;

Update note:
Good morning Jon, now in the morning I took my 3pi to test in school, I made some changes in it, but nothing has changed. The problem is only in the 90 ° curves.
I talked to my teacher about 3pi’s behavior in the curves, and we noticed that he starts the curves but gets lost in the middle of them going straight for off the track. So I explained to him how the code was, and said that reading the flaws was a priority (if) and the control in the curves was in the background (else)
And maybe that’s the problem !!
Because he starts the curve, but maybe for a moment his sensors are all on the white lane and that makes him stop making the curve and start going straight?
So we thought about how to leave the control of the motors in the turns as priority (if) and the detection of white as a second option (else). I’ve tried only to change the codes, but I was not able to use the (if) and (else) properly.
And you, Jon, do you think this could be the solution? How could I change the priority of the controls? Would it have a better solution? For as I said earlier, this problem in curves only appears when the fault detection code is placed.
Sorry if I’m bothering with many emails, but this makes me very anxious because I can not solve it and the challenge will be June 10th

It does not seem like it would be in the spirit of the challenge for us to give you this level of assistance, and it really seems like this is the kind of thing you should be trying to figure out for yourself. Since you already have it successfully following the line on your course without errors at lower speeds, you might go back to that code and use it as a starting point for your attempt to handle the 90 degree turns. Test your new code at the same low speed that the 3pi was already working at. If things are working and the 3pi can successfully handle those 90 degree turns, then you can try incrementally increasing the speed.

-Jon

You’re right, I understand.

But can I ask three questions?

According to the video I recorded now, why if he goes clockwise he gets lost? And why does he get off the track from nowhere? There are times when it starts to spinning over faults on the black line. Up to a certain speed he does not get lost in the curves, but sometimes turns over the faults in the black line, but with higher speed he is still failing in the curves. Even changing the formula it still does this, Is it a logic error?
My video: https://www.youtube.com/watch?v=ge3BdeUNWXk

Here is my program:

int main()
{
	unsigned int sensors[5];
	unsigned int last_proportional=0;
	long integral=0;

	initialize();
	
	while(1)
	{
		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/3 + integral/50000 + derivative*4/1;

			const int max = 200;

			if(power_difference > max)
			power_difference = max;
			else if(power_difference < -max)
			power_difference = -max;
			
			if(power_difference <0)
			{
				set_motors(max+power_difference, max);
			}
			else if(sensors[0] < 350 && sensors[1] < 350 && sensors[2] < 350 && sensors[3] < 350 && sensors[4] < 350)
			{
				set_motors(160, 160);
			}
			else if(power_difference >0)
			{
				set_motors(max, max-power_difference);
			}

		}
		
	}

Good night, one more question.
The maximum speed that 3pi can provide is 255? Or is there any way to get more speed?

In general, if a 3pi robot is running PID code to follow a line and it is following fine at low speeds, but it fails while handling turns or during breaks in the line at higher speeds, that is not necessarily an indication that there is an error with the way the PID algorithm is implemented. Basically, there is only so much manual tuning of P, I, and D that you can do before the 3pi’s hardware limits its ability to respond to the errors it calculates. It takes a certain amount of time for the 3pi to send logic signals to the motor driver, for the motor driver to interpret the signal and adjust the battery voltage supplied to the motors, and for the current flowing through the coils of the motor to increase or decrease in response to the voltage being changed. The AVR microcontroller running the PID controller on the 3pi is able to calculate the error of the system faster than the 3pi robot as a system can respond. So, at high speeds when there is a large change in the input to the system, (the input is the position of the line) like when the line curves during a 90 degree turn, the 3pi robot cannot perform its response quick enough to keep following the line.

As for your last question, the set_motors() function takes a speed value between -255 and 255. So, yes, 255 is the maximum speed you can set. There is no way to set a motor speed larger than that.

-Jon