Chief Delphi

Chief Delphi (http://www.chiefdelphi.com/forums/index.php)
-   Java (http://www.chiefdelphi.com/forums/forumdisplay.php?f=184)
-   -   Using Coniditionals to Build Custom Command Groups (http://www.chiefdelphi.com/forums/showthread.php?t=126305)

aziobro 12-02-2014 11:28

Using Coniditionals to Build Custom Command Groups
 
What is the proper way to build a custom command group based on a runtime change?

Example:
Program will look at smartdashboard and get the number of blobs seen.
Based on the number it will either drive straight and shot or
turn, drive straight and shoot.

I tied the following code in the command group constructor.

Code:

if (blobs < 2.0) {
            addSequential(new DriveToLeftAndPrepareShot());
            addSequential(new ShortDelay());
            addSequential(new TossBall3QPower());
            addSequential(new TossBallResetPosition());
           
        }
        else
        {
            addSequential(new DriveToRightAndPrepareShot());
            addSequential(new ShortDelay());
            addSequential(new TossBall3QPower());
            addSequential(new TossBallResetPosition());
        }

But it gets run during program load when the command group is constructed.
I want it to run After autonomous is started.

Joe Ross 12-02-2014 12:02

Re: Using Coniditionals to Build Custom Command Groups
 
Why not have two command groups built, and then decide which to run at the beginning of Autonomous? This is what we've done in the past.

Alternately, you would build the Command Group in your autonomousInit, rather then in the constructor of the Command Group.

aziobro 12-02-2014 12:22

Re: Using Coniditionals to Build Custom Command Groups
 
The addsequential method does not work in a command for me?

It says that it is not defined.

I think that only works in a command group?

Joe Ross 12-02-2014 12:34

Re: Using Coniditionals to Build Custom Command Groups
 
Quote:

Originally Posted by aziobro (Post 1341814)
The addsequential method does not work in a command for me?

It says that it is not defined.

I think that only works in a command group?

That's correct.

mwtidd 12-02-2014 15:15

Re: Using Coniditionals to Build Custom Command Groups
 
One thing we did, was stored the hot value in the Robot variable to reference later.

Here is an example of how we did that:

DriveForwardAndWatch:
-drives forward for n seconds
-watches while doing it
-if it determines the goal is hot, writes to the Robot hot variable.

WaitForShot:
-checks to see whether or not the first command saw hot through the Robot hot variable
-if it saw hot, finish
-if it didn't wait for n seconds

Shoot:
-

Not exactly what you were looking for, but may be good enough.

I for one wish there was a better way to do conditional commands, to support more complex state machines (i.e. firing different commands on success, failure, and timeout). However, I've never really been able to get this to work with the wpilib command structure.

otherguy 13-02-2014 00:12

Re: Using Coniditionals to Build Custom Command Groups
 
Quote:

Originally Posted by aziobro (Post 1341770)
But it gets run during program load when the command group is constructed.
I want it to run After autonomous is started.

Move where you're instantiating the auto command. I think the default project creates the auto command in robotInit(). I'll assume that's where you're instantiating the command in your program.

If you move this statement down into autoInit() you should get what you're asking for, no?

Code:

public void autonomousInit() {
            // instantiate and schedule the command used for the autonomous period
        autonomousCommand = new YourAutoCommand();
        autonomousCommand.start();

...


Ginto8 13-02-2014 01:48

Re: Using Coniditionals to Build Custom Command Groups
 
My team created a class just for this purpose here. To use it:
Code:

addSequential(new Conditional(<Command for true>,<Command for false>) {
    protected boolean condition() {
        return <condition>;
    }
});

<Command for true> and <Command for false> can be any command, or null if you want nothing to run in that case.

pblankenbaker 13-02-2014 06:25

Re: Using Coniditionals to Build Custom Command Groups
 
Quote:

Originally Posted by Ginto8 (Post 1342247)
My team created a class just for this purpose here. To use it:
Code:

addSequential(new Conditional(<Command for true>,<Command for false>) {
    protected boolean condition() {
        return <condition>;
    }
});

<Command for true> and <Command for false> can be any command, or null if you want nothing to run in that case.

Hey, just wanted to say thanks for posting your Conditional class - that is an awesome solution to dealing with building conditional command groups! I will be forwarding this to our programmers as they were just recently asking about conditional commands.

irvingc 13-02-2014 20:00

Re: Using Coniditionals to Build Custom Command Groups
 
Quote:

Originally Posted by Ginto8 (Post 1342247)
My team created a class just for this purpose here. To use it:
Code:

addSequential(new Conditional(<Command for true>,<Command for false>) {
    protected boolean condition() {
        return <condition>;
    }
});

<Command for true> and <Command for false> can be any command, or null if you want nothing to run in that case.

Have you tested your full autonomous sequence to be working using this Conditional command? My experience is that this pattern (a Command that instantiates and then .start()s another Command) does not work as intended.

Ginto8 13-02-2014 20:55

Re: Using Coniditionals to Build Custom Command Groups
 
Quote:

Originally Posted by irvingc (Post 1342777)
Have you tested your full autonomous sequence to be working using this Conditional command? My experience is that this pattern (a Command that instantiates and then .start()s another Command) does not work as intended.

We haven't had a chance to thoroughly test it, but initial tests seem successful. The key aspect of this implementation is that it does not just start the Command, but also waits for the Command to finish. There may be an issue with the internal Command killing the CommandGroup it is called from because they each require() the same Subsystem. I will see what I can do to mitigate that.

irvingc 14-02-2014 01:33

Re: Using Coniditionals to Build Custom Command Groups
 
Quote:

Originally Posted by Ginto8 (Post 1342797)
<snip> There may be an issue with the internal Command killing the CommandGroup it is called from because they each require() the same Subsystem. I will see what I can do to mitigate that.

Yeah, that's exactly the issue we ran into last year. Another drawback we found is that if you put a button on the SmartDashboard for this kind of nested command, you can't click on the button again to cancel the command like usual, because the original command already finished execution, it's the newly instantiated command that's making the robot move.

Anyway, I'll be interested to see what solution you come up with!

Ginto8 15-02-2014 04:50

Re: Using Coniditionals to Build Custom Command Groups
 
We will not be testing this until later today, but I wanted to share my expected solution to Conditional cancelling itself. It requires an extra class, edu.wpi.first.wpilibj.command.PublicCommand, which just exposes a number of Command's methods that are protected or package-private normally:
Code:

package edu.wpi.first.wpilibj.command;

import java.util.Enumeration;

/** A Command that exposes more internals to the world. */
public class PublicCommand extends Command {
    private final Command _c;

    public PublicCommand(Command c) {
        _c = c;
        for(Enumeration e = c.getRequirements();e.hasMoreElements();) {
            requires((Subsystem) e.nextElement());
        }
    }
    public Enumeration getRequirements() {
        return _c.getRequirements();
    }

    public void initialize() {
        if(_c != null) {
            _c.initialize();
        }
    }
    public void _initialize() {
        if(_c != null) {
            _c._initialize();
        }
    }

    public void execute() {
        if(_c != null) {
            _c.execute();
        }
    }
    public void _execute() {
        if(_c != null) {
            _c._execute();
        }
    }

    public boolean isFinished() {
        return _c == null || _c.isFinished();
    }

    public void end() {
        if(_c != null) {
            _c.end();
        }
    }
    public void _end() {
        if(_c != null) {
            _c._end();
        }
    }

    public void interrupted() {
        if(_c != null) {
            _c.interrupted();
        }
    }
    public void _interrupted() {
        if(_c != null) {
            _c._interrupted();
        }
    }
   
}

Then, Conditional becomes:
Code:

package storm2014.commands.control;

import edu.wpi.first.wpilibj.command.Command;
import edu.wpi.first.wpilibj.command.PublicCommand;
import edu.wpi.first.wpilibj.command.Subsystem;
import java.util.Enumeration;

public abstract class Conditional extends Command {
    private final PublicCommand _ifTrue,_ifFalse;
    private PublicCommand _running = null;

    public Conditional(final Command ifTrue,final Command ifFalse) {
        // Wrap the Commands to expose protected methods
        if(ifTrue != null) {
            _ifTrue  = new PublicCommand(ifTrue);
            for(Enumeration e = _ifTrue.getRequirements();e.hasMoreElements();) {
                requires((Subsystem) e.nextElement());
            }
        } else {
            _ifTrue = null;
        }
        if(ifFalse != null) {
            _ifFalse  = new PublicCommand(ifFalse);
            for(Enumeration e = _ifFalse.getRequirements();e.hasMoreElements();) {
                requires((Subsystem) e.nextElement());
            }
        } else {
            _ifFalse = null;
        }
    }
   
    protected abstract boolean condition();

    protected void initialize() {
        if(condition()) {
            _running = _ifTrue;
        } else {
            _running = _ifFalse;
        }
        if(_running != null) {
            _running._initialize();
            _running.initialize();
        }
    }

    protected void execute() {
        if(_running != null) {
            _running._execute();
            _running.execute();
        }
    }

    protected boolean isFinished() {
        return _running == null || _running.isFinished();
    }

    protected void end() {
        if(_running != null) {
            _running._end();
            _running.end();
        }
    }

    protected void interrupted() {
        if(_running != null) {
            _running._interrupted();
            _running.interrupted();
        }
    }
}

Instead of start()ing the Commands, it wraps them entirely. The Conditional has all the combined requirements of ifTrue and ifFalse, and each of initialize(), execute(), isFinished(), end(), and interrupted() call the corresponding method in the selected Command. Because of that, running it should have the same effect as start()ing, except that it will not cancel a CommandGroup it is in.


All times are GMT -5. The time now is 11:20.

Powered by vBulletin® Version 3.6.4
Copyright ©2000 - 2017, Jelsoft Enterprises Ltd.
Copyright © Chief Delphi