Disim Highway Simulator/Creating a new car behavior

From Wikibooks, open books for an open world
Jump to navigation Jump to search

Simple Example[edit | edit source]

Disim allows the creation of totally arbitrary behavior without having to modify its internal code. To illustrate this, let us start by a simple example: imagine that a car should accelerate as to reach the speed limit of its current lane and should decelerate if it comes too close to the car ahead. The script would look like this:

K = 1.0
safety_distance = 5

function init(self)
  -- Nothing to do here
end

function think(self, dt, neighbors)
  -- Current maximal speed allowed on this lane
  lane_speed = self:getLane():getSpeedLimit()
  lane_acceleration = (lane_speed - self:getSpeed())*K

  -- Get distance to leading car
  lead = neighbors[LEAD].car
  if (lead) then
    f = self:getGeometry()
    phi,r = lead:getGeometry()
    lead_distance = neighbors[LEAD].distance - f - r
    lead_acceleration = (lead:getSpeed()^2 - self:getSpeed()^2)/(lead_distance-safety_distance)
  else
    lead_acceleration = 1000
  end

  return math.min(lane_acceleration, lead_acceleration), 0
end

function destroy(self)
  -- Nothing to do here too
end

What is the scripting language?[edit | edit source]

This script was made using LUA (http://www.lua.org/manual/5.1/manual.html): Lua is an extension programming language designed to support general procedural programming with data description facilities. It also offers good support for object-oriented programming, functional programming, and data-driven programming. Lua is intended to be used as a powerful, light-weight scripting language for any program that needs one. Lua is implemented as a library, written in clean C (that is, in the common subset of ANSI C and C++).

Disim allows anyone to create and redefine the car behaviors using LUA as a scripting language. Creating your car behavior in LUA has several advantages: compilation is not needed, a simplified API is available and you benefit from all the LUA capabilities (tables, anonymous functions, dictionaries, ...). As we can observe from the example above, each script should provide the following 3 functions:

function init(self, options)

This function takes as input two variables. The self variable is a LuaCar pointer on the current car being initialized (this car just came into the highway) and the options variable which is the string passed through the lua-args commandline option to Disim. Note that if the script needs to save specific data related to that car, it should do so in an external variable or array (e.g. vars[self] = { max_speed = 10.0 }). The script is not individually loaded for each vehicle , hence self is bound to be different at each call of this function. This function does not return any values.

function think(self, dt, neighbors)

This function takes three variables as input:

  • self: Just like the input function, this is a pointer to the car currently being controlled.
  • dt: This is the time-step duration in seconds since the last call to that function for that specific car.
  • neighbors: This array contains at least 6 elements that you can access with the LEAD, TRAIL, LEFT_LEAD, LEFT_TRAIL, RIGHT_LEAD, RIGHT_TRAIL keys (e.g. neighbors[LEFT_LEAD]). Each element of this array is an array indexed with 2 keys: car and distance. Hence you can access the car pointer of the leading vehicle with neighbors[LEAD].car and the longitudinal distance to that car with neighbors[LEAD].distance.

This function needs to return 2 values: first an acceleration (that will be applied to the car until the next time-step) and a lane change command. As an example, to make the car accelerate at 2.0 m/s2 and change to the left lane, one would do: return 2.0, -1. To change to the right lane breaking at -1.0 m/s2 one could do return -1.0, 1 and to not do anything return 0, 0.

function destroy(self)

This function takes as input a single variable. This variable is a pointer on the current car being destroyed (this car just went out of the highway). In this function you should clean up any variable that has been initialized by init for that vehicle.

The API[edit | edit source]

As seen above, all the functions provided take as argument a pointer to the current vehicle being controlled. This pointer describes an object in LUA: the LuaCar. To see what you can do with this object, check out the LUA API of Disim available here.

What's next?[edit | edit source]

In the next section, we are going to see how one can create a script to control the infrastructure.