Log in

View Full Version : Trouble with Autonomous


popnbrown
25-02-2007, 20:00
Well the title of the thread actually isnt exactly my problem. Autonomous works however one of my functions doesn't work. We are trying to get our robot to rotate (a 0 degree turn). I'm using WPILib so we have to write totally new code.

Well anways here is the function Rotate():

void Rotate(char direction, int degrees, char speed)
{
int time = (1000 * (degrees/ 300));
char RightMotor = NEUTRAL + (speed * direction * (SPEED_TO_PWM));
char LeftMotor = NEUTRAL + (speed * direction * (SPEED_TO_PWM));
//the SPEED_TO_PWM = 127/10 which converts the speed to PWM value

printf("Rotate()\r");

SetPWM(LEFT_WHEEL, LeftMotor);
SetPWM(LEFT_FRONT_WHEEL, LeftMotor);
SetPWM(RIGHT_WHEEL, RightMotor);
SetPWM(RIGHT_FRONT_WHEEL, RightMotor);

printf("time: %d\r", time);

Wait(time);

SetPWM(LEFT_WHEEL, NEUTRAL);
SetPWM(LEFT_FRONT_WHEEL, NEUTRAL);
SetPWM(RIGHT_WHEEL, NEUTRAL);
SetPWM(RIGHT_FRONT_WHEEL, NEUTRAL);
//NEUTRAL = 127

}


now the main problem is the time. When I pass for example:
Rotate(-1, 30, 10)
the time displays as 0. I find it really odd. However I ran time as a constant:
time = 300; and the function worked perfectly. So the real problem here is one of the variables involved in the time equation and I dont know which one or what is wrong.

Any help would be appreciated

Racer26
25-02-2007, 20:07
I can almost assure you the problem has to do with your equation in the line "int time...." you're generating a float in the middle of it (30/300)= 0.1, which the integer math in the PIC reduces to 0, before continuing with the rest of the math.

As for how to fix it, you could multiply all the numbers involved by say 1000, and divide by 1000 as your last step... or... something.

Joe Ross
25-02-2007, 20:13
The problem is with your order of operations.

time = (1000 * (degrees/ 300)); is evaluated in the following order (with degrees being 30).

ime = (1000 * (degrees/ 300));
time = (1000 * (30/300));
time = (1000 * 0);
time = 0;

Since you don't really care what order the operations happen, the following will work for you.

time = (1000 * degrees) / 300;
time = (1000 * 30) / 300;
time = (30000) / 300;
time = 100;

The only problem with the above example is that if degrees gets above 32, you'd overflow the integer value. You could either declare time as a long, or change your constants, since multiplying by 1000 then dividing by 300 is the same as multiplying by 10 then dividing by 3.

TimCraig
25-02-2007, 21:12
Since you don't really care what order the operations happen, the following will work for you.

time = (1000 * degrees) / 300;
time = (1000 * 30) / 300;
time = (30000) / 300;
time = 100;

The only problem with the above example is that if degrees gets above 32, you'd overflow the integer value. You could either declare time as a long, or change your constants, since multiplying by 1000 then dividing by 300 is the same as multiplying by 10 then dividing by 3.

If he doesn't want to declare time as a long and carry that through the rest of the calculations, the following will work with time left as an int.

time = (int) ((long) 1000 * degrees / 300);

or more simply if the compiler is really ANSI compliant

time = (int) (1000L * degrees / 300);

Alan Anderson
26-02-2007, 00:17
The other problem I see is your putting parentheses around your SPEED_TO_PWM macro. With them there, you have a similar rounding issue, and the 127/10 ends up being truncated to 12. If you leave the paretheses off but everything else as it is, the division by 10 won't happen until after all the multiplications are done and you'll end up with more like what you want.

Bharat Nain
26-02-2007, 00:19
Sometimes, really simple is really good.

Stvn
26-02-2007, 01:14
I don't know if it makes a difference, but it might be better if you went:

int time;
char RightMotor;
char LeftMotor;

time = (1000 * (degrees/ 300));
RightMotor = NEUTRAL + (speed * direction * (SPEED_TO_PWM));
LeftMotor = NEUTRAL + (speed * direction * (SPEED_TO_PWM));

