Robotics requires expertise from several domains, with the goal to produce systems that combine this broad expertise into desired results. The domains can vary greatly, from computer vision to motion control, machine learning to haptic feedback, and more. I created the ROS trees library to apply behaviour trees to this challenge—how can a robot address challenging real world robotics problems by making the most of the cross-domain expertise at its disposal?
Since release, the ROS trees library has powered a range of robotics research results for QUT's Centre for Robotics (QCR), including:
The ROS trees library was an output from the ACRV's entry into the 2019 RoboCup@Home challenge. Robots completed a range of service and assistive domestic tasks to score points, like taking out rubbish bags, greeting and hosting guests, and arranging plates in kitchen shelves. ACRV researchers had expertise that could translate to this domain—robot manipulation, mobile robotics, best-grasp and object detectors, etc.—but we were missing a system to apply this expertise to robotic tasks.
Roboticists often reach for finite state machines (FSMs) when building complex robot systems, but managing state transition logic becomes overwhelming as the systems grow (the number of potential state transitions grows exponentially with the number of states). Adaptations like hierarchical state machines exist to help limit this growth, but it still doesn't get around a state's implementation depending on the system's possible state transitions. This makes it troublesome to define states that are independent of system or task. Should roboticists really have to create a slightly different state implementation for every task that requires checking if a door is open? Or even worse, implement the same state multiple times within a single task?
Behaviour trees were suggested as an alternative to the state gridlock presented by FSMs. Instead, behaviour trees encode transition logic in the structure of the tree. This allows a leaf, which are behaviour tree's equivalent of states, to be written once and used in any task requiring its capability. An example of how the structure of a tree can be used to solve a bottle binning task is shown below.
Realising the benefits of behaviour trees required one more step: creating abstractions to manage how data flows through the tree. Unfortunately, ROS by default needs a lot of boilerplate for simple translations between functionally equivalent datatypes (e.g. using a
Pose from a
PoseWithCovarianceStamped, or using a service response as a request for another service). To address this, I created methods to automatically infer data passing strategies and translations from a tree's structure. From here, the ROS trees library was born.
The main contribution of the ROS trees library is a structured, consistent, and flexible definition of leaf internals. This definition allows users to configure every aspect of a leaf's behaviour, while also providing sensible defaults that minimise code re-use and need for tedious manual data translations. The library is built atop the
py_trees library, including full support for data persistence using their shared 'blackboard' singleton. An overview of ROS tree's leaf lifecycle, and configuration points, is shown below.
The ROS trees library has provided a lot of value internally at QCR, and I'm glad to be able to share it with the wider community. I'd love to hear thoughts on the ROS trees library, whether it's something you'd like to do, have done, an exciting result, bugs or feature requests—any and all feedback is welcome. ROS trees is an exciting step towards modular task-specific systems in ROS, and I look forward to seeing how we can expand this further in the future.
© Ben Talbot. All rights reserved.