Shooter Subsystem

Now that we have a way to spin up the shooter wheels, we need a way to raise the ball up so that it engages with the wheels and actually shoots.  The robot has a plastic cup which holds the ball below the spinning wheels.  This cup is attached to a servo motor which can raise and lower it.

20160719_130842

We will now create a new subsystem which will control that servo, and we will call it the ShooterSubsystem.  In Eclipse, create a new class in the subsystem folder named ShooterSubsystem.  Then copy the contents of ExampleSubsystem.java into the newly created ShooterSubsystem.java file.  Then, as before, replace all occurrences of ExampleSubsystem with ShooterSubsystem.  At this point your ShooterSubsystem.java file should look like:

package subsystem;

import robotCore.Logger;
import wpilib.Subsystem;

/**
 *
 */
public class ShooterSubsystem extends Subsystem 
{
    public void initDefaultCommand() 
    {
    	Logger.Log("ShooterSubsystem", 2, "initDefaultCommand()");
    }
    
    public void Init()
    {
    	Logger.Log("ShooterSubsystem", 2, "Init()");
    }
    
}

The first thing we need to do is to declare a variable which will allow us to control the servo motor that moves the ball.  Add the following line to the beginning of your ShooterSubsystem class:

	private ServoMotor m_shooter	= null;

ServoMotor is the class that we need to use to handle the type of servo we are using on the robot (remember that you will probably need to import the ServoMotor class).  We now need to initialize this variable.  Looking at the documentation for the ServoMotor class, we see that the constructor takes one integer parameter which specifies the pin number to which the servo is connected.  For this robot, the shooter servo is connected to pin 5, however, like before, rather than using that number directly in the code, we are going to define a constant at the beginning of the class and use that.  Insert the following line at the beginning of the ShooterSubsystem class:

	private final static int	k_shooterPin	= 5;

We can then initialize our m_shooter in the init() function as follows.

		m_shooter	= new ServoMotor(k_shooterPin);

We need to add functions that will allow us to position the shooter in either the Release position, where the ball is not in contact with the shooter wheels, or the Shoot position where the ball is in contact with the shooter position.

Looking at the documentation for the ServoMotor class, we see that the set(,..) function is used to position the servo and it takes a floating point number between -1.0 and +1.0. which will move the servo from it’s minimum position to it’s maximum position.  We have determined that the position represented by +1.0 is the position where the ball is not in contact with the wheels, and the position represented by -1.0 is the position where the ball is in contact.

As we have done previously, rather than using those values directly in our code, we are going to create some constants which define their values and then used those constants in our code. At the top of the ShooterSubsystem class add the following two lines:

	private final static double k_releasePos	= 1.0;
	private final static double k_shootPos		= -1.0;

We can then add the two following functions to control the shooter position as follows:

	public void ReleaseShooter()
	{
		m_shooter.set(k_releasePos);
	}
	
	public void Shoot()
	{
		m_shooter.set(k_shootPos);
	}

At this point, your ShooterSubsystem.java file should look like this:

package subsystem;

import robotCore.Logger;
import robotCore.ServoMotor;
import wpilib.Subsystem;

/**
 *
 */
public class ShooterSubsystem extends Subsystem 
{
	private ServoMotor m_shooter					= null;
	private final static int		k_shooterPin	= 5;
	private final static double k_releasePos		= 1.0;
	private final static double k_shootPos		= -1.0;
	
    public void initDefaultCommand() 
    {
    	Logger.Log("ShooterSubsystem", 2, "initDefaultCommand()");
    }
    
    public void Init()
    {
    	Logger.Log("ShooterSubsystem", 2, "Init()");
		
    	m_shooter	= new ServoMotor(k_shooterPin);
    }
    
	public void ReleaseShooter()
	{
		m_shooter.set(k_releasePos);
	}
	
	public void Shoot()
	{
		m_shooter.set(k_shootPos);
	}
}

Now that we have the ShooterSubsystem defined, we need to add it to our Robot class.  Add the following line to the top of the Robot class definition (and import the ShooterSubsystem class).

	public static final ShooterSubsystem m_shooterSubsystem = new ShooterSubsystem();

Then initialize this subsystem by adding the following line to the robotInit() function:

		m_shooterSubsystem.Init();

At this point, your Robot.java file should look like:

