Controllable - ChargingStation

This contains detailed documentation on the ChargingStation controllable plugin.

To use this Controllable Plugin:

1) Clone the repo into Assets/External/Controllables/ChargingStation inside of your Simulator Unity Project

2) Build the Controllable Plugin for use with the Simulator, navigate to the Simulator -> Build Controllables Unity Editor menu item. Select ChargingStation controllable and build. Output bundle will be in AssetBundles/Controllables folder in root of Simulator Unity Project

3) Simulator will load, at runtime, all custom Controllable Plugin bundles in AssetBundles/Controllables directory

Custom Logic top#

To implement custom logic, contained in a given Controllable Plugin project there must be an IControllable implementation. An example of this is in TrafficCone.cs

The interface requires the following to be implemented:

public bool Spawned { get; set; } = false;
public string UID { get; set; }
public string GUID => UID;
public string ControlType { get; set; } = "chargingstation";
public string CurrentState { get; set; }
public string[] ValidStates { get; set; } = new[] { "on", "off" };
public string[] ValidActions { get; set; } = new string[] { };
public List<ControlAction> DefaultControlPolicy { get; set; } =
    new List<ControlAction>
    {
        new ControlAction { Action = "state", Value = "off" }
    };

public List<ControlAction> CurrentControlPolicy { get; set; }

public Control(List<ControlAction> controlActions)
{
    //
}

On Awake() CurrentControlPolicy and CurrentState must be set, e.g.

private void Awake()
{
    Lights.AddRange(GetComponentsInChildren<Light>());
    SetLights(false);
    ChargingStationRenderer = GetComponent<Renderer>();
    foreach (var mat in ChargingStationRenderer.materials)
    {
        if (mat.name.Contains("Emission"))
        {
            EmissionMaterials.Add(mat);
        }
    }

    CurrentControlPolicy = DefaultControlPolicy;
    Control(CurrentControlPolicy);
}

Control checks the parsed ControlActions and sets the CurrentState

public void Control(List<ControlAction> controlActions)
{
    foreach (var action in controlActions)
    {
        switch (action.Action)
        {
            case "state":
                SetChargingStationState(action.Value);
                break;
            default:
                Debug.LogError($"'{action.Value}' is an invalid action for '{ControlType}'");
                break;
        }
    }
}

public void SetChargingStationState(string value)
{
    if (!ValidStates.Contains(value))
    {
        Debug.LogError($"'{value}' is an invalid state for '{ControlType}'");
        return;
    }

    CurrentState = value;
    switch (CurrentState)
    {
        case "on":
            EmissionMaterials?.ForEach(x => x.SetColor("_EmissiveColor", Color.white));
            EmissionMaterials?.ForEach(x => x.SetFloat("_EmissiveIntensity", 3f));
            SetLights(true);
            break;
        case "off":
            EmissionMaterials?.ForEach(x => x.SetColor("_EmissiveColor", Color.black));
            EmissionMaterials?.ForEach(x => x.SetFloat("_EmissiveIntensity", 0f));
            SetLights(false);
            break;
        default:
            break;
    }
}

private void SetLights(bool state)
{
    Lights.ForEach(l => l.enabled = state);
}

Python API example top#

Each controllable object has its own valid actions (e.g., green, yellow, red, trigger, wait, loop, on, off, "") that it can take and is controlled based on control policy, which defines rules for control actions.

To get a list of controllable objects in a scene:

controllables = sim.get_controllables()

For a controllable object of interest, you can get following information:

station = controllables[0]
print("Type:", station.type)
print("Transform:", station.transform)
print("Current state:", station.current_state)
print("Valid actions:", station.valid_actions)

For control policy, each controllable object always has default control policy (read-only). When you load a scene for the first time or reset a scene to the initial state, a controllable object resets current control policy to default one follows it.

You can get default control policy and current control policy as follows:

print("Default control policy:", station.default_control_policy)
print("Current control policy:", station.control_policy)

To change a current control policy, you can create a new control policy and call control function as below:

control_policy = "on"
station.control(control_policy)

To add a plugin controllable and set object state

state = lgsvl.ObjectState()
state.transform.position = lgsvl.Vector(0,0,0)
state.transform.rotation = lgsvl.Vector(0,0,0)
state.velocity = lgsvl.Vector(0,10,0)
state.angular_velocity = lgsvl.Vector(6.5,0,0)

cone = sim.controllable_add("ChargingStation", state)

To get plugin controllable object state

station.object_state

To set plugin controllable object state

state = lgsvl.ObjectState()
state.transform.position = lgsvl.Vector(0, 0, -10)
station.object_state = state

Controllables can also have a Unity RigidBody component at the root and apply velocity from the API. If no rigidbody exists then the velocity is ignored.

#!/usr/bin/env python3
#
# Copyright (c) 2020-2021 LG Electronics, Inc.
#
# This software contains code licensed as described in LICENSE.
#

from environs import Env
import lgsvl

sim = lgsvl.Simulator(env.str("LGSVL__SIMULATOR_HOST", lgsvl.wise.SimulatorSettings.simulator_host), env.int("LGSVL__SIMULATOR_PORT", lgsvl.wise.SimulatorSettings.simulator_port))
if sim.current_scene == lgsvl.wise.DefaultAssets.map_borregasave:
    sim.reset()
else:
    sim.load(lgsvl.wise.DefaultAssets.map_borregasave)

spawns = sim.get_spawn()

state = lgsvl.AgentState()
forward = lgsvl.utils.transform_to_forward(spawns[0])
right = lgsvl.utils.transform_to_right(spawns[0])
up = lgsvl.utils.transform_to_up(spawns[0])
state.transform = spawns[0]

ego = sim.add_agent(env.str("LGSVL__VEHICLE_0", lgsvl.wise.DefaultAssets.ego_lincoln2017mkz_apollo5), lgsvl.AgentType.EGO, state)

print("Python API Quickstart #28: How to Add/Control Charging Station")

obj_state = lgsvl.ObjectState()
obj_state.transform.position = lgsvl.Vector(38, 0, 7)
obj_state.transform.rotation = lgsvl.Vector(0, 180, 0)

station = sim.controllable_add("ChargingStation", obj_state)

station = sim.get_controllable(lgsvl.Vector(38, 0, 7), "chargingstation")
print("\n# Charging Station of interest:")
print(station)

seconds = 1
input("\nPress Enter to run simulation for {} seconds".format(seconds))
print("\nRunning simulation for {} seconds...".format(seconds))
sim.run(seconds)

# Get current controllable state
print("\n# Current charging station control policy:")
print(station.control_policy)

print("\n# Current charging station object state")
print(station.object_state)

print("\n# Update charging station object state")
new_state = lgsvl.ObjectState()
new_state.transform.position = lgsvl.Vector(38, 0, 7)
new_state.transform.rotation = lgsvl.Vector(0, 180, 0)
station.object_state = new_state

print("\n# New object state")
print(station.object_state)

# Set time of day for light effects
sim.set_time_of_day(19.0)
print(sim.time_of_day)

# Create a new control policy
control_policy = "on"

# Control this traffic light with a new control policy
station.control(control_policy)

print("\n# Updated control policy:")
print(station.control_policy)

# Get current state of charging station
print("\n# Current station state:")
print(station.current_state)

print("\nDone!")