AustinSchuh
26-02-2007, 01:21
time = (int) (1000L * degrees / 300);
It might be better to simplify that further using some algebra to something like
time = (int)((long)10 * (long)degrees / (long)3)

That way, you won't run into interger or long overflow problems until degrees is 100 times as large as it would have had to be earlier.

popnbrown
27-02-2007, 15:12
Well I decided to take advice. And:

long time = (1000 * degrees) / 300;

Yet When I call it as:

Rotate(-1, 30, 10);

and still time = 0;. This is really getting to me as we have two days till regional. Any1 know what is going on?

TimCraig
27-02-2007, 15:39
Well I decided to take advice. And:

long time = (1000 * degrees) / 300;

Yet When I call it as:

Rotate(-1, 30, 10);

and still time = 0;. This is really getting to me as we have two days till regional. Any1 know what is going on?

One problem but it's probably not your error is that making time long will not force the calculation on the right of the = to be done as long. C only looks at the participants in the equation to decide how to do the arithmetic, not what you're assigning the result to. So again, you need to cast one of one of the leading values on the right side as (long) or use 1000L. C will call 1000 an int and 1000L is a long.

How are you displaying time to know it's zero? Are you still using the %d specifier in your printf? I can't remember if the PICs are little endian or big endian. If they're big endian, you'll only see the high order half of the long value which in this case is zero.

TimCraig
27-02-2007, 16:11
It might be better to simplify that further using some algebra to something like
time = (int)((long)10 * (long)degrees / (long)3)

That way, you won't run into interger or long overflow problems until degrees is 100 times as large as it would have had to be earlier.

True, he doesn't gain anything in using 1000 and 300 vs 10 and 3. And in that case he doesn't need to force the compiler to do the computation as long. 10 * 360 = 3600 which fits quite comfortably in an int.

BTW, you only need the first (long) cast. Once one element of that calcuation is long, the compiler will force the rest to long to complete it. Actually, casting either the 10 or degrees will do it. Casting the 3 to long will force the result to long but the compiler is free to do the calculation in the parentheses as int then promote it to long before the division.

popnbrown
27-02-2007, 19:12
I tried it this way too and it doesnt work.

long time = ((long)1000* degrees)/ 300; //degrees is 30

And BTW anyone have gmail and could possibly help me around 8:00 EST today, would reely appreciate it and thank you anyways for your help so far.

Dave Flowerday
27-02-2007, 19:19
And BTW anyone have gmail and could possibly help me around 8:00 EST today, would reely appreciate it and thank you anyways for your help so far.
You do realize it's illegal to be working on your robot code right now right?
On the software side, developing detailed pseudo-code, writing actual lines of code, verification of syntax, final debugging, etc would all be considered development of the final software implementation, and must be completed during the approved fabrication periods.
No writing, no debugging allowed right now.

TimCraig
27-02-2007, 19:21
I tried it this way too and it doesnt work.

long time = ((long)1000* degrees)/ 300; //degrees is 30

And BTW anyone have gmail and could possibly help me around 8:00 EST today, would reely appreciate it and thank you anyways for your help so far.

But you didn't answer the burning question. How are you displaying time to get the value of zero?

If you're doing:

printf("Time = %d\r\n", time);

it won't work since %d is going to display a 2 byte integer and not the 4 byte long. It will only display either the upper or lower two bytes depending on whether the PIC is little or big endian.

You need to either:

printf("Time = %d\r\n", (int) time);

or

printf("Time = %ld\r\n", time);

Assuming the implementation of printf you're using is complete enough to accept the %ld specification to print longs.

I don't know this is your problem since you haven't shown your latest version with the printf, but it's a high probability on my list.

popnbrown
27-02-2007, 20:32
O yea we're done working on our code. It's just that I'm gonna be programmin cap next year and I'm trying to get my stuff down. So sry if I seemd to be doin somethin against the rules but thank you for letting me now I guess. Well I'm done anyways. the printf("%ld") works. Thank you

popnbrown
27-02-2007, 20:48
Hey Mr. Tim Craig, it seems as if you are pretty good at C. Is there any chance I can get your e-mail, I have a couple of questions in C?