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

Introduce a common TaskRemapper with wildcard support #55

Open
wants to merge 6 commits into
base: main
Choose a base branch
from

Conversation

luca-della-vedova
Copy link
Member

This PR refactors the task remapping capability in nexus_system_orchestrator (which was fully fledged) and the one in nexus_workcell_orchestrator (that was actually unimplemented) into a common TaskRemapper class.

This class has basic wildcard support, if it finds such a remapping:

    pick_and_place: ["*"],

It will override every other defined remap and just remap every single task to the requested pick_and_place.
I added a set of unit tests to show how the functionality works and now both system and workcell orchestrator share the same codebase for task remapping.

In the future we can consider more complex behaviors (i.e. proper wildcard support)

Signed-off-by: Luca Della Vedova <lucadv@intrinsic.ai>
Signed-off-by: Luca Della Vedova <lucadv@intrinsic.ai>
Signed-off-by: Luca Della Vedova <lucadv@intrinsic.ai>
Comment on lines 981 to 992
const auto new_task = this->_task_remapper->remap(ctx->task.type);
if (new_task != ctx->task.type)
{
RCLCPP_DEBUG(
this->get_logger(),
"Loading remapped BT [%s] for original task type [%s]",
new_task.c_str(),
ctx->task.type.c_str()
);
}
return this->_bt_factory->createTreeFromFile(this->_bt_store.get_bt(
ctx->task.type));
new_task));
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note here we could either:

  • Use the new name to only load the behavior tree (what I did)
  • Override the task type (what I didn't do)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer what you did which preserves the original request. Users can always look for the remapping if needed from ctx-> task_remapper

Signed-off-by: Luca Della Vedova <lucadv@intrinsic.ai>
Copy link
Member

@Yadunund Yadunund left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor feedback on the TaskRemapper API but this is looking good otherwise!

/*
* Initialize the remapper with the value of a ROS parameter containing a YAML
*/
TaskRemapper(const std::string& param);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This API is error prone especially if users do not pass a string that can be deserialized into a YAML. ie YAML::Load() can throw an exception in the implementation.
I suggest we accept a concrete type here instead like an std::multimap where the key is the remapped process and the values for each key are the process steps in the work order.

This way if the param definition changes in the orchestrators, this API would not have to change.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR doesn't introduce any new exception since all uses of this class were doing YAML::Load anyway, so they would have thrown on an invalid YAML.
The "proper" way I considered going for was either passing a YAML node as an input (so we won't throw) or keep the string and make the constructor fallible (i.e. a make function, return nullptr if the YAML failed deserializing). I didn't do it only because I saw that the codebase doesn't seem to use this paradigm but I'm happy to do it.

I feel that if we add a multimap and users of the API need to manually parse the YAML, handle exceptions, add its content to a multimap, then we read the multimap, iterate over it, check for wildcards, populate internal data structures accordingly, it becomes much more complex and clunky. Instead of being a refactor to reduce duplicated code we actually end up with a fair bit more code and complexity.

nexus_common/include/nexus_common/task_remapper.hpp Outdated Show resolved Hide resolved
nexus_common/src/task_remapper_test.cpp Show resolved Hide resolved
Comment on lines 981 to 992
const auto new_task = this->_task_remapper->remap(ctx->task.type);
if (new_task != ctx->task.type)
{
RCLCPP_DEBUG(
this->get_logger(),
"Loading remapped BT [%s] for original task type [%s]",
new_task.c_str(),
ctx->task.type.c_str()
);
}
return this->_bt_factory->createTreeFromFile(this->_bt_store.get_bt(
ctx->task.type));
new_task));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer what you did which preserves the original request. Users can always look for the remapping if needed from ctx-> task_remapper

Signed-off-by: Luca Della Vedova <lucadv@intrinsic.ai>
Signed-off-by: Luca Della Vedova <lucadv@intrinsic.ai>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants