Merge remote-tracking branch 'upstream/master' into toyota-fuzzy-v2

pull/28641/head
Shane Smiskol 2 years ago
commit 34683788c8
  1. 2
      .devcontainer/Dockerfile
  2. 3
      .devcontainer/devcontainer.json
  3. 9
      .github/workflows/selfdrive_tests.yaml
  4. 1
      .pre-commit-config.yaml
  5. 4
      selfdrive/test/helpers.py
  6. 2
      selfdrive/thermald/tests/test_power_monitoring.py
  7. 62
      selfdrive/ui/translations/main_zh-CHT.ts
  8. 2
      tools/sim/bridge/common.py
  9. 156
      tools/sim/bridge/metadrive.py
  10. 4
      tools/sim/lib/simulated_car.py
  11. 6
      tools/sim/run_bridge.py
  12. 43
      tools/sim/tests/test_carla_bridge.py
  13. 15
      tools/sim/tests/test_metadrive_bridge.py
  14. 37
      tools/sim/tests/test_sim_bridge.py

@ -9,3 +9,5 @@ RUN pip install ipython jupyter jupyterlab
RUN cd $HOME && \
curl -O https://raw.githubusercontent.com/commaai/agnos-builder/master/userspace/home/.tmux.conf && \
curl -O https://github.com/commaai/agnos-builder/blob/master/userspace/home/.vimrc
ENV CARLA_HOST="host.docker.internal"

