1010import us .ihmc .behaviors .tools .walkingController .ControllerStatusTracker ;
1111import us .ihmc .communication .crdt .CRDTInfo ;
1212import us .ihmc .handsros2 .abilityHand .AbilityHandROS2HardwareCommunication ;
13- import us .ihmc .log .LogTools ;
1413import us .ihmc .tools .io .WorkspaceResourceDirectory ;
1514
1615import java .util .ArrayList ;
@@ -25,7 +24,6 @@ public class BehaviorTreeRootNodeExecutor extends BehaviorTreeNodeExecutor<Behav
2524 private final List <LeafNodeExecutor <?, ?>> currentlyExecutingLeaves = new ArrayList <>();
2625 private final List <LeafNodeExecutor <?, ?>> failedLeaves = new ArrayList <>();
2726 private final List <LeafNodeExecutor <?, ?>> successfulLeaves = new ArrayList <>();
28- private final List <LeafNodeExecutor <?, ?>> failedLeavesWithoutFallback = new ArrayList <>();
2927
3028 public BehaviorTreeRootNodeExecutor (long id ,
3129 CRDTInfo crdtInfo ,
@@ -66,7 +64,10 @@ private void updateNodeListsRecursive(BehaviorTreeNodeExecutor<?, ?> node)
6664 orderedActions .add (actionNode );
6765 }
6866 else if (child instanceof FallbackNodeExecutor fallbackNode )
67+ {
68+ fallbackNode .update ();
6969 fallbackNodes .add (fallbackNode );
70+ }
7071
7172 updateNodeListsRecursive (child );
7273 }
@@ -101,189 +102,133 @@ public void update()
101102 }
102103 }
103104
104- // Update is next for execution
105+ // Determine the concurrent group
106+ int next = state .getExecutionNextIndex ();
105107 for (int i = 0 ; i < state .getOrderedLeaves ().size (); i ++)
106108 {
107- int next = state .getExecutionNextIndex ();
108- int after = state .getOrderedLeaves ().get (i ).getExecuteAfterLeafIndex ();
109- for (int j = after + 1 ; j < i ; j ++) // Might have to wait on nearer leaves
110- after = Math .max (after , state .getOrderedLeaves ().get (j ).getExecuteAfterLeafIndex ());
111- state .getOrderedLeaves ().get (i ).setIsNextForExecution (i >= next && after < next );
109+ LeafNodeExecutor <?, ?> leaf = orderedLeaves .get (i );
110+ int after = effectiveExecuteAfterLeafIndex (leaf );
111+ leaf .getState ().setIsNextForExecution (i >= next && after < next );
112112 }
113113
114- failedLeaves .clear ();
115- successfulLeaves .clear ();
116114 for (LeafNodeExecutor <?, ?> currentlyExecutingLeaf : currentlyExecutingLeaves )
117115 {
118116 currentlyExecutingLeaf .updateCurrentlyExecuting ();
119117
120- // This leaf has completed on this update
121118 if (!currentlyExecutingLeaf .getState ().getIsExecuting ())
122- {
123- boolean success = !currentlyExecutingLeaf .getState ().getFailed ();
124- if (success )
125- successfulLeaves .add (currentlyExecutingLeaf );
126- else
127- failedLeaves .add (currentlyExecutingLeaf );
128-
129- reportLeafCeasedExecution (currentlyExecutingLeaf , success );
130- }
119+ leafCeasedExecution (currentlyExecutingLeaf );
131120 }
132121 currentlyExecutingLeaves .removeAll (failedLeaves );
133122 currentlyExecutingLeaves .removeAll (successfulLeaves );
134123
135- failedLeavesWithoutFallback .clear ();
136- failedLeavesWithoutFallback .addAll (failedLeaves );
137- for (FallbackNodeExecutor fallbackNode : fallbackNodes )
138- {
139- fallbackNode .update ();
140-
141- if (!fallbackNode .getFallbackLeaves ().isEmpty ())
142- failedLeavesWithoutFallback .removeAll (fallbackNode .getTryLeaves ());
143- }
144-
145- // Handle skipping the fallback if try leaf group is successful
146- boolean leafEnded = !failedLeaves .isEmpty () || !successfulLeaves .isEmpty ();
147- if (leafEnded && currentlyExecutingLeaves .isEmpty () && !isEndOfSequence ())
148- {
149- LeafNodeExecutor <?, ?> nextNodeToExecute = orderedLeaves .get (state .getExecutionNextIndex ());
150-
151- for (FallbackNodeExecutor fallbackNode : fallbackNodes )
152- {
153- if (fallbackNode .getFallbackLeaves ().indexOf (nextNodeToExecute ) == 0 )
154- {
155- boolean anyFailed = false ;
156- for (LeafNodeExecutor <?, ?> tryLeaf : fallbackNode .getTryLeaves ())
157- {
158- if (tryLeaf .getState ().getFailed ())
159- {
160- anyFailed = true ;
161- break ;
162- }
163- }
164-
165- if (anyFailed ) // Nothing is executing and a tried leaf failed -- falling back
166- {
167- LogTools .warn ("Leaves failed, fallback leaves are next for execution." );
168- }
169- else // Nothing is executing and none of the try leaves failed -- skip fallback
170- {
171- LeafNodeExecutor <?, ?> lastFallbackLeaf = fallbackNode .getFallbackLeaves ().get (fallbackNode .getFallbackLeaves ().size () - 1 );
172- LogTools .info ("Leaves successful, skipping fallback leaves(s)" );
173- state .setExecutionNextIndex (lastFallbackLeaf .getState ().getLeafIndex () + 1 );
174- }
175- }
176- }
177- }
178-
179- if (state .getAutomaticExecution ())
124+ boolean keepTrying = state .getAutomaticExecution () || state .pollManualExecutionRequested ();
125+ executionLoop :
126+ while (keepTrying )
180127 {
181128 if (isEndOfSequence ())
182129 {
183130 state .getLogger ().info ("End of sequence." );
184131 state .setAutomaticExecution (false );
132+ break ;
185133 }
186- else if (!failedLeavesWithoutFallback .isEmpty ())
134+
135+ LeafNodeExecutor <?, ?> leafToExecute = orderedLeaves .get (state .getExecutionNextIndex ());
136+
137+ if (!state .getAutomaticExecution () && !leafToExecute .getState ().getIsNextForExecution ())
138+ break ;
139+
140+ for (FallbackNodeExecutor fallbackNode : fallbackNodes )
141+ if (fallbackNode .tryLeafIsBlocking (leafToExecute ))
142+ break executionLoop ;
143+ // Break if anything earlier than effective after execute is still going
144+ for (int i = effectiveExecuteAfterLeafIndex (leafToExecute ); i >= 0 ; i --)
145+ if (state .getOrderedLeaves ().get (i ).getIsExecuting ())
146+ break executionLoop ;
147+
148+ leafToExecute .update (); // Make sure can execute is up to date
149+ if (leafToExecute .getState ().getCanExecute ())
187150 {
188- state .getLogger ().error ("A leaf failed. Disabling automatic execution.\n Failed: %s" .formatted (failedLeavesWithoutFallback ));
189- state .setAutomaticExecution (false );
151+ state .getLogger ().info ("%s executing leaf: %s (%s)" .formatted (state .getAutomaticExecution () ? "Automatically" : "Manually" ,
152+ leafToExecute .getDefinition ().getName (),
153+ leafToExecute .getClass ().getSimpleName ()));
154+ leafToExecute .triggerExecution ();
155+ if (!leafToExecute .getState ().getIsExecuting ()) // Handle immediately ceased execution
156+ keepTrying = leafCeasedExecution (leafToExecute );
157+ else
158+ currentlyExecutingLeaves .add (leafToExecute );
159+ state .stepForwardNextExecutionIndex ();
190160 }
191161 else
192162 {
193- while (wouldExecuteNextLeaf () && tryExecuteNextLeaf ("Automatically" ));
163+ state .getLogger ().error ("Cannot execute leaf: %s: %s\n %s" .formatted (leafToExecute .getClass ().getSimpleName (),
164+ leafToExecute .getDefinition ().getName (),
165+ leafToExecute .getCantExecuteMessage ()));
166+ keepTrying = false ;
194167 }
195168 }
196- else if (state .pollManualExecutionRequested ())
197- {
198- while (wouldExecuteNextLeaf () && tryExecuteNextLeaf ("Manually" ));
199- }
200169
201170 if (state .pollFailureResetRequested ())
202- {
203- failedLeaves .clear ();
204171 for (int i = 0 ; i < state .getOrderedLeaves ().size (); i ++)
205172 {
206173 state .getOrderedLeaves ().get (i ).setFailed (false );
207174 state .getOrderedLeaves ().get (i ).setIsExecuting (false );
208175 }
209- }
210176 }
211177
212- private boolean tryExecuteNextLeaf ( String adjective )
178+ private boolean leafCeasedExecution ( LeafNodeExecutor <?, ?> leaf )
213179 {
214180 boolean keepGoing = true ;
215- LeafNodeExecutor <?, ?> leafToExecute = orderedLeaves . get ( state . getExecutionNextIndex () );
216- leafToExecute . update (); // Make sure can execute is up to date
217- if (leafToExecute .getState (). getCanExecute () )
181+ String name = leaf . getDefinition (). getName ( );
182+ boolean failed = leaf . getState (). getFailed ();
183+ if (leaf .getState () instanceof ActionNodeState <?> actionNodeState )
218184 {
219- state .getLogger ().info ("%s executing leaf: %s (%s)" .formatted (adjective ,
220- leafToExecute .getDefinition ().getName (),
221- leafToExecute .getClass ().getSimpleName ()));
222- leafToExecute .triggerExecution ();
223- if (leafToExecute .getState ().getFailed ()) // Handle immediate failure
224- {
225- keepGoing = false ;
226- reportLeafCeasedExecution (leafToExecute , false );
227- }
228- else
229- currentlyExecutingLeaves .add (leafToExecute );
230- state .stepForwardNextExecutionIndex ();
185+ String resultMessage = failed ? "failed after" : "completed successfully in" ;
186+ double elapsedExecutionTime = actionNodeState .getElapsedExecutionTime ();
187+ state .getLogger ().log (failed ? Level .ERROR : Level .INFO , "Action %s %.2f s: %s" .formatted (resultMessage , elapsedExecutionTime , name ));
231188 }
232189 else
233190 {
234- state .getLogger ().error ("Cannot execute leaf: %s: %s\n %s" .formatted (leafToExecute .getClass ().getSimpleName (),
235- leafToExecute .getDefinition ().getName (),
236- leafToExecute .getCantExecuteMessage ()));
237- keepGoing = false ;
191+ String resultMessage = failed ? "failed" : "completed successfully" ;
192+ state .getLogger ().log (failed ? Level .ERROR : Level .INFO , "Leaf %s: %s" .formatted (resultMessage , name ));
238193 }
239194
240- if (!keepGoing )
195+ boolean isTryLeaf = false ;
196+ for (FallbackNodeExecutor fallbackNode : fallbackNodes )
197+ if (fallbackNode .getChildrenLeaves ().contains (leaf ))
198+ isTryLeaf |= fallbackNode .leafCeasedExecution (leaf );
199+
200+ if (!isTryLeaf && failed )
201+ {
202+ state .getLogger ().error ("A leaf failed. Disabling automatic execution.\n Failed: %s" .formatted (leaf ));
241203 state .setAutomaticExecution (false );
204+ keepGoing = false ;
205+ }
206+
207+ if (failed )
208+ failedLeaves .add (leaf );
209+ else
210+ successfulLeaves .add (leaf );
242211
243212 return keepGoing ;
244213 }
245214
246- private boolean wouldExecuteNextLeaf ( )
215+ private int effectiveExecuteAfterLeafIndex ( LeafNodeExecutor <?, ?> leaf )
247216 {
248- if (isEndOfSequence ())
249- return false ;
217+ int i = leaf .getState ().getLeafIndex ();
250218
251- LeafNodeExecutor <?, ?> nextNodeToExecute = orderedLeaves .get (state .getExecutionNextIndex ());
219+ if (!state .getConcurrencyEnabled ())
220+ return i - 1 ;
252221
253- // If a fallback catch is up next, block if any corresponding try leaves are executing
254- for (FallbackNodeExecutor fallbackNode : fallbackNodes )
255- if (fallbackNode .getFallbackLeaves ().indexOf (nextNodeToExecute ) == 0 ) // The first fallback catch leaf is next
256- for (LeafNodeExecutor <?, ?> tryLeaf : fallbackNode .getTryLeaves ())
257- if (tryLeaf .getState ().getIsExecuting ())
258- return false ;
222+ int after = leaf .getState ().getExecuteAfterLeafIndex ();
259223
260- if (state .getConcurrencyEnabled ())
261- {
262- int executeAfterLeafIndex = nextNodeToExecute .getState ().getExecuteAfterLeafIndex ();
224+ for (int j = after + 1 ; j < i ; j ++) // Might have to wait on nearer leaves
225+ after = Math .max (after , state .getOrderedLeaves ().get (j ).getExecuteAfterLeafIndex ());
263226
264- if (executeAfterLeafIndex < 0 ) // Execute after beginning
265- return true ;
266- else
267- return !orderedLeaves .get (executeAfterLeafIndex ).getState ().getIsExecuting ();
268- }
269- else
270- return currentlyExecutingLeaves .isEmpty ();
271- }
227+ for (FallbackNodeExecutor fallbackNode : fallbackNodes ) // catch group can't execute with anything above catch
228+ if (fallbackNode .getCatchLeaves ().contains (leaf ))
229+ after = Math .max (after , fallbackNode .getCatchLeaves ().get (0 ).getState ().getLeafIndex () - 1 );
272230
273- private void reportLeafCeasedExecution (LeafNodeExecutor <?, ?> currentlyExecutingLeaf , boolean success )
274- {
275- String name = currentlyExecutingLeaf .getDefinition ().getName ();
276- if (currentlyExecutingLeaf .getState () instanceof ActionNodeState <?> actionNodeState )
277- {
278- String resultMessage = success ? "completed successfully in" : "failed after" ;
279- double elapsedExecutionTime = actionNodeState .getElapsedExecutionTime ();
280- state .getLogger ().log (success ? Level .INFO : Level .ERROR , "Action %s %.2f s: %s" .formatted (resultMessage , elapsedExecutionTime , name ));
281- }
282- else
283- {
284- String resultMessage = success ? "completed successfully" : "failed" ;
285- state .getLogger ().log (success ? Level .INFO : Level .ERROR , "Leaf %s: %s" .formatted (resultMessage , name ));
286- }
231+ return after ;
287232 }
288233
289234 public boolean isEndOfSequence ()
0 commit comments