Policy Entry Point

A key point of the Discra architecture is to provide a convenient framework for implementing and testing different conflict resolution algorithms. In fact, the same architecture could be used for other “derived” UTM services, such as trajectory planning and traffic flow management services for clients that might not have flight optimization capabilities.

Policy in Discra

Policy is a class in Discra that implements the conflict resolution algorithm. Once instantiated, the Policy object is broadcast by the advisor server’s Spark driver to its worker nodes and used to resolve conflicts.

No matter how the user decides to define the class, there are two instance methods that must be defined:

def defaultPolicy(): Policy
def advisories(drones: Array[DroneGlobalState], ids: Array[String]): Array[String]

Defining Policy

Policy

The instance variables and methods should be defined in the class statement, and the class methods should be defined in the object statement. This type of class definition is common in OOP. It’s entirely up to the user’s discretion how to define these. One thing to note is that the Policy class must be defined as a subclass of Serializable:

class Policy(...) extends Serializable {...}

This inheritance is important since it lets Policy inherit certain members of the class Serializable that allows us to broadcast an instance of the Policy object from the Spark driver to its worker nodes.

defaultPolicy

When the advisor application is started up, it looks in the Policy.scala file for the defaultPolicy class method, which instantiates a Policy object defined by the user. In our conflict resolution algorithm, defaultPolicy loads the utility function lookup table and the set of advisories, conducts basic verification tests, and returns the newly instantiated Policy object.

As can be seen in the function signature:

def defaultPolicy(): Policy

defaultPolicy doesn’t take in any arguments and it returns an instance of the Policy object with some default parameters.

advisories

When there is a new set of conflicting aircraft flight states sent to the advisor worker node, the JSON representation of these flight states is converted into its DroneGlobalState internal representation and fed to advisories for conflict resolution. DroneGlobalState is defined:

class DroneGlobalState(
    var latitude: Double,
    var longitude: Double,
    var heading: Double,
    var speed: Double)

The instance method is called on its Policy object, and the return value is an Array of Strings. Each array element is a string of a user-defined format. In our implementation, we chose a JSON format for each element derived from the case class Advisory (i.e., each array element is a stringified version of Advisory):

case class Advisory(gufi: String, clearOfConflict: String, waypoints: List[Waypoint])
case class Waypoint(
    lat: String,      // m
    lon: String,      // m
    speed: String,    // m/s
    heading: String,  // rad
    period: String,   // s
    turn: String)     // rad/s

Using this format, any client can filter the gufi’s such that they can identify which are meant for their aircraft. The client would then quickly check if their aircraft are clear of conflict from the second instance variable clearOfConflict. For any aircraft without a clear of conflict status, the client will then check the list of Waypoint fields for the resolution advisory.

To interpret the advisory, the client uses a standard Dubin’s kinematics model that starts at the coordinates, speed, and heading and turns for the specified period at the turn rate indicated by turn. An execution of the advisory thus involves flying on trajectory generated by this list of waypoints as closely as possible.

Note that if the user decides to use a different format, the user will need to change the simulator server to be able to interpret the new advisory format. The function to change is

def getDroneAdvisories(raw: String): Array[DroneAdvisory]

where it takes an advisory string that the user defined and outputs an array of DroneAdvisory objects:

class DroneAdvisory(
    val gufi: String,
    val clearOfConflict: Boolean,
    val turnRate: Double,
    val period: Double)

The function can be modified in the file at

[discra-root]/src/simulator/src/main/scala/drone/Advisory.scala