package robot;

import robotCore.IterativeRobot;
import robotCore.Logger;
import subsystem.DriveSubsystem;
import subsystem.ExampleSubsystem;
import subsystem.ShooterSubsystem;
import subsystem.SpinnerSubsystem;
import wpilib.Scheduler;

public class Robot extends IterativeRobot 
{
	public static final ShooterSubsystem m_shooterSubsystem = new ShooterSubsystem();
	public static final SpinnerSubsystem m_spinnerSubsystem = new SpinnerSubsystem();
	public static final DriveSubsystem m_driveSubsystem = new DriveSubsystem();
	public static final ExampleSubsystem m_exampleSubsystem = new ExampleSubsystem();
	public static OI m_OI = null;
	
	Robot()
	{
		Logger.Log("Robot", 2, "Robot()");
	}
	
	/**
	 * Called once to initialize the robot
	 */
	@Override
    public void robotInit() 
    {
		Logger.Log("Robot", 2, "robotInit()");
		
		m_driveSubsystem.Init();
		m_exampleSubsystem.Init();
		m_spinnerSubsystem.Init();
		m_shooterSubsystem.Init();
		m_OI = new OI();
    }
    
	/*
	 * Called at the start of autonomous mode
	 */
	@Override
    public void autonomousInit() 
    {
		Logger.ResetElapsedTime();
		Logger.Log("Robot", 2, "autonomousInit()");
    }

    /**
     * Called periodically during autonomous
     */
	@Override
    public void autonomousPeriodic() 
    {
		Logger.Log("Robot",  -1, "autonomousPeriodic()");
		
		Scheduler.getInstance().run();
		
		Sleep(10);
    }

	/**
	 * Called at the start of teleop mode
	 */
	@Override
	public void teleopInit()
	{
		Logger.ResetElapsedTime();
		Logger.Log("Robot", 2, "teleopInit()");
	}
	
	/**
     * Called periodically during operator control
     */
	@Override
    public void teleopPeriodic()
	{
		Logger.Log("Robot", -1, "teleopPeriodic()");
		
		Scheduler.getInstance().run();
		
		Sleep(10);
    }
	
	/**
	 * Called a the start of test mode
	 */
	@Override
	public void testInit()
	{
		Logger.ResetElapsedTime();
		Logger.Log("Robot", 2, "testInit()");
	}
    
    /**
     * Called periodically during test mode
     */
	@Override
    public void testPeriodic() 
	{
		Logger.Log("Robot", 0, "testPeriodic()");
		
		Sleep(10);
    }
 	
	/**
	 * Main program entry point
	 * 
	 */
    public static void main(String args[]) 
    {
    	Robot Robot = new Robot();
    	
    	Robot.Start(args);
    }

}

// END SNIPPET: serial-snippet

We are going to want to create a command that will activate the shooter when we press the trigger.  However before we do that we need to create a ShootReleaseCommand that we can set as the default command for the ShooterSubsystem.  We want to do this to ensure that the shooter is in the release position, whenever it is not being used to shoot.  Create a new class ShootReleaseCommand under the commands folder.  Copy the contents of ExampleCommand.java into this new file and replace all occurrences of ExampleCommand with ShootReleaseCommand.  Your ShootReleaseCommand.java file should now look like:

package commands;

import robotCore.Logger;
import wpilib.Command;

/**
 *
 */
public class ShootReleaseCommand extends Command 
{
    public ShootReleaseCommand() 
    {
    	Logger.Log("ShootReleaseCommand", 3, "ShootReleaseCommand()");
    	
        // Use requires() here to declare subsystem dependencies
//        requires(Robot.m_exampleSubsystem);
    }

    // Called just before this Command runs the first time
    protected void initialize() 
    {
    	Logger.Log("ShootReleaseCommand", 2, "initialize()");
    }

    // Called repeatedly when this Command is scheduled to run
    protected void execute() 
    {
    	Logger.Log("ShootReleaseCommand", -1, "execute()");
    }

    // Make this return true when this Command no longer needs to run execute()
    protected boolean isFinished() 
    {
    	Logger.Log("ShootReleaseCommand", -1, "isFinished()");
        
    	return (false);
    }

    // Called once after isFinished returns true
    protected void end() 
    {
    	Logger.Log("ShootReleaseCommand", 2, "end()");
    }

