2020-12-26 14:12:05 -08:00
|
|
|
// Copyright (c) FIRST and other WPILib contributors.
|
|
|
|
|
// Open Source Software; you can modify and/or share it under the terms of
|
|
|
|
|
// the WPILib BSD license file in the root directory of this project.
|
2013-12-15 18:30:16 -05:00
|
|
|
|
|
|
|
|
package edu.wpi.first.wpilibj;
|
|
|
|
|
|
2018-09-23 21:20:12 -07:00
|
|
|
import edu.wpi.first.cameraserver.CameraServerShared;
|
|
|
|
|
import edu.wpi.first.cameraserver.CameraServerSharedStore;
|
2018-09-20 21:59:46 -07:00
|
|
|
import edu.wpi.first.hal.HAL;
|
|
|
|
|
import edu.wpi.first.hal.HALUtil;
|
2020-08-06 23:57:39 -07:00
|
|
|
import edu.wpi.first.math.MathShared;
|
|
|
|
|
import edu.wpi.first.math.MathSharedStore;
|
2022-10-08 10:01:31 -07:00
|
|
|
import edu.wpi.first.networktables.MultiSubscriber;
|
2024-11-18 09:16:29 -08:00
|
|
|
import edu.wpi.first.networktables.NetworkTableEvent;
|
2017-08-28 00:32:53 -07:00
|
|
|
import edu.wpi.first.networktables.NetworkTableInstance;
|
2023-02-17 17:53:17 -05:00
|
|
|
import edu.wpi.first.util.WPIUtilJNI;
|
2016-10-20 23:54:04 -07:00
|
|
|
import edu.wpi.first.wpilibj.util.WPILibVersion;
|
2020-12-29 22:45:16 -08:00
|
|
|
import java.util.concurrent.locks.ReentrantLock;
|
|
|
|
|
import java.util.function.Supplier;
|
2013-12-15 18:30:16 -05:00
|
|
|
|
|
|
|
|
/**
|
2023-05-13 00:29:39 -04:00
|
|
|
* Implement a Robot Program framework. The RobotBase class is intended to be subclassed to create a
|
|
|
|
|
* robot program. The user must implement {@link #startCompetition()}, which will be called once and
|
|
|
|
|
* is not expected to exit. The user must also implement {@link #endCompetition()}, which signals to
|
|
|
|
|
* the code in {@link #startCompetition()} that it should exit.
|
|
|
|
|
*
|
|
|
|
|
* <p>It is not recommended to subclass this class directly - instead subclass IterativeRobotBase or
|
|
|
|
|
* TimedRobot.
|
2013-12-15 18:30:16 -05:00
|
|
|
*/
|
2018-05-22 23:33:17 -07:00
|
|
|
public abstract class RobotBase implements AutoCloseable {
|
2020-12-29 22:45:16 -08:00
|
|
|
/** The ID of the main Java thread. */
|
2016-12-23 11:48:56 -05:00
|
|
|
// This is usually 1, but it is best to make sure
|
2019-10-07 20:45:33 -07:00
|
|
|
private static long m_threadId = -1;
|
2016-12-23 11:48:56 -05:00
|
|
|
|
2022-10-08 10:01:31 -07:00
|
|
|
private final MultiSubscriber m_suball;
|
|
|
|
|
|
2024-11-18 09:16:29 -08:00
|
|
|
private final int m_connListenerHandle;
|
|
|
|
|
|
2018-04-29 13:29:07 -07:00
|
|
|
private static void setupCameraServerShared() {
|
2020-12-29 22:45:16 -08:00
|
|
|
CameraServerShared shared =
|
|
|
|
|
new CameraServerShared() {
|
|
|
|
|
@Override
|
2025-02-07 12:37:23 -08:00
|
|
|
public void reportUsage(String resource, String data) {
|
|
|
|
|
HAL.reportUsage(resource, data);
|
2020-12-29 22:45:16 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void reportDriverStationError(String error) {
|
|
|
|
|
DriverStation.reportError(error, true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public Long getRobotMainThreadId() {
|
|
|
|
|
return RobotBase.getMainThreadId();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public boolean isRoboRIO() {
|
2023-09-15 20:05:16 -07:00
|
|
|
return !RobotBase.isSimulation();
|
2020-12-29 22:45:16 -08:00
|
|
|
}
|
|
|
|
|
};
|
2018-04-29 13:29:07 -07:00
|
|
|
|
|
|
|
|
CameraServerSharedStore.setCameraServerShared(shared);
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-06 23:57:39 -07:00
|
|
|
private static void setupMathShared() {
|
2020-12-29 22:45:16 -08:00
|
|
|
MathSharedStore.setMathShared(
|
|
|
|
|
new MathShared() {
|
|
|
|
|
@Override
|
|
|
|
|
public void reportError(String error, StackTraceElement[] stackTrace) {
|
|
|
|
|
DriverStation.reportError(error, stackTrace);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
2025-02-07 12:37:23 -08:00
|
|
|
public void reportUsage(String resource, String data) {
|
|
|
|
|
HAL.reportUsage(resource, data);
|
2020-12-29 22:45:16 -08:00
|
|
|
}
|
2023-02-17 17:53:17 -05:00
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public double getTimestamp() {
|
2024-11-16 10:43:38 -05:00
|
|
|
return Timer.getTimestamp();
|
2023-02-17 17:53:17 -05:00
|
|
|
}
|
2020-12-29 22:45:16 -08:00
|
|
|
});
|
2020-08-06 23:57:39 -07:00
|
|
|
}
|
|
|
|
|
|
2015-06-25 15:07:55 -04:00
|
|
|
/**
|
2023-05-13 00:29:39 -04:00
|
|
|
* Constructor for a generic robot program. User code can be placed in the constructor that runs
|
|
|
|
|
* before the Autonomous or Operator Control period starts. The constructor will run to completion
|
|
|
|
|
* before Autonomous is entered.
|
2015-06-25 15:07:55 -04:00
|
|
|
*
|
2016-05-20 12:07:40 -04:00
|
|
|
* <p>This must be used to ensure that the communications code starts. In the future it would be
|
2022-12-26 14:32:13 -05:00
|
|
|
* nice to put this code into its own task that loads on boot so ensure that it runs.
|
2015-06-25 15:07:55 -04:00
|
|
|
*/
|
|
|
|
|
protected RobotBase() {
|
2020-08-06 23:57:39 -07:00
|
|
|
final NetworkTableInstance inst = NetworkTableInstance.getDefault();
|
2025-07-26 06:45:40 +08:00
|
|
|
m_threadId = Thread.currentThread().threadId();
|
2018-04-29 13:29:07 -07:00
|
|
|
setupCameraServerShared();
|
2020-08-06 23:57:39 -07:00
|
|
|
setupMathShared();
|
2022-12-26 14:32:13 -05:00
|
|
|
// subscribe to "" to force persistent values to propagate to local
|
2022-10-08 10:01:31 -07:00
|
|
|
m_suball = new MultiSubscriber(inst, new String[] {""});
|
2023-09-15 20:05:16 -07:00
|
|
|
if (!isSimulation()) {
|
2025-06-02 16:42:56 -07:00
|
|
|
inst.startServer("/home/systemcore/networktables.json");
|
2019-12-29 18:55:02 -06:00
|
|
|
} else {
|
|
|
|
|
inst.startServer();
|
|
|
|
|
}
|
2022-10-08 10:01:31 -07:00
|
|
|
|
|
|
|
|
// wait for the NT server to actually start
|
|
|
|
|
try {
|
|
|
|
|
int count = 0;
|
2022-11-04 20:25:37 -07:00
|
|
|
while (inst.getNetworkMode().contains(NetworkTableInstance.NetworkMode.kStarting)) {
|
2022-10-08 10:01:31 -07:00
|
|
|
Thread.sleep(10);
|
|
|
|
|
count++;
|
|
|
|
|
if (count > 100) {
|
|
|
|
|
throw new InterruptedException();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} catch (InterruptedException ex) {
|
|
|
|
|
System.err.println("timed out while waiting for NT server to start");
|
|
|
|
|
}
|
2017-07-08 10:50:56 -04:00
|
|
|
|
2024-11-18 09:16:29 -08:00
|
|
|
m_connListenerHandle =
|
|
|
|
|
inst.addConnectionListener(
|
|
|
|
|
false,
|
|
|
|
|
event -> {
|
|
|
|
|
if (event.is(NetworkTableEvent.Kind.kConnected)) {
|
2025-02-07 12:37:23 -08:00
|
|
|
HAL.reportUsage("NT/" + event.connInfo.remote_id, "");
|
2024-11-18 09:16:29 -08:00
|
|
|
}
|
|
|
|
|
});
|
2015-06-25 15:07:55 -04:00
|
|
|
}
|
|
|
|
|
|
2024-01-05 07:35:59 -08:00
|
|
|
/**
|
|
|
|
|
* Returns the main thread ID.
|
|
|
|
|
*
|
|
|
|
|
* @return The main thread ID.
|
|
|
|
|
*/
|
2019-10-07 20:45:33 -07:00
|
|
|
public static long getMainThreadId() {
|
|
|
|
|
return m_threadId;
|
|
|
|
|
}
|
|
|
|
|
|
2018-05-22 23:33:17 -07:00
|
|
|
@Override
|
2022-10-08 10:01:31 -07:00
|
|
|
public void close() {
|
|
|
|
|
m_suball.close();
|
2024-11-18 09:16:29 -08:00
|
|
|
NetworkTableInstance.getDefault().removeListener(m_connListenerHandle);
|
2022-10-08 10:01:31 -07:00
|
|
|
}
|
2015-06-25 15:07:55 -04:00
|
|
|
|
2021-09-13 22:05:38 -07:00
|
|
|
/**
|
|
|
|
|
* Get the current runtime type.
|
|
|
|
|
*
|
|
|
|
|
* @return Current runtime type.
|
|
|
|
|
*/
|
|
|
|
|
public static RuntimeType getRuntimeType() {
|
|
|
|
|
return RuntimeType.getValue(HALUtil.getHALRuntimeType());
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-25 15:07:55 -04:00
|
|
|
/**
|
2017-07-28 22:24:05 -07:00
|
|
|
* Get if the robot is a simulation.
|
|
|
|
|
*
|
2015-06-25 15:07:55 -04:00
|
|
|
* @return If the robot is running in simulation.
|
|
|
|
|
*/
|
|
|
|
|
public static boolean isSimulation() {
|
2023-10-18 14:15:35 -07:00
|
|
|
return getRuntimeType() == RuntimeType.kSimulation;
|
2015-06-25 15:07:55 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2017-07-28 22:24:05 -07:00
|
|
|
* Get if the robot is real.
|
|
|
|
|
*
|
2015-06-25 15:07:55 -04:00
|
|
|
* @return If the robot is running in the real world.
|
|
|
|
|
*/
|
|
|
|
|
public static boolean isReal() {
|
2021-09-13 22:05:38 -07:00
|
|
|
RuntimeType runtimeType = getRuntimeType();
|
2025-06-02 16:42:56 -07:00
|
|
|
return runtimeType == RuntimeType.kSystemCore;
|
2015-06-25 15:07:55 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Determine if the Robot is currently disabled.
|
2016-05-20 12:07:40 -04:00
|
|
|
*
|
2023-03-10 22:23:57 -05:00
|
|
|
* @return True if the Robot is currently disabled by the Driver Station.
|
2015-06-25 15:07:55 -04:00
|
|
|
*/
|
|
|
|
|
public boolean isDisabled() {
|
2021-06-15 23:06:03 -07:00
|
|
|
return DriverStation.isDisabled();
|
2015-06-25 15:07:55 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Determine if the Robot is currently enabled.
|
2016-05-20 12:07:40 -04:00
|
|
|
*
|
2023-03-10 22:23:57 -05:00
|
|
|
* @return True if the Robot is currently enabled by the Driver Station.
|
2015-06-25 15:07:55 -04:00
|
|
|
*/
|
|
|
|
|
public boolean isEnabled() {
|
2021-06-15 23:06:03 -07:00
|
|
|
return DriverStation.isEnabled();
|
2015-06-25 15:07:55 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2023-03-10 22:23:57 -05:00
|
|
|
* Determine if the robot is currently in Autonomous mode as determined by the Driver Station.
|
2016-05-20 12:07:40 -04:00
|
|
|
*
|
|
|
|
|
* @return True if the robot is currently operating Autonomously.
|
2015-06-25 15:07:55 -04:00
|
|
|
*/
|
|
|
|
|
public boolean isAutonomous() {
|
2021-06-15 23:06:03 -07:00
|
|
|
return DriverStation.isAutonomous();
|
2015-06-25 15:07:55 -04:00
|
|
|
}
|
|
|
|
|
|
2020-08-29 16:32:19 -04:00
|
|
|
/**
|
2023-03-10 22:23:57 -05:00
|
|
|
* Determine if the robot is currently in Autonomous mode and enabled as determined by the Driver
|
|
|
|
|
* Station.
|
2020-08-29 16:32:19 -04:00
|
|
|
*
|
|
|
|
|
* @return True if the robot is currently operating autonomously while enabled.
|
|
|
|
|
*/
|
|
|
|
|
public boolean isAutonomousEnabled() {
|
2021-06-15 23:06:03 -07:00
|
|
|
return DriverStation.isAutonomousEnabled();
|
2020-08-29 16:32:19 -04:00
|
|
|
}
|
|
|
|
|
|
2015-06-25 15:07:55 -04:00
|
|
|
/**
|
2023-03-10 22:23:57 -05:00
|
|
|
* Determine if the robot is currently in Test mode as determined by the Driver Station.
|
2016-05-20 12:07:40 -04:00
|
|
|
*
|
|
|
|
|
* @return True if the robot is currently operating in Test mode.
|
2015-06-25 15:07:55 -04:00
|
|
|
*/
|
|
|
|
|
public boolean isTest() {
|
2021-06-15 23:06:03 -07:00
|
|
|
return DriverStation.isTest();
|
2015-06-25 15:07:55 -04:00
|
|
|
}
|
|
|
|
|
|
2021-08-11 23:04:43 -07:00
|
|
|
/**
|
2023-03-10 22:23:57 -05:00
|
|
|
* Determine if the robot is current in Test mode and enabled as determined by the Driver Station.
|
|
|
|
|
*
|
|
|
|
|
* @return True if the robot is currently operating in Test mode while enabled.
|
|
|
|
|
*/
|
|
|
|
|
public boolean isTestEnabled() {
|
|
|
|
|
return DriverStation.isTestEnabled();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Determine if the robot is currently in Operator Control mode as determined by the Driver
|
|
|
|
|
* Station.
|
2021-08-11 23:04:43 -07:00
|
|
|
*
|
|
|
|
|
* @return True if the robot is currently operating in Tele-Op mode.
|
|
|
|
|
*/
|
|
|
|
|
public boolean isTeleop() {
|
|
|
|
|
return DriverStation.isTeleop();
|
2015-06-25 15:07:55 -04:00
|
|
|
}
|
|
|
|
|
|
2021-08-11 23:04:43 -07:00
|
|
|
/**
|
2023-03-10 22:23:57 -05:00
|
|
|
* Determine if the robot is currently in Operator Control mode and enabled as determined by the
|
|
|
|
|
* Driver Station.
|
2021-08-11 23:04:43 -07:00
|
|
|
*
|
|
|
|
|
* @return True if the robot is currently operating in Tele-Op mode while enabled.
|
|
|
|
|
*/
|
|
|
|
|
public boolean isTeleopEnabled() {
|
|
|
|
|
return DriverStation.isTeleopEnabled();
|
2020-08-29 16:32:19 -04:00
|
|
|
}
|
|
|
|
|
|
2023-05-13 00:29:39 -04:00
|
|
|
/**
|
|
|
|
|
* Start the main robot code. This function will be called once and should not exit until
|
|
|
|
|
* signalled by {@link #endCompetition()}
|
|
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
public abstract void startCompetition();
|
|
|
|
|
|
2023-05-13 00:29:39 -04:00
|
|
|
/** Ends the main loop in {@link #startCompetition()}. */
|
2019-11-05 21:33:09 -08:00
|
|
|
public abstract void endCompetition();
|
|
|
|
|
|
|
|
|
|
private static final ReentrantLock m_runMutex = new ReentrantLock();
|
|
|
|
|
private static RobotBase m_robotCopy;
|
|
|
|
|
private static boolean m_suppressExitWarning;
|
|
|
|
|
|
2020-12-29 22:45:16 -08:00
|
|
|
/** Run the robot main loop. */
|
2019-09-28 15:43:24 -07:00
|
|
|
private static <T extends RobotBase> void runRobot(Supplier<T> robotSupplier) {
|
2017-07-08 10:50:56 -04:00
|
|
|
System.out.println("********** Robot program starting **********");
|
|
|
|
|
|
2018-07-18 22:01:19 -07:00
|
|
|
T robot;
|
2015-06-25 15:07:55 -04:00
|
|
|
try {
|
2018-07-18 22:01:19 -07:00
|
|
|
robot = robotSupplier.get();
|
2016-05-20 12:07:40 -04:00
|
|
|
} catch (Throwable throwable) {
|
2017-10-30 21:50:14 -07:00
|
|
|
Throwable cause = throwable.getCause();
|
|
|
|
|
if (cause != null) {
|
|
|
|
|
throwable = cause;
|
|
|
|
|
}
|
2018-07-18 22:01:19 -07:00
|
|
|
String robotName = "Unknown";
|
|
|
|
|
StackTraceElement[] elements = throwable.getStackTrace();
|
|
|
|
|
if (elements.length > 0) {
|
|
|
|
|
robotName = elements[0].getClassName();
|
|
|
|
|
}
|
2020-12-29 22:45:16 -08:00
|
|
|
DriverStation.reportError(
|
2023-12-03 16:21:32 -08:00
|
|
|
"Unhandled exception instantiating robot " + robotName + " " + throwable, elements);
|
2021-06-17 23:52:48 -07:00
|
|
|
DriverStation.reportError(
|
2021-06-16 15:24:06 -05:00
|
|
|
"The robot program quit unexpectedly."
|
|
|
|
|
+ " This is usually due to a code error.\n"
|
|
|
|
|
+ " The above stacktrace can help determine where the error occurred.\n"
|
|
|
|
|
+ " See https://wpilib.org/stacktrace for more information.\n",
|
|
|
|
|
false);
|
2017-10-30 21:50:14 -07:00
|
|
|
DriverStation.reportError("Could not instantiate robot " + robotName + "!", false);
|
2015-06-25 15:07:55 -04:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-05 21:33:09 -08:00
|
|
|
m_runMutex.lock();
|
|
|
|
|
m_robotCopy = robot;
|
|
|
|
|
m_runMutex.unlock();
|
|
|
|
|
|
2015-06-25 15:07:55 -04:00
|
|
|
boolean errorOnExit = false;
|
|
|
|
|
try {
|
|
|
|
|
robot.startCompetition();
|
2016-05-20 12:07:40 -04:00
|
|
|
} catch (Throwable throwable) {
|
2017-10-30 21:50:14 -07:00
|
|
|
Throwable cause = throwable.getCause();
|
|
|
|
|
if (cause != null) {
|
|
|
|
|
throwable = cause;
|
|
|
|
|
}
|
2023-12-03 16:21:32 -08:00
|
|
|
DriverStation.reportError("Unhandled exception: " + throwable, throwable.getStackTrace());
|
2015-06-25 15:07:55 -04:00
|
|
|
errorOnExit = true;
|
|
|
|
|
} finally {
|
2019-11-05 21:33:09 -08:00
|
|
|
m_runMutex.lock();
|
|
|
|
|
boolean suppressExitWarning = m_suppressExitWarning;
|
|
|
|
|
m_runMutex.unlock();
|
|
|
|
|
if (!suppressExitWarning) {
|
|
|
|
|
// startCompetition never returns unless exception occurs....
|
2021-06-16 15:24:06 -05:00
|
|
|
DriverStation.reportWarning(
|
|
|
|
|
"The robot program quit unexpectedly."
|
|
|
|
|
+ " This is usually due to a code error.\n"
|
|
|
|
|
+ " The above stacktrace can help determine where the error occurred.\n"
|
|
|
|
|
+ " See https://wpilib.org/stacktrace for more information.",
|
|
|
|
|
false);
|
2019-11-05 21:33:09 -08:00
|
|
|
if (errorOnExit) {
|
|
|
|
|
DriverStation.reportError(
|
|
|
|
|
"The startCompetition() method (or methods called by it) should have "
|
2020-12-29 22:45:16 -08:00
|
|
|
+ "handled the exception above.",
|
|
|
|
|
false);
|
2019-11-05 21:33:09 -08:00
|
|
|
} else {
|
|
|
|
|
DriverStation.reportError("Unexpected return from startCompetition() method.", false);
|
|
|
|
|
}
|
2015-06-25 15:07:55 -04:00
|
|
|
}
|
|
|
|
|
}
|
2019-09-28 15:43:24 -07:00
|
|
|
}
|
|
|
|
|
|
2021-06-10 20:46:47 -07:00
|
|
|
/**
|
2021-06-16 15:24:06 -05:00
|
|
|
* Suppress the "The robot program quit unexpectedly." message.
|
2021-06-10 20:46:47 -07:00
|
|
|
*
|
|
|
|
|
* @param value True if exit warning should be suppressed.
|
|
|
|
|
*/
|
2019-11-05 21:33:09 -08:00
|
|
|
public static void suppressExitWarning(boolean value) {
|
|
|
|
|
m_runMutex.lock();
|
|
|
|
|
m_suppressExitWarning = value;
|
|
|
|
|
m_runMutex.unlock();
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-10 20:46:47 -07:00
|
|
|
/**
|
|
|
|
|
* Starting point for the applications.
|
|
|
|
|
*
|
|
|
|
|
* @param <T> Robot subclass.
|
|
|
|
|
* @param robotSupplier Function that returns an instance of the robot subclass.
|
|
|
|
|
*/
|
2019-09-28 15:43:24 -07:00
|
|
|
public static <T extends RobotBase> void startRobot(Supplier<T> robotSupplier) {
|
2024-11-05 08:51:48 -08:00
|
|
|
// Check that the MSVC runtime is valid.
|
|
|
|
|
WPIUtilJNI.checkMsvcRuntime();
|
|
|
|
|
|
2019-09-28 15:43:24 -07:00
|
|
|
if (!HAL.initialize(500, 0)) {
|
|
|
|
|
throw new IllegalStateException("Failed to initialize. Terminating");
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-15 16:36:44 -08:00
|
|
|
// Force refresh DS data
|
|
|
|
|
DriverStation.refreshData();
|
|
|
|
|
|
2025-02-07 12:37:23 -08:00
|
|
|
HAL.reportUsage("Language", "Java");
|
|
|
|
|
HAL.reportUsage("WPILibVersion", WPILibVersion.Version);
|
2019-09-28 15:43:24 -07:00
|
|
|
|
2021-08-14 11:42:35 -07:00
|
|
|
if (!Notifier.setHALThreadPriority(true, 40)) {
|
|
|
|
|
DriverStation.reportWarning("Setting HAL Notifier RT priority to 40 failed", false);
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-28 15:43:24 -07:00
|
|
|
if (HAL.hasMain()) {
|
2020-12-29 22:45:16 -08:00
|
|
|
Thread thread =
|
|
|
|
|
new Thread(
|
|
|
|
|
() -> {
|
|
|
|
|
runRobot(robotSupplier);
|
|
|
|
|
HAL.exitMain();
|
|
|
|
|
},
|
|
|
|
|
"robot main");
|
2019-09-28 15:43:24 -07:00
|
|
|
thread.setDaemon(true);
|
|
|
|
|
thread.start();
|
|
|
|
|
HAL.runMain();
|
2019-11-05 21:33:09 -08:00
|
|
|
suppressExitWarning(true);
|
|
|
|
|
m_runMutex.lock();
|
|
|
|
|
RobotBase robot = m_robotCopy;
|
|
|
|
|
m_runMutex.unlock();
|
|
|
|
|
if (robot != null) {
|
|
|
|
|
robot.endCompetition();
|
|
|
|
|
}
|
|
|
|
|
try {
|
|
|
|
|
thread.join(1000);
|
|
|
|
|
} catch (InterruptedException ex) {
|
|
|
|
|
Thread.currentThread().interrupt();
|
|
|
|
|
}
|
2019-09-28 15:43:24 -07:00
|
|
|
} else {
|
|
|
|
|
runRobot(robotSupplier);
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-09 09:55:49 -08:00
|
|
|
// On RIO, this will just terminate rather than shutting down cleanly (it's a no-op in sim).
|
|
|
|
|
// It's not worth the risk of hanging on shutdown when we want the code to restart as quickly
|
|
|
|
|
// as possible.
|
|
|
|
|
HAL.terminate();
|
|
|
|
|
|
2020-09-04 08:59:26 -07:00
|
|
|
HAL.shutdown();
|
|
|
|
|
|
2020-08-31 00:34:34 -07:00
|
|
|
System.exit(0);
|
2015-06-25 15:07:55 -04:00
|
|
|
}
|
2013-12-15 18:30:16 -05:00
|
|
|
}
|