Skip to content
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

Blackboards with tracking #222

Merged
merged 15 commits into from
Oct 3, 2019
Merged

Blackboards with tracking #222

merged 15 commits into from
Oct 3, 2019

Conversation

stonier
Copy link
Member

@stonier stonier commented Sep 10, 2019

Breaking API

  • [decorators] updated EternalGuard to accommodate new blackboard variable tracking
  • [behaviours] decoupled CheckBlackboardVariableExists, WaitForBlackboardVariable
  • [behaviours] decoupled CheckBlackboardVariableValue, WaitForBlackboardVariableValue
  • [behaviours] dropped use of the largely redundant ClearingPolicy for blackboard behaviours
  • [visitors] collapsed SnapshotVisitor and WindsOfChangeVisitor functionality

New Features

  • [blackboard] read/write access configuration for clients on blackboard keys
  • [blackboard] log the activity on the blackboard
  • [display] dot graphs now have an option to display blackboard variables
  • [display] unicode to console the entire blackboard key-value store
  • [display] unicode to console the blackboard activity stream
  • [visitors] new DisplaySnapshotVisitor to simplify collection/printing the tree to console

Out of Scope

  • Properly decoupling global blackboard and blackboard client code. The user doesn't touch any of the global blackboard code, so can easily follow in a PR. It is however noisesome having attributes and methods side by side in the same class. Just didn't get done in this PR because it was an additional increment. ... This has been done.
  • Exclusive locks ... now that we're here, wouldn't be hard to put exclusive locking on blackboard keys
  • A data format with structure (... JSON) that would permit easier nested access / tracking on reads / pickling without problems, but require users to convert their data before writing

Examples

examples-1

examples-2

examples-3

examples-4

examples-5

examples-6

And a dot graph on a larger tree - ranking them via edge writers and leaving edge readers free of constraints leaves it pretty readable.

tutorial_eight

examples-7

Note - the captured "Blackboard Data" above is only the key-value pairs that are associated with behaviours on the visited path for that tick.

examples-8

@liangfok
Copy link
Contributor

liangfok commented Oct 2, 2019

Regarding:

Image of Yaktocat

In the second half where it describes read/write access, it looks like it first creates a blackboard client that has read access to key "foo" and write access to key "bar". Subsequently, it adds write access to key "foo", and finally writes to key "foo". Is this correct?

What will happen if a user attempts to write to a blackboard variable without first declaring write access?

blackboard = py_trees.blackboard.Blackboard(
    name="Client",
    read={"foo"},
    write={"bar"}
)
blackboard.foo = "foo"  # Error?

Likewise, what happens if a variable is read without first getting read access?

blackboard = py_trees.blackboard.Blackboard(
    name="Client",
    read={"foo"},
    write={"bar"}
)
temp = blackboard.bar  # Error?

@liangfok
Copy link
Contributor

liangfok commented Oct 2, 2019

Are the following two identical?

blackboard.set("foo", "bar", overwrite=True)
blackboard.foo = "bar"

@liangfok
Copy link
Contributor

liangfok commented Oct 2, 2019

Does blackboard support an atomic read + write?

@stonier
Copy link
Member Author

stonier commented Oct 2, 2019

Are the following two identical?

blackboard.set("foo", "bar", overwrite=True)
blackboard.foo = "bar"

No difference in technical implementation but they serve different use cases. The former is useful if you programatically generate the name of your variable at runtime and can't use the approach exemplified in the latter. The latter is just incredibly convenient if that name is hard coded.

@liangfok
Copy link
Contributor

liangfok commented Oct 2, 2019

Is there any mechanism to prevent multiple blackboard clients from having the same name?

client_1 = py_trees.blackboard.Blackboard(name="alice", unique_identifier=uuid.uuid64())
client_2 = py_trees.blackboard.Blackboard(name="alice", unique_identifier=uuid.uuid64())  # Error?

@stonier
Copy link
Member Author

stonier commented Oct 2, 2019

Does blackboard support an atomic read + write?

If used with behaviour trees and only used in behaviour life cycles or crafted tree life cycle (pre-tick handler, ticks, visitors, post-tick handlers), then there is no concurrency. As a result, there is no need for expensive locking operations nor need to be concerned about atomic vs non-atomic. This is a feature that makes writing trees very simple.

