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
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
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
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.