Log in

View Full Version : problem with autonomous that has stumped all programmers so far


bd02
08-03-2004, 19:04
The autonomous mode i programmed for our robot for dead wreckoning was working fine. It would count the # of 26.2 ms and use them to time the movements of the bot. The first time i setup the code with sample times it worked just fine, but once i put actual times in that we received from out test runs, the cpu seemed to skip the first few steps and and go directly to the area where the robot is todl to move forward for 3 seconds. I asked a group of programmers at the Regional in Trenton, which were mostly coaches or people with enough knowledge of the language to comprehend my code, and they all said my code was written fine and should be working ok. I myself do web programming the usual html (even though it isn't really considered a language), vbscript, javascript, asp, sql, and php, and have had no real trouble in the past with debugging, but now I'm just stuck. Can anyone help me with this? :confused:

Attatched is my working code. Whenever i changed the time values for each state or change SECS_TO_TICKS to MSECS_TO_TICKS, it throws it off for some reason and makes it skip states. Any ideas?

jacob_dilles
08-03-2004, 19:13
we orignaly had an atonomus code that looke strikingly similar to yours and had a very similar problem, we could not resolve it. after 2 days of total frustration, i compleatly re-wrote the code using 6 big if statements and a simple counter. from then on it worked perfectly. i think that there might be an issue with how the compiler disassembles complex switch statements. i hope you can get it working!

bd02
08-03-2004, 19:20
I'll have to try that. It actually seems more practical than these huge cases. The reason the code might look so familiar is because it is based on a few lines of code I found here on the Delphi forums.

jacob_dilles
08-03-2004, 19:22
what i did... if youll hold on ill get you the actual code... is not actualy a timer but a inturupt on a wheel counter. this however can be used exactly like a timer except it is not speed dependent ( i.e. you can change speed without haveing to wory about distance ). stand by

KenWittlief
08-03-2004, 19:26
My first guess would be that the variables used in auton mode, ie tick count or the states... are not being cleared when auton mode is not running - it should be done at the end of your driver mode code, so that whenever the bot is switched into (back into?) auton mode, it starts from the beginning.

bd02
08-03-2004, 19:29
My first guess would be that the variables used in auton mode, ie tick count or the states... are not being cleared when auton mode is not running - it should be done at the end of your driver mode code, so that whenever the bot is switched into (back into?) auton mode, it starts from the beginning.

Auton mode is only activated once every round, and pressing reset on the FRC before or after a round automatically clears these values for us.

KenWittlief
08-03-2004, 19:30
I just checked again

tick_count is cleared to 0 when your auton code is first called, but AUTO_STATE is not set to the first state.

bd02
08-03-2004, 19:31
I just checked again

tick_count is cleared to 0 when your auton code is first called, but AUTO_STATE is not set to the first state.

It's set to the first state in the auton mode variables up top

KenWittlief
08-03-2004, 19:34
reset does not clear your variables unless you have then specified with a init value somewhere else in the code, where they are declared or in the initialization section.

but either way, you should be able to switch back and forth between auton and driver mode without someone having to push a reset button - just have a section at the end of your driver mode code that sets up the auton variables to start from the beginning - it will make testing your bot much easier.

BTW - when the bot is disabled it is in normal(driver) mode - the pwm outputs are disabled but that code is still running - when they do auton mode they enable it for a cycle or two, then they switch to auton mode.

