Task Executive¶
A set of nodes and libraries for defining and executing long-term task-level behaviour.
Overview¶
The task executor is the central element of the strands_executive
framework. It receives tasks from clients, queues them for execution,
then manages their execution and the required navigation between tasks.
This package provides two executors: the simple fifo_task_executor
which simply executes tasks in the order it receives them (ignoring
their timing constraints) and the scheduled_task_executor
which uses
the scheduler
node
to create and maintain an execution schedule based on the time windows
of the tasks. This package also provides the task_routine
Python
module which facilitates the creation of daily task routines with
repeating temporal structure.
Modules¶
For the task routine module see the description on the overview page, and the API documentation.
Runtime Dependencies¶
For the executive framework to function correctly, you must have the mongodb_store nodes running. These are used by the framework to store tasks with arbitrary arguments.
roslaunch mongodb_store mongodb_store.launch
or with path specifying, where should the db is stored:
roslaunch mongodb_store mongodb_store.launch db_path:=/...
Currently the task executive abstracts over navigation actions using the STRANDS topological navigation framework. Therefore you must have this framework running. For testing, or if you’re not running the full topological navigation system, you can run a simple simulated topological system with the following command:
roslaunch topological_utils dummy_topological_navigation.launch
This produces a map with 9 nodes: ChargingPoint
in the centre, with
v_-2
, v_-1
to v_2
running vertically and h_-2
to h_2
running horizontally, joining ChargingPoint
in the middle.
Nodes¶
scheduled_task_executor.py
¶
This node receives tasks via the services, schedules them for execution, then executes them in the order defined by the schedule.
Execution Status¶
When the executor is started, it will not start executing any tasks
until the execution status is set to True
via a call to the
/task_executor/set_execution_status
(strands_executive_msgs/GetExecutionStatus
) service. If execution
status is set to False
then execution pauses, interrupting any
currently executing task.
Task Addition and Scheduling¶
Tasks are added using the add_task
(single task) and add_tasks
(multiple tasks) services. All received tasks are added to a queue for
scheduling which is monitored by the executor. When then queue contains
tasks, the new tasks, plus the tasks already scheduled are sent to the
scheduler
node.
If a task is successfully created, this replaces the previous schedule
and execution continues. If scheduling fails then the newly added tasks
are dropped by the executor and the previous schedule is reinstated.
Adding new tasks does not interrupt the currently executing task.
Task Demanding¶
If a task should be executed immediately, the demand_task
(strands_executive_msgs/DemandTask
) service can be used. This
interrupts the currently executing task and replaces it with the
demanded task. The schedule is then recreated to respect the execution
constraints of the demanded task, and, if possible the interrupted task
is included in this new schedule.
Interruptibility¶
By default the execution of tasks is interruptible (via actionlib
preempt). If you do not wish your task to be interrupted in these
condition you can provide the IsTaskInterruptible.srv
service at the
name <task name>_is_interruptible
, e.g.
do_dishes_is_interruptible
from the example above. You can change
the return value at runtime as this will be checked prior to
interruption.
Here’s an example from the node which provides the wait_action
.
class WaitServer:
def __init__(self):
self.server = actionlib.SimpleActionServer('wait_action', WaitAction, self.execute, False)
self.server.start()
# this is not necessary in this node, but included for testing purposes
rospy.Service('wait_action_is_interruptible', IsTaskInterruptible, self.is_interruptible)
def is_interruptible(self, req):
# rospy.loginfo('Yes, interrupt me, go ahead')
# return True
rospy.loginfo('No, I will never stop')
return False
Task Execution and Monitoring¶
When a task is executed it pass through two phases: navigation and
action execution. If the task has a start_node_id
set then the
executor uses topological navigation to move the robot to this start
node. Before doing so it obtains an estimate of the travel time from the
topological_navigation/travel_time_estimator
service. If the travel
time greatly exceeds this estimate, the topological navigation action is
preempted and the task execution is failed. If the
topological_navigation action reports anything but success on
completion then the task execution is failed. If it reports success then
the task moves on to the action execution phase. This phases triggers
the action server described by the task. If execution of the action
server greatly exceeds the max_duration
of the task, it is preempted
and execution is considered failed. The overall execution state machine
is pictured below.
Services¶
task_executor/add_tasks
(strands_executive_msgs/AddTasks)
Add a list of tasks to be scheduled for execution.
task_executor/add_task
(strands_executive_msgs/AddTask)
Add a single task to be scheduled for execution.
task_executor/demand_task
(strands_executive_msgs/DemandTask)
Triggers the immediate execution of a task, interrupting the currently executing task.
task_executor/set_execution_status
(strands_executive_msgs/SetExecutionStatus)
Sets the execution status of the executor. Set to false to pause execution. Starts at false so much be set to true on start-up.
task_executor/get_execution_status
(strands_executive_msgs/GetExecutionStatus)
Gets the current execution status of the executor.
task_executor/clear_schedule
(std_srvs/Empty
)
Clears all tasks scheduled for execution. Cancels any active task.
task_executor/cancel_task
(strands_executive_msgs/CancelTask)
Removes the task with the given id from the schedule. If this task is currently executing, execution is interrupted.
task_executor/get_active_task
(strands_executive_msgs/GetActiveTask)
Gets the task which is currently executing.
Published Topics¶
task_executor/events
strands_executive_msgs/TaskEvent)
Events that happen as the task executor passes through its state machine for each task.
current_schedule
strands_executive_msgs/ExecutionStatus)
The list of upcoming tasks and what is currently being executed.
fifo_task_executor.py
¶
A greatly simplified task executor that executes tasks in the order they
are added, and only supports task addition and very little else when
compared to the scheduled_task_executor
.
schedule_status.py
¶
Prints a summary of the current_schedule
topic.
Original page: https://github.com/strands-project/strands_executive/blob/indigo-devel/task_executor/README.md