001/*----------------------------------------------------------------------------*/
002/* Copyright (c) FIRST 2008-2017. All Rights Reserved.                        */
003/* Open Source Software - may be modified and shared by FRC teams. The code   */
004/* must be accompanied by the FIRST BSD license file in the root directory of */
005/* the project.                                                               */
006/*----------------------------------------------------------------------------*/
007
008package edu.wpi.first.wpilibj;
009
010import edu.wpi.first.wpilibj.hal.FRCNetComm.tInstances;
011import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
012import edu.wpi.first.wpilibj.hal.HAL;
013import edu.wpi.first.wpilibj.livewindow.LiveWindow;
014
015/**
016 * IterativeRobot implements a specific type of Robot Program framework, extending the RobotBase
017 * class.
018 *
019 * <p>The IterativeRobot class is intended to be subclassed by a user creating a robot program.
020 *
021 * <p>This class is intended to implement the "old style" default code, by providing the following
022 * functions which are called by the main loop, startCompetition(), at the appropriate times:
023 *
024 * <p>robotInit() -- provide for initialization at robot power-on
025 *
026 * <p>init() functions -- each of the following functions is called once when the appropriate mode
027 * is entered: - DisabledInit() -- called only when first disabled - AutonomousInit() -- called each
028 * and every time autonomous is entered from another mode - TeleopInit() -- called each and every
029 * time teleop is entered from another mode - TestInit() -- called each and every time test mode is
030 * entered from anothermode
031 *
032 * <p>Periodic() functions -- each of these functions is called iteratively at the appropriate
033 * periodic rate (aka the "slow loop"). The period of the iterative robot is synced to the driver
034 * station control packets, giving a periodic frequency of about 50Hz (50 times per second). -
035 * disabledPeriodic() - autonomousPeriodic() - teleopPeriodic() - testPeriodoc()
036 */
037public class IterativeRobot extends RobotBase {
038  private boolean m_disabledInitialized;
039  private boolean m_autonomousInitialized;
040  private boolean m_teleopInitialized;
041  private boolean m_testInitialized;
042
043  /**
044   * Constructor for RobotIterativeBase.
045   *
046   * <p>The constructor initializes the instance variables for the robot to indicate the status of
047   * initialization for disabled, autonomous, and teleop code.
048   */
049  public IterativeRobot() {
050    // set status for initialization of disabled, autonomous, and teleop code.
051    m_disabledInitialized = false;
052    m_autonomousInitialized = false;
053    m_teleopInitialized = false;
054    m_testInitialized = false;
055  }
056
057  /**
058   * Provide an alternate "main loop" via startCompetition().
059   */
060  public void startCompetition() {
061    HAL.report(tResourceType.kResourceType_Framework,
062                                   tInstances.kFramework_Iterative);
063
064    robotInit();
065
066    // Tell the DS that the robot is ready to be enabled
067    HAL.observeUserProgramStarting();
068
069    // loop forever, calling the appropriate mode-dependent function
070    LiveWindow.setEnabled(false);
071    while (true) {
072      // Wait for new data to arrive
073      m_ds.waitForData();
074      // Call the appropriate function depending upon the current robot mode
075      if (isDisabled()) {
076        // call DisabledInit() if we are now just entering disabled mode from
077        // either a different mode or from power-on
078        if (!m_disabledInitialized) {
079          LiveWindow.setEnabled(false);
080          disabledInit();
081          m_disabledInitialized = true;
082          // reset the initialization flags for the other modes
083          m_autonomousInitialized = false;
084          m_teleopInitialized = false;
085          m_testInitialized = false;
086        }
087        HAL.observeUserProgramDisabled();
088        disabledPeriodic();
089      } else if (isTest()) {
090        // call TestInit() if we are now just entering test mode from either
091        // a different mode or from power-on
092        if (!m_testInitialized) {
093          LiveWindow.setEnabled(true);
094          testInit();
095          m_testInitialized = true;
096          m_autonomousInitialized = false;
097          m_teleopInitialized = false;
098          m_disabledInitialized = false;
099        }
100        HAL.observeUserProgramTest();
101        testPeriodic();
102      } else if (isAutonomous()) {
103        // call Autonomous_Init() if this is the first time
104        // we've entered autonomous_mode
105        if (!m_autonomousInitialized) {
106          LiveWindow.setEnabled(false);
107          // KBS NOTE: old code reset all PWMs and relays to "safe values"
108          // whenever entering autonomous mode, before calling
109          // "Autonomous_Init()"
110          autonomousInit();
111          m_autonomousInitialized = true;
112          m_testInitialized = false;
113          m_teleopInitialized = false;
114          m_disabledInitialized = false;
115        }
116        HAL.observeUserProgramAutonomous();
117        autonomousPeriodic();
118      } else {
119        // call Teleop_Init() if this is the first time
120        // we've entered teleop_mode
121        if (!m_teleopInitialized) {
122          LiveWindow.setEnabled(false);
123          teleopInit();
124          m_teleopInitialized = true;
125          m_testInitialized = false;
126          m_autonomousInitialized = false;
127          m_disabledInitialized = false;
128        }
129        HAL.observeUserProgramTeleop();
130        teleopPeriodic();
131      }
132      robotPeriodic();
133    }
134  }
135
136  /* ----------- Overridable initialization code ----------------- */
137
138  /**
139   * Robot-wide initialization code should go here.
140   *
141   * <p>Users should override this method for default Robot-wide initialization which will be called
142   * when the robot is first powered on. It will be called exactly one time.
143   *
144   * <p>Warning: the Driver Station "Robot Code" light and FMS "Robot Ready" indicators will be off
145   * until RobotInit() exits. Code in RobotInit() that waits for enable will cause the robot to
146   * never indicate that the code is ready, causing the robot to be bypassed in a match.
147   */
148  public void robotInit() {
149    System.out.println("Default IterativeRobot.robotInit() method... Overload me!");
150  }
151
152  /**
153   * Initialization code for disabled mode should go here.
154   *
155   * <p>Users should override this method for initialization code which will be called each time the
156   * robot enters disabled mode.
157   */
158  public void disabledInit() {
159    System.out.println("Default IterativeRobot.disabledInit() method... Overload me!");
160  }
161
162  /**
163   * Initialization code for autonomous mode should go here.
164   *
165   * <p>Users should override this method for initialization code which will be called each time the
166   * robot enters autonomous mode.
167   */
168  public void autonomousInit() {
169    System.out.println("Default IterativeRobot.autonomousInit() method... Overload me!");
170  }
171
172  /**
173   * Initialization code for teleop mode should go here.
174   *
175   * <p>Users should override this method for initialization code which will be called each time the
176   * robot enters teleop mode.
177   */
178  public void teleopInit() {
179    System.out.println("Default IterativeRobot.teleopInit() method... Overload me!");
180  }
181
182  /**
183   * Initialization code for test mode should go here.
184   *
185   * <p>Users should override this method for initialization code which will be called each time the
186   * robot enters test mode.
187   */
188  @SuppressWarnings("PMD.JUnit4TestShouldUseTestAnnotation")
189  public void testInit() {
190    System.out.println("Default IterativeRobot.testInit() method... Overload me!");
191  }
192
193  /* ----------- Overridable periodic code ----------------- */
194
195  private boolean m_rpFirstRun = true;
196
197  /**
198   * Periodic code for all robot modes should go here.
199   *
200   * <p>This function is called each time a new packet is received from the driver station.
201   *
202   * <p>Packets are received approximately every 20ms.  Fixed loop timing is not guaranteed due to
203   * network timing variability and the function may not be called at all if the Driver Station is
204   * disconnected.  For most use cases the variable timing will not be an issue.  If your code does
205   * require guaranteed fixed periodic timing, consider using Notifier or PIDController instead.
206   */
207  public void robotPeriodic() {
208    if (m_rpFirstRun) {
209      System.out.println("Default IterativeRobot.robotPeriodic() method... Overload me!");
210      m_rpFirstRun = false;
211    }
212  }
213
214  private boolean m_dpFirstRun = true;
215
216  /**
217   * Periodic code for disabled mode should go here.
218   *
219   * <p>Users should override this method for code which will be called each time a new packet is
220   * received from the driver station and the robot is in disabled mode.
221   *
222   * <p>Packets are received approximately every 20ms.  Fixed loop timing is not guaranteed due to
223   * network timing variability and the function may not be called at all if the Driver Station is
224   * disconnected.  For most use cases the variable timing will not be an issue.  If your code does
225   * require guaranteed fixed periodic timing, consider using Notifier or PIDController instead.
226   */
227  public void disabledPeriodic() {
228    if (m_dpFirstRun) {
229      System.out.println("Default IterativeRobot.disabledPeriodic() method... Overload me!");
230      m_dpFirstRun = false;
231    }
232  }
233
234  private boolean m_apFirstRun = true;
235
236  /**
237   * Periodic code for autonomous mode should go here.
238   *
239   * <p>Users should override this method for code which will be called each time a new packet is
240   * received from the driver station and the robot is in autonomous mode.
241   *
242   * <p>Packets are received approximately every 20ms.  Fixed loop timing is not guaranteed due to
243   * network timing variability and the function may not be called at all if the Driver Station is
244   * disconnected.  For most use cases the variable timing will not be an issue.  If your code does
245   * require guaranteed fixed periodic timing, consider using Notifier or PIDController instead.
246   */
247  public void autonomousPeriodic() {
248    if (m_apFirstRun) {
249      System.out.println("Default IterativeRobot.autonomousPeriodic() method... Overload me!");
250      m_apFirstRun = false;
251    }
252  }
253
254  private boolean m_tpFirstRun = true;
255
256  /**
257   * Periodic code for teleop mode should go here.
258   *
259   * <p>Users should override this method for code which will be called each time a new packet is
260   * received from the driver station and the robot is in teleop mode.
261   *
262   * <p>Packets are received approximately every 20ms.  Fixed loop timing is not guaranteed due to
263   * network timing variability and the function may not be called at all if the Driver Station is
264   * disconnected.  For most use cases the variable timing will not be an issue.  If your code does
265   * require guaranteed fixed periodic timing, consider using Notifier or PIDController instead.
266   */
267  public void teleopPeriodic() {
268    if (m_tpFirstRun) {
269      System.out.println("Default IterativeRobot.teleopPeriodic() method... Overload me!");
270      m_tpFirstRun = false;
271    }
272  }
273
274  private boolean m_tmpFirstRun = true;
275
276  /**
277   * Periodic code for test mode should go here.
278   *
279   * <p>Users should override this method for code which will be called each time a new packet is
280   * received from the driver station and the robot is in test mode.
281   *
282   * <p>Packets are received approximately every 20ms.  Fixed loop timing is not guaranteed due to
283   * network timing variability and the function may not be called at all if the Driver Station is
284   * disconnected.  For most use cases the variable timing will not be an issue.  If your code does
285   * require guaranteed fixed periodic timing, consider using Notifier or PIDController instead.
286   */
287  @SuppressWarnings("PMD.JUnit4TestShouldUseTestAnnotation")
288  public void testPeriodic() {
289    if (m_tmpFirstRun) {
290      System.out.println("Default IterativeRobot.testPeriodic() method... Overload me!");
291      m_tmpFirstRun = false;
292    }
293  }
294}