Announcement

Collapse
No announcement yet.

Purpose of idle()

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Purpose of idle()

    I'm not clear on the purpose of adding the idle() call at the end of the while loop. What other processes/threads would be waiting to run?

  • #2
    Hardware read/writes, telemetry, the event loop, etc. run on separate threads from the code in a LinearOpMode. It is good practice to idle() because you likely won't get new values from sensors and timers anywhere near as fast as you would be using them in a tight loop, so you would be wasting significant processing time dealing with the same stale values. You can get strange, unexpected behavior if you rob the SDK internals of their processing time, and this makes it very hard to debug issues caused by a lack of calls to idle().

    Comment


    • #3
      Originally posted by GearTicks View Post
      Hardware read/writes, telemetry, the event loop, etc. run on separate threads from the code in a LinearOpMode. It is good practice to idle() because you likely won't get new values from sensors and timers anywhere near as fast as you would be using them in a tight loop, so you would be wasting significant processing time dealing with the same stale values. You can get strange, unexpected behavior if you rob the SDK internals of their processing time, and this makes it very hard to debug issues caused by a lack of calls to idle().
      Actually, reading sensors and writing to actuators is not effected much (if at all) by the idle() call. These actions are performed inline (synchronously) and don't need background processing like last season.

      My own tests have also shown that the idle() call does not add an appreciable delay to the cycle time of your while loop. If you want to pace your processing, you really need to use a timer of some sort, and add appropriate sleep calls to regulate the loop timing.

      Idle() does do a yield, which permits the OS time for background processing, but another key function of the call is to permit the linear thread to respond to a termination request.
      This is why ALL conditional loops in your code should include a call to idle(), so they can break out if needed.

      Phil.

      Comment


      • #4
        Originally posted by GearTicks View Post
        Hardware read/writes, telemetry, the event loop, etc. run on separate threads from the code in a LinearOpMode. It is good practice to idle() because you likely won't get new values from sensors and timers anywhere near as fast as you would be using them in a tight loop, so you would be wasting significant processing time dealing with the same stale values. You can get strange, unexpected behavior if you rob the SDK internals of their processing time, and this makes it very hard to debug issues caused by a lack of calls to idle().
        Android is a preemptive multi-tasking OS. idle() is just calling Thread.yield(). So it means if your loop is done before your timeslice is up, you are giving it back to the OS so it could give it to somebody else. Even if you don't give it back, you are still just limited by your own timeslice (i.e. you can't hog more than your own timeslice unless you play with thread priorities). Unless the other threads are demanding more than their fair share of time slices, I am not sure why it would cause problems with other threads even if I don't call idle() in our loop. It is true that some sensors don't get benefit even if you read it more frequently. However, if I have other time sensitive processing to do, it may benefit from a tighter loop. I am on the border so I still need some more convincing that I need to call idle().

        Comment


        • #5
          Originally posted by Philbot View Post
          but another key function of the call is to permit the linear thread to respond to a termination request.
          This is why ALL conditional loops in your code should include a call to idle(), so they can break out if needed.

          Phil.
          If your loop has the while (opModeIsActive()) test, it will permit the linear thread to respond to termination request. (i.e. both idle() and opModeIsActive() called isStopRequested()).

          Comment


          • #6
            Originally posted by mikets View Post
            If your loop has the while (opModeIsActive()) test, it will permit the linear thread to respond to termination request. (i.e. both idle() and opModeIsActive() called isStopRequested()).
            I'm quickly getting out of my depth here... can you see the bubbles... so bear with me...
            If you have a opmode while loop that does not ever do a yield (which is what the idle() adds), can you be certain how quickly your app will respond to the condition that causes isStopRequested() to return a true.
            eg: incomming DS requests.

            I don't know if the idle() request is a precaution or essential, but if it improves the reliability of the opMode stopping process, it seems like a very small price to pay.

            Comment


            • #7
              Originally posted by Philbot View Post
              if it improves the reliability of the opMode stopping process, it seems like a very small price to pay.
              Our opmode while loop has the opModeIsActive() call, so responding to StopRequests is not a concern but I agree that if idle() costs very little, there is no reason not to have it. I will do some timing test on it.

              Comment


              • #8
                Originally posted by mikets View Post
                Our opmode while loop has the opModeIsActive() call, so responding to StopRequests is not a concern but I agree that if idle() costs very little, there is no reason not to have it. I will do some timing test on it.
                Just thought I'd follow up on this topic.

                The FTC Tech Team took a hard look at the questions that were raised regarding the use and purpose of the idle() call.
                Also of concern was that the code after the main processing loop wasn't really being executed in a linearOpMode.

                So, in the BETA FTC_SDK that was released today, these issues have been resolved and clarified.

                The main visible change is that LinnearOpMode.runOpMode() is no longer declared as "throws InterruptedException"....

                I'm not an expert here (this was figured out by somone who is) but the upshot of the change is that runOpMode() isn't immediately terminated when the driver presses Stop.
                The main loop is now given the opportunity to detect that opModeIsAtive() is now false, (along with isStopRequested() being True), and it can do any required cleanup.

                Also, to avoid confusion, opModeIsActive() does a yield() automatically, so there is no need to call idle() any more in a loop that is terminating on !opModeIsActive();

                BUT.. If you aren't testing opModeIsActive() an any loop you have (eg: waiting for gyro calibration), you should use one of the other tests (like isStopRequested()) to make sure you exit immediately if the driver presses Stop. This will prevent a Stuck Loop exception.

                There are some caveats...
                1) during your cleanup (any time after Stop is pressed) the sleep() method won't actually sleep. This would potentially delay the stop and cleanup process, so it's short circuited.
                2) If it takes you more than 2 seconds to notice the stop, do your cleanup, and exit runOpMode() then the thread WILL be terminated and a Stuck Stop() exception will occur and your Robot will be reset.

                The great news is:
                All existing opmods will work still with the new system.
                But remember that if that if your runOpMode has "throws InterruptedException" then it will be interrupted immediately when Stop is pressed, and your cleanup code won't get run (unless you explicitly handle the exception).

                So, you should consider just removing "throws InterruptedException" from your linearOpMode.runOpMode() methods.

                Comment


                • #9
                  Great report, Phil! Thanks!

                  May I humbly suggest that you post this information in its own thread or somewhere more noticeable for folks who might not bother to check the 8th post in an old thread?

                  Comment


                  • #10
                    Originally posted by Cheer4FTC View Post
                    Great report, Phil! Thanks!

                    May I humbly suggest that you post this information in its own thread or somewhere more noticeable for folks who might not bother to check the 8th post in an old thread?
                    I think the BETA is due to go official very soon, so there will be a more mainstream post then.

                    Comment


                    • #11
                      Nit: removing the "throws InterruptedException" allows you to easily see if you are calling any functions that can throw an interrupt: your opmode won't compile if you are. That is, it's whether or not you're actually calling any such function that's the important point, whether you've got "throws InterruptedException" in your declaration or not is secondary.

                      Comment


                      • #12
                        Originally posted by Philbot View Post
                        I think the BETA is due to go official very soon, so there will be a more mainstream post then.
                        I hope they release a very accurate account of what changed. We rely on this to figure out what will be broken by this new release in our library. It sounds like our Cooperative Multi-tasking Scheduler module needs to change. We did exception handling on InterruptedException, it sounds like we don't need to do it any more.

                        Comment


                        • #13
                          For those with some git proficiency, using a git merge (w/o commit) of a branch with the 'after' state into a branch with the 'before' state and then looking at the diffs can be a very effective and efficient way of discerning exactly what changed.

                          With regards to interrupts, it's possible that your Scheduler might be able to become simpler now, but the existing behavior will absolutely continue to work.

                          Comment


                          • #14
                            Pardon my thickness: that is, of course, regrettably made more difficult by the current packaging approach which has much in binary form.

                            Comment


                            • #15
                              Originally posted by FTC0417 View Post
                              Pardon my thickness: that is, of course, regrettably made more difficult by the current packaging approach which has much in binary form.
                              Yep, exactly.

                              Comment

                              Working...
                              X