-
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
Use behaviour trees in scriptlets demo #208
Conversation
delphyne-demos/demos/scriptlets.py
Outdated
@@ -75,8 +74,16 @@ def record_tick(self): | |||
self.reset() | |||
self.start() | |||
|
|||
def pos_tick_handler(self, behaviour_tree): | |||
if self._current_start_time is None: | |||
self.start() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@BMarchi SimulationStats.start()
should be called before the first tick happens.
delphyne-demos/demos/scriptlets.py
Outdated
if self._current_start_time is None: | ||
self.start() | ||
else: | ||
self.record_tick() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@BMarchi if SimulationStats
is completely initialized by the time a post tick handler gets called, we don't need the additional method and we can simple use record_tick()
or a lambda
to drop any unused arguments.
delphyne-demos/demos/scriptlets.py
Outdated
speed=4.0 | ||
) | ||
decorator = delphyne.decorators.additional_action.AdditionalAction( | ||
child=rail_car, conditional_object=monitor) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The first issue will be that the SetSpeed behaviour would require to reference the agent by using a call to parent->parent
to pass the decorator or using a blackboard, which seems an overkill.
When I created this decorator, I had on my mind to do any kind of stuff with the decorator's child. We could just change the name's value of the decorator if we require to do other stuff, instead of creating a ton of different behaviours just to do set_speed = 20
for instance
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The first issue will be that the SetSpeed behaviour would require to reference the agent by using a call to parent->parent to pass the decorator or using a blackboard, which seems an overkill.
Hmm, can't we give it a reference to the agent behaviour during subtree construction? Instead of traversing the tree I mean. I agree though that this has somewhat less to do with behaviour and more with structure, so it looks funny.
When I created this decorator, I had on my mind to do any kind of stuff with the decorator's child. We could just change the name's value of the decorator if we require to do other stuff, instead of creating a ton of different behaviours just to do set_speed = 20 for instance
Hmm not convinced the potential for reuse is enough to bypass the tree (which IMO is what we're doing here in TimeMonitor.do_action()
, replacing an entire subtree with code). That's why I said it's non-idiomatic, as opposed to non functional. How would you augment this to follow a speed profile over time, braking in several places and steering the vehicle?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, can't we give it a reference to the agent behaviour during subtree construction?
We can. I fear it could lead to a bunch of behaviours touching the same thing.
braking in several places and steering the vehicle?
To me, that's the point of blackboards. Keep track of the variables modified by behaviours and use them when you need it in any moment (i.e behaviours). Since we have a global one it can get big in no time, but I'm thinking that having an object that it's related to one and only one agent in the blackboard where we can save the variables we want, is the way to go. The big picture for me is that any child of the agent's behaviour should monitorize something and save somewhere the result, so in the next tick the agent is "aware" of that thanks to the blackboard.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can. I fear it could lead to a bunch of behaviours touching the same thing.
Hmm, I'm not sure I follow why that is a problem. It is problematic in the sense that not all relationships are explicit in the tree, but that's not the case right now either nor is the case if several behaviours, be them children or siblings, share state in the blackboard,
To me, that's the point of blackboards. Keep track of the variables modified by behaviours and use them when you need it in any moment (i.e behaviours).
Sure, that makes sense for state, but what about behaviour? If we express behaviour in the tree, it's explicit and easy to compose, if we do it through code to boost reuse we are back in procedural programming land.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, I'm not sure I follow why that is a problem.
Tons of behaviours modifying the agent directly will make things more complex for someone who didn't write the code rather than modifying the agent in just one place. I don't know how this can impact in understanding the tree if we have a tree with a considerable depth where a child modifies a parent that it's way above it instead of touching a variable and let anyone read it if they need to.
it's explicit and easy to compose
I agree with adding behaviours, using composites and such. What I don't think it's good is what I said. Modify a parent by a child that can be 5, 10 or even more levels of depth instead of touching a variable in the blackboard and let the others use it as they need.
delphyne-demos/demos/scriptlets.py
Outdated
def random_print(): | ||
''' | ||
behaviour_tree parameter is necessary to add it as a pos/pre tick handler | ||
''' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@BMarchi nit: put this in the function's docstring.
delphyne-demos/demos/scriptlets.py
Outdated
print("Running simulation indefinitely.") | ||
stats.start() | ||
simulation_tree.tick_tock( | ||
period=time_step) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@BMarchi nit: why the line wrap?
delphyne-demos/demos/scriptlets.py
Outdated
else: | ||
# run for a finite time | ||
print("Running simulation for {0} seconds.".format( | ||
args.duration)) | ||
runner.run_async_for(args.duration, launcher.terminate) | ||
stats.start() | ||
simulation_tree.tick_tock( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@BMarchi nit: same about line wraps
delphyne-demos/demos/scriptlets.py
Outdated
@@ -35,6 +37,29 @@ | |||
############################################################################## | |||
|
|||
|
|||
class ChangeSpeed(py_trees.behaviour.Behaviour): | |||
|
|||
def __init__(self, parent_name, speed=1.0, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@BMarchi nit: parent_name
-> agent_name
delphyne-demos/demos/scriptlets.py
Outdated
speed=4.0 | ||
) | ||
|
||
change_speed = ChangeSpeed('rail0', 20.0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@BMarchi nit: use keyword arguments for improved readability
delphyne-demos/demos/scriptlets.py
Outdated
|
||
timeout_decorator = py_trees.decorators.Timeout( | ||
child=change_speed, | ||
duration=5.0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@BMarchi It seems the standard Timeout
decorator uses system time. We cannot rely on the real time factor to be 1, thus we can't use it. Also, using a timeout to instrument a wait is a bit odd. Could the new decorator/behaviour have wait/delay/until in the name?
parent_attributes = blackboard.get(self.parent_name) | ||
parent_attributes["speed"] = self.speed | ||
blackboard.set(self.parent_name, parent_attributes, True) | ||
self.status = py_trees.common.Status.SUCCESS |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@BMarchi if you move away from Timeout
to a Wait
maybe this can migrate to update()
.
delphyne-demos/demos/scriptlets.py
Outdated
blackboard = py_trees.blackboard.Blackboard() | ||
parent_attributes = blackboard.get(self.parent_name) | ||
parent_attributes["speed"] = self.speed | ||
blackboard.set(self.parent_name, parent_attributes, True) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@BMarchi this is a bit verbose, can we wrap it somehow? Assuming you chose not to simply use the agent for X reasons.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM for a few nits.
delphyne-demos/demos/scriptlets.py
Outdated
simulation.get_current_time() >= 10.0: | ||
print("Speed up!") | ||
blackboard = py_trees.blackboard.Blackboard() | ||
parent_attributes = blackboard.get(self.agent_name) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@BMarchi nit: parent_attributes
-> agent_attributes
|
||
""" | ||
Change speed of agent_name after 10 seconds passed in the simulation. | ||
""" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@BMarchi this is good as-is, but just out of curiosity, why did you decide not to have a generic Delay
behaviour tied to simulation time?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By behaviour you mean a decorator, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess you could do it either way. A decorator probably makes more sense, yes.
|
||
one_shot_decorator = py_trees.decorators.OneShot( | ||
child=change_speed, | ||
policy=py_trees.common.OneShotPolicy.ON_COMPLETION) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@BMarchi if we're using the OneShot
decorator here, why do we need the speed_changed
boolean flag on DelayChangeSpeed
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I saw that the update method was getting fired anyway, I'll double check again
|
||
change_speed = DelayChangeSpeed(agent_name='rail0', speed=20.0) | ||
|
||
one_shot_decorator = py_trees.decorators.OneShot( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@BMarchi nit: consider collapsing behaviour initialization so that it reads:
change_speed = py_trees.decorators.OneShot(child=DelayChangeSpeed(...), ...)
@@ -75,9 +107,15 @@ def record_tick(self): | |||
self.reset() | |||
self.start() | |||
|
|||
def pos_tick_handler(self, behaviour_tree): | |||
self.record_tick() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@BMarchi nit: if you use lambda _: stats.record_tick()
for a post tick handler, there's no need for this tailor-made method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I left it as it is just to show an example
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, I see. Nevermind then.
delphyne-demos/demos/scriptlets.py
Outdated
from . import helpers | ||
|
||
############################################################################## | ||
# Supporting Classes & Methods | ||
############################################################################## | ||
|
||
|
||
class DelayChangeSpeed(py_trees.behaviour.Behaviour): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@BMarchi nit^2: consider DelayedChangeSpeed
instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM pending green CI
runner.run_async_for(args.duration, launcher.terminate) | ||
stats.start() | ||
simulation_tree.tick_tock(period=time_step, | ||
number_of_iterations=args.duration/time_step) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@BMarchi mind to add launcher.terminate()
considering #213 (comment) ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, no, let's merge and do so in a follow-up PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
3d27b95
to
2ea708e
Compare
2ea708e
to
f175abb
Compare
* Fix bad python import in delphyne_gui. Signed-off-by: Michel Hidalgo <michel@ekumenlabs.com> * Refactor delphyne-dragway to use new behaviour tree-based API. Signed-off-by: Michel Hidalgo <michel@ekumenlabs.com> * Add behaviour trees to gazoo example * Tidy up, functionalize subtree creation * Add termination after time is up * Refactor delphyne-crash to use new behaviour tree-based API. Signed-off-by: Michel Hidalgo <michel@ekumenlabs.com> * Update some delphyne-* demos to use delphyne.behaviours.roads Signed-off-by: Michel Hidalgo <michel@ekumenlabs.com> * Use behaviour trees in scriptlets demo (#208) * Rename scriptlets maliput package for roads (#206) * Use behaviour trees in scriplets demo * Use behaviour trees delphyne-city demo (#209) * Polished demos refactored to use behaviour trees. Signed-off-by: Michel Hidalgo <michel@ekumenlabs.com> * Use same time step for all demos. Signed-off-by: Michel Hidalgo <michel@ekumenlabs.com>
This demo shows how to use a pre/pos tick handler with objects and plain functions, while also including a object that can do anything when a decorator calls it