def run_scenario(vehicle_model='etk800',
                 deflation_pattern=[0, 0, 0, 0],
                 parts_config='vehicles/hopper/custom.pc',
                 run_number=0):
    global base_filename, default_color, default_scenario, default_spawnpoint, steps_per_sec
    global integral, prev_error, setpoint
    integral = 0.0
    prev_error = 0.0

    # setup DNN model + weights
    sm = DAVE2Model()
    # steering_model = Model().define_model_BeamNG("BeamNGmodel-racetracksteering8.h5")
    # throttle_model = Model().define_model_BeamNG("BeamNGmodel-racetrackthrottle8.h5")
    dual_model = sm.define_dual_model_BeamNG()
    # dual_model = sm.load_weights("BeamNGmodel-racetrackdualcomparison10K.h5")
    # dual_model = sm.define_multi_input_model_BeamNG()
    # dual_model = sm.load_weights("BeamNGmodel-racetrackdual-comparison10K-PIDcontrolset-4.h5")
    # dual_model = sm.load_weights("BeamNGmodel-racetrackdual-comparison40K-PIDcontrolset-1.h5")
    # BeamNGmodel-racetrack-multiinput-dualoutput-comparison10K-PIDcontrolset-1.h5
    # BeamNGmodel-racetrackdual-comparison100K-PIDcontrolset-2
    dual_model = sm.load_weights(
        "BeamNGmodel-racetrackdual-comparison100K-PIDcontrolset-2.h5")
    # dual_model = sm.load_weights("BeamNGmodel-racetrack-multiinput-dualoutput-comparison103K-PIDcontrolset-1.h5")

    random.seed(1703)
    setup_logging()

    beamng = BeamNGpy('localhost',
                      64256,
                      home='H:/BeamNG.research.v1.7.0.1clean',
                      user='******')
    scenario = Scenario(default_scenario, 'research_test')
    vehicle = Vehicle('ego_vehicle',
                      model=vehicle_model,
                      licence='EGO',
                      color=default_color)
    vehicle = setup_sensors(vehicle)
    spawn = spawn_point(default_scenario, default_spawnpoint)
    scenario.add_vehicle(
        vehicle, pos=spawn['pos'], rot=None,
        rot_quat=spawn['rot_quat'])  #, partConfig=parts_config)
    add_barriers(scenario)
    # Compile the scenario and place it in BeamNG's map folder
    scenario.make(beamng)

    # Start BeamNG and enter the main loop
    bng = beamng.open(launch=True)
    #bng.hide_hud()
    bng.set_deterministic()  # Set simulator to be deterministic
    bng.set_steps_per_second(steps_per_sec)  # With 60hz temporal resolution
    bng.load_scenario(scenario)
    bng.start_scenario()
    # bng.spawn_vehicle(vehicle, pos=spawn['pos'], rot=None, rot_quat=spawn['rot_quat'], partConfig=parts_config)
    # Put simulator in pause awaiting further inputs
    bng.pause()
    assert vehicle.skt
    # bng.resume()

    # perturb vehicle
    print("vehicle position before deflation via beamstate:{}".format(
        vehicle.get_object_position()))
    print("vehicle position before deflation via vehicle state:{}".format(
        vehicle.state))
    image = bng.poll_sensors(vehicle)['front_cam']['colour'].convert('RGB')
    # plt.imshow(image)
    # plt.pause(0.01)
    vehicle.deflate_tires(deflation_pattern)
    bng.step(steps_per_sec * 6)
    vehicle.update_vehicle()
    # print("vehicle position after deflation via beamstate:{}".format(vehicle.get_object_position()))
    # print("vehicle position after deflation via vehicle state:{}".format(vehicle.state))
    pitch = vehicle.state['pitch'][0]
    roll = vehicle.state['roll'][0]
    z = vehicle.state['pos'][2]
    image = bng.poll_sensors(vehicle)['front_cam']['colour'].convert('RGB')
    # plt.imshow(image)
    # plt.pause(0.01)

    # bng.resume()
    # vehicle.break_all_breakgroups()
    # vehicle.break_hinges()

    wheelspeed = 0.0
    throttle = 0.0
    prev_error = setpoint
    damage_prev = None
    runtime = 0.0
    kphs = []
    traj = []
    pitches = []
    rolls = []
    steering_inputs = []
    throttle_inputs = []
    timestamps = []
    damage = None
    final_img = None
    # Send random inputs to vehice and advance the simulation 20 steps
    overall_damage = 0.0
    total_loops = 0
    total_imgs = 0
    total_predictions = 0
    while overall_damage <= 0:
        # collect images
        sensors = bng.poll_sensors(vehicle)
        image = sensors['front_cam']['colour'].convert('RGB')
        # plt.imshow(image)
        # plt.pause(0.01)
        total_imgs += 1
        img = sm.process_image(np.asarray(image))
        wheelspeed = sensors['electrics']['wheelspeed']
        kph = ms_to_kph(wheelspeed)
        dual_prediction = dual_model.predict(x=[img, np.array([kph])])
        # steering_prediction = steering_model.predict(img)
        # throttle_prediction = throttle_model.predict(img)
        dt = sensors['timer']['time'] - runtime
        runtime = sensors['timer']['time']

        # control params

        brake = 0
        # steering = float(steering_prediction[0][0]) #random.uniform(-1.0, 1.0)
        # throttle = float(throttle_prediction[0][0])
        steering = float(dual_prediction[0][0])  #random.uniform(-1.0, 1.0)
        throttle = float(dual_prediction[0][1])
        total_predictions += 1
        if abs(steering) > 0.2:
            setpoint = 20
        else:
            setpoint = 40
        # if runtime < 10:
        throttle = throttle_PID(kph, dt)
        #     if throttle > 1:
        #         throttle = 1
        # if setpoint < kph:
        #     brake = 0.0 #throttle / 10000.0
        #     throttle = 0.0
        vehicle.control(throttle=throttle, steering=steering, brake=brake)

        steering_inputs.append(steering)
        throttle_inputs.append(throttle)
        timestamps.append(runtime)

        steering_state = sensors['electrics']['steering']
        steering_input = sensors['electrics']['steering_input']
        avg_wheel_av = sensors['electrics']['avg_wheel_av']

        damage = sensors['damage']
        overall_damage = damage["damage"]
        new_damage = diff_damage(damage, damage_prev)
        damage_prev = damage
        vehicle.update_vehicle()
        traj.append(vehicle.state['pos'])
        pitches.append(vehicle.state['pitch'][0])
        rolls.append(vehicle.state['roll'][0])

        kphs.append(ms_to_kph(wheelspeed))
        total_loops += 1

        if new_damage > 0.0:
            final_img = image
            break
        bng.step(1, wait=True)

        if runtime > 300:
            print("Exited after 5 minutes successful runtime")
            break

        if distance(
                spawn['pos'],
                vehicle.state['pos']) < 5 and sensors['timer']['time'] > 10:
            reached_start = True
            break

    #     print("runtime:{}".format(round(runtime, 2)))
    # print("time to crash:{}".format(round(runtime, 2)))
    bng.close()
    # avg_kph = float(sum(kphs)) / len(kphs)
    plt.imshow(final_img)
    plt.savefig("Run-{}-finalimg.png".format(run_number))
    plt.pause(0.01)
    plot_input(timestamps, steering_inputs, "Steering", run_number=run_number)
    plot_input(timestamps, throttle_inputs, "Throttle", run_number=run_number)
    plot_input(timestamps, kphs, "KPHs", run_number=run_number)
    print("Number of steering_inputs:", len(steering_inputs))
    print("Number of throttle inputs:", len(throttle_inputs))
    results = "Total loops: {} \ntotal images: {} \ntotal predictions: {} \nexpected predictions ={}*{}={}".format(
        total_loops, total_imgs, total_predictions, round(runtime, 3),
        steps_per_sec, round(runtime * steps_per_sec, 3))
    print(results)
    results = {
        'runtime': round(runtime, 3),
        'damage': damage,
        'kphs': kphs,
        'traj': traj,
        'pitch': round(pitch, 3),
        'roll': round(roll, 3),
        "z": round(z, 3),
        'final_img': final_img,
        'total_predictions': total_predictions,
        'expected_predictions': round(runtime * steps_per_sec, 3)
    }
    return results