jacob_dilles
08-03-2004, 19:36
this is the meat of my code... as you can guess the drive motors are on pwms 15,16 and the inturpts incrment count.
/************************************************** ******
************jacobs autonoumus code....********************
************************************************** *****/
relay8_fwd = !rc_dig_in18; // Power pump only if pressure switch is on.
relay8_rev = 0;
//this start start it moving... ladies and gents start your engins
if(count >= 0 && count < 2) {
pwm15 = 127 + 50; //drive strait
pwm16 = 127 + 50; //drive strait
//turn to get the ball
if(count> 12 && count < 14) {
foward = 0; //turn off correction algoritiom (cuz were turning duh)
pwm15 = 127 + 50; //make right wheel turn fowards
pwm16 = 127 - 50; //make left wheel turn backwards
pwm01 = 254; //make arm go up
}
if(rc_dig_in16 == 1) { //make sure arm doesnt go to high!!!
pwm01 = 127;
}
//then we have to go strait slightly to get to the ball
if(count > 14 && count < 16) {
pwm15 = 127 + 50; //go foward
pwm16 = 127 + 50; //go foward
relay3_fwd = 1; //open the gripers...
relay3_rev = 0; //open the grpiers...
}
//now turn to AND close the gippers to knock/grab ball off... combo move HI-YAH
if(count > 18 && count < 23) {
pwm15 = 127 - 50; //turn the other way
pwm16 = 127 + 50; //turn the other way
relay3_fwd = 0; //close grippers
relay3_rev = 1; //close grippers

}

//NOW we shut down motors
if(count > 24 && count < 100) {
pwm15 = 127; //turn the other way
pwm16 = 127; //turn the other way
}
/************************************************** *********
*******************end jacobs auton code******************
************************************************** *********/

bd02
08-03-2004, 19:37
I noticed the prob with the vars not returning to their original values when i first modified the code, so i couldn't run it again once i had already ran it, but once i pressed the reset button it would run it perfectly as though i had never ran it before, so i just figured it cleared my values to the original state

jacob_dilles
08-03-2004, 19:39
but either way, you should be able to switch back and forth between auton and driver mode without someone having to push a reset button - just have a section at the end of your driver mode code that sets up the auton variables to start from the beginning - it will make testing your bot much easier.

in the begening of the auton mode code you should have a:

unsigned count = 0;
unsigend leftcount = 0;
unsigned rightcount = 0;


so that you dont have to reset. it is a matter of pricaple. this way you will never get thos errors

bd02
08-03-2004, 19:45
I'll try it out and let you know how it works out. I just found out my team is totally redesigning the electronics board, so that complicates things a bit for me, but i'll let you know in a few days or so what's goin' on.

KenWittlief
08-03-2004, 19:48
if the only thing you changed was adding this stuff:

SECS_TO_TICKS(a) ( ((int)(a)) * 10000 / 262 )

then maybe its not doing what you think it is?

int is signed, isnt it? so if a = 4 you end up with 40,000 which is a negative number divide by 262?

if this is what you changed and it got weird on you, just work with the tick counts in your code forget the fancy translations.

also could try running with a few printf statements and see what is happening at the start and end of each state - there might be something weird going on.

deltacoder1020
08-03-2004, 20:09
int is signed, isnt it? so if a = 4 you end up with 40,000 which is a negative number divide by 262?

if this is what you changed and it got weird on you, just work with the tick counts in your code forget the fancy translations.

also could try running with a few printf statements and see what is happening at the start and end of each state - there might be something weird going on.

nice catch, Ken. the code this is based off of is an example that I posted on the forums here: http://www.chiefdelphi.com/forums/showthread.php?p=233912

the problem is that for any time period larger than about 3 seconds, 10000*a is greater than the max limit for a plain "int", and thus it's either wrapping around or just mucking stuff up.

you can solve this problem by changing the declarations of SECS_TO_TICKS and MSECS_TO_TICKS to the following, which use a "long" instead of an "int" (you'll notice that tickCount is already defined as a "long"... at least I was thinking clearly there! :)):


//A handy-dandy macro to convert a number of seconds into a number of 26.2ms ticks
#define SECS_TO_TICKS(a) ( ((long)(a)) * (long)10000 / (long)262 )
//And milliseconds too:
#define MSECS_TO_TICKS(a) ( ((long)(a)) * (long)10 / (long)262 )

weee... can never have enough type casts.

I remember when I originally typed in the code, i for some reason was thinking that seconds would only need to be multiplied by 1000 - I realized my mistake, but forgot that by changing it to 10000 i needed to increase the type of integer for which that math was done.

So for anyone using the example I posted here, that change should fix it quite nicely. :)

Nice to see my examples are being used and are helpful for some teams.

Ryan M.
08-03-2004, 20:12
If your program is storing its state in a variable, the variable is not reset until the robot is reset. Hit the "robot reset" button on the OI, not the one on the RC. This should solve the problem. Hope that it does. :)

jacob_dilles
08-03-2004, 20:19
WOW i didnt even see that. okay but before you go basing all of your code off 26.6 ms, do a search on CD. it turns out that ( if i understand correctly ) each cycle IS NOT 26.6 ms, and that it varies depending on what code is executed. it is a MAX of 26.6 ms. so use something more concrete. like a timer inturupt. or a wheel counter. if your redoing all of your electronics, you might as well

deltacoder1020
08-03-2004, 20:25
WOW i didnt even see that. okay but before you go basing all of your code off 26.6 ms, do a search on CD. it turns out that ( if i understand correctly ) each cycle IS NOT 26.6 ms, and that it varies depending on what code is executed. it is a MAX of 26.6 ms. so use something more concrete. like a timer inturupt. or a wheel counter. if your redoing all of your electronics, you might as well

