View Full Version : How to make timed sequences in java?
katsauga
07-01-2014, 15:36
I was slighty curious on how to make a timed sequence in Java. (Ex. Push out piston, wait two second, pull back piston, stop) any help would be great! could be a sub-class? or just do it right on the robot main.
If you're interesting in doing stuff like this, I'd recommend using the command based template. You could make a command ExtendPiston and RetractPiston, then make a command group that had ExtendPiston, WaitCommand(2.0), RetractPiston, and it would do what you wanted.
NotInControl
07-01-2014, 16:09
You should not do it in main. As a general rule, you should not sleep or wait in any main function.
Any sleep() command you provide will cause the current thread to sleep. If this is done in main() the main function will sleep. The SimpleRobot Project and IterativeRobot project are single threaded by default, so if you use either of those constructs, and call the sleep command the entire robot will sleep. You should run your code in a separate thread so you are not sleeping the main thread. Failure to do that will cause your entire robot to wait 2 seconds. You can create threads in Java by implementing the Runnable Interface or Extending one of the many Thread classes in the java.util.concurrancy package. In either case you will overide the "run" method which opens a solenoid, sleeps, and closes the solenoid but executes in its own thread.
(i.e Public MyClass extends Thread{
do stuff
}
As Jarad mentioned, using the CommandBase construct is helpful in this sense because CommandBase is multithreaded by default. So if this double solenoid was apart of an Arm subsystem. You could simply create a CommandGroup which calls the command to open the solenoid, waits 2 seconds, then calls the command which closes the solenoid. Each command/CommandGroup executes in its own thread, therefore any waits or sleeps will not hault the entire program.
brennonbrimhall
07-01-2014, 16:50
Disclaimer: We use Java, and this might change depending the language you use.
It's not the best method when considered computationally, but we just increment an integer variable, and use a typical if statement when using the IterativeRobot template.
Here's an example:
DoubleSolenoid solenoid = ... ;
int cycles = 0;
public void teleopPeriodic(){
cycles++;
if(cycles<40){
solenoid.set(DoubleSolenoid.Value.kForward);
}else if(cycles<60){
//Do nothing
}else if (cycles<80){
solenoid.set(DoubleSolenoid.Value.kReverse);
}
}
public void disabledInit(){
//Resetting to zero on disable.
cycles = 0;
}
Of course, you'd need to figure out how many times the cRIO enters teleopPeriodic per second to figure out the correct numbers to compare to above.
Don't worry about running out of int space in Java. An int's maximum value is 2^32-1, and at 50Hz (around what we observed), the cRIO's JVM won't run into errors for just over 994 days, assuming it's still running by then. ;)
If you're using the iterative robot template, you could always just use timers.
http://www.wbrobotics.com/javadoc/edu/wpi/first/wpilibj/Timer.html
notmattlythgoe
07-01-2014, 17:28
I would also highly suggest using Command Based programming with Java, we have been using it for the past couple of years and are very happy with it. Be careful though, it is not multithreaded as NotInControl has stated. It uses a scheduler to run the commands one execution at a time. But, it does use something called a CommandGroup that will allow you to set up a command exactly like you need as Jared stated earlier.
If you'd like a beginners presentation on how to do these things I can post one. Our team gave a workshop presentation on Command Based Java earlier this fall.
NotInControl
08-01-2014, 04:20
Be careful though, it is not multithreaded as NotInControl has stated. It uses a scheduler to run the commands one execution at a time.
I don't want to de-rail from the OP, and get off topic with this, but I'll offer this:
I believe you are limited your definition of "multi-threading" to spawning multiple threads for the operating system to schedule which is known as "kernel-level" threads but you are forgetting about "user-level" threads.
The CommandBased Robot Structure doesn't spwan multiple operating system threads for commands, instead it opts a "user-level" thread model where the scheduler adds each new command to a linked-list and executes each Command's "run" method sequentially in a round-robin fashion. (To be complete, other operating system threads are spawned for certain items like PID controllers, compressor, some sensors etc. and are managed by the operating system, not the WPI scheduler)
The WPI scheduler apart of the CommandBased construct will automatically remove commands which have finished execution and prevent commands from being added if the requirements for the command are not met or conflict with another commands.
All of these items are done at the application-level instead of the using the operating system to manage threads which can be classified as "user-level" threads.
In both models, time-division multiplexing is being done to share the resources of the single processor on board. Which is the basic definition of concurrency.
If there was only a single thread and the program only ran sequentially without time sharing then you would never need a scheduler.
So whether you want to call it multi-threading or not is your opinion, to the end user concurrency on a single processor is being done, I didn't state all of this before because I didn't want to muddy/confuse my original post.
Hope this helps,
Kevin
notmattlythgoe
08-01-2014, 06:00
I don't want to de-rail from the OP, and get off topic with this, but I'll offer this:
I believe you are limited your definition of "multi-threading" to spawning multiple threads for the operating system to schedule which is known as "kernel-level" threads but you are forgetting about "user-level" threads.
The CommandBased Robot Structure doesn't spwan multiple operating system threads for commands, instead it opts a "user-level" thread model where the scheduler adds each new command to a linked-list and executes each Command's "run" method sequentially in a round-robin fashion. (To be complete, other operating system threads are spawned for certain items like PID controllers, compressor, some sensors etc. and are managed by the operating system, not the WPI scheduler)
The WPI scheduler apart of the CommandBased construct will automatically remove commands which have finished execution and prevent commands from being added if the requirements for the command are not met or conflict with another commands.
All of these items are done at the application-level instead of the using the operating system to manage threads which can be classified as "user-level" threads.
In both models, time-division multiplexing is being done to share the resources of the single processor on board. Which is the basic definition of concurrency.
If there was only a single thread and the program only ran sequentially without time sharing then you would never need a scheduler.
So whether you want to call it multi-threading or not is your opinion, to the end user concurrency on a single processor is being done, I didn't state all of this before because I didn't want to muddy/confuse my original post.
Hope this helps,
Kevin
You are right, it is user-threaded. I made the point because the user threads will not force a thread out that is taking too long to execute. So if you create a command that will take a long time to finish one execution it will lock all of the other commands that are waiting on the scheduler to tell them to run. Just something to watch out for.
omalleyj
08-01-2014, 10:32
Because many embedded programming environments do not use operating systems I generally avoid threads for dealing with this sort of situation. (threads are a perfectly valid and useful approach in those environments)
In your main loop (either explicit in Simple or implicit in Iterative) just check the time you start and the current time, e.g.: (all from memory, and I usualy code C, so treat this as pseudocode)
double pistonTimer = 0.0;
while (isTeleop() && isEnabled()){//implicit in Iterative
//check for the condition that starts the piston
if (joystick1.RawButton(5)){
//...stuff that turns on/off the right solenoids...
pistonTimer = Timer.GetTime();//I believe this is now a double, in seconds
}
//lots of other things like driving code mixed in
//check if its done yet
if (pistonTimer > 0.0 //important so you know you've started timing
&& Timer.GetTime() - pistonTimer > 2.0){
//...stuff that turns on/off the other right solenoids...
pistonTimer = 0.0; //don't forget to reset it
}
}
While polling like this isn't super efficient it is easy to implement and follow.
HTH
While polling like this isn't super efficient...
Do you think it's less efficient than time-slicing a separate thread?
Tom Bottiglieri
08-01-2014, 11:09
The CommandRobot way will give you your desired outcome with the least amount of swimming upstream. I recommend giving that a look. (I'd also highly recommend at least looking at the source code you would be building on top of https://github.com/eshsrobotics/wpilib-java/blob/master/src/edu/wpi/first/wpilibj/command/Scheduler.java)
omalleyj
08-01-2014, 11:31
Do you think it's less efficient than time-slicing a separate thread?
Hard to say without looking in detail. You have the constant tests for setting and checking vs. the context switch to handle the thread. If the piston is used exactly once and never again the thread could be deleted. If its used many times the context switching could become onerous.
There are also many opportunuties to do threads badly. For instance if it was coded to check the time constantly rather than sleeping the whole duration it would be enormously worse. For teams that need to ask how to wait for something polling probably has the fewer pitfalls.
Hard to say without looking in detail. You have the constant tests for setting and checking vs. the context switch to handle the thread.
Your "polling" code (a form of state machine as shown) runs once every 20ms yes? While you're waiting for the 2 seconds to elapse, you're doing one simple conditional jump every 20ms.
If CPU usage becomes a problem using this approach, there's probably something seriously wrong elsewhere in the code.
omalleyj
08-01-2014, 12:35
Your "polling" code (a form of state machine as shown) runs once every 20ms yes? While you're waiting for the 2 seconds to elapse, you're doing one simple conditional jump every 20ms.
If CPU usage becomes a problem using this approach, there's probably something seriously wrong elsewhere in the code.
Agreed as stated. The Simple robot code is called once and your own loop runs as often as it can, the Iterative I believe is triggered by packet arrival at 20ms intervals (not in a position to verify at the moment).
I was addressing the more general case. I program microcontrollers where the loop is all yours. In FIRST need there are constraints. I try to teach the generic case (as a statemachine) and mention the FIRSTisms that impact it.
If programming a PIC or similar I would use a timer interupt and be more efficient than either by miles.
Didn't mean to start a debate, just to acknowledge that polling can sometimes be unnecessarily expensive, (and might be compared to a thread whose only instruction was sleep(2000), but I've never profiled either situation), but this was a case where simplicity was probably the best.
The Simple robot code is called once and your own loop runs as often as it can...
You might want to throttle it with a sleep to run only as fast as it needs to. There are other processes running.
omalleyj
08-01-2014, 13:19
You might want to throttle it with a sleep to run only as fast as it needs to. There are other processes running.
Yes, I take the time at the top of the loop and at the end of the loop sleep for the remainder of the 20ms. (Or print a 'broke realtime' message). That's the big downside of an OS, you have to share :(
Or print a 'broke realtime' message).
Yes :-)
On a related note: When designing realtime frameworks and application code for bare metal embedded microcontrollers, it's helpful to increment an element in an array of error counters for realtime margin and other operating assumptions. Monitoring those error counters during development, qualification, stress, and acceptance testing is a great way to increase confidence level that the system is operating as expected.
vBulletin® v3.6.4, Copyright ©2000-2017, Jelsoft Enterprises Ltd.