We’ve been having trouble trying to get a timed action working. We’ve never had much luck with this, even when following Team 358’s awesome examples . We’ve searched different threads and tried many combinations of the instructions in those threads and the code still doesn’t work.
What we want: We want our hatch mechanism to rotate from a stored position inside the robot to a deployed position outside the robot, resting/stalling against a mechanical stop at either end of its travel. When a button is pressed, we want the Hatch Motor to run at -0.7 for 2 seconds and then at -0.1 indefinitely (securely storing the mechanism). When the same button is pressed again, we want the motor to run at 0.7 for 2 seconds and then at 0.1 indefinitely (securely deploying the mechanism).
This seems like an easy thing to accomplish in periodic tasks, but no dice. Here is our current labview code:
The button press boolean is written to a global variable in teleop and read in periodic tasks. The button works fine and the boolean responds as its supposed to, but the motor only seems to be executing the first frame of the flat sequence structure. What’s also odd is that there’s an irregular delay between when the boolean changes to when the motor reverses direction.
Don’t worry about the stall condition. We’re using a bag and only going to be stalling at low outputs. The Hatch Motor while loop in periodic tasks is duplicated to show the True and False cases, only one loop exists in the real code.
Thanks in advance for any help! We really appreciate it!
I am not a big fan of sequence structures - I always use state machines for a variety of reasons. One of which is because I only ever want ONE “set output” VI for each motor anywhere in my code, ever.
I insist on being able to probe the input that runs into my set output vi for debugging - and with multiple set motor vi’s you have to search around to the one that might be running at that given time.
But I suspect what may be happening is that you set the output for 2 seconds, and then it only executes the second frame for 1 loop before returning and starting to execute the first frame again for another 2 seconds. It’s probably so quick you don’t realize it’s happening.
Another thing - you’re seeing that wierd delay because the sequence will not release it’s priority until it’s done, so it doesn’t get out of the sequence so it can’t re-loop the outside loop to look at your button press. You ‘locking’ it into that frame for 2 seconds.
Does that make sense?
You could test this theory by putting a 2 second wait in the second frame.
You need another while loop in the 2nd step of each sequence structure around the “set Output” to -0.1. Add another timer block for 20 ms in it also and then set the Stop input for the while loop to the “Hatch Move” variable. It should loop setting output to -0.1 until Hatch Move changes to the other state. Note that you’ll need to do this for both the true and false case and one of the “Hatch Move” variables will need to be inverted to stop the while loop.
I was using LabVIEW for our first year, and am going to move to Java next year, but I happened to have to do something with timers. When I get a chance, I’m going to send you a screen shot of the code I used, and the names of the functions.
You actually seem to need more cases than you have accounted for.
Each time periodic tasks evaluates the outside loop these seem to be the cases you want:
Move hatch in true case one time
Stall hatch in true case all other true times
Move hatch in false case one time
Stall hatch in false case all other false times
There is an easier way to do this, give me a second…
Maybe something like this (it’s a snippet, so you can drag onto a block diagram to see the False case, which is just a .1 set motor x the direction, i.e., the same motor set using .1 without the delay):
Thanks to everyone for all the replies. Mark’s solution worked great! We still plan to try to get the sequence structure to work in case we have a situation with more than two conditions in the future.
The sequence case can be made to work by letting it only trigger once (i.e., the first time only) in the True case, and once in the False case.
The error was it kept executing over and over when True (or False).
So you needed a case around the case.
Then only enter the outer case when Hatch Move doesn’t equal the previous Hatch Move (Feedback Node).
Something like this:
Is there a reason you aren’t using an event structure? This would eliminate the need for the polling loop in Periodic Tasks.vi.
Couldn’t you accomplish this by probing the input line inside the set output vi? Not that I disagree with only having one set output vi, I’m just curious about your reasoning.
If you probe inside the set output VI, you get the values of every set, not necessarily the one you are probing.
In my opinion, all control code should be designed to run continuously (never blocking/waiting) and return a command to all of the actuators each iteration.
To solve this problem, I would:
Store the desired state (using a typedef enum, but a bool also works if you only have two states)
Store the timestamp (Tick Count) when the state last changed. This is compared to the current tick count to get the time since state changed.
Based on these two things, you have four combinations of output - state A vs state B, and timer low vs timer high.
Oh, duh. I was looking at Mark’s solution and he missed wiring the motor specifier to the set output vi. I was stuck thinking each motor had it’s own unique set output vi (SetHatchMotorOutput.vi). I’ve been out of the labview game a little too long.
Hey,
I just want to mention that this might not be the best method, as it completely limits the speed of the loop with that timer. I do know that there is a built in timer function, that does not require you to stop the loop for the time which it is active. I think this might be a bit better that what you have here.
There is actually a timer that is built into LabVIEW, that counts the seconds past since it was given a “true” value (without delaying the vi). I will post a picture of this, when I get a chance.
To tell you the truth, I’ve never used event structures. We have one polling loop that we use in periodic tasks that gets the necessary axis and buttons from the joysticks and assigns them to globals to be used elsewhere. We run that at 20ms to match up with the timing of new data from the driver station.
I’ve always taught our team members to start from the very bottom. They write their own versions of “on press” and “on release” to interact with inputs, and do the same with PiD loops, sensors, sensor filtering, and state machines. If you looked into our code you’d see booleans, case structures and comparisons make up 99% of our code. We’ve never had the need to use event structures with our style of programming.
Event structures are great for, say, user interfaces (ie labview dashboard), but for sensor based actions, you’d still have to poll for sensor changes and generate a custom user event on change.
Yep, I get it. It served it’s purpose, and I wasn’t expecting you to fix it. Just explaining the thinking behind my weird question.
Interesting. I’ve never actually used labview in an frc environment, but I have used it professionally to control instrumentation. If I were to write frc control software, I would start with the producer consumer pattern. Obviously 1718 is doing something right, is your code publicly available anywhere? I’d be interested in taking a look.
I would consider a joystick a user interface.
When I said removing the polling loop from Periodic Tasks.vi, I was just referring to the implementation showed in the OP. It seemingly has no sensor inputs. Of course there are multiple ways to solve a problem. For the given problem, my solution would start with an event structure
We used to hand it out to teams who attended our beta seminars when we held them regularly. Since then we haven’t published, but I can throw it up at the end of the season. It’s still very much a work in progress.
I see where you’re coming from now. When you said sensor I assumed encoder/gyro/etc. Now I’m realizing the joystick could be considered a sensor. I agree that if you need to poll the joystick to generate a custom event, using an event structure may not be worth it. It still might be worth it in a “split responsibilities” way, though it is far from the obvious solution like I thought.
If I tweaked the original question to “press a front panel button and do the action” do you see the event structure implementation I’m envisioning? Working off that, is there really no way to register a joystick/whatever in NI so that it can automatically show up in the event structure? Even through NI MAX or something?
I don’t actually know if this is possible, though I really would be surprised if it isn’t. If it isn’t possible, then we’re all on the same page.
as you can see, I used a timer function. This allowed me to input any float (in this case 1), and then it sent me a true value if the time had elapsed, without having to stall the whole vi. (It’s measured in seconds.)
The best part about this timer function is you can input a different value, depending on certain conditions.