Your experiences with Command Based Programming?

I am the Programming Mentor for Tech Tiger Robotics (1251) . The past two years (my entire tenure), we have used the (Java) “Command Based” programming pattern provided by wpilib. In general, it has served us well and owe much of our software success to its existence.

I’d like to hear from some other teams (students and/or mentors) that have used the command based pattern and get their thoughts on it. Specifically…

  • Background

    • Do you currently use command-based or have you moved away from it?
    • Do you have experience doing it “another way” or have you always used command-based?
    • Java or C++?
  • Concepts

    • What aspects of command-based did you find most intuitive?
    • What parts were hardest to wrap your head around?
  • Build Season

    • What parts of command-based has really worked well for you?
    • What challenges did you run into?
    • What aspects did you find yourself “working around”?
    • What were common problems/errors/mistakes that repeatedly surfaced?
  • At events

    • How did command-based make it easier for you to code at-event “tweaks”?
    • What specific challenges surfaced in making these adjustments?

The point of all this

I’m looking for opportunities for development patterns that can solve common challenges in the command-based space. Besides the info in this thread, any tangible results of this discussion will be shared openly and freely by team 1251. These might emerge as tutorials, utilities, wrappers, or simply feedback to the wpilib maintainers.

4 Likes

We moved from SimpleRobot (the one where you code the loops yourself) in C++ to Command Based this year (Iterative Robot) and it has been a huge uplift in the amount of abstraction we are able to do.

We haven’t yet been able to have a wrap up meeting and discuss our likes/dislikes of the change and goals for next year, but I still say everyone should use it.

We use Kotlin, and a weird amalgam of command-based programming and some custom methodologies enabled by Kotlin’s asynchronous programming features. Command based is a pretty good system, and very effective when implemented idiomatically. We like to de-emphasize commands on the subsystem side of things, though, and prefer to run some custom state machines. Commands are great for larger action sequences like autonomous, though. I don’t think we ever run into many challenges. Sometimes my lambda abuse can throw a wrench in the works…

Probably the only real challenge I personally have had was understanding the default command system, but it made sense when it was explained to me.

Code maintainability is largely a feature of the codebase, not the framework. Commands can make it easier to encapsulate functionality, bu it’s all about how everything’s actually implemented. I’ve seen some very well written command-less code and some garbage spaghetti unmaintainable command-based code. More idiomatic examples and guides could help with getting people to stick to idiomatic/best practices - I really like 2471’s 2017 code for that.

1 Like

@Tyler_S Thanks for the feedback :slight_smile: … and I agree… I personally can’t (currently) see a world where our team moves away from command-based or recommend against it.

I’d be really interested in the what comes out of this section of the post-season wrap-up, especially since your team just transitioned to Command Based; that’s a perspective I just don’t have.

We’ve been using Command-based in Java since Command-based has been a thing. Personally, I find it extremely easy to manage understanding, which makes it easier to teach to newbies and to manage in the pits. The concept of:

  1. Describe a group of parts as an independent system
  2. Write function-like commands to manage them, and
  3. Call these commands

is one that I just find extremely obvious. It doesn’t necessarily make pit code any easier/harder, though I will admit that there have been many occasions where I cursed the name of WPILib for its implementation of OI. Additionally, I have been through many a day when I just wanted to scream something like “if this were a functional scripting language, I could have [insert seemingly-simple design] done in seconds! Instead I’m forced to write all this extra nonsense just for one little thing…”

Code maintainability is largely a feature of the codebase, not the framework.
:100: agree with this… but I do think some frameworks lend themselves better (or worse) to code organization through their documentation and/or abstractions.

For example, the wpilib examples focus heavily on creating instances via public static properties, effectively making them “globals” with all of the up-front “simplicity” and downstream troubles that have been discussed exhaustively throughout the programming world. (Note, I doubt this practice is isolated to command-based examples but I haven’t spent a lot of time looking at the other code samples offered by wpilib.)

1 Like

“if this were a functional scripting language, I could have [insert seemingly-simple design] done in seconds! Instead I’m forced to write all this extra nonsense just for one little thing…”

I spend a lot of my professional time in nodeJS… so I feel you. What are your thoughts on encouraging more dependency injection rather than public static x? (e.g. through tutorials/documentation)

What are your thoughts on encouraging more dependency injection

I know next to nothing about that topic as a whole, but personally I don’t have much of an issue with public static whatever (perhaps because I’m numb to it after years of programming in this dismal language). At the very least, teams that want to experiment with crazier sorts of things have control over static vs. dynamic, public vs. private, etc. If I recall correctly, 100% of the variables defined in our command and subsystem classes are private, but I see value in public for some tasks

