mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-23 01:21:42 +00:00
Add loop timing to IterativeRobot and TimedRobot (#781)
This commit is contained in:
committed by
Peter Johnson
parent
50b13d2f36
commit
a818c7fd47
@@ -20,7 +20,14 @@ import edu.wpi.first.wpilibj.hal.HAL;
|
||||
* the driver station.
|
||||
*/
|
||||
public class IterativeRobot extends IterativeRobotBase {
|
||||
private static final double kPacketPeriod = 0.02;
|
||||
|
||||
/**
|
||||
* Create a new IterativeRobot.
|
||||
*/
|
||||
public IterativeRobot() {
|
||||
super(kPacketPeriod);
|
||||
|
||||
HAL.report(tResourceType.kResourceType_Framework, tInstances.kFramework_Iterative);
|
||||
}
|
||||
|
||||
|
||||
@@ -42,6 +42,8 @@ import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard;
|
||||
*/
|
||||
@SuppressWarnings("PMD.TooManyMethods")
|
||||
public abstract class IterativeRobotBase extends RobotBase {
|
||||
protected double m_period;
|
||||
|
||||
private enum Mode {
|
||||
kNone,
|
||||
kDisabled,
|
||||
@@ -51,6 +53,17 @@ public abstract class IterativeRobotBase extends RobotBase {
|
||||
}
|
||||
|
||||
private Mode m_lastMode = Mode.kNone;
|
||||
private final Watchdog m_watchdog;
|
||||
|
||||
/**
|
||||
* Constructor for IterativeRobotBase.
|
||||
*
|
||||
* @param period Period in seconds.
|
||||
*/
|
||||
protected IterativeRobotBase(double period) {
|
||||
m_period = period;
|
||||
m_watchdog = new Watchdog(period, this::printLoopOverrunMessage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide an alternate "main loop" via startCompetition().
|
||||
@@ -179,53 +192,77 @@ public abstract class IterativeRobotBase extends RobotBase {
|
||||
}
|
||||
|
||||
protected void loopFunc() {
|
||||
m_watchdog.reset();
|
||||
|
||||
// Call the appropriate function depending upon the current robot mode
|
||||
if (isDisabled()) {
|
||||
// call DisabledInit() if we are now just entering disabled mode from
|
||||
// either a different mode or from power-on
|
||||
// Call DisabledInit() if we are now just entering disabled mode from either a different mode
|
||||
// or from power-on.
|
||||
if (m_lastMode != Mode.kDisabled) {
|
||||
LiveWindow.setEnabled(false);
|
||||
disabledInit();
|
||||
m_watchdog.addEpoch("disabledInit()");
|
||||
m_lastMode = Mode.kDisabled;
|
||||
}
|
||||
|
||||
HAL.observeUserProgramDisabled();
|
||||
disabledPeriodic();
|
||||
m_watchdog.addEpoch("disablePeroidic()");
|
||||
} else if (isAutonomous()) {
|
||||
// call Autonomous_Init() if this is the first time
|
||||
// we've entered autonomous_mode
|
||||
// Call AutonomousInit() if we are now just entering autonomous mode from either a different
|
||||
// mode or from power-on.
|
||||
if (m_lastMode != Mode.kAutonomous) {
|
||||
LiveWindow.setEnabled(false);
|
||||
// KBS NOTE: old code reset all PWMs and relays to "safe values"
|
||||
// whenever entering autonomous mode, before calling
|
||||
// "Autonomous_Init()"
|
||||
autonomousInit();
|
||||
m_watchdog.addEpoch("autonomousInit()");
|
||||
m_lastMode = Mode.kAutonomous;
|
||||
}
|
||||
|
||||
HAL.observeUserProgramAutonomous();
|
||||
autonomousPeriodic();
|
||||
m_watchdog.addEpoch("autonomousPeriodic()");
|
||||
} else if (isOperatorControl()) {
|
||||
// call Teleop_Init() if this is the first time
|
||||
// we've entered teleop_mode
|
||||
// Call TeleopInit() if we are now just entering teleop mode from either a different mode or
|
||||
// from power-on.
|
||||
if (m_lastMode != Mode.kTeleop) {
|
||||
LiveWindow.setEnabled(false);
|
||||
teleopInit();
|
||||
m_watchdog.addEpoch("teleopInit()");
|
||||
m_lastMode = Mode.kTeleop;
|
||||
}
|
||||
|
||||
HAL.observeUserProgramTeleop();
|
||||
teleopPeriodic();
|
||||
m_watchdog.addEpoch("teleopPeriodic()");
|
||||
} else {
|
||||
// call TestInit() if we are now just entering test mode from either
|
||||
// a different mode or from power-on
|
||||
// Call TestInit() if we are now just entering test mode from either a different mode or from
|
||||
// power-on.
|
||||
if (m_lastMode != Mode.kTest) {
|
||||
LiveWindow.setEnabled(true);
|
||||
testInit();
|
||||
m_watchdog.addEpoch("testInit()");
|
||||
m_lastMode = Mode.kTest;
|
||||
}
|
||||
|
||||
HAL.observeUserProgramTest();
|
||||
testPeriodic();
|
||||
m_watchdog.addEpoch("testPeriodic()");
|
||||
}
|
||||
|
||||
robotPeriodic();
|
||||
m_watchdog.addEpoch("robotPeriodic()");
|
||||
m_watchdog.disable();
|
||||
SmartDashboard.updateValues();
|
||||
|
||||
LiveWindow.updateValues();
|
||||
|
||||
// Warn on loop time overruns
|
||||
if (m_watchdog.isExpired()) {
|
||||
m_watchdog.printEpochs();
|
||||
}
|
||||
}
|
||||
|
||||
private void printLoopOverrunMessage() {
|
||||
DriverStation.reportWarning("Loop time of " + m_period + "s overrun\n", false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,9 +22,6 @@ import edu.wpi.first.wpilibj.hal.NotifierJNI;
|
||||
public class TimedRobot extends IterativeRobotBase {
|
||||
public static final double kDefaultPeriod = 0.02;
|
||||
|
||||
// Prevents loop from starting if user calls setPeriod() in robotInit()
|
||||
private boolean m_startLoop;
|
||||
|
||||
// The C pointer to the notifier object. We don't use it directly, it is
|
||||
// just passed to the JNI bindings.
|
||||
private final int m_notifier = NotifierJNI.initializeNotifier();
|
||||
@@ -32,9 +29,23 @@ public class TimedRobot extends IterativeRobotBase {
|
||||
// The absolute expiration time
|
||||
private double m_expirationTime;
|
||||
|
||||
private double m_period = kDefaultPeriod;
|
||||
private double m_period;
|
||||
|
||||
/**
|
||||
* Constructor for TimedRobot.
|
||||
*/
|
||||
protected TimedRobot() {
|
||||
this(kDefaultPeriod);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for TimedRobot.
|
||||
*
|
||||
* @param period Period in seconds.
|
||||
*/
|
||||
protected TimedRobot(double period) {
|
||||
super(period);
|
||||
|
||||
public TimedRobot() {
|
||||
// HAL.report(tResourceType.kResourceType_Framework, tInstances.kFramework_Periodic);
|
||||
HAL.report(tResourceType.kResourceType_Framework, tInstances.kFramework_Iterative);
|
||||
}
|
||||
@@ -56,8 +67,6 @@ public class TimedRobot extends IterativeRobotBase {
|
||||
// Tell the DS that the robot is ready to be enabled
|
||||
HAL.observeUserProgramStarting();
|
||||
|
||||
m_startLoop = true;
|
||||
|
||||
m_expirationTime = RobotController.getFPGATime() * 1e-6 + m_period;
|
||||
updateAlarm();
|
||||
|
||||
@@ -75,20 +84,6 @@ public class TimedRobot extends IterativeRobotBase {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set time period between calls to Periodic() functions.
|
||||
*
|
||||
* @param period Period in seconds.
|
||||
*/
|
||||
public void setPeriod(double period) {
|
||||
m_period = period;
|
||||
|
||||
if (m_startLoop) {
|
||||
m_expirationTime = RobotController.getFPGATime() * 1e-6 + period;
|
||||
updateAlarm();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get time period between calls to Periodic() functions.
|
||||
*/
|
||||
|
||||
122
wpilibj/src/main/java/edu/wpi/first/wpilibj/Watchdog.java
Normal file
122
wpilibj/src/main/java/edu/wpi/first/wpilibj/Watchdog.java
Normal file
@@ -0,0 +1,122 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
package edu.wpi.first.wpilibj;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A class that's a wrapper around a watchdog timer.
|
||||
*
|
||||
* <p>When the timer expires, a message is printed to the console and an optional user-provided
|
||||
* callback is invoked.
|
||||
*
|
||||
* <p>The watchdog is initialized disabled, so the user needs to call enable() before use.
|
||||
*/
|
||||
public class Watchdog {
|
||||
private double m_timeout;
|
||||
private Runnable m_callback;
|
||||
private Notifier m_notifier;
|
||||
|
||||
private double m_startTime;
|
||||
@SuppressWarnings("PMD.UseConcurrentHashMap")
|
||||
private final Map<String, Double> m_epochs = new HashMap<>();
|
||||
boolean m_isExpired;
|
||||
|
||||
/**
|
||||
* Watchdog constructor.
|
||||
*
|
||||
* @param timeout The watchdog's timeout in seconds.
|
||||
*/
|
||||
public Watchdog(double timeout) {
|
||||
this(timeout, () -> {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Watchdog constructor.
|
||||
*
|
||||
* @param timeout The watchdog's timeout in seconds.
|
||||
* @param callback This function is called when the timeout expires.
|
||||
*/
|
||||
public Watchdog(double timeout, Runnable callback) {
|
||||
m_timeout = timeout;
|
||||
m_callback = callback;
|
||||
m_notifier = new Notifier(this::timeoutFunc);
|
||||
enable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the time in seconds since the watchdog was last fed.
|
||||
*/
|
||||
public double getTime() {
|
||||
return Timer.getFPGATimestamp() - m_startTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the watchdog timer has expired.
|
||||
*/
|
||||
public boolean isExpired() {
|
||||
return m_isExpired;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds time since last epoch to the list printed by printEpochs().
|
||||
*
|
||||
* @param epochName The name to associate with the epoch.
|
||||
*/
|
||||
public void addEpoch(String epochName) {
|
||||
double currentTime = Timer.getFPGATimestamp();
|
||||
m_epochs.put(epochName, currentTime - m_startTime);
|
||||
m_startTime = currentTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints list of epochs added so far and their times.
|
||||
*/
|
||||
public void printEpochs() {
|
||||
m_epochs.forEach((key, value) -> {
|
||||
System.out.println("\t" + key + ": " + value + "s");
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the watchdog timer.
|
||||
*
|
||||
* <p>This also enables the timer if it was previously disabled.
|
||||
*/
|
||||
public void reset() {
|
||||
enable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables the watchdog timer.
|
||||
*/
|
||||
public void enable() {
|
||||
m_startTime = Timer.getFPGATimestamp();
|
||||
m_isExpired = false;
|
||||
m_epochs.clear();
|
||||
m_notifier.startPeriodic(m_timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable the watchdog.
|
||||
*/
|
||||
public void disable() {
|
||||
m_notifier.stop();
|
||||
}
|
||||
|
||||
private void timeoutFunc() {
|
||||
if (!m_isExpired) {
|
||||
System.out.println("Watchdog not fed after " + m_timeout + "s");
|
||||
m_callback.run();
|
||||
m_isExpired = true;
|
||||
disable();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user