Module reference · Cross-cutting

Task Goal & Termination

The module that checks a study's stopping rules and ends the trial when the first one is met.

LayerUnite.Kernel
ScopeCross-cutting · trial lifecycle
CoordinatorTaskGoalAndTerminationModule
Criterion baseTaskTerminationCriterion
Demo criteriaTargetRegionEntry, ElapsedTimeLimit
Paper§5.12 · DR6

What

The module coordinates task completion, failure, timeout, and abort rules. It does not define one universal task. Instead, a study attaches one or more TaskTerminationCriterion components, and each criterion decides whether its own terminal condition has been reached.

A criterion returns a TrialTerminationResult with one of four outcomes: Success, Failure, Timeout, or Abort. The first result becomes the timestamped trial-ended event that other study modules can record.

Why

The paper's DR6 separates task and environment content from the rules that end a trial. The condition scene owns terrain, obstacles, lighting, and visible goal content. This module owns the executable rules that determine when the participant has completed the task or when the trial must stop.

This keeps the same teleoperation apparatus reusable across tasks. A goal-entry criterion, collision criterion, time limit, or operator abort can be selected without changing communication, vehicle behavior, observation streams, or presentation.

How

Each termination criterion watches one stopping rule. The flow below shows how current vehicle and task state becomes a terminal result and an event for the rest of the study.

Current vehicle and task statethe information criteria read
Termination criteriaone criterion per stopping rule
Task Goal & Terminationfirst result ends the trial
trial-ended eventoutcome and reason for other modules
  1. Check each rule. A criterion evaluates its own condition against the current vehicle and task state.
  2. End the trial. When a criterion returns Success, Failure, Timeout, or Abort, the module ends the trial.
  3. Notify the study. The module publishes trial-ended with the outcome and reason so other study modules can react or record it.

If multiple criteria become true in the same update, their Inspector order determines which result wins. In the shipped demo, target entry comes before the 300-second timeout.

Boundary

Owns

  • Evaluating the configured termination criteria against current vehicle and task state.
  • Choosing the first terminal result in the configured criterion order.
  • Publishing the trial-ended event with the outcome and reason.

Does not own

  • Creating the terrain, obstacles, lighting, or visible goal content in the condition scene.
  • Changing the vehicle or deciding the authoritative remote state.
  • Writing study data or calculating metrics — Data Capture & Logging's job.

Contract

Study code extends TaskTerminationCriterion, reads its declared dependencies, and returns a TrialTerminationResult when its condition is met. The task module itself is configured in the Unity Inspector.

C#
using UnityEngine;

public abstract class TaskTerminationCriterion : MonoBehaviour
{
    protected abstract bool TryEvaluate(
        double timestampSeconds,
        out TrialTerminationResult result);
}

Configure the kernel module and its criteria through the Unity Inspector. The module reports the lifecycle result through TeleroboticsAgent.TrialEnded. Data Capture & Logging may subscribe to that event; the task module does not write study data.

  • Success, Failure, Timeout, and Abort are lifecycle outcomes.
  • The criterion supplies the outcome and reason; the kernel coordinates evaluation and trial shutdown.
  • Study-specific logging belongs in a DataCaptureImplementation.

Examples

The two criteria read the same Lunar-Target-300s task configuration and produce different terminal outcomes.

TargetRegionEntry succeeds when every corner of the authoritative robot bounds is inside the configured target circle. The visible target marker is authored separately in the condition scene.

C#
public sealed partial class TargetRegionEntry
    : TaskTerminationCriterion
{
    [SerializeField] private Transform authoritativeRobot;
    [SerializeField] private EveryMoveTaskConfiguration configuration;
    [SerializeField, Min(0f)] private float detectionTolerance = 0.15f;
    private Renderer[] robotRenderers = Array.Empty<Renderer>();

    private void Start()
    {
        if (authoritativeRobot)
            robotRenderers = authoritativeRobot.GetComponentsInChildren<Renderer>(true);
    }

    protected override bool TryEvaluate(
        double timestamp,
        out TrialTerminationResult result)
    {
        result = null;
        if (!authoritativeRobot || !configuration)
            return false;
        if (!IsRobotOverTarget())
            return false;

        result = new TrialTerminationResult(
            TrialTerminationOutcome.Success,
            "target-region-entry");
        return true;
    }

    private bool IsRobotOverTarget()
    {
        float effectiveRadius =
            configuration.targetRadius + detectionTolerance;
        Bounds bounds;
        if (!TryGetRobotBounds(out bounds))
        {
            bounds = new Bounds(
                authoritativeRobot.position,
                new Vector3(0.35f, 0.14f, 0.22f));
        }
        Vector2 target = new Vector2(
            configuration.targetCenter.x,
            configuration.targetCenter.z);

        Vector3 center = bounds.center;
        Vector3 extents = bounds.extents;
        Vector2[] corners =
        {
            new Vector2(center.x - extents.x, center.z - extents.z),
            new Vector2(center.x + extents.x, center.z - extents.z),
            new Vector2(center.x - extents.x, center.z + extents.z),
            new Vector2(center.x + extents.x, center.z + extents.z)
        };

        for (int index = 0; index < corners.Length; index++)
        {
            if (Vector2.Distance(corners[index], target) > effectiveRadius)
                return false;
        }

        return true;
    }

    private bool TryGetRobotBounds(out Bounds bounds)
    {
        bounds = default;
        bool found = false;
        for (int index = 0; index < robotRenderers.Length; index++)
        {
            Renderer renderer = robotRenderers[index];
            if (!renderer || !renderer.enabled)
                continue;

            if (!found)
            {
                bounds = renderer.bounds;
                found = true;
            }
            else
            {
                bounds.Encapsulate(renderer.bounds);
            }
        }

        return found;
    }
}

Config

Configure the task through the Unity Inspector. The module coordinates the lifecycle; concrete criterion components provide the rules.

  1. Add one TaskGoalAndTerminationModule to the TeleroboticsAgent GameObject.
  2. Add one component derived from TaskTerminationCriterion for each terminal rule, such as TargetRegionEntry or ElapsedTimeLimit.
  3. Assign each criterion's serialized references, such as the authoritative robot and task configuration.
  4. Drag the criterion components into the module's criteria array in priority order.
  5. Keep the visible goal marker, terrain, and other environment content in the condition scene. The task module evaluates those dependencies but does not own or draw them.