As a result, the current design has no plans to support concurrency yet and shouldn't be used as such without extending it in various ways.

@stonier
Copy link
Member Author

stonier commented Oct 2, 2019

Is there any mechanism to prevent multiple blackboard clients from having the same name?

client_1 = py_trees.blackboard.Blackboard(name="alice", unique_identifier=uuid.uuid64())
client_2 = py_trees.blackboard.Blackboard(name="alice", unique_identifier=uuid.uuid64())  # Error?

Nope. Just like behaviours, the name is just a human friendly hint. Same UUID's would throw an error. This behaviours in the same manner as behaviours do right now.

For behaviours, this is generally just to make the tree more readable. I can see it might not be that great a hint if looking at the list of clients though. I could append an extra '*' to the name like I do for dot graphs when there is duplicity.

@liangfok
Copy link
Contributor

liangfok commented Oct 2, 2019

Regarding:

Image

Is there anything preventing behaviors from instantiating and using their own blackboard client with a name that differs from the blackboard's name?

class Foo(py_trees.behaviours.Behaviour):
    def __init__(self, name):
        super().__init__(name=name)
        # Error? Lead to confusion?
        self.my_other_blackboard = py_trees.blackboard.Blackboard(name="NotFoo", unique_identifier=uuid.uuid64())

@liangfok
Copy link
Contributor

liangfok commented Oct 2, 2019

Is there a way to focus on a single blackboard variable and display how it evolves over time (e.g., over the past 10 tickets, show the variable's value, who wrote to it, and who read from it)? The screenshot above showing the output of py_trees.visitors.DisplaySnapshotVicotor uses the "tick" as the independent variable. I'm wondering if the independent variable can be a blackboard variable.

@stonier
Copy link
Member Author

stonier commented Oct 2, 2019

Is there anything preventing behaviors from instantiating and using their own blackboard client with a name that differs from the blackboard's name?

Nothing stopping them ... and I actually did not want to couple behaviours with their blackboards at all, but found I frequently made human errors getting blackboard and behaviour id associations right so that you could crawl the visited path -> behaviour -> blackboard -> relevant variables journey. Coupling them removes those errors but also means you almost never need to instantiate a client yourself when working with behaviours. That alone should mean people aren't in the habit of creating blackboards that would go off the radar of behaviour/tree debugging tools.

Note, if they do make some, they'll still be on the radar of blackboard/dot debugging tools.

Would be nice to have a mechanism that could warn the user when they do so though. Unfortunately I can discern of no easy mechanism that would help with that.

@stonier
Copy link
Member Author

stonier commented Oct 2, 2019

Is there a way to focus on a single blackboard variable and display how it evolves over time (e.g., over the past 10 tickets, show the variable's value, who wrote to it, and who read from it)? The screenshot above showing the output of py_trees.visitors.DisplaySnapshotVicotor uses the "tick" as the independent variable. I'm wondering if the independent variable can be a blackboard variable.

Aye, but done in layers higher up. As you observed, you could write visitors which track selected variables over time or a layer on top of the blackboard to track the entire blackboard. This would be pretty application/use case specific though, I don't intend to have anything for this in the core library. Not implementing this in the core library though.

I do have a 'next step' to capture the visited path variables when the tree status changes though and pipe/display them in the web viewer. That caches the history of tree changes and with the additional blackboard information, it will save the blackboard context with each change. That means you'll be able to rewind/fast forward along the cached timeline to see how they changes at significant tree events. When I integrate this and update tooling in driving, you'll get this capability.

@stonier
Copy link
Member Author

stonier commented Oct 2, 2019

@peterpena when this goes in, it will result in some (minimal) breaking api changes for the code you have. Plans:

a) update all of your clones as soon as this goes in and try to update accordingly - there should be enough snippets of code in this PR to illustrate the kind of changes that need to go in or you can reach out to me on slack as well
b) don't update anything yet and let's have a small hackathon to upgrade on monday/tuesday when you're at TRI

@peterpena
Copy link

@stonier sounds good to me

@stonier stonier merged commit 2522491 into devel Oct 3, 2019
@stonier stonier deleted the experimental/blackboards branch October 3, 2019 12:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants