Closed Guaziboi closed 1 year ago
Hi, it is possible to connect to an already running instance of BeamNG. However, that instance must be created with arguments that allow the BeamNGpy library to connect. BeamNGpy spawns the simulator with these command-line arguments:
Bin64\BeamNG.tech.x64.exe -rport 64256 -nosteam -console -physicsfps 4000 -lua registerCoreModule('tech/techCore')
Then, you will be able to connect to the existing simulator with the usual way:
from beamngpy import BeamNGpy
beamng = BeamNGpy('localhost', 64256)
beamng.open()
It is also possible to open a specific custom scenario. You use the path
argument of the Scenario
class for that. You can load either scenarios created with BeamNGpy before or also the ones already existing in the simulator:
from beamngpy import BeamNGpy, Scenario, ScenarioObject, Vehicle
beamng = BeamNGpy('localhost', 64256)
beamng.open()
scenario = Scenario('italy', 'electricHypermilling', path='/levels/italy/scenarios/electricHypermilling.json')
beamng.scenario.load(scenario)
beamng.scenario.start()
vehicles = scenario.vehicles
ego = next(iter(vehicles.values()))
print(f'Connected: {ego.is_connected()}')
ego.control(throttle=1.0)
That works perfectly, thank you! Now I'm trying to implement this to a script that tracks the user's inputs. Right now, my script works as intended but when I try to make the changes so that it opens up the Hyper Milling scenario I keep getting errors such as "Unresolved attribute reference 'ai' for class 'dict'". This happens for Sensors, ai, state, and control.
Here's my code:
import time
import threading
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
import pandas as pd
from beamngpy import BeamNGpy, Scenario, Vehicle, angle_to_quat
from beamngpy.sensors import Electrics
import openpyxl
sns.set() # Make seaborn set matplotlib styling
# Instantiate a BeamNGpy instance the other classes use for reference & communication
# This is the host & port used to communicate over
# beamng = BeamNGpy('localhost', 64256)
beamng = BeamNGpy('localhost', 64256, home='C:/BeamNG.tech.v0.28.2.0', user='C:/Users/mtith2')
beamng.open()
scenario = Scenario('italy', 'electricHypermilling', path='/levels/italy/scenarios/electricHypermilling.json')
vehicle = scenario.vehicles
electrics = Electrics()
vehicle.sensors.attach('electrics', electrics)
beamng.scenario.load(scenario)
beamng.scenario.start() # After loading, the simulator waits for further input to actually start
vehicle.ai.set_mode('disabled')
positions = []
directions = []
wheel_speeds = []
throttles = []
brakes = []
steerings = [] # New list to store steering values
vehicle.sensors.poll()
sensors = vehicle.sensors
print('The vehicle position is:')
print(vehicle.state['pos'])
print('The vehicle direction is:')
print(vehicle.state['dir'])
print('The wheel speed is:')
print(sensors['electrics']['wheelspeed'])
print('The throttle intensity is:')
print(sensors['electrics']['throttle'])
print('The brake intensity is:')
print(sensors['electrics']['brake'])
# Function to update vehicle controls based on user input
def update_controls():
while True:
user_input = input("Enter throttle, brake, and steering values (separated by space), or 'q' to quit: ")
if user_input.lower() == 'q':
# Quit the program
beamng.close() # End the scenario and close the connection to the simulator
return False
inputs = user_input.split()
if len(inputs) != 3:
print("Invalid input. Please enter throttle, brake, and steering values.")
continue
try:
throttle = float(inputs[0])
brake = float(inputs[1])
steering = float(inputs[2])
if throttle < 0 or throttle > 1 or brake < 0 or brake > 1:
print("Throttle and brake values should be between 0 and 1.")
continue
if steering < -1 or steering > 1:
print("Steering value should be between -1 and 1.")
continue
vehicle.control(throttle=throttle, brake=brake, steering=steering)
break
except ValueError:
print("Invalid input. Throttle, brake, and steering values should be numeric.")
# Function to collect sensor data
def collect_data():
while True:
time.sleep(0.5)
vehicle.sensors.poll() # Polls the data of all sensors attached to the vehicle
sensors = vehicle.sensors
positions.append(vehicle.state['pos'])
directions.append(vehicle.state['dir'])
wheel_speeds.append(sensors['electrics']['wheelspeed'])
throttles.append(sensors['electrics']['throttle'])
brakes.append(sensors['electrics']['brake'])
steerings.append(sensors['electrics']['steering'])
# Create separate threads for user input and data collection
input_thread = threading.Thread(target=update_controls)
data_thread = threading.Thread(target=collect_data)
# Start the threads
input_thread.start()
data_thread.start()
# Wait for both threads to finish
input_thread.join()
data_thread.join()
beamng.close() # End the scenario and close the connection to the simulator
# Create a DataFrame using the collected data
data = {
'Position': positions,
'Direction': directions,
'Wheel Speed': wheel_speeds,
'Throttle': throttles,
'Brake': brakes,
'Steering': steerings
}
df = pd.DataFrame(data)
# Save the DataFrame to an Excel file using openpyxl explicitly
with pd.ExcelWriter('vehicle_data.xlsx', engine='openpyxl') as writer:
df.to_excel(writer, index=False)
plt.plot(throttles, 'b-', label='Throttle')
plt.plot(brakes, 'r-', label='Brake')
plt.plot(steerings, 'g-', label='Steering')
plt.legend()
plt.show()
plt.clf()
x = [p[0] for p in positions]
y = [p[1] for p in positions]
plt.plot(x, y, '.')
plt.axis('square')
plt.show()
plt.clf()
angles = [np.arctan2(d[1], d[0]) for d in directions]
r = wheel_speeds
plt.subplot(111, projection='polar')
plt.scatter(angles, r)
plt.show()
Hi, scenario.vehicles
is a dictionary of all the vehicles found in the scenario. You should change the line vehicle = scenario.vehicles
to vehicle = next(iter(scenario.vehicles.values()))
and I think the problem you are having should be gone.
Thank you for the quick response. Unfortunately getting an error "StopIteration" at line 33, the warning messages do get resolved though.
Yes, one other small thing, scenario.vehicles
contains the list of vehicles of an existing scenario only after it gets loaded. I tested this code and it seems to behave correctly:
import threading
import time
import matplotlib.pyplot as plt
import numpy as np
import openpyxl
import pandas as pd
import seaborn as sns
from beamngpy import BeamNGpy, Scenario, Vehicle, angle_to_quat
from beamngpy.sensors import Electrics
sns.set() # Make seaborn set matplotlib styling
# Instantiate a BeamNGpy instance the other classes use for reference & communication
# This is the host & port used to communicate over
# beamng = BeamNGpy('localhost', 64256)
beamng = BeamNGpy('localhost', 64256, home='T:/BeamNG/BeamNG.tech.v0.28.2.0')
beamng.open()
scenario = Scenario('italy', 'electricHypermilling', path='/levels/italy/scenarios/electricHypermilling.json')
beamng.scenario.load(scenario)
beamng.scenario.start() # After loading, the simulator waits for further input to actually start
vehicle = next(iter(scenario.vehicles.values()))
electrics = Electrics()
vehicle.sensors.attach('electrics', electrics)
vehicle.ai.set_mode('disabled')
positions = []
directions = []
wheel_speeds = []
throttles = []
brakes = []
steerings = [] # New list to store steering values
vehicle.sensors.poll()
sensors = vehicle.sensors
print('The vehicle position is:')
print(vehicle.state['pos'])
print('The vehicle direction is:')
print(vehicle.state['dir'])
print('The wheel speed is:')
print(sensors['electrics']['wheelspeed'])
print('The throttle intensity is:')
print(sensors['electrics']['throttle'])
print('The brake intensity is:')
print(sensors['electrics']['brake'])
# Function to update vehicle controls based on user input
def update_controls():
while True:
user_input = input("Enter throttle, brake, and steering values (separated by space), or 'q' to quit: ")
if user_input.lower() == 'q':
# Quit the program
beamng.close() # End the scenario and close the connection to the simulator
return False
inputs = user_input.split()
if len(inputs) != 3:
print("Invalid input. Please enter throttle, brake, and steering values.")
continue
try:
throttle = float(inputs[0])
brake = float(inputs[1])
steering = float(inputs[2])
if throttle < 0 or throttle > 1 or brake < 0 or brake > 1:
print("Throttle and brake values should be between 0 and 1.")
continue
if steering < -1 or steering > 1:
print("Steering value should be between -1 and 1.")
continue
vehicle.control(throttle=throttle, brake=brake, steering=steering)
break
except ValueError:
print("Invalid input. Throttle, brake, and steering values should be numeric.")
# Function to collect sensor data
def collect_data():
while True:
time.sleep(0.5)
vehicle.sensors.poll() # Polls the data of all sensors attached to the vehicle
sensors = vehicle.sensors
positions.append(vehicle.state['pos'])
directions.append(vehicle.state['dir'])
wheel_speeds.append(sensors['electrics']['wheelspeed'])
throttles.append(sensors['electrics']['throttle'])
brakes.append(sensors['electrics']['brake'])
steerings.append(sensors['electrics']['steering'])
# Create separate threads for user input and data collection
input_thread = threading.Thread(target=update_controls)
data_thread = threading.Thread(target=collect_data)
# Start the threads
input_thread.start()
data_thread.start()
# Wait for both threads to finish
input_thread.join()
data_thread.join()
beamng.close() # End the scenario and close the connection to the simulator
# Create a DataFrame using the collected data
data = {
'Position': positions,
'Direction': directions,
'Wheel Speed': wheel_speeds,
'Throttle': throttles,
'Brake': brakes,
'Steering': steerings
}
df = pd.DataFrame(data)
# Save the DataFrame to an Excel file using openpyxl explicitly
with pd.ExcelWriter('vehicle_data.xlsx', engine='openpyxl') as writer:
df.to_excel(writer, index=False)
plt.plot(throttles, 'b-', label='Throttle')
plt.plot(brakes, 'r-', label='Brake')
plt.plot(steerings, 'g-', label='Steering')
plt.legend()
plt.show()
plt.clf()
x = [p[0] for p in positions]
y = [p[1] for p in positions]
plt.plot(x, y, '.')
plt.axis('square')
plt.show()
plt.clf()
angles = [np.arctan2(d[1], d[0]) for d in directions]
r = wheel_speeds
plt.subplot(111, projection='polar')
plt.scatter(angles, r)
plt.show()
This works perfectly, thank you!
So in the example codes, I'm seeing a new instance of BeamNG being opened and creating a brand new scenario. I was wondering if it's possible to connect to an already running instance of BeamNG or to open a specific custom scenario