Toast Backwards Compatibility -- Toast will now work with Non-Toast Code!

In the recent Toast 2.2.0 release, we have added support for loading regular FRC Programs (non-toast projects) into the Toast runtime. This means code that is not written as a Toast module, but is written for an FRC Robot, is still capable of being loaded as a module, alongside any other modules present. This also means that they are capable of being simulated in the Toast Simulator.

Backwards Compatibility is as simple as dragging your FRCUserProgram jar into the toast/modules directory. Toast will detect it as FRC code as opposed to a module and treat it accordingly.

Whenever a new Robotics framework is released for FRC, whether it be on Chief Delphi, Reddit or elsewhere, there is always a question of “how does it compare to other frameworks that already exist”. I was asked this question when I first released Toast, and as more have been released, Toast has been a subject for comparison.

In most frameworks that I’ve seen, WPILib is abstracted behind a wall, often to make it easier to simulate, test or what have you. While there’s plenty of subject matter to talk about on why this is a good or bad idea, I’ll save that for another post. The achilles heel of abstracting it, however, is that the programmer now has to learn an entirely new framework. This is where Toast comes in, and why we’ve chosen not to abstract WPILib, and how it fits in with the new Backwards-Compatibility support.

How it works
When Toast detects an FRC Program jar (not a toast module), it will provide a module wrapper around the RobotBase class. These jars are identified through their Robot-Class manifest attribute, which WPILib usually uses to find your RobotBase class. When found, Toast will create a ‘shallow instance’ of the class and place it inside of a ModuleWrapper. A ‘shallow instance’ is simply an instance of the class where the Constructor is not called. This sounds unsafe (and is), but has to occur for multiple reasons:

  • Inside of the RobotBase class, the NetworkTables framework is started in the Constructor. Usually this is not a problem, but as NetworkTables is already started, we can’t use this code as it will throw an Exception and prevent the class from being loaded.
  • All user setup code is inside of the robotInit method anyway, so a Constructor is redundant.

Variables such as m_ds for the DriverStation are manually set by Toast to avoid errors.

The ModuleWrapper will setup the Module attributes, including name and version. The name is very simple, it’s just the Filename appended with !wrapper. The version is simply set to 0.0.0.

All Module hooks are then added. IterativeRobot and SampleRobot will be changed to have their ticking and transition detection done by the StateTracker as opposed to their internal state detection code.

Although this is a solution, more unorthodox implementations might see issues. Currently this will work for any programs that use IterativeRobot or RobotBase, however SampleRobot may run into some issues simply due to its implementation.

Any implementations overriding the RobotBase constructor will also have issues. Keep in mind, however, that you shouldn’t be using the Constructor anyway, and should use the robotInit method instead.

We can only support what we can simulate. New instances of Motor Controllers will just be new instances, and won’t work with the Registrar, and things that can’t be simulated (such as I2C and SPI) will need to have explicit simulation code set, as there is no way for Toast to do it. This lack of simulation support is mostly due to the implementation (we can’t simulate the I2C bus as a whole, as we don’t know if it’s being used by a Gyro, LCD, or whatever else, as all that behavior is determined by the implementation).

I want to simulate my existing code so bad but I got so lost in the instructions. Where do I put my existing code? I don’t see toast/modules in the src or release. gradlew is only for setting up right? I also need more clarification on how to import dependencies. I imported WPILib into the User Libraries and nothing changed. Could you possibly make a video on how to do this from beginning to end?