Timed robot advantages

Hello all,

My team has traditionally used the iterative robot as our robot type, but I noticed that there is a new timed robot option available. How are you considering this new option and what are some potential advantages and pitfalls?

https://wpilib.screenstepslive.com/s/currentCS/m/java/l/599697-choosing-a-base-class

TimedRobot is the same as IterativeRobot except that it uses a timer (Notifier) to guarantee that the periodic methods are called at a predictable time interval. When getting driver station data such as joystick values the most recent value will be provided since the time interval may not line up with the 20 millisecond delivery of data. This is the recommended base class for most robot programs. Just as with IterativeRobot, it is very important to not have long running code or loops in the periodic methods or the timing may slip.

A predictable and consistent “dt” is great for control loops.

TL;DR1 - Use Timed.

More detailed:

Strictly speaking, no chunk of code should run until at least one new input is available, and the output is ready to receive a new value (otherwise you’re wasting computation).

Model-based languages (hey Labview!) do sort of have a leg up in this regard - the fact you have to draw all input and output relationships explicitly gives more info to the toolchain to allow it to run code only when needed. This of course makes lots of assumptions about how detailed the tool gets into analyzing your code, and how adept the user is an inputting their intentions.

In text-based languages, the onus of this tends to fall on the developer, at development time. Most embedded systems tend to force-simplify the problem into 3 steps:

  1. Sample your inputs
  2. Do calculations
  3. Assign output values

And repeat this at a regular rate (say 20ms). If you have an input arrive, you can still guarantee that it will get processed and affect the output within one loop’s worth of time. This is usually sufficient for most engineering analyses.

The regular rate also allows you to hard-code some constants related to time-based math operations (differentiation, integration, etc), and do calculations of elapsed time based on number of loops executed. This is definitely nice, and a common assumption made when look into the academic theories on such things.

That regular loop rate is very important, though.

Say for example you have a robot with a limit switch, a motor, and a joystick input. The limit switch, when triggered, should shut off the motor to prevent damage to the robot. Say you do the trivial implementation and write all the code in TeleopPeriodic for an Iterative Robot. The sequence of events is:

  1. Wait for DS Packet…
  2. Sample Joystick value and limit switch value
  3. Calculate motor command (based on joystick and limit switch)
  4. Assign motor command
  5. goto 1

Steps 2,3,4, and 5 take a fixed and very small amount of time to execute. Step 1 takes a large and variable amount of time. Remember though that the limit switch could be activated at any time. Say it gets activated right at the start of step 1. Note that we don’t actually read that the switch is pressed (and the robot is in a damaging state) until step 2.

How long do we stay in that damaging condition?

It depends on how frequently the driver station sends update packets. It’s supposed to be a regular rate, but due to multiple reasons it can’t really be guaranteed. **

This is, of course, a sub-optimal user implementation. To do this right, with iterative robot, you’d want to do something like spawning a separate thread to read the sensor and calculate the motor outputs, and force that thread to run at a regular rate.

OR, use a Timed Robot, and accept the fact that some driver station packets may be missed for a loop or two. I personally can’t tell the difference between a 20ms and 60ms delay while driving a robot, so I’d declare this acceptable.

TL;DR2: If you have a Timed Robot, you can sample sensors and do time-based math in your *Periodic() methods, and be guaranteed the delay between sample times is constant (and not tied to DS packet arrival). This is a good thing.

** Aside: There are other factors at play here (namely motor-safety watchdogs NI & WPI implement for us), but I am neglecting those for this analysis. They do help for sure, but drive different assumptions into your system.

So follow-up to the question… With a timed bot… Is the ds packet queued, or ignored. The reason why I ask is we have functions that are “one-click”.

I wouldn’t want the code to miss the button-press just because we didn’t press it during the right window of time.

They are queued.

In the robots periodic functions there is a scheduler, which is run every with loop and manages which functions are run. It’s what calls the methods within a command. When you click the button on your DS, it requests a new instance of that command, which is sent in the next packet. Upon arrival, the command is placed in queue for the next run of the scheduler.

Worst case it takes a few loops to run the command (80ms), but unless there is a communications error the command will run.

When you use a JoystickButton, it uses a PressedButtonScheduler or ReleasedButtonScheduler to check for rising or trailing edge events in the button state. That scheduler is run by the Scheduler in the *Periodic() loop. In IterativeRobot, the event check is performed by the Scheduler every time you receive a new DriverStation packet. You would always see every rising and trailing edge event.

In TimedRobot, the event check is performed at an interval independent of the arrival of DriverStation packets. Let’s say you pressed and released a button super fast such that it went up and down again in one packet (packet 1 has low, packet 2 has high, and packet 3 has low again). If, due to some network packet queuing, you received all three of those packets between when TimedRobot ran the Periodic() function, you would miss that button press. While possible, it’s unlikely. There’s an issue at Fix Trigger missing button press/release events with TimedRobot · Issue #786 · wpilibsuite/allwpilib · GitHub about fixing it. The fix will basically use the method described below but within the button scheduler classes.

A workaround is calling Scheduler::GetInstance()->AddCommand() when Joystick’s GetRawButtonPressed() or GetRawButtonReleased() functions return true (or the equivalents in the XboxController class like GetAButtonPressed()). That button state tracking is done by the DriverStation thread when it receives a new packet, so you won’t miss any events in TimedRobot when your code finally checks for button presses.

The above answer is correct. Another way to think about it:

A “one-click” functionality should run when the robot sees a button go from not-pressed to pressed.

As long as the robot code reads the button value at a rate faster than the driver can pulse the button, you will not miss rising-edge events.

If your code is running slower than the driver inputs, then you will probably have many other problems.

Minor tweak for future readers: “guarantee … 1 loop” is inaccurate except in an unrealistic limiting case. The guarantee is one loop period, plus the time to execute computation and output setting. In a more safety-minded limiting scenario, you might set an upper bound at 2 loops for any input to process, and then just make sure you don’t start to slip tasks. Yay real-time scheduling!