This year was our first year programming in Java. Since the cRIO we had programmed in LabVIEW, but due to issues with pushing code to the bot at champs last year we decided that it was time to make the switch.

This year we won Innovation in Control at both of our regional events. I’d put that as a testament to command-based programming.

Nearly all functions on our robot are automated. With the press of a button we can run commands or sequences of commands with ease. Command Groups make things very easy - with several smaller commands we were able piece together a sequence that allowed us to climb to level 3 with just the press of ONE button.

The way commands are structured (init, execute, isFinished, end) make it easy to do safety checks and skip commands if certain properties aren’t met. Also, having a timeout function for each command makes it easy to ensure no command is running for an extended period of time - for instance, our intake command ends when either a cargo has broken the infrared sensor or after a 4 second timeout. This way, if the infrared sensor fails, the intake command will automatically stop intaking after 4 seconds to prevent damage to our intake, especially when a cargo is already in the intake.

It took a little while to understand how it works, but once you get the concept of command-based, it makes programming an FRC robot extremely easy.

Remember, you can get the same functionality without command-based programming. But command-based just makes things a lot easier.

1 Like

A bit tangential to original post, but in case you (or others) don’t recognize it by name… With static access, you would see something like this in your command(s):

public class TeleopDrive extends Command {
  public TeleopDrive() {
    // access static public property of Robot for subsystem 
    requires(Robot.driveBase);
  }
  // ...
  public void execute() {
    Robot.driveBase.drive();
  }

With dependency injection:

public class TeleopDrive extends Command {
  
  private DriveBase driveBase;

  public TeleopDrive(DriveBase driveBase) {
   // Subsystem is "injected" into constructor as arg and it is stored
   // in a local property.
   this.driveBase = driveBase; 
   requires(driveBase);
  }
  // ...
  public void execute() {
    driveBase.drive();
  }
}

edit: fixed constructor names, class declaration

1 Like

Congratulations on the awards! :confetti_ball: :trophy:

1 Like

Oh, gotcha. Not gonna lie, I see the static access solution as being a little bit better.

  1. Subsystems can be statically imported (e.g. import static frc.robot.Robot.drivebase)
  2. Making public static fields in Robot makes clear that they are unique pieces of the robot itself, without being strictly tied to the Robot class (this is more a mindset than an explanation of “public” and “static”)
  3. Only a single object of a subsystem needs to be dealt with, which makes data manipulation across commands easier for teams that choose to do so. It also reinforces the “singleton piece of the whole” ideology

So we’ve been using Command Based since 2017, it works really well for us. We stole a few ideas from oblarg though, using dependency injection for any commands that can use generic subsystems. All of our subsystems extend some sort of generic subsystem. This year, both our climber and our scoring elevator extend the generic Elevator class in our year-to-year library

Forgive my lack of knowledge, but what issues arise from static access down the line?

EDIT: I like dependency injection, and will be trying to convince my team to do so next year, but also want reasons for why it is better.

1 Like

I’ve seen teams get stuck with an NPE because they tried to access a static variable before it was initialised. Fairly common thing to happen in Java.

I’m going to start a new thread about DI vs. static access. Don’t want to go too far off the rails in this thread, but it seems like it is worth talking about. Will reply again with link when it is posted. :slight_smile:

/cc @auscompgeek

2 Likes

A quick background, I am the programming mentor for my team but I am not a software engineer. I started with iterative C++ code on CRios, currently we use JAVA as that is what the school teaches. All told I have 3 years of iterative C++ code, 3 years of command based JAVA and 1 year of of iterative JAVA FRC coding.

My team actually moved away from it this year. We did it for 2 reasons, first I wanted the students to create their own framework and understand what is actually going on at a lower level. Secondly, we had issues with students not understanding multi-tasking in the command based structure, causing the code to get stuck in PID loops.

Since the switch we have found it faster to debug/tweak our code as the students have a deeper knowledge of the framework and what they coded. Also the code has been clean but that might be the current set of coders I have.

Really interesting counter-point. Was the challenge that students where creating their own internal loops instead of relying on the (hidden-from-view) main control loop provided by the framework?

Dedicated thread for DI vs static access:

I haven’t yet used command based patterns in my 10 years around FRC, but I’m going to spend some part of my summer learning how to use it. In my exposure to it from other teams that end up having trouble with it…it seems to make you do a lot more work to do simple things…but again…I haven’t worked everything out yet.

Our team has been using TimedRobot, and before we used SimpleRobot with no issues whatsoever. It will be interesting to see how my exposure to CommandBased patterns will change how we do things…if at all after this summer.

Here’s our code base if you are interested. Not exactly the cleanest thing ever at the moment…