Timed vs Command Based

Based on the past few years in FIRST, it has become clear that a teams level in programming can make a big difference when it comes to team success. So…

Teams like 254 have obviously found success using the timed robot as a base, state machines, and their own system that works in tandem. So much so that their architecture has become the norm and is often copied many other high level teams.

On the other hand, Einstein-level teams like 2910 have been using command based programming for years and have also found tremendous success.

That begs the question, as a programmer who has only known command based programming with FRC, sometimes I feel like I am missing out on something when I don’t have a Robot periodic method that is 450 lines long.

TLDR; For the high level teams like 254, 1678, etc. have you ever considered making the switch to command based? If not, what’s the impetus behind that decision?

2 Likes

You’re not. Monolithic code is bad code, and often survives due to inertia and pressure to keep the application working.

Top teams have codebases that have been in continuous development for years; many of the core design decisions in those codebases predate the addition of ergonomic/performant WPILib alternatives.

13 Likes

State machines are effectively replicating command based programming without calling it command based. That’s an oversimplification but it somewhat gets the point across. Command based programming can simplify making more complex robots with less boilerplate code than timed programming and can also make it easier to program autos. It really boils down to what you know and can use best but I would recommend command based since it can simplify writing your code. Like oblarg said, the only (or maybe main if not only) reason those teams use timed based programming is because they have done so for many seasons in the past and have their own libraries written around it to make it easy to use timed programming.

(i just realized how terribly written this was, sorry, i’m like very very tired right now lol)

10 Likes

At a certain point your timed based robot becomes a command based robot, albeit your own custom implementation. I had switched to Command-Based when i realized this earlier this year.

11 Likes

This is exactly what happened to us. Started organizing our files into subsystems, then started creating state machines for each subsystems, then to reduce lines of codes started using lambda notation… Ohhh crap, the thing that I had refused to learn and teach the kids is the very thing we created a horrible copy of.

Thanks wpilib folk for creating a great framework for our team to adopt.

3 Likes

What immediately popped into my mind was you might be missing what a throbbing pain it is to follow and debug late at night before a competition a few thousand lines of spaghetti code.

Command-based can mitigate the confusion (somewhat reduce the spaghetti code) with a good structure to handle for you the states of your commands without regard to the state of the iterative loop.

You still have to pay attention to writing good code but you won’t have as much code to worry about; you can concentrate on your robot logic and not the iterative robot constraints.

Command-based doesn’t preclude using Finite State Machines (FSM) to organize the logic of more complicated mechanisms such as my team’s intake/shuttle/shooter. Develop an FSM for the logic of your mechanism and let the command-base schedule the commands in the order you specify.

My team has tracked similarly to others’ comments here in trying each year for a better organization and finally (I am hopeful) this upcoming season we’ll drop each season’s ad hoc development of command-base and use the WPILib system.

1 Like

I can confirm this is a great pattern if you want to solidify the state diagram of your robot!

This can work particularly well when combined with sensor-based software triggers for automated state transitions.

4 Likes

This has all been super helpful and definitely stifled any desire to switch. This has led me to another question I have about command based code that I can only describe through an example.

Develop an FSM for the logic of your mechanism and let the command-base schedule the commands in the order you specify.

Let’s say you had a turret subsystem, and you wanted multiple ways of controlling. (Ex. Vision tracked, manual, designated setpoints)

Would it be preferable to create multiple commands (such as TurretTrackingTargetCommand, or ManualTurretControlCommand) where each command is scheduled and then unscheduled based on the desired behavior? To add to that, what if you wanted to change between these commands or states with sensor input (i.e. if the robot detects that it has a ball, it goes into vision tracking mode and vice versa), where would you schedule these commands? **

Or

Would it make sense to create a default turret command that acted like a state machine and transitioned through these behaviours based on a sensors input and if/case statements.

** The only way my team has ever scheduled commands is through joystick inputs but as we try to make our robot more automated, we would like to know the best way to schedule commands when not using driver input. My initial guess would be through the robot periodic method, but unless you’re using some sort of latched Boolean, you’ll start scheduling the same command over and over again. Any advice, prior examples, or your teams standard would be super helpful.

2 Likes

I would recommend taking a look at the documentation for the new and improved command-based framework- a lot has changed in the last few years, and the behavior you’re looking for is very achievable.

Keep in mind there’s still some portions of the documentation that we are working on updating – please feel free to make any comments/suggestions

For the life of me I can’t remember where I read this, but I saw a Quote, Meme, or similar several years ago that basically said

Any in-house software that mimics the functionality of an enterprise tool implements at best 25% of the functionality, and usually fairly poorly.

and as someone who, at my last job, had to architect and write a purpose-specific automation suite similar to what Ansible is designed to do (SSH to machines in parallel and run commands), but with some very specific business logic requirements on top, I agree.

