HARPLab / DReyeVR

VR driving šŸš™ + eye tracking šŸ‘€ simulator based on CARLA for driving interaction research
https://arxiv.org/abs/2201.01931
MIT License
139 stars 37 forks source link

Ensuring DReyeVR does not give ~empty VehicleControl inputs in order to run external agents #125

Closed shh1v closed 11 months ago

shh1v commented 11 months ago

When running a route scenario using scenario_runnerwith a specified route and agent, in every tick, the scenario_manager.py gives control input to the ego vehicle.

python scenario_runner.py --route srunner/data/route_1.xml srunner/data/no_scenarios.json --agent srunner/autoagents/npc_agent.py

In _tick_scenario of scenario_manager.py:

            if self._agent is not None:
                print(f"Ego action for {self.ego_vehicles[0]} (1 of {len(self.ego_vehicles)}): {ego_action}")
                self.ego_vehicles[0].apply_control(ego_action)

However, the current implementation in DReyeVRPawn.cpp retrieves the Logitech wheel data, and gives an empty VehicleControl object if no input from the wheel, or Logitech wheel is disconnected. The problem with this issue is that if no input is given, the implementation flushes empty vehicle controls:

In AEgoVehicle::TickVehicleInputs() of EgoInputs.cpp:

    FVehicleControl LastAppliedControl = GetVehicleControl();
    int bIncludeLast = static_cast<int>(GetAutopilotStatus());
    FVehicleControl ManualInputs;
    // only include LastAppliedControl when autopilot is running (bc it would have flushed earlier this tick)
    ManualInputs.Steer = VehicleInputs.Steering + bIncludeLast * LastAppliedControl.Steer;
    ManualInputs.Brake = VehicleInputs.Brake + bIncludeLast * LastAppliedControl.Brake;
    ManualInputs.Throttle = VehicleInputs.Throttle + bIncludeLast * LastAppliedControl.Throttle;
    ManualInputs.bReverse = bReverse;
    this->ApplyVehicleControl(ManualInputs, EVehicleInputPriority::User);
    // send these inputs to the Carla (parent) vehicle
    FlushVehicleControl();
    VehicleInputs = DReyeVR::UserInputs(); // clear inputs for this frame

Since this function is called in every tick, any other input given by a client is not considered, and thus, validation is required to check if the VehicleControlobject does not have zero parameter. If so, VehicleControl must not be applied.

    // apply inputs to this vehicle only when either one of the parameter is non-zero or autopilot is on
    if ((!FMath::IsNearlyEqual(ManualInputs.Steer, 0.f, 0.02f) ||
        !FMath::IsNearlyEqual(ManualInputs.Brake, 0.f, 0.02f) ||
        !FMath::IsNearlyEqual(ManualInputs.Throttle, 0.f, 0.02f)) ||
        GetAutopilotStatus())
    {
        this->ApplyVehicleControl(ManualInputs, EVehicleInputPriority::User);
        // send these inputs to the Carla (parent) vehicle
        FlushVehicleControl();
    }

Note: FMath::IsNearlyEqual is used because even when input from Logitech steering wheel by the user is not given, it still sends very close to zero values. Note: Initial issue I made at CARLA/scenario_sunner.

I am interested in hearing what would be the drawbacks of my approach.

GustavoSilvera commented 11 months ago

Sounds reasonable to me. This is an approach similar to what we have in DReyeVRPawn.cpp which works well enough.