lgsvl / simulator

A ROS/ROS2 Multi-robot Simulator for Autonomous Vehicles
Other
2.29k stars 779 forks source link

NPCs move too fast when following waypoints and time_limit is low #1827

Open EinfachToll opened 3 years ago

EinfachToll commented 3 years ago

My setup:

Observation:

Below is a kind-of minimal example. The bike rides past a range of traffic cones. The speeds on the waypoints are set so that the last cone should be reached at 17s. In fact, this works when time_limit=5, but when I do time_limit=0.1, the bike approaches the last cone already at around 9s.

import lgsvl
from environs import Env
from lgsvl.geometry import Vector

def load_env(map):
    env = Env()
    simulation = lgsvl.Simulator(
        env.str("LGSVL__SIMULATOR_HOST", lgsvl.wise.SimulatorSettings.simulator_host),
        env.int("LGSVL__SIMULATOR_PORT", lgsvl.wise.SimulatorSettings.simulator_port))
    if simulation.current_scene == map:
        simulation.reset()
    else:
        simulation.load(map, seed=650387)
    return (env, simulation)

def generate_state(position, rotation, velocity):
    state = lgsvl.AgentState()
    state.transform.position = position
    state.transform.rotation = rotation
    state.velocity = velocity
    return state

def generate_scenario():
    env, simulation = load_env(lgsvl.wise.DefaultAssets.map_straight2lanesamecurbrightintersection)

    ego_state = generate_state(
        position=Vector(0,0,0),
        rotation=Vector(0, 180, 0),
        velocity=Vector(0, 0, 0))
    ego_vehicle = simulation.add_agent(
        env.str("LGSVL__VEHICLE_0", "2b791f64-b3d6-4188-a5d5-5695bda8a0dc"),
        lgsvl.AgentType.EGO,
        ego_state)

    bicyclist = simulation.add_agent(
        "Bicyclist",
        lgsvl.AgentType.NPC,
        generate_state(
            Vector(10, 0,  -45),
            Vector(0, 270, 0),
            Vector(0, 0, 0)))
    bicyclist_way_points = [
            lgsvl.DriveWaypoint(
                position=Vector(10, 0, -45),
                speed=1,
                angle=Vector(0, 270, 0),
                acceleration=0,
                ),
            lgsvl.DriveWaypoint(
                position=Vector(0, 0, -45),
                speed=1,
                angle=Vector(0, 270, 0),
                acceleration=0,
                ),
            lgsvl.DriveWaypoint(
                position=Vector(-10, 0, -45),
                speed=2,
                angle=Vector(0, 270, 0),
                acceleration=0,
                ),
            lgsvl.DriveWaypoint(
                position=Vector(-20, 0, -45),
                speed=5,
                angle=Vector(0, 270, 0),
                acceleration=0,
                ),
            ]
    bicyclist.follow(bicyclist_way_points, waypoints_path_type="Linear")

    # place traffic cones as visual cue
    wps = [Vector(10, 0, -44), Vector(0, 0, -44), Vector(-10, 0, -44), Vector(-20, 0, -44)]
    for wp in wps:
        state_charging_station = lgsvl.ObjectState()
        state_charging_station.transform.position = wp
        simulation.controllable_add("TrafficCone", state_charging_station)

    for x in range(10, -21, -1):
        state_charging_station = lgsvl.ObjectState()
        state_charging_station.transform.position = Vector(x, 0, -44.5)
        simulation.controllable_add("TrafficCone", state_charging_station)

    return simulation

def run():
    simulation = generate_scenario()
    while True:
        simulation.run(time_limit=0.1)          # bike is too fast
        #simulation.run(time_limit=5)           # bike is about right

run()
EricBoiseLGSVL commented 3 years ago

This is probably a bug but might not be able to fix. Running at 0.1 runs against logic running in fixed update for physics. We will look into it to see if we can find a solution. Curious, why are you running at such a small interval? What's the use case to check data every 0.1 seconds?

EinfachToll commented 3 years ago

Hello, thank you for your reply.

Use Case: Creation of corner case scenarios for an perception software that creates an environmental model. That is, the sensor data and reference data are of interest for us. Those corner case scenarios require precise control over ego and NPCs.

The Python API provides that high precision controllability of the ego and the NPCs. To gather the sensor output data with a realistic update rate, the simulation is started, stopped, sensor outputs are read, simulation is re-started, ... in that small time interval.

The mentioned unexpected behavior jeopardizes the approach and we are looking for a workaround. As an alternative, we see defining the scenario - including way points for the NPCs - in the Visual Editor, control the ego via ROS2 and gather the sensor data via ROS2. The most critical known unknown is how to steer / control the ego with high precision, i.e., with pre-defined commands that are fired at defined time stamps or whether it is necessary to implement a kind of control circuit to steer the ego via ROS2.

EricBoiseLGSVL commented 3 years ago

Thanks for the clarification, this helps. Tagging @lemketron and @hadiTab to see if they have any ideas on how to best accomplish the goals.