2 Likes

Who ARE you, and WHY are you spying on our GitHub??? :sweat_smile:

In general I advise not writing explicit branching logic (i.e. if statements) whenever possible, and instead representing branching logic with composition (either with composed Trigger conditions or composed Command groups). This doesn’t mean “never write an if statement,” but it does mean “try to minimize the number of if statements you have to write to represent the desired state flow.” If you ever find yourself deeply nesting conditionals, you have probably made a mistake.

Make sure you fully understand the Trigger class and how it can be composed to flexibly represent a variety of binding conditions. Make sure you fully understand the Command decorators and how these can be used to build complicated/conditional actions from simple component pieces.

Once you fully grasp both of those, the decision of “where to put the complexity” doesn’t go away entirely (you always have to make decisions about your code!), but the pros and cons of each option will be much easier to judge.

5 Likes

Cracks Knuckles
Ok, here is the saucy truth. While hitting a file with more characters than days you’ve been alive might see like milestone, it’s often actually indicating a mess that breaks many of the rules of code design, including DRY (Do not Repeat Yourself) or SRP (Single Responsibility Principle). Maybe the worst part is that this much code is just hard to understand without spending a lot of time with it.
From Robert C. Martin’s Book, Cleancode p25.:

In general prorammers are pretty smart people. Smart people sometimes like to show off their smarts by demonstrating their mental juggling abilities…One difference between a smart programmer and a professional programmer is that the professional understands that clarity is king. Professionals use their powers for good and write code that others can understand.

I heavily stand behind the idea that if any file takes up more than 2 computer screen heights, you should take a look at your code and ask if it could be better understood if separated into multiple classes. Almost all teams are guilty of putting way too much code into one file, high level included. Don’t use line count as a metric for your coding ability.

10 Likes

You are more advanced then I am as I’m just beginning learning about command-based and am digging deeper into Oblarg’s helpful comments and I must get past old habits and knowledge.

Part of the answer to your question may be in making a state diagram for your example since your question deals as much with your robot logic as it does with how to use command-base. You get a lot of clarity by organizing your thoughts with a state diagram.

partial FSM example

We developed a FSM for the intake/shuttle/shooter and it all starts with a state diagram of what is to happen based on what events trigger an action. I regret that the beautiful state diagram that a student drew is behind the Slack pay wall due to their change of terms for free service. But here is the transition table written from that diagram (ignore the circles and arrows and then the text was simply converted to Java variables and that shows in the image below).

The code would have one if statement like this:

/**
* table lookup to determine new state given the current state and the event
*
* @param currentState
* @param event
* @return
*/
private static State findNextState (State currentState, Event event)
{
// for efficiency could check for no event but that’s another “if” statement to understand and it’s not
// needed for the logic unless not finding a corresponding transition is considered an error
for (Transition transition : Transition.values())
{
if (transition.currentState == currentState && transition.event == event) return transition.nextState;
}

  // no transition for this state and event so maintain current state
  // if that would be considered an error then throw one and catch caller or return say undefined state
  // and figure out how to maintain current state or enter an error state by adding error state as a choice
  return currentState;
}

}

or if it matters, one more if statement to see if the state changed or not because of the event.

public void checkStateChange(Event event)
{
// make the transition to a new currentState if an event triggered it

State newFanState = FanFSM.Transition.findNextState (currentFanState, event); // the next state

// has the state changed by the event?
// There is a choice here depending on the system.
// If the state didn't change by this event, you could still go through the doExit
// and doEnter because of the event, if that's what makes sense for your FSM.
// This code doesn't redo the doExit, doEnter, and doAction but there is a comment below
// to move the doAction if you always want to execute it even if no event or state change.
if (newState != currentState)
{
  // change states
  currentState.doExit(); // exit current state
  currentState = newState; // switch states
  currentState.doEnter(); // initiate new state
  currentState.doAction();
}
// move above doAction to below to always run it
// currentState.doAction(); // always maintain current state or the new state as determined above

}

FSM training Java exercises
Lectures notes compiled and edited from Internet sources available upon request.

With the clarity of thought required for the state diagram (it went through several quick review and comment cycles made easier with the simplicity and brevity of the diagram) and only one if statement in generalized code, the student’s FSM code worked on the robot the first time it compiled and ran!

We did not have time to develop a good idea about an event handler but did something not to sloppy.

I think what I see and Oblarg is saying is the Trigger class is a good structure to manage events.

And you have the right idea, of course, an event is a change between an old value and a new value that happens once at the time of the change. In the iterative robot we do at most one transition per cycle.

Our team did pretty much the same thing - 2910’s swerve template code kind of kickstarted the shift over and we don’t really see any reason to go back to timed.

2 Likes

This topic was automatically closed 365 days after the last reply. New replies are no longer allowed.