Chief Delphi

Chief Delphi (http://www.chiefdelphi.com/forums/index.php)
-   C/C++ (http://www.chiefdelphi.com/forums/forumdisplay.php?f=183)
-   -   COmmand based software Interrupts (http://www.chiefdelphi.com/forums/showthread.php?t=135550)

Sparkyshires 03-07-2015 04:20 PM

COmmand based software Interrupts
 
Hello again! I'm back with another (possibly) stupid question. Does anyone have any documentation on how command interrupts are handled in command based code? I'm having issues where effectively command 1 which requires subsystem A gets called initially, then before it finishes command 2 gets called which also requires subsystem A, but then they both keep getting called in parallel (I am not using command groups)? I would love to know what exactly goes on inside the code and what order functions are run in, etc., etc., for when situations like these happen.

My google-fu and delphi-fu isn't doing much

TFleig78 03-07-2015 04:50 PM

Re: COmmand based software Interrupts
 
Do you have anything in the interrupted function of the first command? The command itself may be ending but whatever it's doing may continue unless you explicitly tell it to stop in the interrupted function. How do you know they both keep getting called in parallel?

Here's some general command based documentation, but it has some specific detail about interrupting and requires():


http://wpilib.screenstepslive.com/s/...uling-commands

http://wpilib.screenstepslive.com/s/...ed-programming

Sparkyshires 03-07-2015 09:09 PM

Re: COmmand based software Interrupts
 
Ok thank you so much, that was exactly what I wanted! Also, if you know, how do you make a command non-interruptible? It said that in the flow chart about halfway down the page on the second link you gave me.

TFleig78 03-07-2015 09:32 PM

Re: COmmand based software Interrupts
 
Quote:

Ok thank you so much, that was exactly what I wanted! Also, if you know, how do you make a command non-interruptible?
You can use the Command::setInterruptible(bool interruptible) function.

Sparkyshires 03-09-2015 06:04 PM

Re: COmmand based software Interrupts
 
Ok, thank you. I tried using the cancel command in the Interrupted function, but it still did not work :/ do you know how you can force a command to stop once it is interrupted?

RufflesRidge 03-09-2015 06:19 PM

Re: COmmand based software Interrupts
 
Quote:

Originally Posted by Sparkyshires (Post 1455688)
Ok, thank you. I tried using the cancel command in the Interrupted function, but it still did not work :/ do you know how you can force a command to stop once it is interrupted?

If Interrupted() is being called, the command is already being canceled.

You didn't answer the question about how you know they are running in parallel. It shouldn't be possible for two commands that Require the same subsystem to run at the same time.

Sparkyshires 03-09-2015 07:13 PM

Re: COmmand based software Interrupts
 
I'm adding some diagnostics and should be able to test it soon, but I'm assuming that's whats happening because when we call command A that goes to, say, 1000 encoder counts, and then command B (which should go to -1000) before it reaches, it will kinda stutter like it's being repeatedly told to go positive and then zero, going forwards until it hits 1000 and then run in reverse at normal speed until it hits -1000 then stop.

Btw those were arbitrary numbers

Sparkyshires 03-10-2015 09:10 AM

Re: COmmand based software Interrupts
 
Yeah, that's exactly what happened. When we did the printf's, it showed:

CommandA execute
CommandB execute
CommandA execute
CommandB execute
CommandA execute
CommandB execute
CommandA execute
CommandB execute
CommandA execute
CommandB execute
CommandA execute
CommandB execute

Sparkyshires 03-10-2015 05:18 PM

Re: COmmand based software Interrupts
 
Our code is at https://github.com/Sparky384/Team384...ree/master/src if anyone wants to take a look.

otherguy 03-10-2015 05:34 PM

Re: COmmand based software Interrupts
 
Is your repository private? Link doesn't work.

For the commands that are running "in parallel".
* Do they both require the same subsystem?
* What does their isFinished() code look like?
* What command is set as the default command for the subsystem?
* What does the code in OI look like that associates the commands with buttons (or where is new CommandXYZ() called for each command in question)?

TFleig78 03-10-2015 11:01 PM

Re: COmmand based software Interrupts
 
Quote:

Originally Posted by otherguy (Post 1456152)
Is your repository private? Link doesn't work.

For the commands that are running "in parallel".
* Do they both require the same subsystem?
* What does their isFinished() code look like?
* What command is set as the default command for the subsystem?
* What does the code in OI look like that associates the commands with buttons (or where is new CommandXYZ() called for each command in question)?

Also, what is in interrupted()?

Quote:

Ok, thank you. I tried using the cancel command in the Interrupted function, but it still did not work :/ do you know how you can force a command to stop once it is interrupted?
You should very rarely (if ever) have to explicitly cancel a command. The command will end(the scheduler will stop it) if it is interrupted by another command using the same subsystem or if isFinished() returns true. From what's going on, it seems as though your two commands A and B don't require the same subsystem.
Also, how are you starting the commands? It's possible they both keep trying to start, and are therefore interrupting each other repeatedly.

Sparkyshires 03-11-2015 10:17 AM

Re: COmmand based software Interrupts
 
Oh crap, my apologies! The repository is private. My school blocks github :/ so I can't make it public until this afternoon at about 430 EST. I will as soon as I get to our shop.

Yes, they require the same subsystem.

There are two checks in the is finished command, one is if they hit either the upper or lower limit, in which case return true and end the command immediately so you don't break anything, and the other is just to check if you've hit the encoder count you want, in which case return true and end the command. I would like to note that these parts of the command work exemplary and exactly as I want them, and have never given me any issues, except for this "parallel" problem.

The default command is called ElevatorIdle which turns the motors off in the Initialize function, then repeatedly prints out diagnostics in the execute, doesn't have anything in the isFinished except for return false, and turns off the elevator motor in the End and IsInterrupted functions.

The code in the OI is just:
Code:

joy1button2->WhenPressed(new MoveElevatorCarry());
joy1button3->WhenPressed(new MoveElevatorOneTote());

(Carry and OneTote are names for positions on the elevator)

In Interrupted is a printf which is only seen once when the new command is begun, and a function call to turn off the elevator motor.

As I said above, I'm just calling the commands in the OI file. Is there another place where we need to write some code so it knows what to expect? I have the line:
Code:

Requires(CommandBase::Elevator);
in both the commands, is that wrong?

P.S. also all of the above is from memory, as I said my school blocks github so I can't access the code :/ so if anything small in the syntax looks like it might be the issue, there's a high probability it's just me remembering it slightly wrong. As I said, the code works beautifully, I'm in love with commandBased as it's my first year using it, but I think I'm just missing some small nuance that has to happen with it.

P.P.S. Thank you guys so much for your help!!! We're a week four, so we have just about a week until competition, so I'm getting really nervous with this. You guys are lifesavers!!!! :D

otherguy 03-12-2015 02:45 PM

Re: COmmand based software Interrupts
 
In the Elevator subsystem:

How are the upperLimit() and lowerLimit() switches wired up?
If they are just limit switches that pull the channel low when the switch is closed (ground on the NC pin, signal on the C pin), then I would expect your GetLowerLimit() and GetUpperLimit() to return true when the switches are not pressed, and false when they are pressed. This is because there are pull-ups on the discrete input channels.

This would cause your MoveElevatorXXX commands to immediately end.


If you haven't already tested in your subsystem do what you think they should... add some print statements that call elevator.GetLowerLimit() and elevator.GetUpperLimit() from within Robot.TeleopPeriodic(). Without running any commands, press your switches and verify that the functions are retuning True/False when you think they should.

If that's not the problem, can you provide a real log of the output that you're seeing in the console when you run. I suspect that what was provided earlier wasn't real output from the robot. There's a lot more print statements in your code that I would expect to see that aren't in the log you provided. Having a real copy of the log will help us see how the commands are executing and potentially help narrow down where to look.

Sparkyshires 03-12-2015 03:16 PM

Re: COmmand based software Interrupts
 
Quote:

Originally Posted by otherguy (Post 1456994)
In the Elevator subsystem:

How are the upperLimit() and lowerLimit() switches wired up?
If they are just limit switches that pull the channel low when the switch is closed (ground on the NC pin, signal on the C pin), then I would expect your GetLowerLimit() and GetUpperLimit() to return true when the switches are not pressed, and false when they are pressed. This is because there are pull-ups on the discrete input channels.

This would cause your MoveElevatorXXX commands to immediately end.


If you haven't already tested in your subsystem do what you think they should... $@#$@#$@# some print statements that call elevator.GetLowerLimit() and elevator.GetUpperLimit() from within Robot.TeleopPeriodic(). Without running any commands, press your switches and verify that the functions are retuning True/False when you think they should.

If that's not the problem, can you provide a real log of the output that you're seeing in the console when you run. I suspect that what was provided earlier wasn't real output from the robot. There's a lot more print statements in your code that I would expect to see that aren't in the log you provided. Having a real copy of the log will help us see how the commands are executing and potentially help narrow down where to look.

Nah, I know they're wired properly, as I said the code works amazingly well, and I've tested both emergency situation and it works exactly as expected. We specifically wired it this way so if an issue arises, such as a wire coming loose, it'll act like it's hit(?) so it will stop the elevator. At least that's what the electrical guys told me. All I know is that logic is correct for our electrical set-up. The only issue that this code is giving us is that it will run two commands concurrently.

I'll get a proper log later, but yeah that was pretty much it :/ the only thing I changed was adding a printf to the isFinished command. When the new button was pressed it ran the:
old command interrupt
new command init
new command execute
new command isFinished
old command execute
old command isfinished
new command execute
new command isFinished
old command execute
old command isfinished

and et cetera.

otherguy 03-12-2015 05:13 PM

Re: COmmand based software Interrupts
 
Your switches may be wired correctly... but that doesn't mean that your code is reading their states correctly. Hence my suggestion to check that it's doing what you expect. If you're confident that's not the problem, good. I can't make you check it. You're the one that's saying it's not working correctly, so It may be prudent to verify your assumptions.


Other things that could be wrong:

Which commands in particular are you referring to as "new" command and "old" command?

The reason I ask is in OI all the MoveElevatorXXX commands are started when you press a button. These are the command I thought you were talking about previously wrt your logs. They will only execute once unless you're repeatedly pressing the button in question. This is not consistent with the logs you've provided.



On the other hand, if the one of the commands that's running happens to be the DropElevator() or LiftElevator() commands, then there's a different explanation for what may be going on.

I have yet to come up with a case where WhileHeld() actually does what you want it to (if someone has a use case, please let me know). If I understand your code correctly, the way you're attempting to use this command is to have your Lift/DropElevator() commands run until you let go of the button. But what's actually going to happen is each loop iteration, you're going to start a new copy of the Lift/DropElevator() command. Since you have a call to stop the elevator as part of the command, you're going to be in this endless loop of driving the elevator, stopping it, driving it, stopping it, until you let go of the button.

Here's why using the joy1button4->WhileHeld(new DropElevator()); as an example:
  1. Joy 1 Button 4 is pressed.
  2. A new command is created and added into the scheduler (DropElevator)
  3. The active command on the subsystem (elevator) is ElevatorIdle() and it's going to be canceled. Since a new
  4. When the scheduler come around to execute the active command, it runs the execute() function, assume that you're not at end of travel on the elevator, so you're going to run the DropElevatorArm() function, which presumably commands a motor to move the arm.
  5. assume isFinished on this command returns false.
  6. the next time around (assuming the button is still pressed) a new instance of the DropElevator() command is created. It requires the Elevator subsystem, so all active commands on that subsystem are canceled.
  7. The scheduler calls the end method on the first instance of the on the DropElevator command. This in turn calls the StopElevatorArm() function, presumably commanding the elevator motors to zero.
  8. now it's time for the new instance of the DropElevator() command to run: the scheduler runs the execute() function, assume that you're not at end of travel on the elevator, so you're going to run the DropElevatorArm() function, which presumably commands a motor to move the arm.
  9. and the cycle of starting and stopping this command repeats forever until you let go of the button.

What you probably want to do is instead execute the command WhenPressed, then call a command that stops the elevator (ElevatorIdle) When the same button is released.

Code:

joy1button3->WhileHeld(new LiftElevator());
joy1button4->WhileHeld(new DropElevator());
joy2button3->WhileHeld(new LiftElevator());

becomes
Code:

joy1button3->WhenPressed(new LiftElevator());
joy1button3->WhenReleased(new ElevatorIdle());
joy1button4->WhenPressed(new DropElevator());
joy1button4->WhenReleased(new ElevatorIdle());
joy2button3->WhenPressed(new LiftElevator());
joy2button3->WhenReleased(new ElevatorIdle());



All times are GMT -5. The time now is 10:47 AM.

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