actually, reports from various people i've talked to have said that NEW_SPI_DATA gets reset fairly regularly on a 26.2ms basis, because it is the master processor that is timing these updates. because there is no external code running during autonomous mode (unless you added some), chances are fairly good that the flag will be detected quite close to the ms mark. so it should work fairly well for most teams' needs. but yes, if you feel that you need the extra precision and have the programmers to do it, feel free to go down other paths. as I stated when I posted the code, this is for teams that don't really have the programming resources to get really into coding, but do want to experiment some and design a decent autonomous mode.


--edit--

also, let me explain my reasoning for not including a in-code reset for the autonomous mode timer variables. if, for some reason or other, the robot controller got a garbled packet that somehow made it though and set autonomous_mode to 0 for a cycle, i did not want a random team having to watch as their robot restarted its autonomous mode in the middle of the field :/ I felt that it was simpler to have the robot remember where it was, seeing as (as someone already mentioned) one can hit the reset button and have it ready to go again. It's a matter of personal preference, feel free to zero them out if you wish.

Larry Barello
08-03-2004, 20:42
nice catch, Ken. the code this is based off of is an example that I posted on the forums here: http://www.chiefdelphi.com/forums/showthread.php?p=233912

the problem is that for any time period larger than about 3 seconds, 10000*a is greater than the max limit for a plain "int", and thus it's either wrapping around or just mucking stuff up.
...

The easy fix is to use ((unsigned int)(a)) instead of int. you will never need negative time, so why specify a signed number?

Cheers!

deltacoder1020
08-03-2004, 20:45
The easy fix is to use ((unsigned int)(a)) instead of int. you will never need negative time, so why specify a signed number?

Cheers!

making it unsigned only doubles the amount of space you have - anything over 6.5 seconds or so will still overflow it, hence the reason i recommend using longs.

jacob_dilles
08-03-2004, 20:51
unsigned long.... comon guys its got plenty of ram

deltacoder1020
08-03-2004, 22:44
unsigned long.... comon guys its got plenty of ram

unsigned vs. signed doesn't affect the amount of space the variable takes up - use what you want, i highly doubt you'll need the double capacity of an unsigned long vs. a regular long

KenWittlief
08-03-2004, 22:54
easiest fix is to divide it out and multiply the number of seconds you want by 38 - thats what Im doing in my code, assuming 38 cycles per second

and since we are all tweaking this by observing the machine on the field, and nudging the numbers a little, it doenst really matter if your seconds are lockstep with the National Beuro of Standards in Bolder Colorado

or better yet, forget seconds and work in loop counts - one less thing to worry about.

deltacoder1020
08-03-2004, 23:03
easiest fix is to divide it out and multiply the number of seconds you want by 38 - thats what Im doing in my code, assuming 38 cycles per second

and since we are all tweaking this by observing the machine on the field, and nudging the numbers a little, it doenst really matter if your seconds are lockstep with the National Beuro of Standards in Bolder Colorado

or better yet, forget seconds and work in loop counts - one less thing to worry about.

the thing about multiplying by 38 is if you need partial seconds - floating point math is slow. working in raw loop cycles in fine, i just wanted to give less experienced teams other options. :) replacing int with long shouldn't be that hard.

KevinB
08-03-2004, 23:41
if, for some reason or other, the robot controller got a garbled packet that somehow made it though and set autonomous_mode to 0 for a cycle, i did not want a random team having to watch as their robot restarted its autonomous mode in the middle of the field :/
The Radio Modems perform checksum calculation on the data packets. Although possible, its unlikely that a "garbled packet" would ever get through.

deltacoder1020
09-03-2004, 00:05
The Radio Modems perform checksum calculation on the data packets. Although possible, its unlikely that a "garbled packet" would ever get through.

so call me paranoid. mcc18 hasn't made me any less so. *grumble*

Greg Ross
09-03-2004, 20:13
if the only thing you changed was adding this stuff:

SECS_TO_TICKS(a) ( ((int)(a)) * 10000 / 262 )

then maybe its not doing what you think it is?

int is signed, isnt it? so if a = 4 you end up with 40,000 which is a negative number divide by 262?

if this is what you changed and it got weird on you, just work with the tick counts in your code forget the fancy translations.

