Asynchronous Sensory Motor Systems
Support for Asynchronous Sensory-Motor Systems
Some game AI engines schedule the agents and world in a top-level loop. ABL agents, on the other hand, are designed to run fully asynchronously with both the world and each other. This design allows ABL to more easily connect to different worlds. Besides solving the usual synchronization issues of multi-threaded, multi-process programming within the ABL infrastructure, the major ABL support for providing "plug and play" capability with different bodies and worlds is provided by the mechanisms for defining sensors and actions.
Sensors and Actions
Sensors and actions mediate between an ABL agent and the world. To connect an ABL agent to a new sensory-motor system (body within a world), an ABL author defines a new set of appropriate sensors and actions. Sensors and actions are implemented by extending abstract sensor and action classes provided by ABL. These classes define a collection of methods and contracts expected by ABL’s runtime system. As long as the new sensors and actions define these methods appropriately, where appropriately means the method satisfies the expected contract, the new sensors and actions work with the ABL runtime system.
To define a new sensor, the author must define the following methods on the sensor object.
canBeParallel()– return true if the sensor can be run in parallel, false otherwise. Whether a sensor can be run in parallel depends on the details of the sensory-motor system, specifically whether the sensory system is reentrant.
senseOneShot(Object args)– called when sensing is needed to test a precondition. The sensor should update appropriate WME(s) in working memory to reflect the new sensed value. If testing the precondition(s) requires multiple sensing, ABL optimizes sensing by spawning multiple threads to perform parallel sensing for those sensors whose
canBeParallel()flag returns true.
initializeContinuous(Object args)– called when a continuously monitored condition requiring sensing (i.e. a sensed context condition or success test) is first entered. The sensor should update appropriate WME(s) in working memory to reflect the current sensed value and perform any internal bookkeeping to prepare for continuous sensing. As an example of bookkeeping, a position sensor may want to store the sensed value, and, while continuously sensing, only report a new position when the new value differs from the stored value by some threshold.
senseContinuous(Object args)– called while a continuously monitored condition requiring sensing is active. Like
senseContinuousshould update appropriate WME(s) and possibly perform internal bookkeeping. Example sensors for Facade include position and rotation sensors that sense the position and rotation of characters and objects in the world, held object sensors that sense which objects are being held by a character (and in which hands), and a text sensor that senses the text typed by the player.
To define a new action, the author must define the following methods on the action object.
execute(Object args)– called when an ABL act step executes, this method actually starts the action in the world. As the decision cycle blocks on calls to execute, it should return as quickly as possible. This does not mean that the action itself must complete immediately, only that the call to execute should happen as quickly as possible. The action, such as moving an arm, can continue in the world while the decision cycle selects other steps. The act step that resulted in the call to execute doesn’t succeed or fail until the action in the world actually completes (with success or failure).
abort(Object args)– called when an executing act is removed from the ABT. This method should instruct the sensory-motor system to abort the action (whatever that means given the particularities of the action and the motor system) and clean up any internal state being maintained by the action instance.
completionCallback(boolean status)– for those actions that take time to execute in the motor system, the action may request that the sensory-motor system call the action back when it completes. The completion callback takes a boolean parameter: true if the action completed with success, false if it completed with failure. A default implementation is provided that appropriately sets the completion status of the action instance to success or failure.
The execute() method
For defining the execute method, concrete physical actions may employ one of a number of strategies:
- For actions that execute very quickly in the underlying sensory-motor system (e.g. setting a flag), execute can directly perform the appropriate action and set the completion status.
- Actions that take some time to execute may spawn a separate thread and immediately return. The spawned thread is responsible for setting the completion status.
- For actions that take some time to execute and for sensory-motor systems that accept callbacks, execute may initiate the action, register a completion callback, and return immediately. The sensory-motor system then calls the callback when the action finishes executing. The default definition of completionCallback appropriately updates the action’s completion status.
Writing for Multiple, Similar SMAs
You must write agents with a particular sensory-motor architecture in mind. If you're careful, you could write an agent that would work for Unreal Tournament and Doom. To do this you would have to come up with a reasonable set of primitive actions that make sense for both UT and Doom. You would then implement these primitive actions in terms of an abstract backend. That is, you'd write a Java interface to the actions and two backends: one that implements the UT protocol and another the Doom protocol. How would you also abstract how the world talks to ABL? I'm not experienced enough to know.