Autonomous Command-Based Programming Problems - Please Help

Hello all!

We’ve suffered through a myriad number of problems with our autonomous command-based programming, specifically with our pneumatics controls.
Our error messages and code files are posted below. Any help helps, thank y’all so much!!

Robot.java

package org.usfirst.frc.team5212.robot;

import edu.wpi.first.networktables.NetworkTable;
import edu.wpi.first.networktables.NetworkTableEntry;
import edu.wpi.first.networktables.NetworkTableInstance;
import edu.wpi.first.wpilibj.*;
import edu.wpi.first.wpilibj.command.*;

import org.usfirst.frc.team5212.autonomous.commands.*;
import org.usfirst.frc.team5212.autonomous.subsystems.DriveBase;
import org.usfirst.frc.team5212.autonomous.subsystems.Pneumatics;

import com.ctre.phoenix.motorcontrol.can.WPI_TalonSRX;

import edu.wpi.first.wpilibj.CameraServer;
import edu.wpi.first.wpilibj.IterativeRobot;
import edu.wpi.first.wpilibj.Joystick;
import edu.wpi.first.wpilibj.buttons.Button;
import edu.wpi.first.wpilibj.buttons.JoystickButton;
import edu.wpi.first.wpilibj.drive.DifferentialDrive;


public class Robot extends IterativeRobot {
	//states
	boolean compress_state = false;
	boolean shoot_state = true;
	
	//subsystem creations
	static DriveBase driveBase;
	static Pneumatics pneum;
	Timer timer;
	

	/* talons for arcade drive */
	WPI_TalonSRX frontLeftMotor = new WPI_TalonSRX(RobotMap.frontLeftPort); //0 1 5
	WPI_TalonSRX frontRightMotor = new WPI_TalonSRX(RobotMap.frontRightPort); //2 3 4

	/* extra talons and victors for six motor drives */

	//WPI_TalonSRX leftSlave = new WPI_TalonSRX(3);
	//WPI_TalonSRX rightSlave = new WPI_TalonSRX(1);
	
	//WPI_TalonSRX leftSecondSlave = new WPI_TalonSRX();
	//WPI_TalonSRX rightSecondSlave = new WPI_TalonSRX();
	WPI_TalonSRX leftSlave1 = new WPI_TalonSRX(RobotMap.leftSlave1Port);
	WPI_TalonSRX rightSlave1 = new WPI_TalonSRX(RobotMap.rightSlave1Port);

	WPI_TalonSRX leftSlave2 = new WPI_TalonSRX(RobotMap.leftSlave2Port);
	WPI_TalonSRX rightSlave2 = new WPI_TalonSRX(RobotMap.rightSlave2Port);
	
	DifferentialDrive drive = new DifferentialDrive(frontLeftMotor, frontRightMotor);

	public static Joystick joy = new Joystick(0);
	public static Button AButton = new JoystickButton(joy, 2);
	// Button BButton = new JoystickButton(joy, 2);
	
	AutonomousCommand ac = new AutonomousCommand();
	
	NetworkTable table;
	NetworkTableInstance inst;

	NetworkTableEntry leftRawData;
	NetworkTableEntry rightRawData;
	
	final int DEFAULT_DRIVE = 0;
	// speed of robot [0-1]
	double speedR = .84;
	double speedL = 0.71;
	// double speedR = 1;
	// double speedL = 1;
	
	// UsbCamera camera0;
	// UsbCamera camera1;

	/**
	 * This function is run when the robot is first started up and should be
	 * used for any initialization code.
	 */
	public void robotInit() {
		/*
		 * take our extra talons and just have them follow the Talons updated in
		 * arcadeDrive
		 */
		// leftSlave.follow(frontLeftMotor);
		// rightSlave.follow(frontRightMotor);
		timer = new Timer();
		
		driveBase = new DriveBase();
		pneum = new Pneumatics();
		
		leftSlave1.follow(frontLeftMotor);
		rightSlave1.follow(frontRightMotor);

		leftSlave2.follow(frontLeftMotor);
		rightSlave2.follow(frontRightMotor);
		
		/* drive robot forward and make sure all 
		 * motors spin the correct way.
		 * Toggle booleans accordingly.... */
		frontLeftMotor.setInverted(false);
		// leftSlave.setInverted(false);
		
		frontRightMotor.setInverted(false);
		// rightSlave.setInverted(false);
		
		// Pneumatics Setup
		//mainCompressor.setClosedLoopControl(true);
		//mainCompressor.stop();
//		solenoidOne.set(DoubleSolenoid.Value.kOff);

	}
	
	public void autonomousInit() {
		// ac.start();
	}
	
	public void autonomousPeriodic() {

		CameraServer.getInstance().startAutomaticCapture();
		// mainCompressor.setClosedLoopControl(false);
	}

	/**
	 * This function is called periodically during operator control
	 */
	public void teleopPeriodic() {
		
                AButton.whenPressed(new PrepareShoot());
		System.out.println("Joy0Y:" + joy.getRawAxis(1) + "Joy1Y:" + joy.getRawAxis(3));
		
		drive.tankDrive(-(1) * (speedL)*joy.getRawAxis(1), -(1) * (speedR)*joy.getRawAxis(3));
		
	}
}

Pneumatics.java

package org.usfirst.frc.team5212.autonomous.subsystems;


