Announcement

Collapse
No announcement yet.

Asynchronous / Multi-threading Functions in Autonomous

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

  • Asynchronous / Multi-threading Functions in Autonomous

    Greetings all -- looking to speed up our Autonomous -- ie. move X motor and Y motor at the same time (but either for different sleep duration or to different encoder values, so can't just set power to both and sleep - which we do currently to run multiple motors at the same time).

    The team is researching asynchronous / multi-threading -- and found the following article https://developer.samsung.com/galaxy...ing-in-android

    Our Attempt #1:

    new Thread(new Runnable() {
    @Override
    public void run() {
    robot.extendArmMotor.setPower(1);
    sleep(1000);
    }
    }).start();

    new Thread(new Runnable() {
    @Override
    public void run() {
    robot.liftMotor.setPower(1);
    sleep(3000);
    }
    }).start();

    Our Attempt #2:

    public class ExtendArmAsync extends Thread {
    @Override
    public void run() {
    robot.extendArmMotor.setPower(1);
    sleep(1000);
    }
    }

    public class RaiseLifterAsync extends Thread {
    @Override
    public void run() {
    robot.liftMotor.setPower(1);
    sleep(3000);
    }
    }

    Call the above using

    new ExtendArmAsync().start();
    new RaiseLifterAsync().start();


    Neither of these approaches work as expected -- ie. don't run for the entire sleep, etc.

    These were just tests -- so no running to encoder (yet).

    This should be pretty simple -- so any words of wisdom from teams that have gotten this working would be highly appreciated...

    Good Coding to All!



    Team Phoenix Force - FTC 10100
    www.FTCRobotics.com

  • #2
    You can accomplish this sort of thing with a state machine. For instance, here is my state machine for deploying the team marker. Notice that the runIteration() method is not blocking. This allows you to run multiple state machine simultaneously with cooperative multitasking.

    Code:
    package net.frogbots.roverruckus.opmodes.extended.auto;
    
    import net.frogbots.roverruckus.meta.statemachine.StateMachineImpl;
    
    public class DeployMarkerStateMachine extends StateMachineImpl<DeployMarkerStateMachine.State>
    {
        @Override
        public String getName()
        {
            return "DeployMarkerStateMachine";
        }
    
        enum State
        {
            START,
            LOWER_INTAKE,
            SPIT_MARKER,
            RAISE_INTAKE,
            END
        }
    
        DeployMarkerStateMachine()
        {
            state = State.START;
        }
    
        @Override
        public ReturnState runIteration()
        {
            switch (state)
            {
                case START:
                {
                    switchState(State.LOWER_INTAKE);
                    break;
                }
    
                case LOWER_INTAKE:
                {
                    robot.intake.setFlipPower(-1, true);
    
                    if(robot.intake.getFlipPosition() < robot.intake.MIN_ENCODER_COUNT)
                    {
                        robot.intake.setFlipPower(0, true);
                        switchState(State.SPIT_MARKER);
                    }
    
                    break;
                }
    
                case SPIT_MARKER:
                {
                    if(getElapsedStateTime() < 1000)
                    {
                        robot.intake.reverseNFT();
                    }
                    else
                    {
                        robot.intake.stopNFT();
                        switchState(State.RAISE_INTAKE);
                    }
                    break;
                }
    
                case RAISE_INTAKE:
                {
                    robot.intake.commandPidRaise();
                    switchState(State.END);
    
                    /*robot.intake.setFlipPower(1, true);
    
                    if(robot.intake.getFlipPosition() > robot.intake.TRANSFER_ENCODER_COUNT)
                    {
                        robot.intake.setFlipPower(0, true);
                        switchState(State.END);
                    }*/
    
                    break;
                }
    
                case END:
                {
                    return ReturnState.PROCEED;
                }
            }
    
            return ReturnState.KEEP_RUNNING_ME;
        }
    }

    Comment


    • #3
      We use state machines as well to accomplish multiple "simultaneous" tasks in autonomous, and in tele-op. Our state machines are object-oriented states, but the concept is the same. It also allows us to re-use mechanisms between autonomous and tele-op.

      The only place we use a separate thread is with VuForia, and this season TensorFlow, to save time, and to make our OpModes that use those libraries more robust to failures -- for example this season, if TF crashes, or fails to find the gold mineral, the team's autonomous program isn't adversely affected.

      Our research has dug up enough anecdotal evidence that threads and the SDK don't always play well together, so we've avoided using them when working with the FTC SDK methods dealing with sensors, motors, etc.

      Comment


      • #4
        There are very few reasons in FTC to use multithreaded solutions. In your case I think you would be adding complexity and difficult to resolve problems for very little benefit.

        Comment


        • #5
          Appreciate everyone's feedback -- as to doing this yielding "very little benefit" -- I would counter with the fact that everyone only has 30 seconds for autonomous -- if we can move multiple elements on the robot at the same time (as opposed to sequentially) -- that is often the difference between finishing in 30 seconds or not.

          Even from FLL - teams have experience with parallel operations (as it's easy to do in mindstorms), and this is obviously done in real world robotics, programming, etc.

          So coming up a with an easily understandable and easily implemented code example does have important role to continue to elevate the possibility of a team's ability to accomplish even more amazing things in autonomous.

          To your points however, it does have the possibilities to introduce complexity -- thus a clean example is needed.

          We'll certainly need to play around more with the state machine approach -- thank you to "4634 Programmer" very much for that example!

          Everyone here is amazing... good coding to all... and remember -- "...with great code, comes great responsibility..."
          Team Phoenix Force - FTC 10100
          www.FTCRobotics.com

          Comment


          • #6
            Lance, you are correct that parallel operations are done in the real world, but the FTC architecture isn't really conducive to doing it. Main problem in using states is the unpredictability of loop times.

            The "real-world" would never use Java for the lower-level critical control, we use compiled C running on our microcontrollers. In my mind, the "ideal" architecture would have a microcontroller running all the real-time control, then interface to higher level UI. All of the critical timing things would be done on the microcontroller, and you wouldn't worry about the limitations Java for control.

            There is a certain "leveling the playing field" aspect of FTC. Since the control under Java is really dodgy, the occasional burps and lack of precise control forces teams to put in some extra work to gain consistency.

            Comment


            • #7
              Lance - you say sequential, but it isn't really sequential even without multithreading. For instance, you said you wanted to move 2 motors running for different amounts of time. You can do that without multithreading much easier than you can do it with multithreading. I would love to have some reasons to do multithreaded, I really would, but the benefits are rarely there compared to the problems you can introduce in FTC. I have mentored 4 teams for 5 years, and in that time we have done multithreading once, and I am a relatively proficient programmer.

              robot.extendArmMotor.setPower(1);
              robot.liftMotor.setPower(1);
              sleep(1000);
              robot.extendArmMotor.setPower(0);
              sleep(2000);
              robot.liftMotor.setPower(0);

              This is essentially parallel as the bulk of your time is with the motors running, and the setting them running is a tremendously small fraction of that time and in real world happening simultaneously.

              Without seeing the rest of your code, I would guess perhaps the main is ending and the threads are dying as a result. Try putting a sleep(3000); after your thread starts. Also, you need to add a setPower(0); after your sleeps in your different thread functions or the motors will keep running. There are a few other multithreading things that should be reinforced if you used multithreading more, but shouldn't cause a problem in your simple use case.

              Sorry if "very little benefit" was in some way taken poorly. Perhaps that wasn't worded well, but I do want to help you be successful.

              Comment


              • #8
                We are interested multithreading because it would simplify multitasking for us. But, we don't do it because we don't know how the various parts of the FTC SDK might get broken.

                We like to use a true linear approach to our autonomous programming, as opposed to a state machine (just our preference). We have several tried and true, very flexible methods for navigating our mechanum-wheeled bot, which we call in sequence. For example, one method causes the bot to drive straight in any specified direction, at a specified speed, while maintaining the bot's orientation at any specified direction, stopping when the "isTrue" method of a Predicate object passed in as an argument becomes true.

                Sometimes, we'd like to do something else while navigating, such as move an arm to a specified position and hold it there (we use a gyro to get arm position, because the encoders on its two motors are broken). We'd rather not write a new version of our navigation method just to add arm-control to it. Multi-threading could be a great solution, but we don't do it.

                Our workaround is to add the arm-control code to the "isTrue" method of the Predicate object that gets passed in to our navigation method, as it gets called during each iteration of the control loop in the navigation method.

                Comment

                Working...
                X