Simulator: Fix CI and set low_quality default (#24354)

* Change low_quality argument and fix closing carla bridge

* Some fixes

* Change carla process in test

* Change fov to 120, higher doesn't look good

* Update readme and remove redundant test

* update

* Add folder description
old-commit-hash: ee433dfa57
taco
Gijs Koning 3 years ago committed by GitHub
parent effe065577
commit d0fc9afa48
  1. 46
      tools/sim/README.md
  2. 76
      tools/sim/bridge.py
  3. 2
      tools/sim/lib/keyboard_ctrl.py
  4. 2
      tools/sim/start_carla.sh
  5. 28
      tools/sim/test/test_carla_integration.py

@ -5,40 +5,52 @@ openpilot implements a [bridge](bridge.py) that allows it to run in the [CARLA s
## System Requirements
openpilot doesn't have any extreme hardware requirements, however CARLA requires an NVIDIA graphics card and is very resource-intensive and may not run smoothly on your system. For this case, we have a low quality mode you can activate by running:
```
./start_openpilot_docker.sh --low_quality
```
openpilot doesn't have any extreme hardware requirements, however CARLA requires an NVIDIA graphics card and is very resource-intensive and may not run smoothly on your system.
For this case, we have a the simulator in low quality by default.
You can also check out the [CARLA python documentation](https://carla.readthedocs.io/en/latest/python_api/) to find more parameters to tune that might increase performance on your system.
## Running the simulator
First, start the CARLA server in one terminal.
```
Start Carla simulator, openpilot and bridge processes located in tools/sim:
``` bash
# Terminal 1
./start_carla.sh
# Terminal 2 - Run openpilot and bridge in one Docker:
./start_openpilot_docker.sh
# Running the latest local code execute
# Terminal 2:
./launch_openpilot.sh
# Terminal 3
./bridge.py
```
Then, start the bridge and openpilot in another terminal.
### Bridge usage
_Same commands hold for start_openpilot_docker_
```
./start_openpilot_docker.sh
$ ./bridge.py -h
Usage: bridge.py [options]
Bridge between CARLA and openpilot.
Options:
-h, --help show this help message and exit
--joystick Use joystick input to control the car
--high_quality Set simulator to higher quality (requires good GPU)
--town TOWN Select map to drive in
--spawn_point NUM Number of the spawn point to start in
```
To engage openpilot press 1 a few times while focused on bridge.py to increase the cruise speed.
## Controls
You can control openpilot driving in the simulation with the following keys
All inputs:
| key | functionality |
| :---: | :---------------: |
|:----:|:-----------------:|
| 1 | Cruise up 5 mph |
| 2 | Cruise down 5 mph |
| 3 | Cruise cancel |
| q | Exit all |
To see the options for changing the environment, such as the town, spawn point or precipitation, you can run `./start_openpilot_docker.sh --help`.
This will print the help output inside the docker container. You need to exit the docker container before running `./start_openpilot_docker.sh` again.
| wasd | Control manually |
## Further Reading

@ -32,11 +32,10 @@ STEER_RATIO = 15.
pm = messaging.PubMaster(['roadCameraState', 'wideRoadCameraState', 'sensorEvents', 'can', "gpsLocationExternal"])
sm = messaging.SubMaster(['carControl', 'controlsState'])
def parse_args(add_args=None):
parser = argparse.ArgumentParser(description='Bridge between CARLA and openpilot.')
parser.add_argument('--joystick', action='store_true')
parser.add_argument('--low_quality', action='store_true')
parser.add_argument('--high_quality', action='store_true')
parser.add_argument('--town', type=str, default='Town04_Opt')
parser.add_argument('--spawn_point', dest='num_selected_spawn_point', type=int, default=16)
@ -86,9 +85,8 @@ class Camerad:
# TODO: move rgb_to_yuv.cl to local dir once the frame stream camera is removed
kernel_fn = os.path.join(BASEDIR, "selfdrive", "camerad", "transforms", "rgb_to_yuv.cl")
self._kernel_file = open(kernel_fn)
prg = cl.Program(self.ctx, self._kernel_file.read()).build(cl_arg)
with open(kernel_fn) as f:
prg = cl.Program(self.ctx, f.read()).build(cl_arg)
self.krnl = prg.rgb_to_yuv
self.Wdiv4 = W // 4 if (W % 4 == 0) else (W + (4 - W % 4)) // 4
self.Hdiv4 = H // 4 if (H % 4 == 0) else (H + (4 - H % 4)) // 4
@ -130,10 +128,6 @@ class Camerad:
setattr(dat, pub_type, msg)
pm.send(pub_type, dat)
def close(self):
self._kernel_file.close()
def imu_callback(imu, vehicle_state):
vehicle_state.bearing_deg = math.degrees(imu.compass)
dat = messaging.new_message('sensorEvents', 2)
@ -240,13 +234,13 @@ def can_function_runner(vs: VehicleState, exit_event: threading.Event):
def connect_carla_client():
client = carla.Client("127.0.0.1", 2000)
client.set_timeout(10)
client.set_timeout(5)
return client
class CarlaBridge:
def __init__(self, args):
def __init__(self, arguments):
set_params_enabled()
msg = messaging.new_message('liveCalibration')
@ -254,32 +248,48 @@ class CarlaBridge:
msg.liveCalibration.rpyCalib = [0.0, 0.0, 0.0]
Params().put("CalibrationParams", msg.to_bytes())
self._args = args
self._args = arguments
self._carla_objects = []
self._camerad = None
self._threads_exit_event = threading.Event()
self._exit_event = threading.Event()
self._threads = []
self._shutdown = False
self._keep_alive = True
self.started = False
signal.signal(signal.SIGTERM, self._on_shutdown)
self._exit = threading.Event()
def _on_shutdown(self, signal, frame):
self._shutdown = True
self._keep_alive = False
def bridge_keep_alive(self, q: Queue, retries: int):
while not self._shutdown:
try:
while self._keep_alive:
try:
self._run(q)
break
except RuntimeError as e:
self.close()
if retries == 0:
raise
# Reset for another try
self._carla_objects = []
self._threads = []
self._exit_event = threading.Event()
retries -= 1
if retries <= -1:
print(f"Restarting bridge. Error: {e} ")
else:
print(f"Restarting bridge. Retries left {retries}. Error: {e} ")
finally:
# Clean up resources in the opposite order they were created.
self.close()
def _run(self, q: Queue):
client = connect_carla_client()
world = client.load_world(self._args.town)
settings = world.get_settings()
settings.synchronous_mode = True # Enables synchronous mode
settings.fixed_delta_seconds = 0.05
@ -287,7 +297,7 @@ class CarlaBridge:
world.set_weather(carla.WeatherParameters.ClearSunset)
if self._args.low_quality:
if not self._args.high_quality:
world.unload_map_layer(carla.MapLayer.Foliage)
world.unload_map_layer(carla.MapLayer.Buildings)
world.unload_map_layer(carla.MapLayer.ParkedVehicles)
@ -324,7 +334,7 @@ class CarlaBridge:
blueprint.set_attribute('image_size_x', str(W))
blueprint.set_attribute('image_size_y', str(H))
blueprint.set_attribute('fov', str(fov))
if self._args.low_quality:
if not self._args.high_quality:
blueprint.set_attribute('enable_postprocess_effects', 'False')
camera = world.spawn_actor(blueprint, transform, attach_to=vehicle)
camera.listen(callback)
@ -332,7 +342,7 @@ class CarlaBridge:
self._camerad = Camerad()
road_camera = create_camera(fov=40, callback=self._camerad.cam_callback_road)
road_wide_camera = create_camera(fov=163, callback=self._camerad.cam_callback_wide_road) # fov bigger than 163 shows unwanted artifacts
road_wide_camera = create_camera(fov=120, callback=self._camerad.cam_callback_wide_road) # fov bigger than 120 shows unwanted artifacts
self._carla_objects.extend([road_camera, road_wide_camera])
@ -349,16 +359,13 @@ class CarlaBridge:
self._carla_objects.extend([imu, gps])
# launch fake car threads
self._threads.append(threading.Thread(target=panda_state_function, args=(vehicle_state, self._threads_exit_event,)))
self._threads.append(threading.Thread(target=peripheral_state_function, args=(self._threads_exit_event,)))
self._threads.append(threading.Thread(target=fake_driver_monitoring, args=(self._threads_exit_event,)))
self._threads.append(threading.Thread(target=can_function_runner, args=(vehicle_state, self._threads_exit_event,)))
self._threads.append(threading.Thread(target=panda_state_function, args=(vehicle_state, self._exit_event,)))
self._threads.append(threading.Thread(target=peripheral_state_function, args=(self._exit_event,)))
self._threads.append(threading.Thread(target=fake_driver_monitoring, args=(self._exit_event,)))
self._threads.append(threading.Thread(target=can_function_runner, args=(vehicle_state, self._exit_event,)))
for t in self._threads:
t.start()
# can loop
rk = Ratekeeper(100, print_delay_threshold=0.05)
# init
throttle_ease_out_counter = REPEAT_COUNTER
brake_ease_out_counter = REPEAT_COUNTER
@ -376,7 +383,14 @@ class CarlaBridge:
brake_manual_multiplier = 0.7 # keyboard signal is always 1
steer_manual_multiplier = 45 * STEER_RATIO # keyboard signal is always 1
while not self._shutdown:
# Simulation tends to be slow in the initial steps. This prevents lagging later
for _ in range(20):
world.tick()
# loop
rk = Ratekeeper(100, print_delay_threshold=0.05)
while self._keep_alive:
# 1. Read the throttle, steer and brake from op or manual controls
# 2. Set instructions in Carla
# 3. Send current carstate to op via can
@ -495,13 +509,9 @@ class CarlaBridge:
rk.keep_time()
self.started = True
# Clean up resources in the opposite order they were created.
self.close()
def close(self):
self._threads_exit_event.set()
if self._camerad is not None:
self._camerad.close()
self.started = False
self._exit_event.set()
for s in self._carla_objects:
try:
s.destroy()

@ -38,7 +38,7 @@ def getch() -> str:
def keyboard_poll_thread(q: 'Queue[str]'):
while True:
c = getch()
# print("got %s" % c)
print("got %s" % c)
if c == '1':
q.put("cruise_up")
elif c == '2':

@ -25,4 +25,4 @@ docker run \
-v /tmp/.X11-unix:/tmp/.X11-unix:rw \
-it \
carlasim/carla:0.9.12 \
/bin/bash ./CarlaUE4.sh -opengl -nosound -RenderOffScreen -benchmark -fps=20 -quality-level=High
/bin/bash ./CarlaUE4.sh -opengl -nosound -RenderOffScreen -benchmark -fps=20 -quality-level=Low

@ -15,27 +15,18 @@ class TestCarlaIntegration(unittest.TestCase):
Tests need Carla simulator to run
"""
processes = None
carla_process = None
def setUp(self):
self.processes = []
# We want to make sure that carla_sim docker is still running. Skip output shell
# We want to make sure that carla_sim docker isn't still running.
subprocess.run("docker rm -f carla_sim", shell=True, stderr=subprocess.PIPE, check=False)
self.processes.append(subprocess.Popen(".././start_carla.sh"))
self.carla_process = subprocess.Popen(".././start_carla.sh")
# Too many lagging messages in bridge.py can cause a crash. This prevents it.
unblock_stdout()
def test_run_bridge(self):
# Test bridge connect with carla and runs without any errors for 60 seconds
test_duration = 60
carla_bridge = CarlaBridge(bridge.parse_args(['--low_quality']))
p = carla_bridge.run(Queue(), retries=3)
self.processes = [p]
time.sleep(test_duration)
self.assertEqual(p.exitcode, None, f"Bridge process should be running, but exited with code {p.exitcode}")
# Wait 10 seconds to startup carla
time.sleep(10)
def test_engage(self):
# Startup manager and bridge.py. Check processes are running, then engage and verify.
@ -44,7 +35,7 @@ class TestCarlaIntegration(unittest.TestCase):
sm = messaging.SubMaster(['controlsState', 'carEvents', 'managerState'])
q = Queue()
carla_bridge = CarlaBridge(bridge.parse_args(['--low_quality']))
carla_bridge = CarlaBridge(bridge.parse_args([]))
p_bridge = carla_bridge.run(q, retries=3)
self.processes.append(p_bridge)
@ -70,7 +61,7 @@ class TestCarlaIntegration(unittest.TestCase):
no_car_events_issues_once = True
break
self.assertTrue(no_car_events_issues_once, f"Failed because sm offline, or CarEvents '{car_event_issues}' or processes not running '{not_running}'")
self.assertTrue(no_car_events_issues_once, f"Failed because no messages received, or CarEvents '{car_event_issues}' or processes not running '{not_running}'")
start_time = time.monotonic()
min_counts_control_active = 100
@ -99,8 +90,11 @@ class TestCarlaIntegration(unittest.TestCase):
p.wait(15)
else:
p.join(15)
subprocess.run("docker rm -f carla_sim", shell=True, stderr=subprocess.PIPE, check=False)
# Stop carla simulator by removing docker container
subprocess.run("docker rm -f carla_sim", shell=True, stderr=subprocess.PIPE, check=False)
if self.carla_process is not None:
self.carla_process.wait()
if __name__ == "__main__":

Loading…
Cancel
Save