Charging Station: Sharing a Resource Between Agents

Two robots need a charger that can serve only one robot at a time. A station receives their requests, grants access to one robot, and waits for its release before granting another. This example demonstrates concurrent agents, message events, belief-based waiting and a single intention that owns a shared resource.

Run the example

Use an ASTRA 2.6.1 project from the Quick Start. Put the following files in src/main/astra. Each file name must match its agent class.

Station.astra

Download Station.astra

agent Station {
    module Console C;

    types charging {
        formula charge();
        formula granted();
        formula released();
        formula pending(string);
        formula finished(string);
    }

    initial !serve();

    plan @message(request, string Robot, charge()) {
        +pending(Robot);
    }

    plan @message(inform, string Robot, released()) {
        +finished(Robot);
    }

    // One long-running intention owns the charger.
    plan +!serve() {
        while (true) {
            wait(pending(string Robot));
            -pending(Robot);
            C.println("granting charger to " + Robot);
            send(agree, Robot, granted());
            wait(finished(Robot));
            -finished(Robot);
            C.println("charger released by " + Robot);
        }
    }
}

ChargingRobot.astra

Download ChargingRobot.astra

agent ChargingRobot {
    module Console C;
    module System S;

    types charging {
        formula charge();
        formula granted();
        formula released();
        formula completed(string);
        formula permission();
    }

    plan +!main([string StationName]) {
        send(request, StationName, charge());
        wait(permission());
        -permission();
        C.println("charging");
        S.sleep(150);
        send(inform, StationName, released());
        send(inform, "main", completed(S.name()));
    }

    plan @message(agree, string Sender, granted()) {
        +permission();
    }
}

ChargingDemo.astra

Download ChargingDemo.astra

agent ChargingDemo {
    module Console C;
    module System S;

    types charging {
        formula completed(string);
    }

    plan +!main(list args) {
        S.createAgent("station", "Station");
        S.createAgent("robot1", "ChargingRobot");
        S.createAgent("robot2", "ChargingRobot");
        S.setMainGoal("robot1", ["station"]);
        S.setMainGoal("robot2", ["station"]);
        wait(completed("robot1") & completed("robot2"));
        C.println("both robots finished");
        S.exit();
    }

    plan @message(inform, string Robot, completed(Robot)) {
        +completed(Robot);
    }
}

From the project folder, run:

mvn -Dastra.main=ChargingDemo

Expected output

The robot order can vary. One possible run is:

[station] granting charger to robot1
[robot1] charging
[station] charger released by robot1
[station] granting charger to robot2
[robot2] charging
[main] both robots finished

The final release message from the station may also appear before the launcher exits. The essential property is that the station waits for the current robot’s release before granting access to another robot.

How it works

The launcher creates the station and both robots, then starts each robot with the station’s name as its argument. A robot sends a request and waits for a permission belief. Receiving agree adds that belief and allows the robot to continue. When charging finishes, the robot sends a release to the station and a completion message to the launcher.

The station’s message plans record requests and releases as beliefs. They do not allocate the charger themselves. A single !serve() intention performs allocation: it removes a pending request, sends permission, then waits for that robot to finish. Messages from other robots can still arrive while it waits, and their requests remain pending for a later iteration.

This small simulation assumes cooperative robots, one request per robot and reliable local delivery. It does not promise FIFO ordering, recover a crashed robot’s allocation, or authenticate the station. Those are useful extensions once the basic coordination pattern is clear.

Try a change

Create a third robot and include its completion belief in the launcher’s wait condition. Give the robots different charging durations and confirm that charging still happens one at a time. Then add a timeout policy for a robot that never releases the charger; decide how to prevent a late robot from continuing to use an expired allocation.

See Creating Multiple Agents, Agent Communication and Interaction Protocols.