View Single Post
  #19   Spotlight this post!  
Unread 09-02-2015, 12:41
cstelter cstelter is offline
Programming Mentor
AKA: Craig Stelter
FRC #3018 (Nordic Storm)
Team Role: Mentor
 
Join Date: Apr 2012
Rookie Year: 2012
Location: Mankato, MN
Posts: 77
cstelter will become famous soon enough
Re: How to Program Mecanum

Quote:
Originally Posted by LFRobotics View Post
Okay I got pnuematics working like a charm - I got our lifter(window motor) working great - but turning is still an issue - I assigned it to two buttons and it does work just fine but when after i'm done turning and I want to go back to joysticks(forward/backward straffing) the controls are unresponsive unless I disable and enable again.
THANKS!
I think I see what you did to fix the turn problem. You started with a whilePressed command to turn right or left and you also had a whenReleased that called the command baseStop.

Your framework was good I think, but your commands needed just a minor tweak.

Your solution seems to be to check the button state in DriveTele execute() method. I think this code works, but could be a bit cleaner.


Here is the new code in DriveTele

Code:
    protected void execute() {
    	Robot.mec.mecanumDrive(
                (oi.stick.getLeftJoyX()+oi.stick.getLeftJoyY())/2,
                (oi.stick.getLeftJoyY()-oi.stick.getLeftJoyX())/2,
                -(oi.stick.getLeftJoyY()-oi.stick.getLeftJoyX())/2,
                -(oi.stick.getLeftJoyX()+oi.stick.getLeftJoyY())/2);
    	
    	if(oi.stick.getRawButton(5)) {
    		Robot.mec.turnLeft();
    	}
    	
    	if(oi.stick.getRawButton(6)){
    		Robot.mec.turnRight();
    	}
    }
First of all, in the case where a button is pushed-- you first tell the drivetrain to drive off the joysticks. Then if 5 is pressed you immediately tell it to turnLeft. If both are pressed, it will then make a 3rd call to turn right. You essentially send all 1, 2 or 3 directions quickly to the drivetrain and then wait 20ms for the next call to execute(). It may be harmless to send all these alternative powers to the controllers, but it is also unnecessary. Cleaner may be

Code:
    protected void execute() {
    	if(oi.stick.getRawButton(5)) {
    		Robot.mec.turnLeft();
    	} else if(oi.stick.getRawButton(6)){
    		Robot.mec.turnRight();
    	} else {
   	        Robot.mec.mecanumDrive(
                (oi.stick.getLeftJoyX()+oi.stick.getLeftJoyY())/2,
                (oi.stick.getLeftJoyY()-oi.stick.getLeftJoyX())/2,
                -(oi.stick.getLeftJoyY()-oi.stick.getLeftJoyX())/2,
                -(oi.stick.getLeftJoyX()+oi.stick.getLeftJoyY())/2);
        }
    	
    }
This way you only send one set of commands to the drive train every 20ms on telopPeriodic.

I believe your previous attempt could have worked too with just a couple tweaks. I think the reason you lost control was becuase of your baseStop command. The isFinished() returns false. Once that command is scheduled by releasing a button, it scheduled itself and never returned true to isFinished() to unschedule itself. Unless another drivetrain command is scheudled, that command will keep running.

The way whilePressed() commands work is that the command is repeatedly scheduled to run as long as the button is triggered. But when it is released no action is taken, so a quick press or a long press has little difference other than the command is repeatedly instantiated longer on a long press.

The whileHeld() on the other hand will cancel the command when the pressing action stops. When it does this, it doesn't matter that your command may be saying isFinished() is false. It's going to de-schedule when the button is released. In this way your default command for the drive train (DriveTele) will again take over.

So I think the original code could be fixed 3 different ways in addition to the solution you chose.

1) return true from isFinished() in your turn-right or turn-left commands-- then each time through the loop, they will do the turn and then be done and as long as the button is pressed it will reschedule each time and continue sending the command until the button is released. In this case you can remove the stop whenReleased() calls to baseStop because as soon as the button is released your turn command will have finished and it will revert to DriveTele

2) Keep the whenPressed and change the baseStop to return true. Then the baseStop will interrupt the turnRight command and stop. Actually-- I'm not sure this will work-- I'm not that intimate with the code so possibly after baseStop, it might fall back to most recently interrupted command (the turn command) or possibly the interruption will have fully cancelled the command in which case you'd fall back to driveTele. I'm not 100% sure on this but I think there is a solution in this direction.

2) Probably easiest to understand (and quite honestly the one I'm most confident would work) is to use whileHeld() instead of whenPressed() and no other changes are required apart from removing the two stop whenReleased baseStop commands. There is no need for a stop with whileHeld-- it will go to DriveTele as soon as it is no longer held which will then send all stop (if no-one is touching joystick) or send whatever the joystick is sending.

I think the solution you chose was fine, but I wanted you to understand why the previous version was failing.

Last edited by cstelter : 09-02-2015 at 12:45.
Reply With Quote