import edu.wpi.first.wpilibj.Compressor;
import edu.wpi.first.wpilibj.DoubleSolenoid;
import edu.wpi.first.wpilibj.command.Subsystem;

import org.usfirst.frc.team5212.autonomous.commands.PrepareShoot;
import org.usfirst.frc.team5212.robot.*;

public class Pneumatics extends Subsystem {

	Compressor mainCompressor = new Compressor(0);
	//	DoubleSolenoid solenoidOne = new DoubleSolenoid(0, 1);

	boolean isEnabled = mainCompressor.enabled();
	boolean pressureSwitch = mainCompressor.getPressureSwitchValue();
	double current = mainCompressor.getCompressorCurrent();
	// or we could do something related to Robot.somethingdu? 

	PrepareShoot ps = new PrepareShoot();
	@Override
	protected void initDefaultCommand() {
		setDefaultCommand(ps);
		System.out.println("Compressor init");
		mainCompressor.setClosedLoopControl(true);

		mainCompressor.stop();

	}

	public void compressAir()
	{
		System.out.println("Compressor compressing");
		mainCompressor.start();
	}

	public void stopCompress()
	{
		mainCompressor.stop();
	}

	/*	public void shootMyKintama () throws InterruptedException
	{

		solenoidOne.set(DoubleSolenoid.Value.kForward);

		solenoidOne.wait(5000);
	}

	public void stopShooting ()
	{
		solenoidOne.set(DoubleSolenoid.Value.kOff);
	}*/
}

PrepareShoot.java

package org.usfirst.frc.team5212.autonomous.commands;

import edu.wpi.first.wpilibj.command.Command;

import org.usfirst.frc.team5212.robot.*;

import org.usfirst.frc.team5212.autonomous.subsystems.Pneumatics;

public class PrepareShoot extends Command {

	Pneumatics pneum = new Pneumatics();
	public PrepareShoot() {
		super("PrepareShoot");
		requires(pneum);
	}

	protected void initialize() {
		System.out.println("command init");
		// TODO Auto-generated method stub
	}

	protected void execute() {
		// TODO Auto-generated method stub
		System.out.println("Trying to compress");
		pneum.compressAir();
	}

	protected boolean isFinished() {
		return false;
	}

	protected void end() {
		if (isFinished()) {
			pneum.stopCompress();
		}
		else {
			pneum.stopCompress();
		}
	}

	protected void interrupted() {
		end();
		// TODO Auto-generated method stub
	}
}

Error Log
The error log simply keeps repeating the error


<packagename>.<Pneumatics.java:21>
<packagename>.<PrepareShoot.java:11>

in an infinite loop while the driver station is running,
there is no other error message that appears :frowning:

We’d highly appreciate any help/advice you all could give us.
Thank you again,

team5212

It doesn’t make much sense to put all the pneumatics in a single subsystem in code, since two completely independent subsystems on the robot can both use pneumatics. It’s better to have one subsystem class in your project for each real subsystem on the robot, and each of those classes is responsible for its own pneumatics (and sensors and other actuators, as well).


To answer the question:

This is your problem:


Pneumatics pneum = new Pneumatics();

Use this instead:


Pneumatics pneum = Robot.pneumatics;

First, thank you for your response!
We’ve tried your suggestion, and the same error occures
Our implementation of the solution:


public PrepareShoot() {
        super("PrepareShoot");
        requires(Robot.pneum);
}

In our Robot.java:


public class Robot {
        Pneumatics pneum;
...
        public void robotInit()
        {
                pneum = new Pneumatics();
        }
}

So the crux of the problem here is needing better strategy of what to do when.

The main benefit of command-based design is missing here:

  1. subsystems are permanent but they know absolutely nothing about teleOP vs autonomous, and they should no nothing or close to nothing about aliance, joysticks, game-rules, etc. (and other than init-default-command, nothing else about commands).

  2. commands should typically be teleop-focused (with-joystick variables) or else auto-focused (lacking joystick variables).

How your are getting into trouble is by putting command-logic directly into teleopPeriodic().

Rather than this…

	public void teleopPeriodic() {

		// this doesn't check if the button is pressed NOW
                AButton.whenPressed(new PrepareShoot());
		// but rather it creates a new command instances continuously!  

		System.out.println("Joy0Y:" + joy.getRawAxis(1) + "Joy1Y:" + joy.getRawAxis(3));

What you want is more like this…

	protected void execute() {
		// TODO Auto-generated method stub
		System.out.println("Trying to compress");
		if (joy.getRawAxis(1) || joy.getRawAxis(3))
		     pneum.compressAir();
		else
		     pneum.stopCompress();
	}

… this at least would work as your default-teleOP command. It doesn’t need any initialize() nor end() nor interupted() code. Rather if you do want/need to control this within autonomous then you just need a new/separate command for that without any joystick references. (because both commands will require the same subsystem, the tele-command will interrupt during autonomous and then restart after that).

And one last note about your startAutomaticCapture(); That should be done once from robotInit() rather than repeatedly from autonomousPeriodic().

The two post above are correct. You are kind of messing with the way commandbased works. All physical actions should exist in the subsystems. Button command should exist in the OI class. By creating these “new class” in different area’s you are having command compete against themselves and it could cause a conflict of these physical devices.