I have been thinking about this for a little while. Why not have 2 sets of initializations and loops? 1 for autonomous, 1 for regular. And while we’re at it, include a HALT() routine. Here’s my version. Where do I put the prototype for HALT()?
Frc_NewMain.zip (50.7 KB)
Frc_NewMain.zip (50.7 KB)
It’s an interesting idea, but I’d advise against it. I looked at what you did at main.c and there’s two major problems that I see. The first is that your code now depends on the fact that autonomous will be active when the robot is powered on. I don’t believe this will be the case at the competitions. I’m pretty sure that last year, when you were setting up your robot on the field, the “Disabled” bit was set but the “Autonomous” bit was clear. Then, when the round started, it would change from “Disabled - no auto” to “Enabled - auto mode” in one packet. Even if they did plan to have the autonomous bit set when you plug your robot in on the field, there might be a delay or something - I wouldn’t rely on it.
The second problem is that once your autonomous routine ends, there’s no going back. This probably isn’t such a big deal, but if somehow one packet from the OI comes down during autonomous mode with the autonomous flag cleared, your robot will stop autonomous mode and you won’t be able to get back in. I highly doubt this would happen since IFI checksums the packets to ensure that they are valid before passing them to the user cpu, but still… you never know what might happen.
Finally, your idea of halting the robot is interesting, but I don’t see the purpose for it. Why would you want your robot to ever shut down? And more importantly, why would you want code to do that in there when you compete? I know our drive team would be rather upset if we had code like that in our robot and then a bug or something caused that condition to occur… Also, if you really want to have this halt option, it would probably be a wise idea to turn off all your outputs beforehand (PWMs to 127, relay outputs off, etc).
there is also the fact that such could result in code duplication - you may use some of the same code for the Process_Data_from_Local as you would for autonomous.
There really is no advantage to doing this. If you’re worried about code readability, try splitting the actual code up into separate files like this:
if (autonomous_mode) {
#include "auton.c"
} else {
#include "manual.c"
}
What? #include statements are pre-processor directives … they are (quite necessarily) executed before compilation and definately before you upload the code to the robot. For conditional includes, you’d have to use the pre-processor directive #ifdef … #endif – but this isn’t what you mean to do. Presumably, everytime you run the robot you’d want to execute both autonomous mode, and manual mode – meaning you’d more than likely want both “auton.c” and “manual.c” to be included every time. Instead of #include “auton.c”, perhaps you mean some sort of function call, where the function is defined in auton.c? color me confused
there is also the fact that such could result in code duplication - you may use some of the same code for the Process_Data_from_Local as you would for autonomous.
That’s not such a big concern, though. If something increases readability, or efficiency, or some other desirable thing, you very may well say “re-usability be damned.” Reducing code duplication is good because it reduces your work, and reduces the amount of errors creeping up because of subtly different versions … but it isn’t necessarily bad (not that it is–or isn’t-- justified here). Oh, and all I really wanted was an excuse to say this (sorry that I forget who it was that said it): For code to be re-usable, it first has to be usable
No, that should work as is… since the preprocessor would stick both of the files in and then everything would compile. That being said, I do agree that making then relevant sections into functions (in seperate files if you insist), would make much more sense.
of course it does. i comment the heck out of my code, as well as try to arrange it in the most logical way possible
I think what Random Dude meant was that you could use #includes so that you could be sure that the code you were writing would be executed for one mode or another, depending on what file you put it in. that way, you still have both autonomous mode and operator mode, but the code for each is in separate files.
I didn’t use #ifdef or #endif because thats not what I’m trying to accomplsh. The #include directive simply takes the contents of that file and shoves it into the spot where the #include line was.
You get the conveinence of having the autonomous routine in 1 file and the main routine in the other file, and you save the CPU cycles necessary to jump to and from the function.
It is perfectly reasonable to rewrite main(). I did it. I don’t understand why IFI put in such a baroque superstructure in the FRC default code. The EDU code was cleaner.
You can replace everything that IFI gave you, except for their library. All I saved was the printf (modified slightly) and the main library with the rxget and txput routines since those are “hidden” in a library. The important thing to keep the same is how the IFI stuff is initialized and how you go about getting and putting the packet from the master CPU. Every thing else is fair game.
In short, my main looks like this:
void main (void)
{
#ifdef UNCHANGEABLE_DEFINITION_AREA
IFI_Initialization (); /* DO NOT CHANGE! */
#endif
User_Initialization(); /* You edit this in user_routines.c */
statusflag.NEW_SPI_DATA = 0; /* DO NOT CHANGE! */
while (1)
{
#ifdef _SIMULATOR
statusflag.NEW_SPI_DATA = 1;
#endif
if (statusflag.NEW_SPI_DATA) /* 26.2ms loop area */
{
Getdata(&rxdata);
ProcessPacket(); // User_routines.c
Putdata(&txdata); /* DO NOT DELETE, or you will get no PWM outputs! */
}
Process_Tasks(); // user_routines.c
} /* while (1) */
} /* END of Main */
and my user_code looks like this:
void ProcessPacket(void)
{
int c;
// Put common stuff here
CheckSwitches(); // Mass examine digital input for change
if (autonomous_mode)
{
User_Autonomous_Code();
}
else
{
User_Normal_Code();
}
pwm01 = DoPid(&Left, &LeftEncoder);
pwm02 = DoPid(&Right, &RightEncoder);
//---------- Inputs to Relays--------------------------------------------
relay8_fwd = !rc_dig_in18; /* Power pump only if pressure switch is off. */
relay8_rev = 0;
...
and finally, my “tasking code” which was more complicated, but now is pretty simple
void Process_Tasks(void)
{
static char GyroTimer = 0, PrintTimer = 0;
Poll_Rx1(); // The fast loop runs > 100khz
Poll_Tx1(); // Poll rather than interrupts
Poll_Rx2();
Poll_Tx2();
while (MsTimer) // Incremented by TimerInterrupt.
{
MsTimer--; // Section.
if (++GyroTimer == 10) // 100hz
{
GyroTimer = 0;
Gyro_Task();
} // END GyroTimer
if (++PrintTimer == 100) // 10hz
{
PrintTimer = 0;
TetherTask(STDIO);
} // END Print task
}// END Tasking
}
In short my “packet driver” code does common stuff up front (read sensors) the calls appropriate normal or autonomous code, then at the back end formats up stuff to send out.
Just pay attention to those lines with /* DO NOT CHANGE */ appended to them. Not all, but most are important.
Also, if you are interested in my tasking code, I put a zip called “sensors.zip” out on one of the programming forums (PID or Gyro, one of the two…)
Thanx, Every one!
Unfortunately, I didn’t even compile the code I posted. I would be surprised if thier weren’t syntax errors or whatnot.
Let’s keep discussing about editing core areas for making code faster, more efficent, adding functionality, or just for the heck of it.
A few challenges:
- write a template for a ‘minimum-boot’ program. just initialize, comment “//Put Stuff here!” and de-init
- Write a full program from scratch. Doesn’t have to do anything fancy, you just can’t use anything from default code (except for lib declarations). :yikes:
- Have you done it using ALL
your own code (no libs)? let’s hear about it!
Still cracking, Astronouth7303
If anyone really feels like abuse… would it be possible without messing with IFI stuff to actually write a full control with just ASM?
If so… anyone want to give it a try?
:yikes: Yikes, ouch, assembley language, yikes, ouch, wow. :SinksIn: You really took that to heart!
No, I don’t know any asm’s. But someone’s got to do the first one. May be this will be an off-season thing.
Again, Yikes, ouch, wow.
It is possible…after all MPLAB/C18 has ASM capabilities, and the processer converts the code into asm then binary (i believe) anyways.
I just remembered: some of IFI’s routines are written in ASM (or ASM and C). Check those!
Hrm… editing main.c, sounds like a good idea. Only I can’t. MPLAB won’t let me change it – it isn’t accepting any input at all when I have that file in focus. Is there some sort of default protection to protect the unawares that I am unaware about? It was somewhat distressing when, during testing, I did actually want to put something there. Just another reason why MPLAB was getting me angry … it has several, well “interesting” qualities.
Check that the file isn’t read-only, and doesn’t have other protection. If that doesn’t work, there’s always notepad.
PS to other Main.c readers: In the Programming code Fix FRC thread, a recent post brings up something about PWMs 13, 14, 15, and 16. READ IT!
In MPLAB with any file open go to EDIT -> Properties…
and unclick the “Protect Read Only files” box.
Why did IF protect almost all the source files anyways?
So your overzealous aspiring programming teammates don’t destroy the source code I guess.
Oh, You have other programmers on your team? You got it good!