Search requires an index. Run npm run build once, then restart dev.
Try-Catch Exception Handling
intermediate70 min
What are Exceptions?
Exceptions are errors that occur during program execution that can disrupt the normal flow of your program. In robotics, exceptions might happen when sensors fail, motors disconnect, or invalid data is received. Java provides try-catch blocks to handle these errors gracefully instead of crashing your robot program.
Why Use Try-Catch?
In FRC robotics, your program must be robust and handle unexpected situations. Without proper exception handling, a single sensor failure could crash your entire autonomous routine. Try-catch blocks allow your robot to continue operating even when errors occur, providing fallback behavior and error recovery.
Basic Try-Catch Structure:
// Basic try-catch syntaxtry { // Code that might throw an exception // This is the "risky" code} catch (ExceptionType e) { // Code to handle the exception // This runs if an exception occurs}// Simple example with divisiontry { int result = 10 / 0; // This will throw ArithmeticException System.out.println("Result: " + result);} catch (ArithmeticException e) { System.out.println("Error: Cannot divide by zero!"); System.out.println("Exception message: " + e.getMessage());}System.out.println("Program continues...");
Common Java Exceptions
Understanding common exceptions helps you write better error handling code. Here are the most frequent exceptions you’ll encounter in robot programming:
Common Exception Examples:
// 1. NumberFormatException - Invalid string to number conversiontry { String userInput = "abc"; // Invalid number int number = Integer.parseInt(userInput);} catch (NumberFormatException e) { System.out.println("Invalid number format: " + userInput);}// 2. ArrayIndexOutOfBoundsException - Invalid array accesstry { int[] motorPowers = {0, 1, 2, 3}; int power = motorPowers[5]; // Index 5 doesn't exist} catch (ArrayIndexOutOfBoundsException e) { System.out.println("Motor index out of range!");}// 3. NullPointerException - Accessing null objecttry { String sensorName = null; int length = sensorName.length(); // Calling method on null} catch (NullPointerException e) { System.out.println("Sensor object is null!");}
Multiple Catch Blocks
You can have multiple catch blocks to handle different types of exceptions differently. This allows for specific error handling based on the type of problem that occurred.
Multiple Catch Example:
import java.util.Scanner;public class RobotSensorReader { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); String[] sensorNames = {"Ultrasonic", "Color", "Touch", "Gyro"}; try { System.out.print("Enter sensor index (0-3): "); String input = scanner.nextLine(); int index = Integer.parseInt(input); // Could throw NumberFormatException String selectedSensor = sensorNames[index]; // Could throw ArrayIndexOutOfBoundsException System.out.println("Selected sensor: " + selectedSensor); double reading = readSensor(selectedSensor); System.out.println("Sensor reading: " + reading); } catch (NumberFormatException e) { System.out.println("[ERROR] Error: Please enter a valid number!"); } catch (ArrayIndexOutOfBoundsException e) { System.out.println("[ERROR] Error: Sensor index out of range!"); System.out.println(" Valid range: 0 to " + (sensorNames.length - 1)); } catch (Exception e) { // Generic catch for any other exceptions System.out.println("[ERROR] Unexpected error: " + e.getMessage()); } } public static double readSensor(String sensorName) { return Math.random() * 100; }}
The Finally Block
The finally block contains code that always executes, whether an exception occurs or not. This is perfect for cleanup operations like stopping motors, closing files, or releasing resources.
Finally Block Example:
public class RobotMotorTest { public static void main(String[] args) { boolean motorStarted = false; try { System.out.println("Starting motor test..."); startMotor(); motorStarted = true; // Simulate motor test that might fail performMotorTest(); System.out.println("Motor test completed successfully!"); } catch (Exception e) { System.out.println("[ERROR] Motor test failed: " + e.getMessage()); } finally { // Always stop the motor, even if test fails if (motorStarted) { System.out.println("[STOP] Stopping motor for safety..."); stopMotor(); } System.out.println("Motor test cleanup completed."); } } public static void startMotor() { System.out.println("[START] Motor started"); } public static void stopMotor() { System.out.println("[STOPPED] Motor stopped"); } public static void performMotorTest() { // Simulate a test that might fail randomly if (Math.random() > 0.5) { throw new RuntimeException("Motor overheated during test!"); } System.out.println("Motor test passed"); }}
Exception Handling Best Practices:
Guidelines for Robust Robot Code:
Be Specific: Catch specific exception types rather than generic Exception
Log Useful Information: Include context about what the robot was doing
Provide Fallbacks: Have backup plans when primary systems fail
Don’t Ignore Exceptions: Always handle or log exceptions appropriately
Use Finally for Cleanup: Stop motors and release resources in finally blocks
Fail Gracefully: Allow robot to continue operating when possible
Try It Yourself:
Exercise 1: Exception Handling Practice
Create a safe sensor reading system with exception handling
Build a motor control system with input validation and error recovery
Implement a robot configuration loader with multiple exception types
Design an autonomous routine with step-by-step error handling
Practice implementing try-catch blocks for robot programming scenarios:
Create a safe sensor reading system with exception handling
Create a safe sensor reading system with exception handling
import java.util.Scanner;
public class SafeSensorSystem {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String[] sensors = {"Ultrasonic", "Color", "Touch", "Gyro"};
double[] lastReadings = {0.0, 0.0, 0.0, 0.0};
while (true) {
try {
System.out.println("\nAvailable sensors:");
for (int i = 0; i < sensors.length; i++) {
System.out.printf("%d: %s (last: %.1f)\n", i, sensors[i], lastReadings[i]);
}
System.out.print("Enter sensor index (-1 to exit): ");
String input = scanner.nextLine().trim();
int index = Integer.parseInt(input);
if (index == -1) {
break;
}
if (index < 0 || index >= sensors.length) {
throw new ArrayIndexOutOfBoundsException("Sensor index out of range");
}
String sensor = sensors[index];
double reading = readSensorSafely(sensor, lastReadings[index]);
lastReadings[index] = reading;
System.out.println("[OK] " + sensor + " reading: " + String.format("%.2f", reading));
} catch (NumberFormatException e) {
System.out.println("[ERROR] Please enter a valid number!");
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("[ERROR] " + e.getMessage());
System.out.println(" Valid range: 0 to " + (sensors.length - 1));
} catch (Exception e) {
System.out.println("[ERROR] Sensor system error: " + e.getMessage());
System.out.println(" Attempting system recovery...");
// Reset all readings to safe defaults
for (int i = 0; i < lastReadings.length; i++) {
lastReadings[i] = 0.0;
}
}
}
System.out.println("Sensor system shut down safely.");
}
public static double readSensorSafely(String sensorName, double lastReading) {
try {
// Simulate sensor reading with potential failure
if (Math.random() > 0.8) { // 20% chance of sensor failure
throw new RuntimeException("Sensor communication error");
}
// Generate realistic sensor reading
return Math.random() * 100;
} catch (RuntimeException e) {
System.out.println("[WARNING] Sensor " + sensorName + " failed: " + e.getMessage());
System.out.println(" Using last known reading: " + lastReading);
return lastReading; // Fallback to last known value
}
}
}
Build a motor control system with input validation and error recovery
Build a motor control system with input validation and error recovery
import java.util.Scanner;
public class SafeMotorControl {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String[] motors = {"Front Left", "Front Right", "Back Left", "Back Right"};
double[] powers = {0.0, 0.0, 0.0, 0.0};
boolean emergencyStop = false;
System.out.println("=== FRC Safe Motor Control System ===");
while (true) {
try {
System.out.println("\n=== Motor Status ===" + (emergencyStop ? " [EMERGENCY STOP]" : ""));
displayMotors(motors, powers, emergencyStop);
if (emergencyStop) {
System.out.println("\nEmergency stop active. Commands:");
System.out.println("R: Reset emergency stop");
System.out.println("Q: Quit");
} else {
System.out.println("\nCommands:");
System.out.println("0-3: Set motor power");
System.out.println("A: Set all motors");
System.out.println("S: Emergency stop");
System.out.println("Q: Quit");
}
System.out.print("Enter command: ");
String command = scanner.nextLine().trim().toUpperCase();
if (command.equals("Q")) {
break;
}
if (emergencyStop) {
if (command.equals("R")) {
emergencyStop = false;
System.out.println("[OK] Emergency stop reset. Motors can be controlled.");
} else {
System.out.println("[ERROR] Emergency stop is active. Use 'R' to reset.");
}
continue;
}
if (command.equals("S")) {
emergencyStop = true;
for (int i = 0; i < powers.length; i++) {
powers[i] = 0.0;
}
System.out.println("[ALERT] EMERGENCY STOP ACTIVATED!");
continue;
}
if (command.equals("A")) {
setAllMotors(scanner, powers);
} else if (command.matches("[0-3]")) {
int motorIndex = Integer.parseInt(command);
setIndividualMotor(scanner, motors, powers, motorIndex);
} else {
System.out.println("[ERROR] Invalid command: " + command);
}
} catch (Exception e) {
System.out.println("[ERROR] Critical error: " + e.getMessage());
System.out.println("[ALERT] Activating emergency stop for safety!");
emergencyStop = true;
for (int i = 0; i < powers.length; i++) {
powers[i] = 0.0;
}
}
}
// Shutdown sequence
System.out.println("\n[STOP] Shutting down motor control system...");
for (int i = 0; i < powers.length; i++) {
powers[i] = 0.0;
}
System.out.println("All motors stopped. System shut down safely.");
}
public static void displayMotors(String[] motors, double[] powers, boolean emergencyStop) {
for (int i = 0; i < motors.length; i++) {
String status = emergencyStop ? "[STOPPED] STOPPED" : (powers[i] == 0 ? "[IDLE] IDLE" : "[RUNNING] RUNNING");
System.out.printf("%d: %-12s %6.2f %s\n", i, motors[i], powers[i], status);
}
}
public static void setIndividualMotor(Scanner scanner, String[] motors, double[] powers, int index) {
try {
System.out.print("Enter power for " + motors[index] + " (-1.0 to 1.0): ");
String powerInput = scanner.nextLine().trim();
double power = Double.parseDouble(powerInput);
if (power < -1.0 || power > 1.0) {
throw new IllegalArgumentException("Power must be between -1.0 and 1.0");
}
powers[index] = power;
System.out.println("[OK] " + motors[index] + " set to " + power);
} catch (NumberFormatException e) {
System.out.println("[ERROR] Invalid power value. Please enter a decimal number.");
} catch (IllegalArgumentException e) {
System.out.println("[ERROR] " + e.getMessage());
}
}
public static void setAllMotors(Scanner scanner, double[] powers) {
try {
System.out.print("Enter power for all motors (-1.0 to 1.0): ");
String powerInput = scanner.nextLine().trim();
double power = Double.parseDouble(powerInput);
if (power < -1.0 || power > 1.0) {
throw new IllegalArgumentException("Power must be between -1.0 and 1.0");
}
for (int i = 0; i < powers.length; i++) {
powers[i] = power;
}
System.out.println("[OK] All motors set to " + power);
} catch (NumberFormatException e) {
System.out.println("[ERROR] Invalid power value. Please enter a decimal number.");
} catch (IllegalArgumentException e) {
System.out.println("[ERROR] " + e.getMessage());
}
}
}
Implement a robot configuration loader with multiple exception types
Implement a robot configuration loader with multiple exception types
import java.util.Scanner;
import java.util.HashMap;
import java.util.Map;
public class RobotConfigLoader {
private static Map<String, String> config = new HashMap<>();
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("=== FRC Robot Configuration Loader ===");
// Load default configuration
loadDefaultConfig();
while (true) {
try {
System.out.println("\nConfiguration Commands:");
System.out.println("1. Load config from input");
System.out.println("2. Display current config");
System.out.println("3. Validate configuration");
System.out.println("4. Save configuration");
System.out.println("0. Exit");
System.out.print("Enter command: ");
String input = scanner.nextLine().trim();
int command = Integer.parseInt(input);
switch (command) {
case 0:
System.out.println("Configuration system shut down.");
return;
case 1:
loadConfigFromInput(scanner);
break;
case 2:
displayConfig();
break;
case 3:
validateConfiguration();
break;
case 4:
saveConfiguration();
break;
default:
throw new IllegalArgumentException("Invalid command: " + command);
}
} catch (NumberFormatException e) {
System.out.println("[ERROR] Please enter a valid command number.");
} catch (IllegalArgumentException e) {
System.out.println("[ERROR] " + e.getMessage());
} catch (Exception e) {
System.out.println("[ERROR] Configuration error: " + e.getMessage());
System.out.println(" Restoring default configuration...");
loadDefaultConfig();
}
}
}
public static void loadDefaultConfig() {
config.clear();
config.put("robot_name", "FRC_Robot");
config.put("team_number", "12345");
config.put("motor_count", "4");
config.put("sensor_count", "5");
config.put("max_speed", "1.0");
System.out.println("[OK] Default configuration loaded.");
}
public static void loadConfigFromInput(Scanner scanner) {
System.out.println("\nEnter configuration values (empty line to finish):");
while (true) {
try {
System.out.print("Key=Value (or press Enter to finish): ");
String line = scanner.nextLine().trim();
if (line.isEmpty()) {
break;
}
if (!line.contains("=")) {
throw new IllegalArgumentException("Invalid format. Use: key=value");
}
String[] parts = line.split("=", 2);
if (parts.length != 2) {
throw new IllegalArgumentException("Invalid format. Use: key=value");
}
String key = parts[0].trim();
String value = parts[1].trim();
if (key.isEmpty() || value.isEmpty()) {
throw new IllegalArgumentException("Key and value cannot be empty");
}
// Validate specific configuration values
validateConfigValue(key, value);
config.put(key, value);
System.out.println("[OK] Set " + key + " = " + value);
} catch (IllegalArgumentException e) {
System.out.println("[ERROR] " + e.getMessage());
} catch (Exception e) {
System.out.println("[ERROR] Error processing input: " + e.getMessage());
}
}
}
public static void validateConfigValue(String key, String value) {
try {
switch (key) {
case "team_number":
int teamNum = Integer.parseInt(value);
if (teamNum < 1 || teamNum > 99999) {
throw new IllegalArgumentException("Team number must be 1-99999");
}
break;
case "motor_count":
int motorCount = Integer.parseInt(value);
if (motorCount < 1 || motorCount > 12) {
throw new IllegalArgumentException("Motor count must be 1-12");
}
break;
case "sensor_count":
int sensorCount = Integer.parseInt(value);
if (sensorCount < 0 || sensorCount > 20) {
throw new IllegalArgumentException("Sensor count must be 0-20");
}
break;
case "max_speed":
double maxSpeed = Double.parseDouble(value);
if (maxSpeed <= 0 || maxSpeed > 1.0) {
throw new IllegalArgumentException("Max speed must be 0.0-1.0");
}
break;
case "robot_name":
if (value.length() > 50) {
throw new IllegalArgumentException("Robot name too long (max 50 chars)");
}
break;
}
} catch (NumberFormatException e) {
throw new IllegalArgumentException("Invalid numeric value for " + key + ": " + value);
}
}
public static void displayConfig() {
System.out.println("\n[LIST] Current Configuration:");
if (config.isEmpty()) {
System.out.println(" No configuration loaded.");
} else {
for (Map.Entry<String, String> entry : config.entrySet()) {
System.out.printf(" %-15s: %s\n", entry.getKey(), entry.getValue());
}
}
}
public static void validateConfiguration() {
System.out.println("\n[CHECK] Validating configuration...");
try {
// Check required fields
String[] required = {"robot_name", "team_number", "motor_count"};
for (String field : required) {
if (!config.containsKey(field)) {
throw new IllegalStateException("Missing required field: " + field);
}
}
// Validate all current values
for (Map.Entry<String, String> entry : config.entrySet()) {
validateConfigValue(entry.getKey(), entry.getValue());
}
System.out.println("[OK] Configuration is valid!");
} catch (IllegalStateException | IllegalArgumentException e) {
System.out.println("[ERROR] Configuration validation failed: " + e.getMessage());
} catch (Exception e) {
System.out.println("[ERROR] Validation error: " + e.getMessage());
}
}
public static void saveConfiguration() {
try {
// Validate before saving
validateConfiguration();
// Simulate saving to file
System.out.println("[SAVE] Saving configuration...");
Thread.sleep(1000); // Simulate file write delay
System.out.println("[OK] Configuration saved successfully!");
} catch (IllegalStateException | IllegalArgumentException e) {
System.out.println("[ERROR] Cannot save invalid configuration: " + e.getMessage());
} catch (InterruptedException e) {
System.out.println("[ERROR] Save operation interrupted.");
} catch (Exception e) {
System.out.println("[ERROR] Save failed: " + e.getMessage());
}
}
}
Design an autonomous routine with step-by-step error handling
Design an autonomous routine with step-by-step error handling
public class AutonomousRoutine {
private static boolean robotInitialized = false;
private static String currentStep = "None";
public static void main(String[] args) {
System.out.println("=== FRC Autonomous Routine with Error Handling ===");
try {
executeAutonomousSequence();
System.out.println("\n[SUCCESS] Autonomous routine completed successfully!");
} catch (Exception e) {
System.out.println("\n[CRITICAL] Autonomous routine failed: " + e.getMessage());
System.out.println("Last completed step: " + currentStep);
emergencyStop();
} finally {
System.out.println("\n[FINISH] Autonomous routine finished.");
shutdownSafely();
}
}
public static void executeAutonomousSequence() {
// Step 1: Initialize Robot
executeStep("Robot Initialization", () -> {
System.out.println("Initializing robot systems...");
if (Math.random() > 0.9) { // 10% chance of init failure
throw new RuntimeException("Hardware initialization failed");
}
robotInitialized = true;
Thread.sleep(500);
});
// Step 2: Move to Scoring Position
executeStep("Move to Scoring Position", () -> {
System.out.println("Moving to scoring position...");
if (!robotInitialized) {
throw new IllegalStateException("Robot not initialized");
}
if (Math.random() > 0.8) { // 20% chance of movement failure
throw new RuntimeException("Obstacle detected - path blocked");
}
Thread.sleep(1000);
});
// Step 3: Deploy Arm
executeStep("Deploy Arm", () -> {
System.out.println("Deploying arm mechanism...");
if (Math.random() > 0.85) { // 15% chance of arm failure
throw new RuntimeException("Arm motor stalled");
}
Thread.sleep(800);
});
// Step 4: Score Element
executeStep("Score Element", () -> {
System.out.println("Scoring game element...");
if (Math.random() > 0.9) { // 10% chance of scoring failure
throw new RuntimeException("Element not detected in gripper");
}
Thread.sleep(600);
});
// Step 5: Return to Start
executeStep("Return to Start", () -> {
System.out.println("Returning to starting position...");
if (Math.random() > 0.95) { // 5% chance of return failure
throw new RuntimeException("Navigation sensor error");
}
Thread.sleep(1200);
});
}
public static void executeStep(String stepName, Runnable stepCode) {
int maxRetries = 2;
int retryCount = 0;
while (retryCount <= maxRetries) {
try {
System.out.println("\n[STEP] Executing: " + stepName +
(retryCount > 0 ? " (Retry " + retryCount + ")" : ""));
stepCode.run();
currentStep = stepName;
System.out.println("[OK] Completed: " + stepName);
return; // Success - exit retry loop
} catch (RuntimeException e) {
retryCount++;
System.out.println("[ERROR] Step failed: " + stepName + " - " + e.getMessage());
if (retryCount <= maxRetries) {
System.out.println("[RETRY] Attempting recovery and retry...");
try {
performStepRecovery(stepName);
Thread.sleep(500); // Recovery delay
} catch (Exception recoveryError) {
System.out.println("[WARNING] Recovery failed: " + recoveryError.getMessage());
}
} else {
System.out.println("[CRITICAL] Max retries exceeded for step: " + stepName);
throw new RuntimeException("Step " + stepName + " failed after " + maxRetries + " retries: " + e.getMessage());
}
} catch (InterruptedException e) {
System.out.println("[IDLE] Step interrupted: " + stepName);
Thread.currentThread().interrupt();
throw new RuntimeException("Step interrupted: " + stepName);
} catch (Exception e) {
System.out.println("[CRITICAL] Unexpected error in step: " + stepName + " - " + e.getMessage());
throw new RuntimeException("Unexpected error in " + stepName + ": " + e.getMessage());
}
}
}
public static void performStepRecovery(String stepName) {
System.out.println(" [REPAIR] Performing recovery for: " + stepName);
switch (stepName) {
case "Robot Initialization":
System.out.println(" → Resetting hardware connections");
System.out.println(" → Clearing error flags");
robotInitialized = false; // Force re-initialization
break;
case "Move to Scoring Position":
System.out.println(" → Checking for obstacles");
System.out.println(" → Recalculating path");
break;
case "Deploy Arm":
System.out.println(" → Checking arm motor connections");
System.out.println(" → Resetting arm position");
break;
case "Score Element":
System.out.println(" → Checking gripper sensors");
System.out.println(" → Adjusting element position");
break;
case "Return to Start":
System.out.println(" → Recalibrating navigation sensors");
System.out.println(" → Using backup navigation method");
break;
default:
System.out.println(" → Generic recovery procedure");
}
}
public static void emergencyStop() {
try {
System.out.println("\n[ALERT] EMERGENCY STOP ACTIVATED");
System.out.println(" → Stopping all motors");
System.out.println(" → Retracting arm");
System.out.println(" → Disabling autonomous mode");
// Simulate emergency stop procedures
Thread.sleep(200);
System.out.println("[OK] Emergency stop completed");
} catch (InterruptedException e) {
System.out.println("[ERROR] Emergency stop interrupted - CRITICAL!");
Thread.currentThread().interrupt();
} catch (Exception e) {
System.out.println("[CRITICAL] Error during emergency stop: " + e.getMessage());
}
}
public static void shutdownSafely() {
try {
System.out.println("\n[RETRY] Performing safe shutdown...");
System.out.println(" → Stopping all motors");
System.out.println(" → Saving telemetry data");
System.out.println(" → Closing sensor connections");
Thread.sleep(300);
System.out.println("[OK] Safe shutdown completed");
} catch (InterruptedException e) {
System.out.println("[WARNING] Shutdown interrupted");
Thread.currentThread().interrupt();
} catch (Exception e) {
System.out.println("[ERROR] Error during shutdown: " + e.getMessage());
}
}
}