So as this year begins to end I’m looking to next year. I am Programming lead for my team. This year we used the WPI Command Based Form given by FIRST. My question is, for next year, is this form the best option? I was not particularly pleased with the constant overhead that it forces. I do however realize the merit in the system, it allows for beginners to learn structure and the basics of programming in java. Next year however we wont have as many beginners and i was wondering what other teams are doing? is there an established, better way? or is command based the best?
It’s not necessarily better but our team has developed a library for the past eight years. It was in C++ first but we converted it to Java last year when we switched to Java. This year, we even merged with our FTC library so the library is compatible with both FTC and FRC. If you want to take a look, you can access it at GitHub (https://github.com/trc492/Frc2016FirstStronghold/tree/master/FirstStronghold/src)
The main file is in frc492/Robot.java
Our framework was based on the same concept as Iterative Robot but it supports Cooperative Multi-tasking (multi-task with one thread) so it is easier to learn. You started with putting code in a method called initRobot where it creates the entire robot configuration (drive base and subsystems). Then at the end of initRobot, you create the RobotModes: Autonomous, TeleOp and Test. Each of them implements the RobotMode interface which includes the methods: startMode, stopMode, runPeriodic and runContinuous. startMode and stopMode are methods that will be called one time before the competition mode starts or stops. For example, before autonomous starts, teleop starts, autonomous stops or teleop stops. Then the methods runPeriodic and runContinuous will be called periodically. The difference between runPeriodic and runContinuous is the frequency it is called. runPeriodic is called when there is new driver station data and runContinuous is called in a loop as fast as it can. So typically, TeleOp code goes into runPeriodic and autonomous goes into runContinuous for better resolution.
Not only does this framework makes it a lot easier to write multi-tasking code without the gotcha’s of multitasking (i.e. resource contention and tasks synchronization), it also cumulates all the knowledge we learned about different mechanisms. For example, how to use PID control to drive a robot base accurately in all different drive modes: arcade drive, tank drive and mecanum drive. Our PID control for the drive base is overall PID control, not individual motor PID control. It means it will combine encoders, gyro, ultrasonic or any sensors to determine what power should be distributed to each of the motors of the drive base so it will drive straight if you wish so. Also, it supports using PID control to control an elevator/arm so it will hold its position fighting gravity? It also provides supports for event driven actions such as calling you back if a joystick button is pressed or if a limit switch is activated and much more.
@OP - my personal advice is not to bother with this for two reasons:
- You’re new and aren’t an expert with FRC’s ins and outs. Debugging will be very hard and CD won’t be able to help you. The only person that will understand why something is breaking is the maintainer of that software.
- The project could be discontinued at any time and next year you’ll be forced back to the position you are in now.
As someone who has used iterative and command based for multiple (independent) seasons, I feel that command based is more intuitive and powerful than iterative. I view iterative as one giant while(true) loop, while command based has the #basedscheduler and allows subsystems to run in parallel (and be delayed without locking other robot functionality). Also, command based builds off of object-oriented concepts, something new programmers should be very familiar with if they’ve taken AP Computer Science.
That being said, command based has some flaws, but I personally believe that it has less flaws than iterative. I can go more in-depth into command based’s weaknesses if you’d like.
I’m taking a page out of #254’s book to reprogram our robot in the offseason. They use a mix between iterative and command based, which looks really organized (at least compared to ours). ::rtm::
We have used the Command Based structure since it’s inception and have always been very happy with it.
I’ve always used iterative, and have no issues with it. Some people say command based is more intuitive, but I’ve always thought the opposite. I think command based lends itself to automation very well, so I’ll definitely be taking a look into it during the summer/offseason. Ultimately, it’s easy to try both and figure out what works best for you, just pick the one that you like the best and run with it.
I wouldn’t say intuitive. I’ve always told people it makes it harder to do very simple things but easier to do more complex things.
The design of our library is supposed to be as easy to use as Iterative robot but also supports complex scenarios you can find in command-based code but simpler to understand.
Sorry to hop on a bit late, it took me a little while to prepare what I was going to show you. If you want to look at an example of a custom coded but non-library structure, take a look here:
It is built off of the iterative model but it has a structure similar to command-based. It does require a bit more knowledge of Java than entry-level but it does show how a custom structure can be created manually to fit your needs. I’ve also documented it as best I can. Our 2016 code (we haven’t pushed our CMP code) is also on GitHub, but it is much messier and has significantly less comments although it does show how our structure can function with autonomous modes.
Your code implemented a framework. It is a light weight framework but it is still essentially a library although it is structured not very library friendly (i.e. all reusable code scattered in various folders instead of concentrating in one library folder).
Wanted to post here to avoid reposting.
I’m currently facing this same question.
It seems like its a tradeoff, from my point of view. Iterative seems to be good at simple things but bad at complex operations. Command based seems to be good at complex things (like autonomous routines) but bad at simple things (lots of redundant-seeming commands, etc etc).
We stripped down our robot from last year, which is just a 4 CIM mecanum drive with a gyro. No encoders or anything, super barebones. We were using iterative last year, because no one bothered to figure out command based. It worked reasonably well for us, but I was wondering what it would be like had we used command based. I rewrote the code we had used last year in command based, and it just seems like there is wayyy too much wrapping and nearly-empty classes.
The obvious answer to this problem is going custom, but where to start? I would love to have a nice clean framework which gives a ton of control without any BS. We’re planning on using the SRXs’ motion profiling features, as well as things like velocity drive, so it would be really handy to use a setup which accommodates more complex features (like concurrency/routines) better than iterative.
I’ve looked at 254’s custom code, and honestly reverse-engineering their repo and trying to implement it seems like it would be a PITA. I feel like it would be easier to try and implement my own.
The command-based framework really does not have that much overhead, and the point of the overhead is not to make it easier for beginners so much as to make it possible to build nontrivial code in the first place. In fact, if anything, the stock-standard command-based framework doesn’t have enough structure; we’ve had to build a fairly significant framework on top of it to do what we want.
The “harder to do simple things, easier to do complex things” description is one that applies to pretty much any framework. Frameworks have overhead. If your robot’s functionality is simple enough that you could easily roll your own state machine in robot.java, then it is unsurprising that the framework seems superfluous. However, “easy,” unstructured solutions do not scale; you can only build on them to a point before they become big balls of mud. If you don’t see the need for the command-based framework or something similar to it, it is likely only because your code is not yet substantial enough to benefit from it.
Recently I developed a programming framework called “KT-Iterative” which utilizes the best of both worlds. The structure uses standard iterative for Tele-Op events for simplicity and organization, and uses a modified form of Commands called Tasks, along with pre-made auto classes for Autonomous, along with having the trajectory calculation system “PathFinder” built in. This structure removes the organizational element of FRC programming and allows for rapid and clean development of FRC code.
You can check it out here:
KT-Iterative Github Link
Wow, this looks awesome. You should write some documentation for it
A couple thoughts from a guy even older than this thread.
Custom
First regarding a custom framework, this is a common refrain in software development. No piece of software is perfect, and it is easy to find fault in someone else’s design, see where you would do things different and then run off and develop your own solution. If an existing framework has fundamental issues than this can be the only choice, but frequently it turns out to be more of a case of not invented here.
Other times a new framework is developed because the other choices did not offer a desired feature or were not well understood. If a desired feature is missing implementing inside of the command based framework is generally going to be easier than developing a new framework that also includes that feature/capability.
Writing a custom framework is fun, I wrote a C++ string class (before the standard library had std::string, yes I am old), I have written my own libraries and frameworks for handling many different base cases, and it is frequently the type of code I enjoy writing the most. When possible I still try and use standard options and build on top of them or contribute to them (WPILib is a little hard to jump into, but all of the source it in github).
Iterative
Using iterative is fine for simple teleop control and trivial autonomous control, but beyond that you are going to either get lost in complexity or begin writing your own framework.
Command
Command based robot is not perfect, it requires a far amount of boilerplate code, but robot builder is an excellent tool, that helps teams structure their code and saves lots of typing. You can choose to use it once and then implement changes internally, but with a bit of discipline it can be used throughout your development process as new subsystems are created, and your auton becomes more complex.
Note that 2018 also introduces the TimedRobot base class, which is like IterativeRobot but loops are triggered based on timers rather than the arrival of DS packets.
FWIW 254 code uses a mix of TimedRobot (control loops) and IterativeRobot (processing DS packets) concepts, and our autonomous modes look a lot like CommandBasedRobot (wrapping subroutines in blocking calls that can be composed into a sequence). There are several reasons for this:
-
History. Back in the day, IterativeRobot was basically all there was.
-
Familiarity. Partially because of (1), many of the 254 mentors have used a similar architecture for a long time.
-
Control loop requirements. Control loops often need to be executed in a low-jitter timed loop, and in a deterministic order (we often have cascaded control loops, where the output of loop X is the input to loop Y). This requires hardware timer-driven periodic execution in a separate thread from other tasks.
-
Ease of autonomous mode scripting. Most autonomous programs naturally decompose themselves into a sequence of subroutines.
That said…we do run into subtle bugs that are a product of our custom/hybrid architecture from time to time. As with anything else in FRC, I’d recommend trying to use one of the well-documented, well-supported “COTS” options before rolling your own, and if you do something custom then start with the simplest option possible and build from there. Don’t just copy something because some other well-known team does it that way.
Exactly this, if you don’t have a good reason to not use the COTs options you probably shouldn’t be rolling your own. You’ll end up with edge cases that you most likely didn’t think of and it could cost you a match.
As an aside, there is nothing in the command based framework that prevents you from spinning up a thread for tighter timing. We have created subsystems that run their own low jitter threads and commands that do the same.
But Jared hit the biggest good reason to not used command based – you have existing code/knowledge of a different system that already works for you – certainly stick with that.
Strongly disagree. Robot builder saves a very mild amount of boilerplate at the cost of structuring your code in a way that is absolutely terrible (all robot components are declared global). Do not use it.
Worth noting that even in the command-based framework, WPILib executes control loops in separate threads.
We do code reviews and pretty much require access of components through interface methods in subsystems from all other command/subsystems. There is only one instance of X (a given physical component on the robot), having a static instance of that object is not a problem. I would prefer that the instances were inside the subsystems, and that robot builder by default made those static instances private (or protected), but I also understand that there might be more order of initialization issues with that approach. We have more than 20 kids in our programming group dealing with each of them making slightly different initialization routines and debugging them versus having it done consistently is a win.
I view this in the same way as using Command based in general, it is not the way I would have done it, but it works, is well tested, it is not worth reinventing. I do wish it was easier to customize the code generation from robot builder, so issues like this could be addressed.