How to prevent code crash when missing FMS data?

Hello All,

After significant support from Peter Johnson and adopting code from BenBernard we were able to get our autonomous mode selection working for week 1. There is still one issue that I haven’t solved.

If there is a case where the FMS data is not sent, I still get the robot code crashing. I think it is the same issue as when you try to access the field before the information is available. I can reproduce this by clearing out the FMS field in the driver station. Has anyone solved this? I guess it would be more of a fail safe as hopefully it would never happen, but you never know.

Here is our code:

public void autonomousInit() {
        RobotMap.drivetrainleftFrontMotorController.configOpenloopRamp(RobotConstants.TalonSrxAutoOpenRamp, 10);	// Disable motor ramp limiting
        RobotMap.drivetrainrightFrontMotorController.configOpenloopRamp(RobotConstants.TalonSrxAutoOpenRamp, 10);
        RobotMap.drivetrainleftFrontMotorController.configClosedloopRamp(0, 10);	// Disable motor ramp limiting in closed loop
        RobotMap.drivetrainrightFrontMotorController.configClosedloopRamp(0, 10);
        
        try {
        	gameData = DriverStation.getInstance().getGameSpecificMessage();
        	if(gameData == null) { gameData = "";}    		
    	}catch (Exception e) {
    		gameData = "";
    	}
    	int retries = 100;
    	while (gameData.length() < 2 && retries >0) {
    		try {
    			Thread.sleep(5);
    			gameData = DriverStation.getInstance().getGameSpecificMessage();
    			if (gameData == null) { gameData = "";}
    	 		} catch (Exception e) {
    	 		}
			retries--;
 			}
    	
    	SmartDashboard.putString("TestField", gameData);
//       autonomousCommand = chooser.getSelected();
    	
    	String ChooserCommand = chooser.getSelected();
    	
    	if (ChooserCommand.equals("AutoRedScale")) {
    		autonomousCommand = new AutoRedScale();
    	}
    	else if (ChooserCommand.equals("AutoRedSwitch")) {
    		autonomousCommand = new AutoRedSwitch();
    	}
    	else if (ChooserCommand.equals("AutoBlueScale")) {
    		autonomousCommand = new AutoBlueScale();
    	}
    	else if (ChooserCommand.equals("AutoBlueSwitch")) {
    		autonomousCommand = new AutoBlueSwitch();
    	}
    	else {
    		autonomousCommand = new AutoCrossLine();
    	}
      
        // schedule the autonomous command (example)
        if (autonomousCommand != null) autonomousCommand.start();

Your code is checking for the null or empty string condition, but it still proceeds in that case. You should have a default condition that runs if game data is not received, and only look at the game data if it’s available.

Thanks Joe. My attempt to abort if the gameData is not valid occurs in the autonomousCommand class. Please see below.

public class AutoBlueScale extends CommandGroup {


    public AutoBlueScale() {

    	if(Robot.gameData != null && Robot.gameData != "")
        {
        	if(Robot.gameData.charAt(1) == 'L')
        	{
              	SmartDashboard.putString("Auto Status", "Left scale");
            	addSequential(new calibrateGyro());
//            	addParallel(new AutoRaiseFrontElevatorEject(0.5, 0));
            	addSequential(new AutoDriveStraightGyroEncoder(300, RobotConstants.autoSpeed, 0));
            	addSequential(new AutoDriveTurn(90));
//            	addSequential(new AutoDriveStraightGyroEncoder(24, RobotConstants.autoSpeed, 90));
//            	addSequential(new AutoDriveTurn(90));
//            	addSequential(new AutoRaiseFrontElevatorEject(2, 0.5));
            	addSequential(new AutoRaiseFrontElevator(3));
            	addSequential(new AutoEjectCube(0.5));
        	} 
        	else {
              	SmartDashboard.putString("Auto Status", "Right scale");
              	addSequential(new calibrateGyro());
            	addSequential(new AutoDriveStraightGyroEncoder(214, RobotConstants.autoSpeed, 0));
            	addSequential(new AutoDriveTurn(90));
            	addSequential(new AutoDriveStraightGyroEncoder(189, RobotConstants.autoSpeed, 90));
            	addSequential(new AutoDriveTurn(0));
//            	addParallel(new AutoRaiseFrontElevatorEject(2, 0.5));
            	addSequential(new AutoDriveStraightGyroEncoder(18, RobotConstants.autoSpeed, 0));
            	addParallel(new AutoDriveTurn(0));
            	addSequential(new AutoRaiseFrontElevator(2.7));            	
            	addSequential(new AutoEjectCube(0.5));
        	}
        }
        else
        {
        	addSequential(new AutoCrossLine());

        }
    } 
}

Where are you getting the crash? One general suggestion would be to change your != “” checks to .Length() > 1 checks. Your code is referencing charAt(1) which will fail if the string has only one character.

The other reason to do this is that != doesn’t do string comparison in Java, it compares whether the object references are the same. If you want string comparison you need to use .equals() (and ! it if you want not-equals).

Thanks again. Eventually you guys will help me get past a novice Java programmer. Especially Peter already told me about string compares.

I think I have it working now. What was causing the crash was the auto commands being constructed in OI due to telling Robot Builder to create buttons on the dashboard. Getting rid of those and changing to use the methods for string compares seems to have helped. Here is the code for reference.

    public void autonomousInit() {
        RobotMap.drivetrainleftFrontMotorController.configOpenloopRamp(RobotConstants.TalonSrxAutoOpenRamp, 10);	// Disable motor ramp limiting
        RobotMap.drivetrainrightFrontMotorController.configOpenloopRamp(RobotConstants.TalonSrxAutoOpenRamp, 10);
        RobotMap.drivetrainleftFrontMotorController.configClosedloopRamp(0, 10);	// Disable motor ramp limiting in closed loop
        RobotMap.drivetrainrightFrontMotorController.configClosedloopRamp(0, 10);
        
        try {
        	gameData = DriverStation.getInstance().getGameSpecificMessage();
        	if(gameData.equals(null)) { gameData = "";}    		
    	}catch (Exception e) {
    	}
    	int retries = 100;
    	while (gameData.length() < 2 && retries >0) {
    		try {
    			Thread.sleep(5);
    			gameData = DriverStation.getInstance().getGameSpecificMessage();
    			if(gameData.equals(null)) { gameData.equals("");}
    	 		} catch (Exception e) {
    	 		}
			retries--;
 			} 
    	
    	SmartDashboard.putString("TestField", gameData);
    	
    	String ChooserCommand = chooser.getSelected();
    	
    	if (ChooserCommand.equals("AutoRedScale")) {
    		autonomousCommand = new AutoRedScale();
    	}
    	else if (ChooserCommand.equals("AutoRedSwitch")) {
    		autonomousCommand = new AutoRedSwitch();
    	}
    	else if (ChooserCommand.equals("AutoBlueScale")) {
    		autonomousCommand = new AutoBlueScale();
    	}
    	else if (ChooserCommand.equals("AutoBlueSwitch")) {
    		autonomousCommand = new AutoBlueSwitch();
    	}
    	else {
    		autonomousCommand = new AutoCrossLine();
    	}
      
        // schedule the autonomous command (example)
        if (autonomousCommand != null) autonomousCommand.start();
    }

public class AutoBlueScale extends CommandGroup {

    public AutoBlueScale() {

    	if(Robot.gameData.length() > 1)
        {
        	if(Robot.gameData.charAt(1) == 'L')
        	{
              	SmartDashboard.putString("Auto Status", "Left scale");
            	addSequential(new calibrateGyro());
//            	addParallel(new AutoRaiseFrontElevatorEject(0.5, 0));
            	addSequential(new AutoDriveStraightGyroEncoder(300, RobotConstants.autoSpeed, 0));
            	addSequential(new AutoDriveTurn(90));
//            	addSequential(new AutoDriveStraightGyroEncoder(24, RobotConstants.autoSpeed, 90));
//            	addSequential(new AutoDriveTurn(90));
//            	addSequential(new AutoRaiseFrontElevatorEject(2, 0.5));
            	addSequential(new AutoRaiseFrontElevator(3));
            	addSequential(new AutoEjectCube(0.5));
        	} 
        	else {
              	SmartDashboard.putString("Auto Status", "Right scale");
              	addSequential(new calibrateGyro());
            	addSequential(new AutoDriveStraightGyroEncoder(214, RobotConstants.autoSpeed, 0));
            	addSequential(new AutoDriveTurn(90));
            	addSequential(new AutoDriveStraightGyroEncoder(189, RobotConstants.autoSpeed, 90));
            	addSequential(new AutoDriveTurn(0));
//            	addParallel(new AutoRaiseFrontElevatorEject(2, 0.5));
            	addSequential(new AutoDriveStraightGyroEncoder(18, RobotConstants.autoSpeed, 0));
            	addParallel(new AutoDriveTurn(0));
            	addSequential(new AutoRaiseFrontElevator(2.7));            	
            	addSequential(new AutoEjectCube(0.5));
        	}
        }
        else
        {
          	SmartDashboard.putString("Auto Status", "Cross Line");
        	addSequential(new AutoCrossLine());

        }
    } 
}

Hi, I don’t know about Command based but I will still post what I have for iterative fro others who might read this thread. Here it is:


@Override
	public void autonomousPeriodic() {
		//this runs the selected auto. 
		switch (m_autoSelected) {
			//the autonomus chooser. it compares  m_autoSelected to each case, then runs the code after the semicolin 
			//if the strings match. to add a new auto, make a new string, and make a case for it here 
			// make sure to end each case with break. 
		
		
			case leftAuto:
				//this is where the left switch auto code goes.
				if (timer.get() < 0.5) {					
						myrobot.drive(-0.5,0.0);			//drive forward half speed for .5 second
						
					}else if (timer.get() < (0.5+0.5)){  	
						myrobot.drive(0.0,-0.5);			//turn left half speed for .5 seconds
						
					}else if (timer.get() < (0.5+0.5+2)){
						myrobot.drive(-0.5,0.0);			//drive forward half speed for 2 seconds
						
					}else if (timer.get() < (0.5+0.5+2+.05)){
						myrobot.drive(0.0,0.5);				// turn right half speed for .5 seconds
							
					}
				
			case rightAuto
				// this is where the right switch auto code goes
				if (timer.get() < 0.5) {
					myRobot.drive(-0.5,0.0); // drive forwards half speed for .5 second
				}else{
					myRobot.drive(0.0, 0.0); // stop robot
				}
			
				if (timer.get() < 1.0) {
					myRobot.drive(0.0, 0.5); // turn right half speed for 1 second
				}else{
					myRobot.drive(0.0,0.0); // stop robot
				}
				break;
				}
				
			case kDefaultAuto:
			default:	// Put default auto code here
				if (timer.get() < 3.0) {
					myRobot.drive(-0.5,0.0); //drive forward half speed for 3 seconds
				}else{
					myRobot.drive(0.0,0.0); // stop robot
				}
				break;
		}
	}

The case kDefaultAuto is for if the robot doesn’t receive the FMS data, in our case it will still pass the auto line. Don’t mind the drive code I’ve got in it (unless somethings wrong) I’ve not completed it, and I will probably use thr gyro I found a few days ago.

Sorry for the late reply.

I actually had this problem at a competition.

What I used was a try catch:


try {
     return gameData.charAt(1)
} catch (Exception e) {
     return ' ';
}