Making new tasks feature in RMF (#140)

Posted by @samuelrawrs:

Hi all, I noticed this new tasks feature being merged into the main branch and would love if the contributors (@mxgrey @Yadunund) could explain how to use this new feature to create custom tasks in RMF? :smile:

Posted by @samuelrawrs:

A new task I’m trying to customise is similar to the cleaning zone task, except perhaps with additional features like being able to control the speed at certain parts within the zone.

Posted by @mxgrey:

The implementation of the new task system allows an extreme level of extensibility and customization for what kind of tasks RMF can support.

That said, the current release of the rmf_fleet_adapter library intentionally puts some limits on how much tasks can be customized through the public API. We were originally going to expose the full degree of extensibility of the new system, but we were afraid that the public API was getting too complex and may be detrimental for users if it’s too hard to understand how to customize and extend tasks.

So until we have more time to fine-tune the public API, we reduced the extensibility to one point, which is the “Perform Action” hook. The Idea behind “Perform Action” is that RMF will pass along an arbitrary command to the platform-specific end of the fleet adapter integration, and will formally release all control of the robot until the action is finished. This is the way that the Clean task will be implemented moving forward, so I believe it will work for your use-case as well.

There are two parts of the API that need to be used to enable performing actions:

  1. rmf_fleet_adapter::agv::FleetUpdateHandle::add_performable_action This is where you tell the fleet adapter what kind of actions your fleet can perform so that the fleet adapter knows when it should accept or reject task requests.
  2. rmf_fleet_adapter::agv::RobotUpdateHandle::set_action_executor This is where you tell the fleet adapter how to instruct your robot to begin performing an action. The callback that you give to this function must accept:
  • a category string which tells you what type of action it is
  • a description JSON message which contains details about how the action should be performed (e.g. what zone to clean or where/how to perform the action)
  • an execution object which the platform-specific side of the fleet adapter must hold onto while the action is being performed, ideally giving periodic updates for remaining time estimates

It is entirely up to you as the system integrator to decide what string the category should use and what kind of structure the description message should have.

Posted by @choobacca-bacca:

Hi, so does this mean in order to implement a new task, we would create a new fleet adapter that can handle the new task definition added in? So like “full control fleet adapter”, it would be “task X full control fleet adapter”.
https://github.com/open-rmf/rmf_ros2/blob/ae22c0c5f67294ad6d210e6769e0b588f66e08db/rmf_fleet_adapter/src/full_control/main.cpp

Noticed in the current implementation of the full control fleet adapter, there is an added task for teleoperation, so we would essentially be following this method.

Posted by @mxgrey:

This depends a bit on what exactly you mean by “implement a new task”.

In the 22.02 release, we recommend defining custom tasks using the task_description__compose.json schema. That lets you “compose” a task from building blocks called “activities”. The currently supported activities are:

  • sequence: Specify a sequence of activities to perform. This can be used to create a tree-like structure of activities to perform.
  • go_to_place: Tell the robot to go to a place.
  • pickup: Tell the robot to pick up a payload at a location.
  • dropoff: Tell the robot to drop off a payload at a location.
  • clean: Tell the robot to clean a zone.
  • perform_action: Tell the robot to perform an action.

The implementation for all these building blocks is built into the implementation of RMF, except for perform_action which requires the system integrator to provide a callback that can handle every action category that the fleet should support.

Noticed in the current implementation of the full control fleet adapter, there is an added task for teleoperation, so we would essentially be following this method.

Yes, that can be used as an example for how to add a custom “action” for the perform_action building block.

Posted by @choobacca-bacca:

Ok, so just spitballing here, why not I just create a task description that follows the same schema as a cleaning task, but rename it to “Activity X”, but the cleaning phase just triggers Activity X on the robot instead. Then there would be no need for me to implement a new activity.

It would be confusing but it would fulfill my immediate needs.

Because otherwise, the current method of creating a new activity would involve me writing a fleet adapter from scratch (as in obviously mostly copied and pasted from the full control fleet adapter), unless I’m wrong and there’s a better way of doing this.

Posted by @mxgrey:

Is there a particular robot platform that you’re targeting, or are you just trying to simulate a proof of concept using nothing besides the out-of-the-box simulation tools of open-rmf?

If it’s the latter, then your proposal would certainly be a way to accomplish that, although it’s obviously not the intended way to use the framework. We should consider refactoring the simulation-targeted fleet adapter to provide these extension points without needing the user to copy/paste any of the implementation.

Posted by @choobacca-bacca:

Its the former way, but I’m just trying to understand the differences here.

Posted by @mxgrey:

For your specific robot platform, are you writing a fleet adapter for it, or are you using free fleet?

Posted by @eliasdc:

What is the intended way of using the framework with or without free fleet for supporting a custom robot? I know free fleet doesn’t support this perform_action yet but I’m willing to add it to the main branch and develop branch. But I’m not 100% sure what the intended way of using the framework is. Free fleet main branch uses the full_control adapter from rmf_ros2 and the main branch rewrites the entire adapter (mostly copy-paste).