-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
State Machine #19
Comments
@jkleiber How does the current implementation look? Code is in the StateMachine Branch |
@avidraccoon the current implementation looks good - I can leave some more specific comments on a PR when one is ready but this looks directionally correct for now |
@aidnem You said you wanted me to look at something, what was it? |
I actually think it wouldn't really work for our use-case with the way you have each state in its own file but I was just saying I liked the syntax of stateless4j. I don't think you can use most of it (also, this state machine would have to be configured in one place and that would make the init of each subsystem describe the entire state machine which would kind of be a nightmare in my opinion). Honestly don't worry about the syntax of this too much because if what you have works we should use it. |
What parts of the syntax do you like? Because mine doesn't work, and I am currently rewriting much of it and modifying the syntax. |
I think this should probably have a way to interface with monitors right? |
public class ScoringSubsystem extends MonitoredSubsystem {
public enum ScoringState {
IDLE (IdleState),
PRIME (PrimeState),
SHOOT (ShootState)
// Attach the AbstractState object to each value of the enum
private final AbstractState state;
ScoringState(AbstractState state) {
this.state = state;
}
public AbstractState state() {
return state;
}
}
StateMachine<ScoringState> stateMachine = new StateMachine<ScoringState>();
public ScoringSubsystem() {
// Do initialization
// ....
// Add monitors
addMonitor(new Monitor.MonitorBuilder.withName("armEncoderUnplugged")
.withStickyness(true)
.withIsStateValidSupplier(() -> {/* arm encoder unplugged check ...*/)
.withTimeToFault(0.1)
.build())
}
@override
public void monitoredPeriodic() {
/* Do whatever periodic stuff is needed for the state machine, I'm unfamiliar with the API */
}
} @avidraccoon @jkleiber please let me know if you have suggestions for this syntax to be improved, this was just what I threw together off the top of my head. |
Don't worry about interfacing monitors with the state machine. As long as we have a way to enable or disable monitors at runtime we can do whatever we need for that |
Also, having the states separated into their own files is not a requirement from me. Here are my requirements:
|
Would you mind elaborating on what you mean by configuring? What could a simple state machine's JSON potentially look like? |
I mean like make it able to get a report of any illegal state transitions attempted by action that way the monitor can access them. Or if we use something like the guarded from stateless4j we will have if about that. |
That's a good point. Although wouldn't it be better to just not code in any illegal state transitions. We're fully in control and if we write code that's broken up enough we might be able to just be really good and not be able to do illegal stuff in the first place. |
Yeah but it would mean we could more easily catch mistakes, things we missed when testing, or problems caused by hardware |
Yeah @avidraccoon I thought about it some more and I completely agree, good idea. |
How do you think the json should look? |
I'm not sure yet. I'm really tired right now so any ideas I had would probably be a little silly anyway. I'll let it percolate and if I come up with anything I'll let you know tomorrow morning :) |
@aidnem do you know how the json should look? |
What if we did: {
"name": "ScoringStateMachine",
"states:" [
{
"name": "idle",
"transitions": ["intake", "prime", "shoot", "amp_prime", "amp_shoot", "pass_prime", "pass_shoot"]
},
{
"name": "intake",
"transitions": ["idle", "prime", "amp_prime", "pass_prime"],
},
{
"name": "prime",
"transitions": ["idle", "shoot", "amp_prime", "pass_prime"],
},
{
"name": "shoot",
"transitions": ["idle", "prime"],
},
{
"name": "amp_prime",
"transitions": ["idle", "amp_shoot", "prime", "pass_prime"],
},
{
"name": "amp_shoot",
"transitions": ["idle", "amp_prime"],
},
{
"name": "pass_prime",
"transitions": ["idle", "pass_shoot", "prime", "amp_prime"],
},
{
"name": "pass_shoot",
"transitions": ["idle", "pass_prime"],
}
]
} |
I just pushed a potential major change to how the state machine works it doesn't have the Json yet, @aidnem could you take a look at it quickly? |
At first glance that looks pretty good, I see you implemented the state machine syntax I was talking about. There's a lot of logic so I'll read it a couple more times since a lot of it went over my head. Something we could consider: could we an interface like abstract state back in, and maybe call it something like state executor (or keep it named AbstractState like I put in the example)? // StateEnum.java
interface StateEnum {
public AbstractState state();
}
// AbstractState.java
public interface AbstractState {
public void onEntry() {}
public void onExit() {}
public void periodic() {}
}
// StateMachine.java
public class StateMachine<State implements StateEnum, Trigger> { /* state machine class ... */}
// ScoringSubsystem
public class ScoringSubsystem extends MonitoredSubsystem {
public enum ScoringState implements StateEnum {
IDLE (IdleState), // IdleState, PrimeState, and ShootState are all classes that implement AbstractState and are imported from other files.
PRIME (PrimeState),
SHOOT (ShootState)
// Attach the AbstractState object to each value of the enum
private final AbstractState state;
ScoringState(AbstractState state) {
this.state = state;
}
public AbstractState state() {
return state;
}
} Let me know if this seems at all sane to you. |
Are we wanting to use enums or separate files? |
My solution was to use enums that then referenced states from separate files. That way we can use the enum when we need to use enum values but still split states into separate files. @jkleiber what's your opinion on this? |
@aidnem I think using enums to represent the available states is fine. I think defining states in separate files is also fine. I assume you would be mapping the current state (enum type) to the state definition (some sort of class derived from an abstract State class). I think that pattern seems good |
Yes, this is correct. I've updated the code snippet with a comment indicating this. |
@jkleiber Do we prefer functionality or loading from json? |
@avidraccoon why can't we have both? But to start out I would take functionality and then we can build in the JSON capability |
@jkleiber With the library I used for json I don't know how to map a json value to a java enum value, but I can look into it. |
Never mind it is possible, but some part might not be possible do to how java works not sure I'll have to do more research, but almost all of it will be able to be loaded from Json eventually. |
@jkleiber do you want me to prioritize merging this branch and then adding more feature or just add them now? |
@aidnem could write some example of how you want it to work with configuration so that I can write Tests based off of the example? |
@avidraccoon since it probably won't be a very high priority to configure the state machine with JSON, let's just try to get the state machine functional and then we can make what I call a "deferred ticket" to make it JSON configurable later. There are certainly higher priority tasks to work on between now and making state machine JSON configurable |
Also please make a draft PR to make the branch more visible for review |
Classes
The text was updated successfully, but these errors were encountered: