splintered-reality / py_trees_ros

ROS extensions and implementations for py_trees
Other
162 stars 40 forks source link

What is the easiest way to get blackboard variable from rclpy node? #171

Open AlexKaravaev opened 3 years ago

AlexKaravaev commented 3 years ago

Hi there!

I am struggling to get blackboard variable from one of my nodes, approaches I've tried: 1) Creating blackboard client in node init


        self.blackboard = py_trees.blackboard.Client(name="stop_client")
        self.blackboard.register_key(key="/stop", access=py_trees.common.Access.WRITE)

And then getting variable like this

self.get_logger().info(f"Stop ? {self.blackboard.get('/stop.data')}")

But it tells me that ther is no such variable, though I can get it from running py-trees-blackboard-watcher

2) Creating blackboard watcher

        self.blackboard_watcher = py_trees_ros.blackboard.BlackboardWatcher(
            namespace_hint=""
        )
        self.blackboard_watcher.setup(timeout_sec=2.0)

But this way it creates new topic and the way for me to get blackboard variable is to subscribe to this topic.

Can you please tell me, what way will be the best to get the data inside blackboard variable?

stonier commented 3 years ago

Perhaps you haven't written anything to the blackboard yet? Registering a key just informs the blackboard what access the client has to the specified variable. It doesn't actually populate the variable, you'll have to write to the blackboard first.

Example program:

#!/usr/bin/env python

import py_trees

class Stop:
    def __init__(self):
        self.data = 5

blackboard = py_trees.blackboard.Client(name="stop_client")
blackboard.register_key(key="/stop", access=py_trees.common.Access.WRITE)
print(f"{py_trees.display.unicode_blackboard()}")
blackboard.stop = Stop()
print(f"Stop : {blackboard.get('stop.data')}")
print(f"{py_trees.display.unicode_blackboard()}")

With output:

Blackboard Data
    /stop: -

Stop : 5
Blackboard Data
    /stop: <__main__.Stop object at 0x7f7693a29400>

The '-' indicates that it's a registered variable, but hasn't been populated yet.

AlexKaravaev commented 3 years ago

No, it was definitely written to. I am not able to come up right now with MWE, but I had set-up like this:

1) 1st terminal launching ros2 node and registering value at blackboard 2) 2st terminal publishing value to topic and behavior from 1st terminal(node) writes it to blackboard 3) 3st trying to access this variable from another node using just py_trees will not succeed. However, using cli tool(blackboard-watcher or something like that, do not remember name exactly) shows that blackboard value is populated. Also, using py_trees_ros.blackboard.blackboardWatcher works too, but I don't like that way, because it creates additional overhead of creating and subscribing to topic.

stonier commented 3 years ago

You're trying to access the blackboard from a process in the 1st terminal from a separate process in the 3rd terminal?

The blackboard is in-memory (RAM) storage accessible only if you're in the same process. If you are in a different process, you absolutely need some kind of middleware (pubs and subs) to ferry the data.

Admittedly, I hadn't expected anyone to want to use something like BlackboardWatcher directly. I'd written that purely to service the py-trees-blackboard-watcher debugging tool, but it's not very usable on it's own (just look at all the glue in py_trees_ros.programs.blackboard_watcher.py).

What you might be wanting is something convenient that (partially) mirrors the blackboard in that other process so, for example, you can make use of the py_trees.blackboard.Client api. For that, I imagine it would be a new class (e.g. MirrorBlackboard) that hides all of the middleware ugliness, initialisation and termination logic, but reconstructs the blackboard for pure pythonic access in that process. Is this sounding more along the lines of what you are looking for?

AlexKaravaev commented 3 years ago

Okay, I see. I thought that key-value storage for blackboard is accessible for all of the system(like a small DB).

Just out of the curiosity, why you have chosen to do blackboard only accessible within the process? Because, I was looking for kind of 'ros parameter server' blackboard. I just want to separate parameters and values that are indented to change the behavior of the agent(these goes to blackboard) and pure configurational stuff, like baudrate, map size etc..(these goes to parameter server).

For me particular use case was like this: I have robot and want to add the functionality of stopping/going forward. I made a web-page with GUI button for that. Ideally, I want to write from that web-page to the blackboard value True/False to the /stop blackboard variable. On the robot ros2 is running and controls all the things within the robot. One of the nodes, that is maintaining behavior will read that variable and report robot to be stopped.

Your last proposal is about mirroring the blackboard could be the solution, but I for me it is a little bit clunky, with adding all the middleware things like creating topic for value retrieval. If there would be a way to get the blackboard variable from different process with ros2 service call for example, it would be much more convenient, I think. Unless, off course, there are some underlying reasons of not doing so.

Just FYI I really liked py-trees in terms of things it can do with behavior trees and after all I think it's like one and only ros-compatible python-solution out there. I have encountered paper about behaviour trees frameworks review and your project was I think literally the only one which is written in python and compatible with ros and still maintained.

stonier commented 2 years ago

Late reply, but for completeness...

Just out of the curiosity, why you have chosen to do blackboard only accessible within the process?

There are many non-ros applications of blackboards and they all need blackboards, so the initial design had to work for a core library that does not have ROS (or some other higher level framework).

py_trees_ros is intended to provide conveniences, exactly like the watcher and the kind of blackboard 'server' we were talking about here. Such a 'server' would be a nice addition. Why not already? Simply just effort and not having a use case come along that wanted it.