Search code examples
javamethodscommandsubsystem

Command based Java: Accessing a method from a subsystem in a command (Java)


this is my first time using Java and I seem to be stuck. I'm trying to access a method (getHeading) from a subsystem (DriveTrain) in a command (DriveStraight), but I keep getting the error that "the type getHeading(double) is undefined for the type Subsystem" when I try heading = Robot.DriveTrain.getHeading();. This is the command:

public class DriveStraight extends Command {

    private double speed;
    private double duration;
    private double heading;

    public DriveStraight(float driveSpeed, float duration) {
        requires(Robot.DriveTrain);
        **heading = Robot.DriveTrain.getHeading();**
    }

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

    // Called repeatedly when this Command is scheduled to run
    protected void execute() {
        **float currentheading = Robot.DriveTrain.getHeading();**
        Robot.DriveTrain.arcadeDrive(speed, (heading - currentheading) * 0.08);
    }

And this is the subsystem:

public class DriveTrain extends Subsystem {
    AnalogGyro gyro;

    RobotDrive drive;
    VictorSP frontLeftMotor, rearLeftMotor, frontRightMotor, rearRightMotor;

    public DriveTrain() {
        frontLeftMotor = new VictorSP(RobotMap.frontLeftMotor);
        rearLeftMotor = new VictorSP(RobotMap.rearLeftMotor);
        frontRightMotor = new VictorSP(RobotMap.frontRightMotor);
        rearRightMotor = new VictorSP(RobotMap.rearRightMotor);

        gyro = new AnalogGyro(RobotMap.analogGyro);
        gyro.setSensitivity(0.00666);
        gyro.calibrate();
    }

    public void arcadeDrive(float speed, float turn) {
        drive.arcadeDrive(OI.joy.getRawAxis(OI.LEFT_Y_AXIS),
                OI.joy.getRawAxis(OI.RIGHT_X_AXIS), true);
    }

    public void tankDrive(float leftValue, float rightValue) {
        drive.tankDrive(OI.joy.getRawAxis(OI.LEFT_Y_AXIS),
                OI.joy.getRawAxis(OI.RIGHT_Y_AXIS), true);
    }

    public double getHeading() {
        return gyro.getAngle();
    }

    protected void initDefaultCommand() {
        arcadeDrive(0, 0);
    }   
}

I just came from using C++ so I think I might be trying to use pointers, but I'm not sure. So what's the right way to call a method from a subsystem?

Thanks, Sethra53


Solution

  • You're not managing an instance of Robot.DriveTrain anywhere - all your method calls on the DriveTrain class are being seen by the compiler as calls to static methods (which don't relate to an object, only to the class). The nearest matching method you have defined anywhere is public double getHeading() {, which is an instance method and so should be called on an instance. There are 4 places in your code which are referring to Robot.DriveTrain and I'm not sure what your requires method is doing so it's tricky to know what you should be passing to it. The other three places, however, should be referring to instances of Robot.DriveTrain.

    e.g.

    public class DriveStraight extends Command {
    
        private double speed;
        private double duration;
        private double heading;
        private Robot.DriveTrain driveTrain;
    
        public DriveStraight(float driveSpeed, float duration) {
            requires(Robot.DriveTrain);
            driveTrain = new Robot.DriveTrain()            // create new shared instance
            heading = driveTrain.getHeading();             // use instance.
        }
    
        // Called just before this Command runs the first time
        protected void initialize() {
            setTimeout(duration);
        }
    
        // Called repeatedly when this Command is scheduled to run
        protected void execute() {
            float currentheading = driveTrain.getHeading();    // use instance created in constructor.
            driveTrain.arcadeDrive(speed, (heading - currentheading) * 0.08);
        }
        ...
    

    I can't guarantee any of that will 'work' however, without understanding how the requires method call works.

    A better approach would be to pass the instance in to the DriveStraight constructor...

    public class DriveStraight extends Command {
        private Robot.DriveTrain driveTrain;
    
        public DriveStraight(float driveSpeed, float duration, DriveTrain driveTrain) {
            this.driveTrain = driveTrain; // use instance created elsewhere
        ...