View Single Post
  #8   Spotlight this post!  
Unread 12-13-2016, 07:13 PM
ahartnet's Avatar
ahartnet ahartnet is offline
Registered User
AKA: Andrew Hartnett
FRC #5414 (Pearadox)
Team Role: Mentor
 
Join Date: Jan 2011
Rookie Year: 2005
Location: Houston, Texas
Posts: 194
ahartnet has a brilliant futureahartnet has a brilliant futureahartnet has a brilliant futureahartnet has a brilliant futureahartnet has a brilliant futureahartnet has a brilliant futureahartnet has a brilliant futureahartnet has a brilliant futureahartnet has a brilliant futureahartnet has a brilliant futureahartnet has a brilliant future
Re: Need help understanding command-based Robots

After being confused at first about command-based programming, I am now a big fan of it. It allows for some pretty complex movements with organized and reusable code. The one definite downside is that it can actually make the code seem more complex than it actually is to someone who hasn't been working on it because of all the extra file structure and such. There's some other downsides to it if you want to really squeeze every bit of performance out of the roboRIO possible - but 5414 isn't at that point yet. euhlmann covered it and screensteps does a pretty good job in my opinion, but I'll just kind of repeat and add a little bit:

I like to start with the RobotMap - adding in static variable names for whatever motors or buttons you plan on having. For instance you might have:

Code:
public class RobotMap {
	public static int CollectorRetract = 12;
	public static int CollectorExtend = 8;	

}
and then in OI, making the connection from your interface to your new functions you'll be adding:

Code:
public class OI {

	private Joystick stick = new Joystick(0);		//Joystick in Driver Station Spot 0
	private Joystick stick2 = new Joystick(1);		//Joystick in Driver Station Spot 1
	
	public OI()
	{
		//Stick 2 Controls
		JoystickButton CollectorInStick2 = new JoystickButton(stick2, RobotMap.CollectorRetract);
		JoystickButton CollectorOutStick2 = new JoystickButton(stick2, RobotMap.CollectorExtend);

		CollectorInStick2.whileHeld(new CollectorInCommand());			//Collector Retract
		CollectorOutStick2.whileHeld(new CollectorOutCommand());			//Collector Extend
		CollectorInStick2.whenReleased(new CollectorStopCommand());		//Collector Retract Stop
		CollectorOutStick2.whenReleased(new CollectorStopCommand());		//Collector Extend Stop
       }
}
then, if it's not defined already, you'll have to define your subsystem. Your subsystem should include any motor controllers or sensors for that group of thing. For a drivetrain, that could be 4-6 CIMs, 2 encoders, a gyro, servos, shifting pneumatics, etc (but start small then add the rest in). For this simple example I'm walking through, it's just one motor. In this, we have three different things we do with our collector: extent, retract, and stop. For something (potentially) more complicated like a drivetrain, you might have functions to get encoder or gyro data, extend or retract cylinders to change gears, drive in arcade mode/tank mode, drive in a slow/demo mode that sets power to 75%, etc.

Code:
public class Collector extends Subsystem {
	private SpeedController deploy;
	// Put methods for controlling this subsystem
    // here. Call these from Commands.

    public void initDefaultCommand() {
        // Set the default command for a subsystem here.
        //setDefaultCommand(new MySpecialCommand());
    }
    public Collector() {
    	super();
    	deploy = new Spark(4);
    }
    public void CollectorIn(){
    	deploy.set(.7);
    }
    public void CollectorOut(){
    	deploy.set(-1);
    }
    public void CollectorStop(){
    	deploy.set(0);
    }
}
Then you have your command files that then use the functions within the subsystems. From what we set up in the OI.java file, we'd also want to create CollectorOutCommand.java and CollectorStopCommand.java. You call the functions that exist within your subsystem from your commands.
Code:
public class CollectorIn extends Command {

    public CollectorInCommand() {
    	requires(Robot.collector);
    }

    // Called just before this Command runs the first time
    protected void initialize() {
    	
    }

    // Called repeatedly when this Command is scheduled to run
    protected void execute() {
    	Robot.collector.CollectorIn();
    }

    // Make this return true when this Command no longer needs to run execute()
    protected boolean isFinished() {
    	return false; //We set this up in the OI so that it would call a function to stop it when the button was released
    }

    // Called once after isFinished returns true
    protected void end() {
    	Robot.collector.CollectorStop();
    }

    // Called when another command which requires one or more of the same
    // subsystems is scheduled to run
    protected void interrupted() {
    	end();
    }
}
You can also make the command groups as discussed on WPI lib. It's simple enough to understand that I won't include an example here. The great thing about using command based programming is that if you make a change to say, how fast you want the collector to extend - it takes affect anywhere you use that command. With sample robot - if you have the collector extend in autonomous and from a button push in tele-op, you have to be careful to make sure and go change it in both places. You can also include variable in it, so you can have a command that say turns your robot X degrees, with a different parameter sent that reuses the rest of the code the same.

Hope this helped some.
__________________
Team 451 The Cat Attack, Student Alumni (2005)
Team 1646 Precision Guessworks, Mentor (2006-2008)
Team 2936 Gatorzillas, Mentor (2011-2014)
Team 5414 Pearadox, Mentor (2015-Present)

Last edited by ahartnet : 12-13-2016 at 07:24 PM.
Reply With Quote