    // Called when another command which requires one or more of the same
    // subsystems is scheduled to run
    protected void interrupted() 
    {
    	Logger.Log("ShootReleaseCommand", 2, "interrupted()");
    }
}

Since this command will use the ShooterSubsystem, we need replace the requires(…) line in the constructor with:

        requires(Robot.m_shooterSubsystem);

When this command is executed, we want to release the shooter.  We do this by adding the following line to the execute() function:

    	Robot.m_shooterSubsystem.ReleaseShooter();

At this point your ShooterReleaseCommand.java file should look like:

package commands;

import robot.Robot;
import robotCore.Logger;
import wpilib.Command;

/**
 *
 */
public class ShootReleaseCommand extends Command 
{
    public ShootReleaseCommand() 
    {
    	Logger.Log("ShootReleaseCommand", 3, "ShootReleaseCommand()");
    	
        // Use requires() here to declare subsystem dependencies
        requires(Robot.m_shooterSubsystem);
    }

    // Called just before this Command runs the first time
    protected void initialize() 
    {
    	Logger.Log("ShootReleaseCommand", 2, "initialize()");
    }

    // Called repeatedly when this Command is scheduled to run
    protected void execute() 
    {
    	Logger.Log("ShootReleaseCommand", -1, "execute()");
    	
    	Robot.m_shooterSubsystem.ReleaseShooter();
    }

    // Make this return true when this Command no longer needs to run execute()
    protected boolean isFinished() 
    {
    	Logger.Log("ShootReleaseCommand", -1, "isFinished()");
        
    	return (false);
    }

    // Called once after isFinished returns true
    protected void end() 
    {
    	Logger.Log("ShootReleaseCommand", 2, "end()");
    }

    // Called when another command which requires one or more of the same
    // subsystems is scheduled to run
    protected void interrupted() 
    {
    	Logger.Log("ShootReleaseCommand", 2, "interrupted()");
    }
}

Now we need to edit the ShooterSubsystem.java file and add the following line to the initDefaultCommand() function:

    	setDefaultCommand(new ShootReleaseCommand());

Your ShooterSubsystem.java file should now look like

package subsystem;

import commands.ShootReleaseCommand;
import robotCore.Logger;
import robotCore.ServoMotor;
import wpilib.Subsystem;

/**
 *
 */
public class ShooterSubsystem extends Subsystem 
{
	private ServoMotor m_shooter				= null;
	private final static int	k_shooterPin	= 5;
	private final static double k_releasePos	= 1.0;
	private final static double k_shootPos		= -1.0;
	
    public void initDefaultCommand() 
    {
    	Logger.Log("ShooterSubsystem", 2, "initDefaultCommand()");
		
    	setDefaultCommand(new ShootReleaseCommand());
    }
    
    public void Init()
    {
    	Logger.Log("ShooterSubsystem", 2, "Init()");
		
    	m_shooter	= new ServoMotor(k_shooterPin);
    }
    
	public void ReleaseShooter()
	{
		m_shooter.set(k_releasePos);
	}
	
	public void Shoot()
	{
		m_shooter.set(k_shootPos);
	}
}

We are now ready to create a command to operate the shooter which we will tie to the trigger button on the joystick.  We will call this command ShootCommand.  Create a new class ShootCommand underneath the commands folder.  As before, copy the contents of the ExampleCommand.java file into the new ShootCommand.java file, and replace all the occurrences of ExampleCommand with ShootCommand.  Your ShootCommand.java file should now look like:

package commands;

import robotCore.Logger;
import wpilib.Command;

/**
 *
 */
public class ShootCommand extends Command 
{
    public ShootCommand() 
    {
    	Logger.Log("ShootCommand", 3, "ShootCommand()");
    	
        // Use requires() here to declare subsystem dependencies
//        requires(Robot.m_exampleSubsystem);
    }

    // Called just before this Command runs the first time
    protected void initialize() 
    {
    	Logger.Log("ShootCommand", 2, "initialize()");
    }

    // Called repeatedly when this Command is scheduled to run
    protected void execute() 
    {
    	Logger.Log("ShootCommand", -1, "execute()");
    }

    // Make this return true when this Command no longer needs to run execute()
    protected boolean isFinished() 
    {
    	Logger.Log("ShootCommand", -1, "isFinished()");
        
    	return (false);
    }

