Hello, I realized that there is a new command-based format for programming our robots, with RobotContainer replacing the OI file and Constants replacing RobotMap and as I looked through the documentation on wpi docs, I am confused to how to program the RobotContainer so when our drivers move the joystick, it will activate our drive command. I will list my github below with our old command-based format as I want to know how I can change the code we have into the new command-based format, as I heard the old command-based format may be subject to removal in future updates with FRC.
The Example Projects have you set the Default Command for a Subsystem in the RobotContainer constructor.
public RobotContainer() {
configureButtonBindings();
subsystem.setDefaultCommand(defaultCommand);
}
I’m a little confused by the intent of the new framework as to where OI code should go. I’ll admit I haven’t read all of the new documentation completely, but I haven’t seen any mention of operator interface functionality, other than binding commands to triggers, which is relatively simplistic.
In our case, we tend to have commands which iteratively access the state of controllers (Xbox or whatever), using OI methods which aren’t always trivial. As a simple example, we may want to implement a method to return a deadbanded joystick value; although we have more complex functionality as well. Or, we just want to abstract the type of controller from the commands using the controller. This functionality is distinctly part of the operator interface and not the robot or its commands, so RobotContainer seems like the wrong place for it, no?
Does it make sense to continue to implement an OI class for such functions? I assume the command-based documentation doesn’t mention this because it’s out of scope. In this sense, I don’t see RobotContainer being a “replacement” for OI, although it may contain some functionality that used to live in OI.
Though I can’t speak to all your exact use-cases. Generally, whenever I wanted more complex functionality from my inputs, I would write my own utility classes, extending Trigger/Button or GenericHID/Joystick/XBoxController as appropriate, and implementing the functionality there so it would look relatively uniform in the OI.
For Commands that require more information, generally “Dependency Injection” is the modern way to go, passing in some object that will give the Command the info it needs instead of the Command going and looking for that info elsewhere in the code.
So as an example, create a DeadbandAxis
Class that takes in a GenericHID controller, int Axis value, as well as optional Deadband range values, and use that in RobotContainer, passing it into the Command that needs it alongside the Subsystem. I can think of at least 2-3 other ways to implement this as well that could make more/less sense in various situations, but also, as long as you release the code, you can re-use these utility classes from year-to-year, at least if the current rules about code-reuse continue to exist.
So if I understand, the gist of it is that it’s better to create (or extend) a class tailored to the resource rather than lumping all OI-related stuff into a single class. It’s cleaner, more appropriate for dependency injection, etc. Makes sense.
Yeah. That is definitely the gist. Sorry if my rushed response wasn’t as clear as I meant it to be.
Yes I have and I am still confused, for example, in my code I made it so the trigger buttons on the Xboxcontrollers to return a double to determine the value for arcadeDrive so the robot can move once it receives these values from the code; however, when I looked through the documentation and the example projects, based on what I seen there wasn’t a project using these trigger buttons on the controller for me to base my code off of.
The way it’s done in the examples is to wrap whatever input you’re using to control your drive in a lambda to pass it to the drive command. For example:
// Set the default drive command to split-stick arcade drive
m_robotDrive.setDefaultCommand(
// A split-stick arcade command, with forward/backward controlled by the left
// hand, and turning controlled by the right.
new DefaultDrive(
m_robotDrive,
() -> m_driverController.getY(GenericHID.Hand.kLeft),
() -> m_driverController.getX(GenericHID.Hand.kRight)));
You can easily change this to use whatever source of driver input you want.
Ok I tried to make it the way the example code was organized in RobotContainer, but I am getting an error and cannot run the code on my robot.
My Code:https://github.com/NatashaSetiadi/New-Command-Based-2020
My Error:
You forgot to instantiate your subsystems, so they’re still null when you’re passing them to your commands.
This is something that our new students struggle with a lot. You need to have a conceptual understanding of what you are doing so the program flow makes sense. Dependency injection is definitely (in my opinion) the proper way to design these systems, where it’s on the developer (or good error checking code) to make sure that all the constraints are met first.
In this case, your RobotContainer flow needs to be something like:
- Instantiate all individual Subsystems
- Instantiate all components required to interact with the subsytem (for example, the controllers required to actuate the subsystems, or camera pipelines, or any other number of things specific to your robot)
- Define subsystem default commands, passing any needed dependencies to the commands
- Map button bindings for non-default commands
Following a flow that is something close to that will ensure that all the requirements are met without crashing.
I would also recommend choosing one method or another. Either declare your member variables and instantiate all of them in the constructor, or outside the constructor. Right now you are doing both. I try to teach my students that constructors are designed to initialize the object, to include instantiating all the member variables.
Ahh, you are correct that is my bad, thank you so much for helping me!
No problem. Happy coding!
where would i instantiate it?
Also, what would the point of having a separate commands file be if we just create it inside of the robot container and go through the subsystem?
This topic was automatically closed 365 days after the last reply. New replies are no longer allowed.