@ -18,7 +18,8 @@
"--volume=${localEnv:HOME}/.comma:/root/.comma",
"--volume=/tmp/comma_download_cache:/tmp/comma_download_cache",
"--volume=/tmp/devcontainer_scons_cache:/tmp/scons_cache",
"--shm-size=1G"
"--shm-size=1G",
"--add-host=host.docker.internal:host-gateway" // required to use host.docker.internal on linux
],
"customizations": {
"vscode": {

@ -70,7 +70,10 @@ jobs:
build:
strategy:
matrix:
arch: ${{ fromJson( (github.repository == 'commaai/openpilot') && '["x86_64", "aarch64"]' || '["x86_64"]' ) }}
arch: ${{ fromJson(
((github.repository == 'commaai/openpilot') &&
((github.event_name != 'pull_request') ||
(github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && '["x86_64", "aarch64"]' || '["x86_64"]' ) }}
runs-on: ${{ (matrix.arch == 'aarch64') && 'buildjet-2vcpu-ubuntu-2204-arm' || 'ubuntu-20.04' }}
steps:
- uses: actions/checkout@v3
@ -277,7 +280,9 @@ jobs:
process_replay:
name: process replay
runs-on: ${{ ((github.event.pull_request.head.repo.full_name == 'commaai/openpilot') || (github.repository == 'commaai/openpilot')) && 'buildjet-8vcpu-ubuntu-2004' || 'ubuntu-20.04' }}
runs-on: ${{ ((github.repository == 'commaai/openpilot') &&
((github.event_name != 'pull_request') ||
(github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'buildjet-8vcpu-ubuntu-2004' || 'ubuntu-20.04' }}
steps:
- uses: actions/checkout@v3
with:

@ -10,6 +10,7 @@ repos:
- id: check-ast
exclude: '^(third_party)/'
- id: check-json
exclude: '.devcontainer/devcontainer.json' # this supports JSON with comments
- id: check-toml
- id: check-xml
- id: check-yaml

@ -69,3 +69,7 @@ def with_processes(processes, init_time=0, ignore_stopped=None):
return wrap
return wrapper
def noop(*args, **kwargs):
pass

@ -3,6 +3,7 @@ import unittest
from unittest.mock import patch
from openpilot.common.params import Params
from openpilot.selfdrive.test.helpers import noop
from openpilot.selfdrive.thermald.power_monitoring import PowerMonitoring, CAR_BATTERY_CAPACITY_uWh, \
CAR_CHARGING_RATE_W, VBATT_PAUSE_CHARGING, DELAY_SHUTDOWN_TIME_S
@ -25,6 +26,7 @@ def pm_patch(name, value, constant=False):
@patch("time.monotonic", new=mock_time_monotonic)
@patch("openpilot.selfdrive.thermald.power_monitoring.put_nonblocking", new=noop) # TODO: Remove this once nonblocking params are safer
class TestPowerMonitoring(unittest.TestCase):
def setUp(self):
self.params = Params()

@ -171,15 +171,15 @@
</message>
<message>
<source>Reset Calibration</source>
<translation></translation>
<translation></translation>
</message>
<message>
<source>RESET</source>
<translation></translation>
<translation></translation>
</message>
<message>
<source>Are you sure you want to reset calibration?</source>
<translation></translation>
<translation></translation>
</message>
<message>
<source>Review Training Guide</source>
@ -227,7 +227,7 @@
</message>
<message>
<source>openpilot requires the device to be mounted within 4° left or right and within 5° up or 8° down. openpilot is continuously calibrating, resetting is rarely required.</source>
<translation>openpilot 4° 5° 8° </translation>
<translation>openpilot 4° 5° 8° </translation>
</message>
<message>
<source> Your device is pointed %1° %2 and %3° %4.</source>
@ -290,7 +290,7 @@
</message>
<message>
<source>PAST WEEK</source>
<translation></translation>
<translation></translation>
</message>
<message>
<source>KM</source>
@ -369,7 +369,7 @@
<name>MapWindow</name>
<message>
<source>Map Loading</source>
<translation></translation>
<translation></translation>
</message>
<message>
<source>Waiting for GPS</source>
@ -452,11 +452,11 @@
</message>
<message>
<source>openpilot was unable to identify your car. Your car is either unsupported or its ECUs are not recognized. Please submit a pull request to add the firmware versions to the proper vehicle. Need help? Join discord.comma.ai.</source>
<translation>openpilot (ECU) Pull Request discord.comma.ai </translation>
<translation>openpilot (ECU) Pull Request discord.comma.ai </translation>
</message>
<message>
<source>openpilot was unable to identify your car. Check integrity of cables and ensure all connections are secure, particularly that the comma power is fully inserted in the OBD-II port of the vehicle. Need help? Join discord.comma.ai.</source>
<translation>openpilot comma power OBD-II discord.comma.ai </translation>
<translation>openpilot comma power OBD-II discord.comma.ai </translation>
</message>
<message>
<source>openpilot detected a change in the device&apos;s mounting position. Ensure the device is fully seated in the mount and the mount is firmly secured to the windshield.</source>
@ -498,7 +498,7 @@
</message>
<message>
<source>Bookmark connect.comma.ai to your home screen to use it like an app</source>
<translation> connect.comma.ai 便 App 使</translation>
<translation> connect.comma.ai 便 App 使</translation>
</message>
</context>
<context>
@ -528,7 +528,7 @@
</message>
<message>
<source>Remote access</source>
<translation></translation>
<translation></translation>
</message>
<message>
<source>24/7 LTE connectivity</source>
@ -611,15 +611,15 @@
<name>Reset</name>
<message>
<source>Reset failed. Reboot to try again.</source>
<translation></translation>
<translation></translation>
</message>
<message>
<source>Are you sure you want to reset your device?</source>
<translation></translation>
<translation></translation>
</message>
<message>
<source>System Reset</source>
<translation></translation>
<translation></translation>
</message>
<message>
<source>Cancel</source>
@ -644,7 +644,7 @@
<message>
<source>Resetting device...
This may take up to a minute.</source>
<translation>
<translation>
</translation>
</message>
</context>
@ -699,7 +699,7 @@ This may take up to a minute.</source>
</message>
<message>
<source>Connect to Wi-Fi</source>
<translation></translation>
<translation></translation>
</message>
<message>
<source>Back</source>
@ -719,7 +719,7 @@ This may take up to a minute.</source>
</message>
<message>
<source>for Custom Software</source>
<translation></translation>
<translation></translation>
</message>
<message>
<source>Downloading...</source>
@ -829,27 +829,27 @@ This may take up to a minute.</source>
</message>
<message>
<source>Wi-Fi</source>
<translation type="unfinished"></translation>
<translation>Wi-Fi</translation>
</message>
<message>
<source>ETH</source>
<translation type="unfinished"></translation>
<translation>ETH</translation>
</message>
<message>
<source>2G</source>
<translation type="unfinished"></translation>
<translation>2G</translation>
</message>
<message>
<source>3G</source>
<translation type="unfinished"></translation>
<translation>3G</translation>
</message>
<message>
<source>LTE</source>
<translation type="unfinished"></translation>
<translation>LTE</translation>
</message>
<message>
<source>5G</source>
<translation type="unfinished"></translation>
<translation>5G</translation>
</message>
</context>
<context>
@ -931,11 +931,11 @@ This may take up to a minute.</source>
<name>SshControl</name>
<message>
<source>SSH Keys</source>
<translation>SSH </translation>
<translation>SSH </translation>
</message>
<message>
<source>Warning: This grants SSH access to all public keys in your GitHub settings. Never enter a GitHub username other than your own. A comma employee will NEVER ask you to add their GitHub username.</source>
<translation> GitHub SSH GitHub comma GitHub </translation>
<translation> GitHub SSH GitHub 使comma GitHub 使</translation>
</message>
<message>
<source>ADD</source>
@ -943,7 +943,7 @@ This may take up to a minute.</source>
</message>
<message>
<source>Enter your GitHub username</source>
<translation> GitHub </translation>
<translation> GitHub 使</translation>
</message>
<message>
<source>LOADING</source>
@ -955,7 +955,7 @@ This may take up to a minute.</source>
</message>
<message>
<source>Username &apos;%1&apos; has no keys on GitHub</source>
<translation>GitHub &apos;%1&apos; </translation>
<translation>GitHub &apos;%1&apos; </translation>
</message>
<message>
<source>Request timed out</source>
@ -1024,7 +1024,7 @@ This may take up to a minute.</source>
</message>
<message>
<source>Upload data from the driver facing camera and help improve the driver monitoring algorithm.</source>
<translation></translation>
<translation></translation>
</message>
<message>
<source>Disengage on Accelerator Pedal</source>
@ -1080,7 +1080,7 @@ This may take up to a minute.</source>
</message>
<message>
<source>WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB).</source>
<translation> openpilot Alpha 使AEB</translation>
<translation> openpilot Alpha 使AEB</translation>
</message>
<message>
<source>On this car, openpilot defaults to the car&apos;s built-in ACC instead of openpilot&apos;s longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha.</source>
@ -1124,11 +1124,11 @@ This may take up to a minute.</source>
</message>
<message>
<source>When navigation has a destination, openpilot will input the map information into the model. This provides useful context for the model and allows openpilot to keep left or right appropriately at forks/exits. Lane change behavior is unchanged and still activated by the driver. This is an alpha quality feature; mistakes should be expected, particularly around exits and forks. These mistakes can include unintended laneline crossings, late exit taking, driving towards dividing barriers in the gore areas, etc.</source>
<translation>openpilot 使 openpilot / Alpha </translation>
<translation>openpilot 使 openpilot / Alpha </translation>
</message>
<message>
<source>The driving visualization will transition to the road-facing wide-angle camera at low speeds to better show some turns. The Experimental mode logo will also be shown in the top right corner. When a navigation destination is set and the driving model is using it as input, the driving path on the map will turn green.</source>
<translation></translation>
<translation></translation>
</message>
</context>
<context>
@ -1143,7 +1143,7 @@ This may take up to a minute.</source>
</message>
<message>
<source>Connect to Wi-Fi</source>
<translation></translation>
<translation></translation>
</message>
<message>
<source>Install</source>

@ -19,7 +19,7 @@ from openpilot.tools.sim.lib.simulated_sensors import SimulatedSensors
def rk_loop(function, hz, exit_event: threading.Event):
rk = Ratekeeper(hz)
rk = Ratekeeper(hz, None)
while not exit_event.is_set():
function()
rk.keep_time()

@ -0,0 +1,156 @@
import math
import numpy as np
import time
from openpilot.tools.sim.bridge.common import World, SimulatorBridge
from openpilot.tools.sim.lib.common import vec3, SimulatorState
from openpilot.tools.sim.lib.camerad import W, H
def apply_metadrive_patches():
from metadrive.engine.core.engine_core import EngineCore
from metadrive.engine.core.image_buffer import ImageBuffer
from metadrive.obs.image_obs import ImageObservation
# By default, metadrive won't try to use cuda images unless it's used as a sensor for vehicles, so patch that in
def add_image_sensor_patched(self, name: str, cls, args):
if self.global_config["image_on_cuda"]:# and name == self.global_config["vehicle_config"]["image_source"]:
sensor = cls(*args, self, cuda=True)
else:
sensor = cls(*args, self, cuda=False)
assert isinstance(sensor, ImageBuffer), "This API is for adding image sensor"
self.sensors[name] = sensor
EngineCore.add_image_sensor = add_image_sensor_patched
# we aren't going to use the built-in observation stack, so disable it to save time
def observe_patched(self, vehicle):
return self.state
ImageObservation.observe = observe_patched
class MetaDriveWorld(World):
def __init__(self, env, ticks_per_frame: float, dual_camera = False):
super().__init__(dual_camera)
self.env = env
self.ticks_per_frame = ticks_per_frame
self.dual_camera = dual_camera
self.steer_ratio = 15
self.vc = [0.0,0.0]
self.reset_time = 0
def get_cam_as_rgb(self, cam):
cam = self.env.engine.sensors[cam]
img = cam.perceive(self.env.vehicle, clip=False)
if type(img) != np.ndarray:
img = img.get() # convert cupy array to numpy
return img
def apply_controls(self, steer_angle, throttle_out, brake_out):
steer_metadrive = steer_angle * 1 / (self.env.vehicle.MAX_STEERING * self.steer_ratio)
steer_metadrive = np.clip(steer_metadrive, -1, 1)
if (time.monotonic() - self.reset_time) > 5:
self.vc[0] = steer_metadrive
if throttle_out:
self.vc[1] = throttle_out/10
else:
self.vc[1] = -brake_out
else:
self.vc[0] = 0
self.vc[1] = 0
def read_sensors(self, state: SimulatorState):
state.velocity = vec3(x=float(self.env.vehicle.velocity[0]), y=float(self.env.vehicle.velocity[1]), z=0)
state.gps.from_xy(self.env.vehicle.position)
state.bearing = float(math.degrees(self.env.vehicle.heading_theta))
state.steering_angle = self.env.vehicle.steering * self.env.vehicle.MAX_STEERING
state.valid = True
def read_cameras(self):
if self.dual_camera:
self.wide_road_image = self.get_cam_as_rgb("rgb_wide")
self.road_image = self.get_cam_as_rgb("rgb_road")
def tick(self):
obs, _, terminated, _, info = self.env.step(self.vc)
if terminated:
self.env.reset()
self.reset_time = time.monotonic()
def close(self):
pass
class MetaDriveBridge(SimulatorBridge):
TICKS_PER_FRAME = 2
def __init__(self, args):
self.should_render = False
super(MetaDriveBridge, self).__init__(args)
def spawn_world(self):
print("----------------------------------------------------------")
print("---- Spawning Metadrive world, this might take awhile ----")
print("----------------------------------------------------------")
from metadrive.component.sensors.rgb_camera import RGBCamera
from metadrive.component.sensors.base_camera import _cuda_enable
from metadrive.envs.metadrive_env import MetaDriveEnv
from panda3d.core import Vec3
apply_metadrive_patches()
C3_POSITION = Vec3(0, 0, 1)
class RGBCameraWide(RGBCamera):
def __init__(self, *args, **kwargs):
super(RGBCameraWide, self).__init__(*args, **kwargs)
cam = self.get_cam()
cam.setPos(C3_POSITION)
lens = self.get_lens()
lens.setFov(160)
class RGBCameraRoad(RGBCamera):
def __init__(self, *args, **kwargs):
super(RGBCameraRoad, self).__init__(*args, **kwargs)
cam = self.get_cam()
cam.setPos(C3_POSITION)
lens = self.get_lens()
lens.setFov(40)
sensors = {
"rgb_road": (RGBCameraRoad, W, H, )
}
if self.dual_camera:
sensors["rgb_wide"] = (RGBCameraWide, W, H)
env = MetaDriveEnv(
dict(
use_render=self.should_render,
vehicle_config=dict(
enable_reverse=False,
image_source="rgb_road",
spawn_longitude=15
),
sensors=sensors,
image_on_cuda=_cuda_enable,
image_observation=True,
interface_panel=[],
out_of_route_done=False,
on_continuous_line_done=False,
crash_vehicle_done=False,
crash_object_done=False,
)
)
env.reset()
return MetaDriveWorld(env, self.TICKS_PER_FRAME)

@ -107,6 +107,8 @@ class SimulatedCar:
def update(self, simulator_state: SimulatorState):
self.send_can_messages(simulator_state)
self.send_panda_state(simulator_state)
if self.idx % 50 == 0: # only send panda states at 2hz
self.send_panda_state(simulator_state)
self.idx += 1

@ -1,11 +1,13 @@
#!/usr/bin/env python
import argparse
import os
from typing import Any
from multiprocessing import Queue
from openpilot.tools.sim.bridge.common import SimulatorBridge
from openpilot.tools.sim.bridge.carla import CarlaBridge
from openpilot.tools.sim.bridge.metadrive import MetaDriveBridge
def parse_args(add_args=None):
@ -18,7 +20,7 @@ def parse_args(add_args=None):
# Carla specific
parser.add_argument('--town', type=str, default='Town04_Opt')
parser.add_argument('--spawn_point', dest='num_selected_spawn_point', type=int, default=16)
parser.add_argument('--host', dest='host', type=str, default='127.0.0.1')
parser.add_argument('--host', dest='host', type=str, default=os.environ.get("CARLA_HOST", '127.0.0.1'))
parser.add_argument('--port', dest='port', type=int, default=2000)
return parser.parse_args(add_args)
@ -30,6 +32,8 @@ if __name__ == "__main__":
simulator_bridge: SimulatorBridge
if args.simulator == "carla":
simulator_bridge = CarlaBridge(args)
elif args.simulator == "metadrive":
simulator_bridge = MetaDriveBridge(args)
else:
raise AssertionError("simulator type not supported")
p = simulator_bridge.run(q)

@ -0,0 +1,43 @@
#!/usr/bin/env python3
import subprocess
import time
import unittest
from openpilot.selfdrive.manager.helpers import unblock_stdout
from openpilot.tools.sim.run_bridge import parse_args
from openpilot.tools.sim.bridge.carla import CarlaBridge
from openpilot.tools.sim.tests.test_sim_bridge import SIM_DIR, TestSimBridgeBase
class TestCarlaBridge(TestSimBridgeBase):
"""
Tests need Carla simulator to run
"""
carla_process = None
def setUp(self):
super().setUp()
# 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.carla_process = subprocess.Popen("./start_carla.sh", cwd=SIM_DIR)
# Too many lagging messages in bridge.py can cause a crash. This prevents it.
unblock_stdout()
# Wait 10 seconds to startup carla
time.sleep(10)
def create_bridge(self):
return CarlaBridge(parse_args([]))
def tearDown(self):
super().tearDown()
# 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__":
unittest.main()

@ -0,0 +1,15 @@
#!/usr/bin/env python3
import unittest
from openpilot.tools.sim.run_bridge import parse_args
from openpilot.tools.sim.bridge.metadrive import MetaDriveBridge
from openpilot.tools.sim.tests.test_sim_bridge import TestSimBridgeBase
class TestMetaDriveBridge(TestSimBridgeBase):
def create_bridge(self):
return MetaDriveBridge(parse_args([]))
if __name__ == "__main__":
unittest.main()

@ -1,40 +1,24 @@
#!/usr/bin/env python3
import os
import subprocess
import time
import unittest
import os
from multiprocessing import Queue
from cereal import messaging
from openpilot.common.basedir import BASEDIR
from openpilot.selfdrive.manager.helpers import unblock_stdout
from openpilot.tools.sim.run_bridge import parse_args
from openpilot.tools.sim.bridge.carla import CarlaBridge
CI = "CI" in os.environ
SIM_DIR = os.path.join(BASEDIR, "tools/sim")
class TestCarlaIntegration(unittest.TestCase):
"""
Tests need Carla simulator to run
"""
processes = None
carla_process = None
class TestSimBridgeBase(unittest.TestCase):
@classmethod
def setUpClass(cls):
if cls is TestSimBridgeBase:
raise unittest.SkipTest("Don't run this base class, run test_carla_bridge.py instead")
def setUp(self):
self.processes = []
if not CI:
# 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.carla_process = subprocess.Popen("./start_carla.sh", cwd=SIM_DIR)
# Too many lagging messages in bridge.py can cause a crash. This prevents it.
unblock_stdout()
# 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.
p_manager = subprocess.Popen("./launch_openpilot.sh", cwd=SIM_DIR)
@ -42,7 +26,7 @@ class TestCarlaIntegration(unittest.TestCase):
sm = messaging.SubMaster(['controlsState', 'carEvents', 'managerState'])
q = Queue()
carla_bridge = CarlaBridge(parse_args([]))
carla_bridge = self.create_bridge()
p_bridge = carla_bridge.run(q, retries=10)
self.processes.append(p_bridge)
@ -99,11 +83,6 @@ class TestCarlaIntegration(unittest.TestCase):
else:
p.join(15)
# 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__":
unittest.main()
Loading…
Cancel
Save