Chief Delphi

Chief Delphi (http://www.chiefdelphi.com/forums/index.php)
-   Programming (http://www.chiefdelphi.com/forums/forumdisplay.php?f=51)
-   -   Making more reusable commands (http://www.chiefdelphi.com/forums/showthread.php?t=123920)

Alan Anderson 03-01-2014 19:25

Re: Making more reusable commands
 
Quote:

Originally Posted by Joe Ross (Post 1319910)
...after writing the same code in a subsystem for the 6th solenoid and the 3rd on/off motor,...

It sounds like you were right when you don't have the experience you need with Object Oriented programming. Instead of writing the same code in multiple places for multiple solenoids, you probably could have extended the Solenoid class with the methods you wanted. Extension though Inheritance is probably one of the best tools you can use for the kind of configurable control you're talking about.

MrRoboSteve 03-01-2014 19:36

Re: Making more reusable commands
 
Here's a nice example of a command that takes a parameter.

Code:

#include "TurnSpecifiedDegreesCommand.h"
#include "math.h"

// If we're within this # of degrees to target, then we're good.

#define DEGREES_PRECISION 2


/*
 * This command turns the number of degrees specified in the dashboard field.
 */
TurnSpecifiedDegreesCommand::TurnSpecifiedDegreesCommand(float degreesToTurn)
        : CommandBase("TurnSpecifiedDegreesCommand") {
        Requires(chassis);
        this->degreesToTurn = degreesToTurn;
}

// Called just before this Command runs the first time
void TurnSpecifiedDegreesCommand::Initialize() {
        this->finished = false;
        this->startingAngle = sensorSubsystem->GetHorizontalAngle();
        this->goalAngle = startingAngle + this->degreesToTurn;
        printf("TurnSpecifiedDegreesCommand %f\n", this->degreesToTurn);
}

// Called repeatedly when this Command is scheduled to run
void TurnSpecifiedDegreesCommand::Execute() {
        float currentAngle = sensorSubsystem->GetHorizontalAngle();
        float angleDifference = goalAngle - currentAngle;
       
        SmartDashboard::PutNumber("Goal angle", goalAngle);
        SmartDashboard::PutNumber("Angle difference", fabs(angleDifference));
        printf("Angle difference %f goalAngle %f currentAngle %f\n", angleDifference, goalAngle, currentAngle);
       
        float turnRate = 0;
       
        if (fabs(angleDifference) < DEGREES_PRECISION) {
                chassis->Stop();
                finished = true;
        } else {
                // We slow our rate of turn as we get close to the angle we want.
                // These values are guesses.  A PID would be better here.
                if (angleDifference > 10 || angleDifference < -10) {
                        turnRate = 0.7;
                } else {
                        // Look at changing this at competition
                        turnRate = 0.6;
                }
               
                SmartDashboard::PutNumber("turn rate", turnRate);
               
                if (angleDifference > 0) {
                        chassis->TurnLeft(turnRate);
                } else {
                        chassis->TurnRight(turnRate);
                }
        }
}

// Make this return true when this Command no longer needs to run execute()
bool TurnSpecifiedDegreesCommand::IsFinished() {
        return finished;       
}

// Called once after isFinished returns true
void TurnSpecifiedDegreesCommand::End() {
        printf("TurnSpecifiedDegreesCommand completed.\n");
}

// Called when another command which requires one or more of the same
// subsystems is scheduled to run
void TurnSpecifiedDegreesCommand::Interrupted() {
}


Joe Ross 03-01-2014 21:40

Re: Making more reusable commands
 
Quote:

Originally Posted by Tom Bottiglieri (Post 1319819)
125 did this last year a little differently by subclassing subsystem, then building Commands that could control those types of subsystems.
https://github.com/kreeve/Nutrons201...Subsystem.java

Thanks, that's very similar to what I was thinking about.

Jefferson 04-01-2014 01:23

Re: Making more reusable commands
 
Quote:

Originally Posted by notmattlythgoe (Post 1319893)
I guess my question is, why not design the systems the solenoids use as a subsystem? We had subsystems this year that were just a single solenoid (trigger, shooter elevation, hopper, and pickup arm). We like to separate the solenoids into subsystems because we feel that it makes the project easier to read and practices good OOD technique by locking those devices into a subsystem that only a command requiring that subsystem is allowed access to control.

By doing it the way you describe, 4 lines of code turn into a subsystem with two additional functions and two commands. Each of those objects add to compile time, which turned into well over a minute with all of our commands in 2013. We'll just have to disagree which option is easier to read. The risk of other code writing to the solenoids, while possible, is not worth the complexity created by using commands.

Ziv 04-01-2014 01:47

Re: Making more reusable commands
 
Tom already mentioned my favorite approach to the problem :). It allows for both abstracting away implementation details (the outside code never sees a solenoid) and easy parametrization (just describe what it means for a subsystem to be on or off and you get a bunch of methods and commands for free). Many shooters in 2013 (including 125's and apparently 330's) were well-suited for this approach, because, unlike shooting baskets or balancing in 2012, shooting frisbees and pyramid pull-ups generally didn't need to be done in more than one or two ways.

It's not frequent that there's such a nice common abstraction for all of a robot's subsystems, but every robot deserves a bit of thought about what code can be shared before throwing the towel in and making it in RobotBuilder. (If you're bored by repetition, don't make the repetition easier without first trying to avoid the repetition altogether. RobotBuilder does the first but not the second.) When designing a set of abstractions, I find the most important thing is to be extremely picky, even if it feels petty. You should *like* the result because you think it's *pretty* (or at least useful, if you don't see how anyone could use that adjective about code :rolleyes:). The 30 minutes of code architecture debate might only save you 30 seconds in the future, but the 30 minutes can be before the robot is ready to test while the 30 seconds will probably be right before a match.


All times are GMT -5. The time now is 22:56.

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