text: // =============================================================================
  // PROJECT CHRONO - http://projectchrono.org
  //
  // Copyright (c) 2014 projectchrono.org
  // All rights reserved.
  //
  // Use of this source code is governed by a BSD-style license that can be found
  // in the LICENSE file at the top level of the distribution and at
  // http://projectchrono.org/license-chrono.txt.
  //
  // =============================================================================
  // Authors: Radu Serban, Justin Madsen
  // =============================================================================
  //
  // Main driver function for the HMMWV 9-body model.
  //
  // The vehicle reference frame has Z up, X towards the front of the vehicle, and
  // Y pointing to the left.
  //
  // =============================================================================
  
  #include "chrono/core/ChStream.h"
  #include "chrono/core/ChRealtimeStep.h"
  #include "chrono/utils/ChUtilsInputOutput.h"
  #include "chrono/utils/ChFilters.h"
  
  #include "chrono_vehicle/ChConfigVehicle.h"
  #include "chrono_vehicle/ChVehicleModelData.h"
  #include "chrono_vehicle/terrain/RigidTerrain.h"
  #include "chrono_vehicle/driver/ChIrrGuiDriver.h"
  #include "chrono_vehicle/output/ChVehicleOutputASCII.h"
  
  #include "chrono_vehicle/wheeled_vehicle/utils/ChWheeledVehicleIrrApp.h"
  
  #include "chrono_models/vehicle/hmmwv/HMMWV.h"
  
  #include "chrono_thirdparty/filesystem/path.h"
  
  using namespace chrono;
  using namespace chrono::vehicle;
  using namespace chrono::vehicle::hmmwv;
  
  // =============================================================================
  
  // Initial vehicle location and orientation
  ChVector<> initLoc(0, 0, 1.0);
  ChQuaternion<> initRot(1, 0, 0, 0);
  // ChQuaternion<> initRot(0.866025, 0, 0, 0.5);
  // ChQuaternion<> initRot(0.7071068, 0, 0, 0.7071068);
  // ChQuaternion<> initRot(0.25882, 0, 0, 0.965926);
  // ChQuaternion<> initRot(0, 0, 0, 1);
  
  // Type of powertrain model (SHAFTS, SIMPLE)
  PowertrainModelType powertrain_model = PowertrainModelType::SHAFTS;
  
  // Type of driveline model
  DrivelineTypeWV driveline_model = DrivelineTypeWV::AWD;
  
  // Type of tire model (RIGID, RIGID_MESH, TMEASY, PACEJKA, PAC89, FIALA)
  TireModelType tire_model = TireModelType::PAC89;
  
  // Rigid terrain dimensions
  double terrainHeight = 0;
  double terrainLength = 200.0;  // size in X direction
  double terrainWidth = 100.0;   // size in Y direction
  
  // Point on chassis tracked by the camera
  ChVector<> trackPoint(0.0, 0.0, .75);
  
  // Simulation step sizes
  double step_size = 3e-3;
  double tire_step_size = 1e-3;
  
  // Time interval between two render frames
  double render_step_size = 1.0 / 50;  // FPS = 50
  
  // POV-Ray output
  bool povray_output = false;
  const std::string out_dir = GetChronoOutputPath() + "HMMWV9";
  const std::string pov_dir = out_dir + "/POVRAY";
  
  // =============================================================================
  
  int main(int argc, char* argv[]) {
      GetLog() << "Copyright (c) 2017 projectchrono.org\nChrono version: " << CHRONO_VERSION << "\n\n";
  
      // --------------
      // Create systems
      // --------------
  
      // Create the HMMWV vehicle, set parameters, and initialize
      HMMWV_Reduced my_hmmwv;
      my_hmmwv.SetContactMethod(ChContactMethod::NSC);
      my_hmmwv.SetChassisFixed(false);
      my_hmmwv.SetChassisCollisionType(CollisionType::NONE);
      my_hmmwv.SetInitPosition(ChCoordsys<>(initLoc, initRot));
      my_hmmwv.SetPowertrainType(powertrain_model);
      my_hmmwv.SetDriveType(driveline_model);
      my_hmmwv.SetTireType(tire_model);
      my_hmmwv.SetTireStepSize(tire_step_size);
      my_hmmwv.Initialize();
  
      my_hmmwv.SetChassisVisualizationType(VisualizationType::PRIMITIVES);
      my_hmmwv.SetSuspensionVisualizationType(VisualizationType::PRIMITIVES);
      my_hmmwv.SetSteeringVisualizationType(VisualizationType::PRIMITIVES);
      my_hmmwv.SetWheelVisualizationType(VisualizationType::NONE);
      my_hmmwv.SetTireVisualizationType(VisualizationType::PRIMITIVES);
  
      // Create the terrain
      RigidTerrain terrain(my_hmmwv.GetSystem());
      auto patch_mat = chrono_types::make_shared<ChMaterialSurfaceNSC>();
      patch_mat->SetFriction(0.9f);
      patch_mat->SetRestitution(0.01f);
      auto patch =
          terrain.AddPatch(patch_mat, ChVector<>(0, 0, terrainHeight), ChVector<>(0, 0, 1), terrainLength, terrainWidth);
      patch->SetColor(ChColor(0.8f, 0.8f, 0.5f));
      patch->SetTexture(vehicle::GetDataFile("terrain/textures/tile4.jpg"), 200, 200);
      terrain.Initialize();
  
      // Create the vehicle Irrlicht interface
      ChWheeledVehicleIrrApp app(&my_hmmwv.GetVehicle(), L"HMMWV-9 Demo", irr::core::dimension2d<irr::u32>(1000, 800),
                                 irr::ELL_NONE);
      app.SetSkyBox();
      app.AddTypicalLights(irr::core::vector3df(30.f, -30.f, 100.f), irr::core::vector3df(30.f, 50.f, 100.f), 250, 130);
      app.SetChaseCamera(trackPoint, 6.0, 0.5);
      app.SetTimestep(step_size);
      app.AssetBindAll();
      app.AssetUpdateAll();
  
      // Create the interactive driver system
      ChIrrGuiDriver driver(app);
      driver.Initialize();
  
      // Set the time response for steering and throttle keyboard inputs.
      double steering_time = 1.0;  // time to go from 0 to +1 (or from 0 to -1)
      double throttle_time = 1.0;  // time to go from 0 to +1
      double braking_time = 0.3;   // time to go from 0 to +1
      driver.SetSteeringDelta(render_step_size / steering_time);
      driver.SetThrottleDelta(render_step_size / throttle_time);
      driver.SetBrakingDelta(render_step_size / braking_time);
  
      // -----------------
      // Initialize output
      // -----------------
  
      if (!filesystem::create_directory(filesystem::path(out_dir))) {
          std::cout << "Error creating directory " << out_dir << std::endl;
          return 1;
      }
  
      if (povray_output) {
          if (!filesystem::create_directory(filesystem::path(pov_dir))) {
              std::cout << "Error creating directory " << pov_dir << std::endl;
              return 1;
          }
      }
  
      // Set up vehicle output
      my_hmmwv.GetVehicle().SetChassisOutput(true);
      my_hmmwv.GetVehicle().SetSuspensionOutput(0, true);
      my_hmmwv.GetVehicle().SetSteeringOutput(0, true);
      my_hmmwv.GetVehicle().SetOutput(ChVehicleOutput::ASCII, out_dir, "output", 0.1);
  
      // Generate JSON information with available output channels
      my_hmmwv.GetVehicle().ExportComponentList(out_dir + "/component_list.json");
  
      // ---------------
      // Simulation loop
      // ---------------
  
      my_hmmwv.GetVehicle().LogSubsystemTypes();
  
      // Number of simulation steps between two 3D view render frames
      int render_steps = (int)std::ceil(render_step_size / step_size);
  
      // Initialize simulation frame counters
      int step_number = 0;
      int render_frame = 0;
  
      ChRealtimeStepTimer realtime_timer;
      utils::ChRunningAverage RTF_filter(50);
  
      while (app.GetDevice()->run()) {
          double time = my_hmmwv.GetSystem()->GetChTime();
  
          // Render scene and output POV-Ray data
          if (step_number % render_steps == 0) {
              app.BeginScene(true, true, irr::video::SColor(255, 140, 161, 192));
              app.DrawAll();
              app.EndScene();
  
              if (step_number % render_steps == 0) {
                  char filename[100];
                  sprintf(filename, "%s/data_%03d.dat", pov_dir.c_str(), render_frame + 1);
                  utils::WriteVisualizationAssets(my_hmmwv.GetSystem(), filename);
              }
  
              render_frame++;
          }
  
          // Driver inputs
          ChDriver::Inputs driver_inputs = driver.GetInputs();
  
          // Update modules (process inputs from other modules)
          driver.Synchronize(time);
          terrain.Synchronize(time);
          my_hmmwv.Synchronize(time, driver_inputs, terrain);
          app.Synchronize(driver.GetInputModeAsString(), driver_inputs);
  
          // Advance simulation for one timestep for all modules
          driver.Advance(step_size);
          terrain.Advance(step_size);
          my_hmmwv.Advance(step_size);
          app.Advance(step_size);
  
          // Increment frame number
          step_number++;
  
          // Spin in place for real time to catch up
          realtime_timer.Spin(step_size);
          ////std::cout << RTF_filter.Add(realtime_timer.RTF) << std::endl;
      }
  
      return 0;
  }
  