def run_scenario_ai_version(vehicle_model='etk800',
                            deflation_pattern=[0, 0, 0, 0],
                            parts_config=None):
    global base_filename, default_color, default_scenario, default_spawnpoint, setpoint, steps_per_sec
    global prev_error

    random.seed(1703)
    setup_logging()

    beamng = BeamNGpy('localhost',
                      64256,
                      home='H:/BeamNG.research.v1.7.0.1clean',
                      user="******")
    scenario = Scenario(default_scenario, 'research_test')
    vehicle = Vehicle('ego_vehicle',
                      model=vehicle_model,
                      licence='AI',
                      color=default_color)
    vehicle = setup_sensors(vehicle)
    spawn = get_spawn_point(default_scenario, default_spawnpoint)
    # scenario.add_vehicle(vehicle, pos=spawn['pos'], rot=None, rot_quat=spawn['rot_quat'])

    # Compile the scenario and place it in BeamNG's map folder
    scenario.make(beamng)

    # Start BeamNG and enter the main loop
    bng = beamng.open(launch=True)

    bng.set_deterministic()  # Set simulator to be deterministic
    bng.set_steps_per_second(steps_per_sec)  # With 100hz temporal resolution

    # Load and start the scenario
    bng.load_scenario(scenario)
    bng.start_scenario()

    # create vehicle to be chased
    chase_vehicle = Vehicle('chase_vehicle',
                            model='miramar',
                            licence='CHASEE',
                            color='Red')
    bng.spawn_vehicle(chase_vehicle,
                      pos=(469.784, 346.391, 144.982),
                      rot=None,
                      rot_quat=(-0.0037852677050978, -0.0031219546217471,
                                -0.78478640317917, 0.61974692344666))

    bng.spawn_vehicle(vehicle,
                      pos=spawn['pos'],
                      rot=None,
                      rot_quat=spawn['rot_quat'],
                      partConfig=parts_config)

    # Put simulator in pause awaiting further inputs
    bng.pause()
    assert vehicle.skt
    #bng.resume()

    # perturb vehicle
    print("vehicle position before deflation via beamstate:{}".format(
        vehicle.get_object_position()))
    print("vehicle position before deflation via vehicle state:{}".format(
        vehicle.state))
    image = bng.poll_sensors(vehicle)['front_cam']['colour'].convert('RGB')
    plt.imshow(image)
    plt.pause(0.01)
    vehicle.deflate_tires(deflation_pattern)
    bng.step(steps_per_sec * 6)
    vehicle.update_vehicle()
    # print("vehicle position after deflation via beamstate:{}".format(vehicle.get_object_position()))
    # print("vehicle position after deflation via vehicle state:{}".format(vehicle.state))
    pitch = vehicle.state['pitch'][0]
    roll = vehicle.state['roll'][0]
    z = vehicle.state['pos'][2]
    image = bng.poll_sensors(vehicle)['front_cam']['colour'].convert('RGB')
    plt.imshow(image)
    plt.pause(0.01)
    bng.resume()

    vehicle.ai_set_mode('chase')
    vehicle.ai_set_target('chase_vehicle')
    vehicle.ai_drive_in_lane(True)
    damage_prev = None
    runtime = 0.0
    traj = []
    kphs = []
    for _ in range(650):
        image = bng.poll_sensors(vehicle)['front_cam']['colour'].convert('RGB')
        damage = bng.poll_sensors(vehicle)['damage']
        wheelspeed = bng.poll_sensors(vehicle)['electrics']['wheelspeed']
        new_damage = diff_damage(damage, damage_prev)
        damage_prev = damage
        runtime = bng.poll_sensors(vehicle)['timer']['time']
        vehicle.update_vehicle()
        traj.append(vehicle.state['pos'])
        kphs.append(ms_to_kph(wheelspeed))
        if new_damage > 0.0:
            break
        bng.step(5)
    bng.close()
    results = {
        'runtime': round(runtime, 3),
        'damage': damage,
        'kphs': kphs,
        'traj': traj,
        'pitch': round(pitch, 3),
        'roll': round(roll, 3),
        "z": round(z, 3),
        'final_img': image
    }
    return results