    // Called once after isFinished returns true
    protected void end() 
    {
    	Logger.Log("ShootCommand", 2, "end()");
    }

    // Called when another command which requires one or more of the same
    // subsystems is scheduled to run
    protected void interrupted() 
    {
    	Logger.Log("ShootCommand", 2, "interrupted()");
    }
}

This command will need to use the ShooterSubsystem, so replace the requires(…) line with the following,  Remember to import the Robot class.

        requires(Robot.m_shooterSubsystem);

When this command is activated, we want to move the shooter into the shoot position, so add the following line to the initialize() function:

    	Robot.m_shooterSubsystem.Shoot();

We will be tying this command to execute as long as the trigger button is pressed, so we always want to return false from the isFinished() routine.  However, when we release the trigger, the interrupted() function will be called, and we need to move the shooter back to the released position.  Do this by adding the following line to the interrupted() function:

    	Robot.m_shooterSubsystem.ReleaseShooter();

Your ShootCommand.java file should now look like:

package commands;

import robot.Robot;
import robotCore.Logger;
import wpilib.Command;

/**
 *
 */
public class ShootCommand extends Command 
{
    public ShootCommand() 
    {
    	Logger.Log("ShootCommand", 3, "ShootCommand()");
    	
        // Use requires() here to declare subsystem dependencies
        requires(Robot.m_shooterSubsystem);
    }

    // Called just before this Command runs the first time
    protected void initialize() 
    {
    	Logger.Log("ShootCommand", 2, "initialize()");
    	
    	Robot.m_shooterSubsystem.Shoot();
    }

    // Called repeatedly when this Command is scheduled to run
    protected void execute() 
    {
    	Logger.Log("ShootCommand", -1, "execute()");
    }

    // Make this return true when this Command no longer needs to run execute()
    protected boolean isFinished() 
    {
    	Logger.Log("ShootCommand", -1, "isFinished()");
        
    	return (false);
    }

    // Called once after isFinished returns true
    protected void end() 
    {
    	Logger.Log("ShootCommand", 2, "end()");
    }

    // Called when another command which requires one or more of the same
    // subsystems is scheduled to run
    protected void interrupted() 
    {
    	Logger.Log("ShootCommand", 2, "interrupted()");
    	
    	Robot.m_shooterSubsystem.ReleaseShooter();
    }
}

Finally, we need to attach the trigger button of the joystick to this command.  Open the OI.java file.  We see that there already exists a declaration for the trigger (i.e. m_trigger), so all we need to do is connect that to the ShootCommand.  Add the following line to the OI() constructor (you will need to also import the ShootCommand class):

    	m_trigger.whileHeld(new ShootCommand());

Your OI.java file should now look like:

package robot;

import commands.ShootCommand;
import commands.SpinupCommand;
import robotCore.Joystick;
import wpilib.Button;
import wpilib.JoystickButton;

/**
 * This class is the glue that binds the controls on the physical operator
 * interface to the commands and command groups that allow control of the robot.
 */
public class OI {
    //// CREATING BUTTONS
    // One type of button is a joystick button which is any button on a joystick.
    // You create one by telling it which joystick it's on and which button
    // number it is.
     Joystick m_stick = new Joystick(0);
     Button m_trigger = new JoystickButton(m_stick, 1);
     Button m_spinup	= new JoystickButton(m_stick, 2);
    
    // There are a few additional built in buttons you can use. Additionally,
    // by subclassing Button you can create custom triggers and bind those to
    // commands the same as any other Button.
    
    //// TRIGGERING COMMANDS WITH BUTTONS
    // Once you have a button, it's trivial to bind it to a button in one of
    // three ways:
    
    // Start the command when the button is pressed and let it run the command
    // until it is finished as determined by it's isFinished method.
    public OI()
    {
//    	m_trigger.whenPressed(new ExampleCommand());
    	m_spinup.whileHeld(new SpinupCommand());
    	m_trigger.whileHeld(new ShootCommand());
    }
}

We can now test our program.  To shoot the ball, place the ball in the shooter, hold the spinup button until the spinners are running at full speed, and then press the trigger.  The ball should fire.

Try and position the robot and make a shot into the tower.

Next: Intake Subsystem