also could try running with a few printf statements and see what is happening at the start and end of each state - there might be something weird going on.
I zeroed in on this line at first too, but then when I looked at where the macro is used, the only argument ever passed to it is 3, which should not cause a problem, so I kept looking.

Daniel
09-03-2004, 20:50
I've only had a robot to test with for 8 days and 7 of them I have been chasing a problem like the initial message had. That is, you do a printf, a calcualtion and another printf - and the second printf never appears!!!

I'm beginning to believe that my problem is using "long" integers. Something in that compiler is weird.

Any body else had this experience? Did youfind a solution?

I have too many lines of code - so rewriting them is impossible. So much code to debug, so little time!

bd02
09-03-2004, 23:11
Sorry it took so long for me to get bak to you all. The code is working now and we should be fine once we get to Atlanta, thanx for all your help people! :)

Ryan M.
10-03-2004, 06:40
I've only had a robot to test with for 8 days and 7 of them I have been chasing a problem like the initial message had. That is, you do a printf, a calcualtion and another printf - and the second printf never appears!!!

I'm beginning to believe that my problem is using "long" integers. Something in that compiler is weird.

Any body else had this experience? Did youfind a solution?

I have too many lines of code - so rewriting them is impossible. So much code to debug, so little time!In the second printf(), are you printing anything other than just a value? Meaning, is there a constant string in there some place? The printf() that is implemented is fairly limited in the format identifiers it can handle and if it encounters one that it doesn't recognize, it ignores it, printing nothing out in its place. If there is a string you can verify it is actually being called.

Daniel
10-03-2004, 09:45
In the following code (with lots of test lines) the Move () function is called many time to determine if the move has completed. The printf which the first line of the function appears and so does the second showing "TT=%d". But the subsequent printf statments never appear and it acts like the function just simply returns to the caller.

I'm suspecting a problem with how C18 handles long math. Read the relese note... it can make a person worry about what works.

I've already logged one bug with Microchip. The SetChanADC function needs to shift the channel number one bit to the right. I'm working on another white paper about "Faster Analog" input. Anyone want to review it?

I have talked to other teams and many have seen this problem - but no one has indetified the "root cause". I'm officially told to re-enter my program. There has to be an answer to help all of us.

int Move (void) {
static long l, r;
int ll, rr;
static int t, t1, t2;

printf("In Move STATE 1.\n");
switch (next_state) {

// Ramp Up. Stay in this state for the ramp up time
// or until the braking distance.
case 1 :
// Have you traveled far enough at this speed to brake in a safe distance?
// Compute the average distance remaining to go.
// l = get_LeftWheelDistance () - StartDistanceLeft;
// r = get_RightWheelDistance () - StartDistanceRight;

// why is 1200 / 2 = 22
ll = 1200;
rr = 0;
t = ll + rr;
printf ("TT = %d\n", t);
t = t / 2; // t = 1200 then t = t /2 results in 22!
printf ("TT = %d\n", t);

printf ("1200/2 %d\n", 1200/2);
l = 1200;
r = 0;
t = (int) l + (int) r;
printf ("T = %d\n", t);
t = t / 2; // t = 1200 then t = t /2 results in 22!
printf ("T = %d\n", t);
t = lAbs((long) t);
printf (" Move 1 l %4d r %4d Avg %4d\n", (int) l, (int) r, t);
...

deltacoder1020
10-03-2004, 12:25
In the following code (with lots of test lines) the Move () function is called many time to determine if the move has completed. The printf which the first line of the function appears and so does the second showing "TT=%d". But the subsequent printf statments never appear and it acts like the function just simply returns to the caller.

I'm suspecting a problem with how C18 handles long math. Read the relese note... it can make a person worry about what works.

I've already logged one bug with Microchip. The SetChanADC function needs to shift the channel number one bit to the right. I'm working on another white paper about "Faster Analog" input. Anyone want to review it?

I have talked to other teams and many have seen this problem - but no one has indetified the "root cause". I'm officially told to re-enter my program. There has to be an answer to help all of us.

...

%d is designed to print out an int, not a long. chances are that is the source of your problem. also, you might try the following to correct the "1200/2 = 22" bug:

t = t / (long)2;
instead of the current t = t / 2; line.

this is because 2 is automatically type cast to an unsigned char, and thus the math is performed in the unsigned char space, not the long space.

Daniel
10-03-2004, 22:22
I'll try it tommorrow between doing inspections.

But as a computer scientis type of person I want to know why something that simple and obscure can make a function prematurely return or act weird. Then I'll know that I have the problem solved, and it will not come back and byte me again.