Code error with while loops??

-History-
I am a student who is currently learning C++, so I know simple commands like a while statement.
I was able to get this code working when I program a PC.
I searched the web for help but found nothing
----==================
Now when I program the Robot using C I get it to do a loop but after a few times the bot will say code error.
I just want the robot to travel for a certain number of seconds.
here is my code what is wrong? or is there a better way to have a robot on a timer?
(this code is under the void Autonomous(void) function)

if(stop == 0)
{
timer = 900;
while(timer > 0)
{
timer = timer - 1;
printf( "timer is %d
", timer );
pwm13 = pwm14 = pwm15 = pwm16 = 255;
}

stop = 1; // this should make sure the code wont run again
}
printf( "stop is %d
", stop );
pwm13 = pwm14 = pwm15 = pwm16 = 127;
printf( "pwm13 is %d
", pwm13 );

If you aren’t communicating with the master proc, by callin GetData and PutData, the master assumes the user proc is locked.

EDIT:


  int timer;
  while (autonomous_mode)   /* DO NOT CHANGE! */
  {
	  if (statusflag.NEW_SPI_DATA)      /* 26.2ms loop area */
	  {
                            timer++;
		  Getdata(&rxdata);   /* DO NOT DELETE, or you will be stuck here forever! */
		  //Put your code here
                           if (timer < 900){}
                           else if (timer < 1000 {}
                           //ect.

		  Putdata(&txdata);   /* DO NOT DELETE, or you will get no PWM outputs! */
	  }
  }

what function do I put that code under?
I tried puting it in the same place as my while loop, but it didn’t do anything.
timer = 0;
while (autonomous_mode) /* DO NOT CHANGE! /
{
if (statusflag.NEW_SPI_DATA) /
26.2ms loop area /
{
timer++;
Getdata(&rxdata); /
DO NOT DELETE, or you will be stuck here forever! */
//Put your code here
if (timer < 900){
pwm13 = pwm14 = pwm15 = pwm16 = 255;
}
else {
pwm13 = pwm14 = pwm15 = pwm16 = 127;
}
//ect.

	  Putdata(&txdata);   /* DO NOT DELETE, or you will get no PWM outputs! */
  }

}

If you’re using IFI defualt code, then you put that entire code block in User_autonomous_code() in user_routines_fast.c.

If you’re using Kevin’s c18 v3 code, then you put the code contained WITHIN “if (statusflag.NEW_SPI_DATA)” in Autonomous() in autonomous.c. You also need to make timer static if you’re using Kevin’s code.

I made this exact same mistake when I first started FRC Programming. What you need to realize is that the architecture of PC Terminal-style programming (When you write a program in C that runs in a black DOS-style window) and the architecture of microcontroller programming is inherently different.

When you write a program in C to run in a DOS-style terminal window, everything executes linearly. The program starts at main() and when it gets to the end, the program terminates. This fact doesn’t change, but there’s a lot more going onin the RC that just what you write. In reality, 90% of what the RC is actually doing is being done in the background, and you don’t ever have to deal with it.

You may not have programmed it, but you know how the OI and the RC communicate through the Radio modems, and how you can program the copper pins on the RC through the PWM and Digial IO and Analog Input variables in the code? All of that stuff is being controlled within the code, primarily by the Getdata() and Putdata() routines which you may have seen and been warned not to mess with.

It probably seems to you like the code variables represent what’s going on in the hardware at the exact moment you look at them, and that when you change one of these variables, the hardware immediately changes what it’s doing. But it only seems that way because Getdata() and Putdata() are being called roughly 38 times per second. Take a look at the main.c file. The program starts at main(), yes, but if you look within that function, you’ll see an infinite loop (while(1)). As a programmer, you know that this loop will never end. Well, this is completely intentional. Within the loop, you’ll see the routine Process_Data_From_Master_uP(), which is called within an if() statement (the NEW_SPI_DATA flag is set automatically when the microprocessor has new data that needs to be processed. This is where the 38 times per second comes in). The function Process_Data_From_Master_uP() basically just calls Getdata(), calls Default_Routine(), calls Putdata(), and ends. Default Routine is probably where you do all of your stuff, like reading the josytick values and setting pwms accordingly to drive the robot, etc. The autonomous routine doesn’t actually call Process_Data_From_Master_uP(), but the Getdata(), do something, Putdata() structure is the same.

Here’s the main point. When you write your own code, you need to realize that the microprocessor is running through the entire thing 38 times per second. Not just that, it NEEDS to run through the entire thing 38 times per second. If you hold everything up in a while loop, then Getdata() and Putdata() don’t get called, and the RC stops communicating with itself and with the OI. The code you posted is actually fine, but the problem is that it only takes a fraction of a second for it to count to 900. From what you say, it seems like the counting to 900, even though it takes under a second, it taking a little bit too long and it throws off Getdata() and Putdata(), or maybe it’s just overtaxing the processor.

The solution to this problem would be to use a timer that increments once during each overall program loop, and check the timer once during each loop to see if it’s time to stop. Like so.


void Auto_Drive(void)
 {
  // The static keyword is required because this function is being called and 
  // terminated 38 times per second. Thus a non-static timer would loose its
  // value every time the function terminated. A static variable remains even
  // after the function terminates and retains its value. Also, it is set to 0 only
  // when it is first defined.
  static unsigned int timer = 0;

  // Let's drive forward for 5 seconds.
  if(timer < 190)
   {
    // Drive straight forward at full speed.
    Main_Drive(127 /*X Joystick Value*/, 255 /*Y Joystick Value*/);
    ++timer;
   }
  else if(timer == 190)
   {
    //Stop moving
    Main_Drive(127 /*X Joystick Value*/, 127 /*Y Joystick Value*/);
   }
 }

I used 190, because the Getdata()/Putdata() combo takes about 26.2milliseconds to execute. So, if one increment of the timer takes .0262seconds, and we want to drive forward for 5 seconds…


              1 program loop
5 seconds  X  ------per------
              .0262 seconds

The seconds cancel each other out, and we’re left with 190.8 program loops. Thus, we increment timer 190 times.

Hope you’ve learned something.

Along with JakeM’s great explanation, I’d like to point you to my white paper “A programming template for Autonomous Mode”: Chief Delphi => CD Media => Papers => Search => keyword => Autonomous mode.

If you hardcode constants like 900 in your example, in order to tune the routine you’ll have to change the constant within the code (and maybe that 900 in several places), and the work will cascade as you do more counts in subsequent steps.

A state machine is a great way to implement steps within Auton. mode and I hope the paper helps. There’s a lot of good information in the White Papers section, and when things calm down you can spend some time looking at what’s there, and see if they will help with the things you’re learning.

GaryK

thanks for your long reply it works now!