mirror of
https://github.com/infiniteCable2/openpilot.git
synced 2026-09-30 19:43:41 +08:00
Merge remote-tracking branch 'comma/master' into sync-20250309
# Conflicts: # .github/workflows/ui_preview.yaml # common/params_keys.h # msgq_repo # opendbc_repo # panda # selfdrive/ui/qt/offroad/firehose.h # selfdrive/ui/tests/test_ui/run.py # system/manager/process_config.py
This commit is contained in:
@@ -1,44 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>openpilot Terms of Service</title>
|
||||
<style type="text/css">
|
||||
p {
|
||||
margin: 45px 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<p>The Terms and Conditions below are effective for all users</p>
|
||||
<p>Last Updated on October 18, 2019</p>
|
||||
<p>Please read these Terms of Use (“Terms”) carefully before using openpilot which is open-sourced software developed by Comma.ai, Inc., a corporation organized under the laws of Delaware (“comma,” “us,” “we,” or “our”).</p>
|
||||
<p><strong>Before using and by accessing openpilot, you indicate that you have read, understood, and agree to these Terms.</strong> These Terms apply to all users and others who access or use openpilot. If others use openpilot through your user account or vehicle, you are responsible to ensure that they only use openpilot when it is safe to do so, and in compliance with these Terms and with applicable law. If you disagree with any part of the Terms, you should not access or use openpilot.</p>
|
||||
<h3 id="communications">Communications</h3>
|
||||
<p>You agree that comma may contact you by email or telephone in connection with openpilot or for other business purposes. You may opt out of receiving email messages at any time by contacting us at support@comma.ai.</p>
|
||||
<p>We collect, use, and share information from and about you and your vehicle in connection with openpilot. You consent to comma accessing the systems associated with openpilot, without additional notice or consent, for the purposes of providing openpilot, data collection, software updates, safety and cybersecurity, suspension or removal of your account, and as disclosed in the Privacy Policy (available at https://connect.comma.ai/privacy).</p>
|
||||
<h3 id="safety">Safety</h3>
|
||||
<p>openpilot performs the functions of Adaptive Cruise Control (ACC) and Lane Keeping Assist System (LKAS) designed for use in compatible motor vehicles. While using openpilot, it is your responsibility to obey all laws, traffic rules, and traffic regulations governing your vehicle and its operation. Access to and use of openpilot is at your own risk and responsibility, and openpilot should be accessed and/or used only when you can do so safely.</p>
|
||||
<p>openpilot does not make your vehicle “autonomous” or capable of operation without the active monitoring of a licensed driver. It is designed to assist a licensed driver. A licensed driver must pay attention to the road, remain aware of navigation at all times, and be prepared to take immediate action. Failure to do so can cause damage, injury, or death.</p>
|
||||
<h3 id="supported-locations-and-models">Supported Locations and Models</h3>
|
||||
<p>openpilot is compatible only with particular makes and models of vehicles. For a complete list of currently supported vehicles, visit https://comma.ai. openpilot will not function properly when installed in an incompatible vehicle. openpilot is compatible only within the geographical boundaries of the United States of America.</p>
|
||||
<h3 id="indemnification">Indemnification</h3>
|
||||
<p><strong>To the maximum extent allowable by law, you agree to defend, indemnify and hold harmless comma, and its employees, partners, suppliers, contractors, investors, agents, officers, directors, and affiliates, from and against any and all claims, damages, causes of action, penalties, interest, demands, obligations, losses, liabilities, costs or debt, additional taxes, and expenses (including but not limited to attorneys’ fees), resulting from or arising out of (i) your use and access of, or inability to use or access, openpilot, (ii) your breach of these Terms, (iii) the inaccuracy of any information, representation or warranty made by you, (iv) activities of anyone other than you in connection with openpilot conducted through your comma device or account, (v) any other of your activities under or in connection with these Terms or openpilot.</strong></p>
|
||||
<h3 id="limitation-of-liability">Limitation of Liability</h3>
|
||||
<p>In no event shall comma, nor its directors, employees, partners, agents, suppliers, or affiliates, be liable for any indirect, incidental, special, consequential or punitive damages, including without limitation, loss of profits, data, use, goodwill, or other intangible losses, resulting from (i) your access to or use of or inability to access or use of the Software; or (ii) any conduct or content of any third party on the Software whether based on warranty, contract, tort (including negligence) or any other legal theory, whether or not we have been informed of the possibility of such damage, and even if a remedy set forth herein is found to have failed of its essential purpose.</p>
|
||||
<h3 id="no-warranty-or-obligations-to-maintain-or-service">No Warranty or Obligations to Maintain or Service</h3>
|
||||
<p>comma provides openpilot without representations, conditions, or warranties of any kind. openpilot is provided on an “AS IS” and “AS AVAILABLE” basis, including with all faults and errors as may occur. To the extent permitted by law and unless prohibited by law, comma on behalf of itself and all persons and parties acting by, through, or for comma, explicitly disclaims all warranties or conditions, express, implied, or collateral, including any implied warranties of merchantability, satisfactory quality, and fitness for a particular purpose in respect of openpilot.</p>
|
||||
<p>To the extent permitted by law, comma does not warrant the operation, performance, or availability of openpilot under all conditions. comma is not responsible for any failures caused by server errors, misdirected or redirected transmissions, failed internet connections, interruptions or failures in the transmission of data, any computer virus, or any acts or omissions of third parties that damage the network or impair wireless service.</p>
|
||||
<p>We undertake reasonable measures to preserve and secure information collected through our openpilot. However, no data collection, transmission or storage system is 100% secure, and there is always a risk that your information may be intercepted without our consent. <em>In using openpilot, you acknowledge that comma is not responsible for intercepted information, and you hereby release us from any and all claims arising out of or related to the use of intercepted information in any unauthorized manner.</em></p>
|
||||
<p>By providing openpilot, comma does not transfer or license its intellectual property or grant rights in its brand names, nor does comma make representations with respect to third-party intellectual property rights.</p>
|
||||
<p>We are not obligated to provide any maintenance or support for openpilot, technical or otherwise. If we voluntarily provide any maintenance or support for openpilot, we may stop any such maintenance, support, or services at any time in our sole discretion.</p>
|
||||
<h3 id="modification-of-software">Modification of Software</h3>
|
||||
<p>In no event shall comma, nor its directors, employees, partners, agents, suppliers, or affiliates, be liable if you choose to modify the software.</p>
|
||||
<h3 id="changes">Changes</h3>
|
||||
<p>We reserve the right, at our sole discretion, to modify or replace these Terms at any time. If a revision is material we will provide at least 15 days’ notice prior to any new terms taking effect. What constitutes a material change will be determined at our sole discretion.</p>
|
||||
<p>By continuing to access or use our Software after any revisions become effective, you agree to be bound by the revised terms. If you do not agree to the new terms, you are no longer authorized to use the Software.</p>
|
||||
<h3 id="contact-us">Contact Us</h3>
|
||||
<p>If you have any questions about these Terms, please contact us at support@comma.ai.</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -12,11 +12,11 @@
|
||||
|
||||
A supported vehicle is one that just works when you install a comma device. All supported cars provide a better experience than any stock system. Supported vehicles reference the US market unless otherwise specified.
|
||||
|
||||
# {{all_car_docs | length}} Supported Cars
|
||||
# {{all_car_docs | selectattr('support_type', 'eq', SupportType.UPSTREAM) | list | length}} Supported Cars
|
||||
|
||||
|{{Column | map(attribute='value') | join('|') | replace(hardware_col_name, wide_hardware_col_name)}}|
|
||||
|---|---|---|{% for _ in range((Column | length) - 3) %}{{':---:|'}}{% endfor +%}
|
||||
{% for car_docs in all_car_docs %}
|
||||
{% for car_docs in all_car_docs | selectattr('support_type', 'eq', SupportType.UPSTREAM) %}
|
||||
|{% for column in Column %}{{car_docs.get_column(column, star_icon, video_icon, footnote_tag)}}|{% endfor %}
|
||||
|
||||
{% endfor %}
|
||||
|
||||
@@ -56,6 +56,9 @@ class VCruiseHelper:
|
||||
if CS.cruiseState.speed == 0:
|
||||
self.v_cruise_kph = V_CRUISE_UNSET
|
||||
self.v_cruise_cluster_kph = V_CRUISE_UNSET
|
||||
elif CS.cruiseState.speed == -1:
|
||||
self.v_cruise_kph = -1
|
||||
self.v_cruise_cluster_kph = -1
|
||||
else:
|
||||
self.v_cruise_kph = V_CRUISE_UNSET
|
||||
self.v_cruise_cluster_kph = V_CRUISE_UNSET
|
||||
|
||||
@@ -270,6 +270,9 @@ class TestCarModelBase(unittest.TestCase):
|
||||
|
||||
def test_panda_safety_tx_cases(self, data=None):
|
||||
"""Asserts we can tx common messages"""
|
||||
if self.CP.dashcamOnly:
|
||||
self.skipTest("no need to check panda safety for dashcamOnly")
|
||||
|
||||
if self.CP.notCar:
|
||||
self.skipTest("Skipping test for notCar")
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ class Controls:
|
||||
poll='selfdriveState')
|
||||
self.pm = messaging.PubMaster(['carControl', 'controlsState'] + ['carControlSP'])
|
||||
|
||||
self.steer_limited = False
|
||||
self.steer_limited_by_controls = False
|
||||
self.desired_curvature = 0.0
|
||||
|
||||
self.pose_calibrator = PoseCalibrator()
|
||||
@@ -121,11 +121,11 @@ class Controls:
|
||||
actuators.accel = float(self.LoC.update(CC.longActive, CS, long_plan.aTarget, long_plan.shouldStop, pid_accel_limits))
|
||||
|
||||
# Steering PID loop and lateral MPC
|
||||
self.desired_curvature = clip_curvature(CS.vEgo, self.desired_curvature, model_v2.action.desiredCurvature)
|
||||
actuators.curvature = float(self.desired_curvature)
|
||||
self.desired_curvature, curvature_limited = clip_curvature(CS.vEgo, self.desired_curvature, model_v2.action.desiredCurvature, lp.roll)
|
||||
actuators.curvature = self.desired_curvature
|
||||
steer, steeringAngleDeg, lac_log = self.LaC.update(CC.latActive, CS, self.VM, lp,
|
||||
self.steer_limited, self.desired_curvature,
|
||||
self.calibrated_pose) # TODO what if not available
|
||||
self.steer_limited_by_controls, self.desired_curvature,
|
||||
self.calibrated_pose, curvature_limited) # TODO what if not available
|
||||
actuators.torque = float(steer)
|
||||
actuators.steeringAngleDeg = float(steeringAngleDeg)
|
||||
# Ensure no NaNs/Infs
|
||||
@@ -176,10 +176,10 @@ class Controls:
|
||||
if self.sm['selfdriveState'].active:
|
||||
CO = self.sm['carOutput']
|
||||
if self.CP.steerControlType == car.CarParams.SteerControlType.angle:
|
||||
self.steer_limited = abs(CC.actuators.steeringAngleDeg - CO.actuatorsOutput.steeringAngleDeg) > \
|
||||
STEER_ANGLE_SATURATION_THRESHOLD
|
||||
self.steer_limited_by_controls = abs(CC.actuators.steeringAngleDeg - CO.actuatorsOutput.steeringAngleDeg) > \
|
||||
STEER_ANGLE_SATURATION_THRESHOLD
|
||||
else:
|
||||
self.steer_limited = abs(CC.actuators.torque - CO.actuatorsOutput.torque) > 1e-2
|
||||
self.steer_limited_by_controls = abs(CC.actuators.torque - CO.actuatorsOutput.torque) > 1e-2
|
||||
|
||||
# TODO: both controlsState and carControl valids should be set by
|
||||
# sm.all_checks(), but this creates a circular dependency
|
||||
@@ -195,7 +195,7 @@ class Controls:
|
||||
|
||||
cs.longitudinalPlanMonoTime = self.sm.logMonoTime['longitudinalPlan']
|
||||
cs.lateralPlanMonoTime = self.sm.logMonoTime['modelV2']
|
||||
cs.desiredCurvature = float(self.desired_curvature)
|
||||
cs.desiredCurvature = self.desired_curvature
|
||||
cs.longControlState = self.LoC.long_control_state
|
||||
cs.upAccelCmd = float(self.LoC.pid.p)
|
||||
cs.uiAccelCmd = float(self.LoC.pid.i)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import numpy as np
|
||||
from cereal import log
|
||||
from opendbc.car.vehicle_model import ACCELERATION_DUE_TO_GRAVITY
|
||||
from openpilot.common.realtime import DT_CTRL
|
||||
|
||||
MIN_SPEED = 1.0
|
||||
@@ -7,20 +8,33 @@ CONTROL_N = 17
|
||||
CAR_ROTATION_RADIUS = 0.0
|
||||
# This is a turn radius smaller than most cars can achieve
|
||||
MAX_CURVATURE = 0.2
|
||||
MAX_VEL_ERR = 5.0 # m/s
|
||||
|
||||
# EU guidelines
|
||||
MAX_LATERAL_JERK = 5.0
|
||||
MAX_VEL_ERR = 5.0
|
||||
MAX_LATERAL_JERK = 5.0 # m/s^3
|
||||
MAX_LATERAL_ACCEL_NO_ROLL = 3.0 # m/s^2
|
||||
|
||||
def clip_curvature(v_ego, prev_curvature, new_curvature):
|
||||
new_curvature = np.clip(new_curvature, -MAX_CURVATURE, MAX_CURVATURE)
|
||||
v_ego = max(MIN_SPEED, v_ego)
|
||||
max_curvature_rate = MAX_LATERAL_JERK / (v_ego**2) # inexact calculation, check https://github.com/commaai/openpilot/pull/24755
|
||||
safe_desired_curvature = np.clip(new_curvature,
|
||||
prev_curvature - max_curvature_rate * DT_CTRL,
|
||||
prev_curvature + max_curvature_rate * DT_CTRL)
|
||||
|
||||
return safe_desired_curvature
|
||||
def clamp(val, min_val, max_val):
|
||||
clamped_val = float(np.clip(val, min_val, max_val))
|
||||
return clamped_val, clamped_val != val
|
||||
|
||||
|
||||
def clip_curvature(v_ego, prev_curvature, new_curvature, roll):
|
||||
# This function respects ISO lateral jerk and acceleration limits + a max curvature
|
||||
v_ego = max(v_ego, MIN_SPEED)
|
||||
max_curvature_rate = MAX_LATERAL_JERK / (v_ego ** 2) # inexact calculation, check https://github.com/commaai/openpilot/pull/24755
|
||||
new_curvature = np.clip(new_curvature,
|
||||
prev_curvature - max_curvature_rate * DT_CTRL,
|
||||
prev_curvature + max_curvature_rate * DT_CTRL)
|
||||
|
||||
roll_compensation = roll * ACCELERATION_DUE_TO_GRAVITY
|
||||
max_lat_accel = MAX_LATERAL_ACCEL_NO_ROLL + roll_compensation
|
||||
min_lat_accel = -MAX_LATERAL_ACCEL_NO_ROLL + roll_compensation
|
||||
new_curvature, limited_accel = clamp(new_curvature, min_lat_accel / v_ego ** 2, max_lat_accel / v_ego ** 2)
|
||||
|
||||
new_curvature, limited_max_curv = clamp(new_curvature, -MAX_CURVATURE, MAX_CURVATURE)
|
||||
return float(new_curvature), limited_accel or limited_max_curv
|
||||
|
||||
|
||||
def get_speed_error(modelV2: log.ModelDataV2, v_ego: float) -> float:
|
||||
|
||||
@@ -17,14 +17,15 @@ class LatControl(ABC):
|
||||
self.steer_max = 1.0
|
||||
|
||||
@abstractmethod
|
||||
def update(self, active, CS, VM, params, steer_limited, desired_curvature, calibrated_pose):
|
||||
def update(self, active, CS, VM, params, steer_limited_by_controls, desired_curvature, calibrated_pose, curvature_limited):
|
||||
pass
|
||||
|
||||
def reset(self):
|
||||
self.sat_count = 0.
|
||||
|
||||
def _check_saturation(self, saturated, CS, steer_limited):
|
||||
if saturated and CS.vEgo > self.sat_check_min_speed and not steer_limited and not CS.steeringPressed:
|
||||
def _check_saturation(self, saturated, CS, steer_limited_by_controls, curvature_limited):
|
||||
# Saturated only if control output is not being limited by car torque/angle rate limits
|
||||
if (saturated or curvature_limited) and CS.vEgo > self.sat_check_min_speed and not steer_limited_by_controls and not CS.steeringPressed:
|
||||
self.sat_count += self.sat_count_rate
|
||||
else:
|
||||
self.sat_count -= self.sat_count_rate
|
||||
|
||||
@@ -11,7 +11,7 @@ class LatControlAngle(LatControl):
|
||||
super().__init__(CP, CI)
|
||||
self.sat_check_min_speed = 5.
|
||||
|
||||
def update(self, active, CS, VM, params, steer_limited, desired_curvature, calibrated_pose):
|
||||
def update(self, active, CS, VM, params, steer_limited_by_controls, desired_curvature, calibrated_pose, curvature_limited):
|
||||
angle_log = log.ControlsState.LateralAngleState.new_message()
|
||||
|
||||
if not active:
|
||||
@@ -23,7 +23,7 @@ class LatControlAngle(LatControl):
|
||||
angle_steers_des += params.angleOffsetDeg
|
||||
|
||||
angle_control_saturated = abs(angle_steers_des - CS.steeringAngleDeg) > STEER_ANGLE_SATURATION_THRESHOLD
|
||||
angle_log.saturated = bool(self._check_saturation(angle_control_saturated, CS, False))
|
||||
angle_log.saturated = bool(self._check_saturation(angle_control_saturated, CS, False, curvature_limited))
|
||||
angle_log.steeringAngleDeg = float(CS.steeringAngleDeg)
|
||||
angle_log.steeringAngleDesiredDeg = angle_steers_des
|
||||
return 0, float(angle_steers_des), angle_log
|
||||
|
||||
@@ -17,7 +17,7 @@ class LatControlPID(LatControl):
|
||||
super().reset()
|
||||
self.pid.reset()
|
||||
|
||||
def update(self, active, CS, VM, params, steer_limited, desired_curvature, calibrated_pose):
|
||||
def update(self, active, CS, VM, params, steer_limited_by_controls, desired_curvature, calibrated_pose, curvature_limited):
|
||||
pid_log = log.ControlsState.LateralPIDState.new_message()
|
||||
pid_log.steeringAngleDeg = float(CS.steeringAngleDeg)
|
||||
pid_log.steeringRateDeg = float(CS.steeringRateDeg)
|
||||
@@ -43,6 +43,6 @@ class LatControlPID(LatControl):
|
||||
pid_log.i = float(self.pid.i)
|
||||
pid_log.f = float(self.pid.f)
|
||||
pid_log.output = float(output_steer)
|
||||
pid_log.saturated = bool(self._check_saturation(self.steer_max - abs(output_steer) < 1e-3, CS, steer_limited))
|
||||
pid_log.saturated = bool(self._check_saturation(self.steer_max - abs(output_steer) < 1e-3, CS, steer_limited_by_controls, curvature_limited))
|
||||
|
||||
return output_steer, angle_steers_des, pid_log
|
||||
|
||||
@@ -37,7 +37,7 @@ class LatControlTorque(LatControl):
|
||||
self.torque_params.latAccelOffset = latAccelOffset
|
||||
self.torque_params.friction = friction
|
||||
|
||||
def update(self, active, CS, VM, params, steer_limited, desired_curvature, calibrated_pose):
|
||||
def update(self, active, CS, VM, params, steer_limited_by_controls, desired_curvature, calibrated_pose, curvature_limited):
|
||||
pid_log = log.ControlsState.LateralTorqueState.new_message()
|
||||
if not active:
|
||||
output_torque = 0.0
|
||||
@@ -73,7 +73,7 @@ class LatControlTorque(LatControl):
|
||||
desired_lateral_accel - actual_lateral_accel, lateral_accel_deadzone, friction_compensation=True,
|
||||
gravity_adjusted=True)
|
||||
|
||||
freeze_integrator = steer_limited or CS.steeringPressed or CS.vEgo < 5
|
||||
freeze_integrator = steer_limited_by_controls or CS.steeringPressed or CS.vEgo < 5
|
||||
output_torque = self.pid.update(pid_log.error,
|
||||
feedforward=ff,
|
||||
speed=CS.vEgo,
|
||||
@@ -87,7 +87,7 @@ class LatControlTorque(LatControl):
|
||||
pid_log.output = float(-output_torque)
|
||||
pid_log.actualLateralAccel = float(actual_lateral_accel)
|
||||
pid_log.desiredLateralAccel = float(desired_lateral_accel)
|
||||
pid_log.saturated = bool(self._check_saturation(self.steer_max - abs(output_torque) < 1e-3, CS, steer_limited))
|
||||
pid_log.saturated = bool(self._check_saturation(self.steer_max - abs(output_torque) < 1e-3, CS, steer_limited_by_controls, curvature_limited))
|
||||
|
||||
# TODO left is positive in this convention
|
||||
return -output_torque, 0.0, pid_log
|
||||
|
||||
@@ -34,7 +34,15 @@ class TestLatControl:
|
||||
lp = generate_livePose()
|
||||
pose = Pose.from_live_pose(lp.livePose)
|
||||
|
||||
# Saturate for curvature limited and controller limited
|
||||
for _ in range(1000):
|
||||
_, _, lac_log = controller.update(True, CS, VM, params, False, 1, pose)
|
||||
_, _, lac_log = controller.update(True, CS, VM, params, False, 0, pose, True)
|
||||
assert lac_log.saturated
|
||||
|
||||
for _ in range(1000):
|
||||
_, _, lac_log = controller.update(True, CS, VM, params, False, 0, pose, False)
|
||||
assert not lac_log.saturated
|
||||
|
||||
for _ in range(1000):
|
||||
_, _, lac_log = controller.update(True, CS, VM, params, False, 1, pose, False)
|
||||
assert lac_log.saturated
|
||||
|
||||
@@ -65,8 +65,7 @@ if __name__ == "__main__":
|
||||
CP = msg.carParams
|
||||
car_fw = [fw for fw in CP.carFw if not fw.logging]
|
||||
if len(car_fw) == 0:
|
||||
print("no fw")
|
||||
break
|
||||
print("WARNING: no fw")
|
||||
|
||||
live_fingerprint = CP.carFingerprint
|
||||
live_fingerprint = MIGRATION.get(live_fingerprint, live_fingerprint)
|
||||
@@ -98,7 +97,7 @@ if __name__ == "__main__":
|
||||
print("New style (exact):", exact_matches)
|
||||
print("New style (fuzzy):", fuzzy_matches)
|
||||
|
||||
padding = max([len(fw.brand or UNKNOWN_BRAND) for fw in car_fw])
|
||||
padding = max([len(fw.brand or UNKNOWN_BRAND) for fw in car_fw] + [0])
|
||||
for version in sorted(car_fw, key=lambda fw: fw.brand):
|
||||
subaddr = None if version.subAddress == 0 else hex(version.subAddress)
|
||||
print(f" Brand: {version.brand or UNKNOWN_BRAND:{padding}}, bus: {version.bus} - " +
|
||||
|
||||
@@ -147,13 +147,13 @@ class LocationEstimator:
|
||||
self.car_speed = abs(msg.vEgo)
|
||||
|
||||
elif which == "liveCalibration":
|
||||
# Note that we use this message during calibration
|
||||
if len(msg.rpyCalib) > 0:
|
||||
calib = np.array(msg.rpyCalib)
|
||||
if calib.min() < -CALIB_RPY_SANITY_CHECK or calib.max() > CALIB_RPY_SANITY_CHECK:
|
||||
return HandleLogResult.INPUT_INVALID
|
||||
|
||||
self.device_from_calib = rot_from_euler(calib)
|
||||
self.calibrated = msg.calStatus == log.LiveCalibrationData.Status.calibrated
|
||||
|
||||
elif which == "cameraOdometry":
|
||||
if not self._validate_timestamp(t):
|
||||
|
||||
@@ -46,18 +46,25 @@ class ParamsLearner:
|
||||
self.yaw_rate_std = 0.0
|
||||
self.roll = 0.0
|
||||
self.steering_angle = 0.0
|
||||
self.roll_valid = False
|
||||
|
||||
def handle_log(self, t, which, msg):
|
||||
if which == 'livePose':
|
||||
device_pose = Pose.from_live_pose(msg)
|
||||
calibrated_pose = self.calibrator.build_calibrated_pose(device_pose)
|
||||
self.yaw_rate, self.yaw_rate_std = calibrated_pose.angular_velocity.z, calibrated_pose.angular_velocity.z_std
|
||||
|
||||
yaw_rate_valid = msg.angularVelocityDevice.valid and self.calibrator.calib_valid
|
||||
yaw_rate_valid = yaw_rate_valid and 0 < self.yaw_rate_std < 10 # rad/s
|
||||
yaw_rate_valid = yaw_rate_valid and abs(self.yaw_rate) < 1 # rad/s
|
||||
if yaw_rate_valid:
|
||||
self.yaw_rate, self.yaw_rate_std = calibrated_pose.angular_velocity.z, calibrated_pose.angular_velocity.z_std
|
||||
else:
|
||||
# This is done to bound the yaw rate estimate when localizer values are invalid or calibrating
|
||||
self.yaw_rate, self.yaw_rate_std = 0.0, np.radians(1)
|
||||
|
||||
localizer_roll, localizer_roll_std = device_pose.orientation.x, device_pose.orientation.x_std
|
||||
localizer_roll_std = np.radians(1) if np.isnan(localizer_roll_std) else localizer_roll_std
|
||||
self.roll_valid = (localizer_roll_std < ROLL_STD_MAX) and (ROLL_MIN < localizer_roll < ROLL_MAX) and msg.sensorsOK
|
||||
if self.roll_valid:
|
||||
roll_valid = (localizer_roll_std < ROLL_STD_MAX) and (ROLL_MIN < localizer_roll < ROLL_MAX) and msg.sensorsOK
|
||||
if roll_valid:
|
||||
roll = localizer_roll
|
||||
# Experimentally found multiplier of 2 to be best trade-off between stability and accuracy or similar?
|
||||
roll_std = 2 * localizer_roll_std
|
||||
@@ -67,18 +74,12 @@ class ParamsLearner:
|
||||
roll_std = np.radians(10.0)
|
||||
self.roll = np.clip(roll, self.roll - ROLL_MAX_DELTA, self.roll + ROLL_MAX_DELTA)
|
||||
|
||||
yaw_rate_valid = msg.angularVelocityDevice.valid and self.calibrator.calib_valid
|
||||
yaw_rate_valid = yaw_rate_valid and 0 < self.yaw_rate_std < 10 # rad/s
|
||||
yaw_rate_valid = yaw_rate_valid and abs(self.yaw_rate) < 1 # rad/s
|
||||
|
||||
if self.active:
|
||||
if msg.posenetOK:
|
||||
|
||||
if yaw_rate_valid:
|
||||
self.kf.predict_and_observe(t,
|
||||
ObservationKind.ROAD_FRAME_YAW_RATE,
|
||||
np.array([[-self.yaw_rate]]),
|
||||
np.array([np.atleast_2d(self.yaw_rate_std**2)]))
|
||||
self.kf.predict_and_observe(t,
|
||||
ObservationKind.ROAD_FRAME_YAW_RATE,
|
||||
np.array([[-self.yaw_rate]]),
|
||||
np.array([np.atleast_2d(self.yaw_rate_std**2)]))
|
||||
|
||||
self.kf.predict_and_observe(t,
|
||||
ObservationKind.ROAD_ROLL,
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
*_pyx.cpp
|
||||
@@ -14,8 +14,14 @@ class ModelConstants:
|
||||
|
||||
# model inputs constants
|
||||
MODEL_FREQ = 20
|
||||
HISTORY_FREQ = 5
|
||||
HISTORY_LEN_SECONDS = 5
|
||||
TEMPORAL_SKIP = MODEL_FREQ // HISTORY_FREQ
|
||||
FULL_HISTORY_BUFFER_LEN = MODEL_FREQ * HISTORY_LEN_SECONDS
|
||||
INPUT_HISTORY_BUFFER_LEN = HISTORY_FREQ * HISTORY_LEN_SECONDS
|
||||
|
||||
FEATURE_LEN = 512
|
||||
FULL_HISTORY_BUFFER_LEN = 100
|
||||
|
||||
DESIRE_LEN = 8
|
||||
TRAFFIC_CONVENTION_LEN = 2
|
||||
LAT_PLANNER_STATE_LEN = 4
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null && pwd)"
|
||||
exec "$DIR/dmonitoringmodeld.py" "$@"
|
||||
@@ -1,4 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null && pwd)"
|
||||
exec "$DIR/modeld.py" "$@"
|
||||
+21
-10
@@ -56,16 +56,24 @@ class ModelState:
|
||||
prev_desire: np.ndarray # for tracking the rising edge of the pulse
|
||||
|
||||
def __init__(self, context: CLContext):
|
||||
self.frames = {'input_imgs': DrivingModelFrame(context), 'big_input_imgs': DrivingModelFrame(context)}
|
||||
self.frames = {
|
||||
'input_imgs': DrivingModelFrame(context, ModelConstants.TEMPORAL_SKIP),
|
||||
'big_input_imgs': DrivingModelFrame(context, ModelConstants.TEMPORAL_SKIP)
|
||||
}
|
||||
self.prev_desire = np.zeros(ModelConstants.DESIRE_LEN, dtype=np.float32)
|
||||
|
||||
self.full_features_buffer = np.zeros((1, ModelConstants.FULL_HISTORY_BUFFER_LEN, ModelConstants.FEATURE_LEN), dtype=np.float32)
|
||||
self.full_desire = np.zeros((1, ModelConstants.FULL_HISTORY_BUFFER_LEN, ModelConstants.DESIRE_LEN), dtype=np.float32)
|
||||
self.full_prev_desired_curv = np.zeros((1, ModelConstants.FULL_HISTORY_BUFFER_LEN, ModelConstants.PREV_DESIRED_CURV_LEN), dtype=np.float32)
|
||||
self.temporal_idxs = slice(-1-(ModelConstants.TEMPORAL_SKIP*(ModelConstants.INPUT_HISTORY_BUFFER_LEN-1)), None, ModelConstants.TEMPORAL_SKIP)
|
||||
|
||||
# policy inputs
|
||||
self.numpy_inputs = {
|
||||
'desire': np.zeros((1, ModelConstants.FULL_HISTORY_BUFFER_LEN, ModelConstants.DESIRE_LEN), dtype=np.float32),
|
||||
'desire': np.zeros((1, ModelConstants.INPUT_HISTORY_BUFFER_LEN, ModelConstants.DESIRE_LEN), dtype=np.float32),
|
||||
'traffic_convention': np.zeros((1, ModelConstants.TRAFFIC_CONVENTION_LEN), dtype=np.float32),
|
||||
'lateral_control_params': np.zeros((1, ModelConstants.LATERAL_CONTROL_PARAMS_LEN), dtype=np.float32),
|
||||
'prev_desired_curv': np.zeros((1, ModelConstants.FULL_HISTORY_BUFFER_LEN, ModelConstants.PREV_DESIRED_CURV_LEN), dtype=np.float32),
|
||||
'features_buffer': np.zeros((1, ModelConstants.FULL_HISTORY_BUFFER_LEN, ModelConstants.FEATURE_LEN), dtype=np.float32),
|
||||
'prev_desired_curv': np.zeros((1, ModelConstants.INPUT_HISTORY_BUFFER_LEN, ModelConstants.PREV_DESIRED_CURV_LEN), dtype=np.float32),
|
||||
'features_buffer': np.zeros((1, ModelConstants.INPUT_HISTORY_BUFFER_LEN, ModelConstants.FEATURE_LEN), dtype=np.float32),
|
||||
}
|
||||
|
||||
with open(VISION_METADATA_PATH, 'rb') as f:
|
||||
@@ -104,8 +112,9 @@ class ModelState:
|
||||
new_desire = np.where(inputs['desire'] - self.prev_desire > .99, inputs['desire'], 0)
|
||||
self.prev_desire[:] = inputs['desire']
|
||||
|
||||
self.numpy_inputs['desire'][0,:-1] = self.numpy_inputs['desire'][0,1:]
|
||||
self.numpy_inputs['desire'][0,-1] = new_desire
|
||||
self.full_desire[0,:-1] = self.full_desire[0,1:]
|
||||
self.full_desire[0,-1] = new_desire
|
||||
self.numpy_inputs['desire'][:] = self.full_desire.reshape((1,ModelConstants.INPUT_HISTORY_BUFFER_LEN,ModelConstants.TEMPORAL_SKIP,-1)).max(axis=2)
|
||||
|
||||
self.numpy_inputs['traffic_convention'][:] = inputs['traffic_convention']
|
||||
self.numpy_inputs['lateral_control_params'][:] = inputs['lateral_control_params']
|
||||
@@ -128,15 +137,17 @@ class ModelState:
|
||||
self.vision_output = self.vision_run(**self.vision_inputs).numpy().flatten()
|
||||
vision_outputs_dict = self.parser.parse_vision_outputs(self.slice_outputs(self.vision_output, self.vision_output_slices))
|
||||
|
||||
self.numpy_inputs['features_buffer'][0,:-1] = self.numpy_inputs['features_buffer'][0,1:]
|
||||
self.numpy_inputs['features_buffer'][0,-1] = vision_outputs_dict['hidden_state'][0, :]
|
||||
self.full_features_buffer[0,:-1] = self.full_features_buffer[0,1:]
|
||||
self.full_features_buffer[0,-1] = vision_outputs_dict['hidden_state'][0, :]
|
||||
self.numpy_inputs['features_buffer'][:] = self.full_features_buffer[0, self.temporal_idxs]
|
||||
|
||||
self.policy_output = self.policy_run(**self.policy_inputs).numpy().flatten()
|
||||
policy_outputs_dict = self.parser.parse_policy_outputs(self.slice_outputs(self.policy_output, self.policy_output_slices))
|
||||
|
||||
# TODO model only uses last value now
|
||||
self.numpy_inputs['prev_desired_curv'][0,:-1] = self.numpy_inputs['prev_desired_curv'][0,1:]
|
||||
self.numpy_inputs['prev_desired_curv'][0,-1,:] = policy_outputs_dict['desired_curvature'][0, :]
|
||||
self.full_prev_desired_curv[0,:-1] = self.full_prev_desired_curv[0,1:]
|
||||
self.full_prev_desired_curv[0,-1,:] = policy_outputs_dict['desired_curvature'][0, :]
|
||||
self.numpy_inputs['prev_desired_curv'][:] = self.full_prev_desired_curv[0, self.temporal_idxs]
|
||||
|
||||
combined_outputs_dict = {**vision_outputs_dict, **policy_outputs_dict}
|
||||
if SEND_RAW_PRED:
|
||||
|
||||
@@ -5,11 +5,12 @@
|
||||
|
||||
#include "common/clutil.h"
|
||||
|
||||
DrivingModelFrame::DrivingModelFrame(cl_device_id device_id, cl_context context) : ModelFrame(device_id, context) {
|
||||
DrivingModelFrame::DrivingModelFrame(cl_device_id device_id, cl_context context, int _temporal_skip) : ModelFrame(device_id, context) {
|
||||
input_frames = std::make_unique<uint8_t[]>(buf_size);
|
||||
temporal_skip = _temporal_skip;
|
||||
input_frames_cl = CL_CHECK_ERR(clCreateBuffer(context, CL_MEM_READ_WRITE, buf_size, NULL, &err));
|
||||
img_buffer_20hz_cl = CL_CHECK_ERR(clCreateBuffer(context, CL_MEM_READ_WRITE, 2*frame_size_bytes, NULL, &err));
|
||||
region.origin = 1 * frame_size_bytes;
|
||||
img_buffer_20hz_cl = CL_CHECK_ERR(clCreateBuffer(context, CL_MEM_READ_WRITE, (temporal_skip+1)*frame_size_bytes, NULL, &err));
|
||||
region.origin = temporal_skip * frame_size_bytes;
|
||||
region.size = frame_size_bytes;
|
||||
last_img_cl = CL_CHECK_ERR(clCreateSubBuffer(img_buffer_20hz_cl, CL_MEM_READ_WRITE, CL_BUFFER_CREATE_TYPE_REGION, ®ion, &err));
|
||||
|
||||
@@ -20,7 +21,7 @@ DrivingModelFrame::DrivingModelFrame(cl_device_id device_id, cl_context context)
|
||||
cl_mem* DrivingModelFrame::prepare(cl_mem yuv_cl, int frame_width, int frame_height, int frame_stride, int frame_uv_offset, const mat3& projection) {
|
||||
run_transform(yuv_cl, MODEL_WIDTH, MODEL_HEIGHT, frame_width, frame_height, frame_stride, frame_uv_offset, projection);
|
||||
|
||||
for (int i = 0; i < 1; i++) {
|
||||
for (int i = 0; i < temporal_skip; i++) {
|
||||
CL_CHECK(clEnqueueCopyBuffer(q, img_buffer_20hz_cl, img_buffer_20hz_cl, (i+1)*frame_size_bytes, i*frame_size_bytes, frame_size_bytes, 0, nullptr, nullptr));
|
||||
}
|
||||
loadyuv_queue(&loadyuv, q, y_cl, u_cl, v_cl, last_img_cl);
|
||||
|
||||
@@ -64,20 +64,21 @@ protected:
|
||||
|
||||
class DrivingModelFrame : public ModelFrame {
|
||||
public:
|
||||
DrivingModelFrame(cl_device_id device_id, cl_context context);
|
||||
DrivingModelFrame(cl_device_id device_id, cl_context context, int _temporal_skip);
|
||||
~DrivingModelFrame();
|
||||
cl_mem* prepare(cl_mem yuv_cl, int frame_width, int frame_height, int frame_stride, int frame_uv_offset, const mat3& projection);
|
||||
|
||||
const int MODEL_WIDTH = 512;
|
||||
const int MODEL_HEIGHT = 256;
|
||||
const int MODEL_FRAME_SIZE = MODEL_WIDTH * MODEL_HEIGHT * 3 / 2;
|
||||
const int buf_size = MODEL_FRAME_SIZE * 2;
|
||||
const int buf_size = MODEL_FRAME_SIZE * 2; // 2 frames are temporal_skip frames apart
|
||||
const size_t frame_size_bytes = MODEL_FRAME_SIZE * sizeof(uint8_t);
|
||||
|
||||
private:
|
||||
LoadYUVState loadyuv;
|
||||
cl_mem img_buffer_20hz_cl, last_img_cl, input_frames_cl;
|
||||
cl_buffer_region region;
|
||||
int temporal_skip;
|
||||
};
|
||||
|
||||
class MonitoringModelFrame : public ModelFrame {
|
||||
|
||||
@@ -20,7 +20,7 @@ cdef extern from "selfdrive/modeld/models/commonmodel.h":
|
||||
|
||||
cppclass DrivingModelFrame:
|
||||
int buf_size
|
||||
DrivingModelFrame(cl_device_id, cl_context)
|
||||
DrivingModelFrame(cl_device_id, cl_context, int)
|
||||
|
||||
cppclass MonitoringModelFrame:
|
||||
int buf_size
|
||||
|
||||
@@ -59,8 +59,8 @@ cdef class ModelFrame:
|
||||
cdef class DrivingModelFrame(ModelFrame):
|
||||
cdef cppDrivingModelFrame * _frame
|
||||
|
||||
def __cinit__(self, CLContext context):
|
||||
self._frame = new cppDrivingModelFrame(context.device_id, context.context)
|
||||
def __cinit__(self, CLContext context, int temporal_skip):
|
||||
self._frame = new cppDrivingModelFrame(context.device_id, context.context, temporal_skip)
|
||||
self.frame = <cppModelFrame*>(self._frame)
|
||||
self.buf_size = self._frame.buf_size
|
||||
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:5cae3285c876804e649b14adadcfb8be79a9bd5a1b928113e37f1f08e25e9688
|
||||
size 16581121
|
||||
oid sha256:98f0121ccb6f850077b04cc91bd33d370fc6cbdc2bd35f1ab55628a15a813f36
|
||||
size 15966721
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:29bbf79f9dfd7048c0013bb81e86d9b2979275b95ea1ed8a86d1a86a88695240
|
||||
oid sha256:897f80d0388250f99bba69b6a8434560cc0fd83157cbeb0bc134c67fe4e64624
|
||||
size 34882971
|
||||
|
||||
@@ -1,101 +0,0 @@
|
||||
// clang++ -O2 repro.cc && ./a.out
|
||||
|
||||
#include <sched.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
|
||||
static inline double millis_since_boot() {
|
||||
struct timespec t;
|
||||
clock_gettime(CLOCK_BOOTTIME, &t);
|
||||
return t.tv_sec * 1000.0 + t.tv_nsec * 1e-6;
|
||||
}
|
||||
|
||||
#define MODEL_WIDTH 320
|
||||
#define MODEL_HEIGHT 640
|
||||
|
||||
// null function still breaks it
|
||||
#define input_lambda(x) x
|
||||
|
||||
// this is copied from models/dmonitoring.cc, and is the code that triggers the issue
|
||||
void inner(uint8_t *resized_buf, float *net_input_buf) {
|
||||
int resized_width = MODEL_WIDTH;
|
||||
int resized_height = MODEL_HEIGHT;
|
||||
|
||||
// one shot conversion, O(n) anyway
|
||||
// yuvframe2tensor, normalize
|
||||
for (int r = 0; r < MODEL_HEIGHT/2; r++) {
|
||||
for (int c = 0; c < MODEL_WIDTH/2; c++) {
|
||||
// Y_ul
|
||||
net_input_buf[(c*MODEL_HEIGHT/2) + r] = input_lambda(resized_buf[(2*r*resized_width) + (2*c)]);
|
||||
// Y_ur
|
||||
net_input_buf[(c*MODEL_HEIGHT/2) + r + (2*(MODEL_WIDTH/2)*(MODEL_HEIGHT/2))] = input_lambda(resized_buf[(2*r*resized_width) + (2*c+1)]);
|
||||
// Y_dl
|
||||
net_input_buf[(c*MODEL_HEIGHT/2) + r + ((MODEL_WIDTH/2)*(MODEL_HEIGHT/2))] = input_lambda(resized_buf[(2*r*resized_width+1) + (2*c)]);
|
||||
// Y_dr
|
||||
net_input_buf[(c*MODEL_HEIGHT/2) + r + (3*(MODEL_WIDTH/2)*(MODEL_HEIGHT/2))] = input_lambda(resized_buf[(2*r*resized_width+1) + (2*c+1)]);
|
||||
// U
|
||||
net_input_buf[(c*MODEL_HEIGHT/2) + r + (4*(MODEL_WIDTH/2)*(MODEL_HEIGHT/2))] = input_lambda(resized_buf[(resized_width*resized_height) + (r*resized_width/2) + c]);
|
||||
// V
|
||||
net_input_buf[(c*MODEL_HEIGHT/2) + r + (5*(MODEL_WIDTH/2)*(MODEL_HEIGHT/2))] = input_lambda(resized_buf[(resized_width*resized_height) + ((resized_width/2)*(resized_height/2)) + (r*resized_width/2) + c]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float trial() {
|
||||
int resized_width = MODEL_WIDTH;
|
||||
int resized_height = MODEL_HEIGHT;
|
||||
|
||||
int yuv_buf_len = (MODEL_WIDTH/2) * (MODEL_HEIGHT/2) * 6; // Y|u|v -> y|y|y|y|u|v
|
||||
|
||||
// allocate the buffers
|
||||
uint8_t *resized_buf = (uint8_t*)malloc(resized_width*resized_height*3/2);
|
||||
float *net_input_buf = (float*)malloc(yuv_buf_len*sizeof(float));
|
||||
printf("allocate -- %p 0x%x -- %p 0x%lx\n", resized_buf, resized_width*resized_height*3/2, net_input_buf, yuv_buf_len*sizeof(float));
|
||||
|
||||
// test for bad buffers
|
||||
static int CNT = 20;
|
||||
float avg = 0.0;
|
||||
for (int i = 0; i < CNT; i++) {
|
||||
double s4 = millis_since_boot();
|
||||
inner(resized_buf, net_input_buf);
|
||||
double s5 = millis_since_boot();
|
||||
avg += s5-s4;
|
||||
}
|
||||
avg /= CNT;
|
||||
|
||||
// once it's bad, it's reliably bad
|
||||
if (avg > 10) {
|
||||
printf("HIT %f\n", avg);
|
||||
printf("BAD\n");
|
||||
|
||||
for (int i = 0; i < 200; i++) {
|
||||
double s4 = millis_since_boot();
|
||||
inner(resized_buf, net_input_buf);
|
||||
double s5 = millis_since_boot();
|
||||
printf("%.2f ", s5-s4);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// don't free so we get a different buffer each time
|
||||
//free(resized_buf);
|
||||
//free(net_input_buf);
|
||||
|
||||
return avg;
|
||||
}
|
||||
|
||||
int main() {
|
||||
while (true) {
|
||||
float ret = trial();
|
||||
printf("got %f\n", ret);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
clang++ -I /home/batman/one/external/tensorflow/include/ -L /home/batman/one/external/tensorflow/lib -Wl,-rpath=/home/batman/one/external/tensorflow/lib main.cc -ltensorflow
|
||||
@@ -1,69 +0,0 @@
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include "tensorflow/c/c_api.h"
|
||||
|
||||
void* read_file(const char* path, size_t* out_len) {
|
||||
FILE* f = fopen(path, "r");
|
||||
if (!f) {
|
||||
return NULL;
|
||||
}
|
||||
fseek(f, 0, SEEK_END);
|
||||
long f_len = ftell(f);
|
||||
rewind(f);
|
||||
|
||||
char* buf = (char*)calloc(f_len, 1);
|
||||
assert(buf);
|
||||
|
||||
size_t num_read = fread(buf, f_len, 1, f);
|
||||
fclose(f);
|
||||
|
||||
if (num_read != 1) {
|
||||
free(buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (out_len) {
|
||||
*out_len = f_len;
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static void DeallocateBuffer(void* data, size_t) {
|
||||
free(data);
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
TF_Buffer* buf;
|
||||
TF_Graph* graph;
|
||||
TF_Status* status;
|
||||
char *path = argv[1];
|
||||
|
||||
// load model
|
||||
{
|
||||
size_t model_size;
|
||||
char tmp[1024];
|
||||
snprintf(tmp, sizeof(tmp), "%s.pb", path);
|
||||
printf("loading model %s\n", tmp);
|
||||
uint8_t *model_data = (uint8_t *)read_file(tmp, &model_size);
|
||||
buf = TF_NewBuffer();
|
||||
buf->data = model_data;
|
||||
buf->length = model_size;
|
||||
buf->data_deallocator = DeallocateBuffer;
|
||||
printf("loaded model of size %d\n", model_size);
|
||||
}
|
||||
|
||||
// import graph
|
||||
status = TF_NewStatus();
|
||||
graph = TF_NewGraph();
|
||||
TF_ImportGraphDefOptions *opts = TF_NewImportGraphDefOptions();
|
||||
TF_GraphImportGraphDef(graph, buf, opts, status);
|
||||
TF_DeleteImportGraphDefOptions(opts);
|
||||
TF_DeleteBuffer(buf);
|
||||
if (TF_GetCode(status) != TF_OK) {
|
||||
printf("FAIL: %s\n", TF_Message(status));
|
||||
} else {
|
||||
printf("SUCCESS\n");
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
import sys
|
||||
import tensorflow as tf
|
||||
|
||||
with open(sys.argv[1], "rb") as f:
|
||||
graph_def = tf.compat.v1.GraphDef()
|
||||
graph_def.ParseFromString(f.read())
|
||||
#tf.io.write_graph(graph_def, '', sys.argv[1]+".try")
|
||||
@@ -1,39 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
# type: ignore
|
||||
|
||||
import os
|
||||
import time
|
||||
import numpy as np
|
||||
|
||||
import cereal.messaging as messaging
|
||||
from openpilot.system.manager.process_config import managed_processes
|
||||
|
||||
|
||||
N = int(os.getenv("N", "5"))
|
||||
TIME = int(os.getenv("TIME", "30"))
|
||||
|
||||
if __name__ == "__main__":
|
||||
sock = messaging.sub_sock('modelV2', conflate=False, timeout=1000)
|
||||
|
||||
execution_times = []
|
||||
|
||||
for _ in range(N):
|
||||
os.environ['LOGPRINT'] = 'debug'
|
||||
managed_processes['modeld'].start()
|
||||
time.sleep(5)
|
||||
|
||||
t = []
|
||||
start = time.monotonic()
|
||||
while time.monotonic() - start < TIME:
|
||||
msgs = messaging.drain_sock(sock, wait_for_one=True)
|
||||
for m in msgs:
|
||||
t.append(m.modelV2.modelExecutionTime)
|
||||
|
||||
execution_times.append(np.array(t[10:]) * 1000)
|
||||
managed_processes['modeld'].stop()
|
||||
|
||||
print("\n\n")
|
||||
print(f"ran modeld {N} times for {TIME}s each")
|
||||
for _, t in enumerate(execution_times):
|
||||
print(f"\tavg: {sum(t)/len(t):0.2f}ms, min: {min(t):0.2f}ms, max: {max(t):0.2f}ms")
|
||||
print("\n\n")
|
||||
@@ -17,14 +17,17 @@ cdef extern from "opendbc/can/common.h":
|
||||
vector[CanFrame] frames
|
||||
|
||||
cdef extern from "can_list_to_can_capnp.cc":
|
||||
void can_list_to_can_capnp_cpp(const vector[CanFrame] &can_list, string &out, bool sendcan, bool valid)
|
||||
void can_list_to_can_capnp_cpp(const vector[CanFrame] &can_list, string &out, bool sendcan, bool valid) nogil
|
||||
void can_capnp_to_can_list_cpp(const vector[string] &strings, vector[CanData] &can_data, bool sendcan)
|
||||
|
||||
def can_list_to_can_capnp(can_msgs, msgtype='can', valid=True):
|
||||
cdef CanFrame *f
|
||||
cdef vector[CanFrame] can_list
|
||||
cdef uint32_t cpp_can_msgs_len = len(can_msgs)
|
||||
|
||||
with nogil:
|
||||
can_list.reserve(cpp_can_msgs_len)
|
||||
|
||||
can_list.reserve(len(can_msgs))
|
||||
for can_msg in can_msgs:
|
||||
f = &(can_list.emplace_back())
|
||||
f.address = can_msg[0]
|
||||
@@ -32,7 +35,10 @@ def can_list_to_can_capnp(can_msgs, msgtype='can', valid=True):
|
||||
f.src = can_msg[2]
|
||||
|
||||
cdef string out
|
||||
can_list_to_can_capnp_cpp(can_list, out, msgtype == 'sendcan', valid)
|
||||
cdef bool is_sendcan = (msgtype == 'sendcan')
|
||||
cdef bool is_valid = valid
|
||||
with nogil:
|
||||
can_list_to_can_capnp_cpp(can_list, out, is_sendcan, is_valid)
|
||||
return out
|
||||
|
||||
def can_capnp_to_list(strings, msgtype='can'):
|
||||
|
||||
@@ -31,6 +31,7 @@ from openpilot.sunnypilot.selfdrive.selfdrived.events import EventsSP
|
||||
REPLAY = "REPLAY" in os.environ
|
||||
SIMULATION = "SIMULATION" in os.environ
|
||||
TESTING_CLOSET = "TESTING_CLOSET" in os.environ
|
||||
IGNORE_PROCESSES = {"loggerd", "encoderd", "statsd"}
|
||||
LONGITUDINAL_PERSONALITY_MAP = {v: k for k, v in log.LongitudinalPersonality.schema.enumerants.items()}
|
||||
|
||||
ThermalStatus = log.DeviceState.ThermalStatus
|
||||
@@ -283,7 +284,7 @@ class SelfdriveD(CruiseHelper):
|
||||
if not_running != self.not_running_prev:
|
||||
cloudlog.event("process_not_running", not_running=not_running, error=True)
|
||||
self.not_running_prev = not_running
|
||||
if self.sm.recv_frame['managerState'] and not_running:
|
||||
if self.sm.recv_frame['managerState'] and (not_running - IGNORE_PROCESSES):
|
||||
self.events.add(EventName.processNotRunning)
|
||||
else:
|
||||
if not SIMULATION and not self.rk.lagging:
|
||||
@@ -352,11 +353,11 @@ class SelfdriveD(CruiseHelper):
|
||||
if lac.active and not recent_steer_pressed and not self.CP.notCar:
|
||||
clipped_speed = max(CS.vEgo, MIN_LATERAL_CONTROL_SPEED)
|
||||
actual_lateral_accel = controlstate.curvature * (clipped_speed**2)
|
||||
desired_lateral_accel = controlstate.desiredCurvature * (clipped_speed**2)
|
||||
desired_lateral_accel = self.sm['modelV2'].action.desiredCurvature * (clipped_speed**2)
|
||||
undershooting = abs(desired_lateral_accel) / abs(1e-3 + actual_lateral_accel) > 1.2
|
||||
turning = abs(desired_lateral_accel) > 1.0
|
||||
good_speed = CS.vEgo > 5
|
||||
if undershooting and turning and good_speed and lac.saturated:
|
||||
# TODO: lac.saturated includes speed and other checks, should be pulled out
|
||||
if undershooting and turning and lac.saturated:
|
||||
self.events.add(EventName.steerSaturated)
|
||||
|
||||
# Check for FCW
|
||||
|
||||
@@ -358,6 +358,7 @@ def migrate_cameraStates(msgs):
|
||||
|
||||
new_msg = messaging.new_message(msg.which())
|
||||
new_camera_state = getattr(new_msg, new_msg.which())
|
||||
new_camera_state.sensor = camera_state.sensor
|
||||
new_camera_state.frameId = encode_id
|
||||
new_camera_state.encodeId = encode_id
|
||||
# timestampSof was added later so it might be missing on some old segments
|
||||
|
||||
@@ -19,8 +19,8 @@ from openpilot.tools.lib.framereader import FrameReader, NumpyFrameReader
|
||||
from openpilot.tools.lib.logreader import LogReader, save_log
|
||||
from openpilot.tools.lib.github_utils import GithubUtils
|
||||
|
||||
TEST_ROUTE = "2f4452b03ccb98f0|2022-12-03--13-45-30"
|
||||
SEGMENT = 6
|
||||
TEST_ROUTE = "8494c69d3c710e81|000001d4--2648a9a404"
|
||||
SEGMENT = 4
|
||||
MAX_FRAMES = 100 if PC else 400
|
||||
|
||||
NO_MODEL = "NO_MODEL" in os.environ
|
||||
@@ -66,6 +66,8 @@ def generate_report(proposed, master, tmp, commit):
|
||||
(lambda x: get_idx_if_non_empty(x.action.desiredCurvature), "desiredCurvature"),
|
||||
(lambda x: get_idx_if_non_empty(x.leadsV3[0].x, 0), "leadsV3.x"),
|
||||
(lambda x: get_idx_if_non_empty(x.laneLines[1].y, 0), "laneLines.y"),
|
||||
(lambda x: get_idx_if_non_empty(x.meta.desireState, 3), "desireState.laneChangeLeft"),
|
||||
(lambda x: get_idx_if_non_empty(x.meta.desireState, 4), "desireState.laneChangeRight"),
|
||||
(lambda x: get_idx_if_non_empty(x.meta.disengagePredictions.gasPressProbs, 1), "gasPressProbs")
|
||||
], "modelV2")
|
||||
DriverStateV2_Plots = zl([
|
||||
@@ -143,7 +145,8 @@ def trim_logs_to_max_frames(logs, max_frames, frs_types, include_all_types):
|
||||
|
||||
def model_replay(lr, frs):
|
||||
# modeld is using frame pairs
|
||||
modeld_logs = trim_logs_to_max_frames(lr, MAX_FRAMES, {"roadCameraState", "wideRoadCameraState"}, {"roadEncodeIdx", "wideRoadEncodeIdx", "carParams"})
|
||||
modeld_logs = trim_logs_to_max_frames(lr, MAX_FRAMES, {"roadCameraState", "wideRoadCameraState"},
|
||||
{"roadEncodeIdx", "wideRoadEncodeIdx", "carParams", "carState", "carControl"})
|
||||
dmodeld_logs = trim_logs_to_max_frames(lr, MAX_FRAMES, {"driverCameraState"}, {"driverEncodeIdx", "carParams"})
|
||||
|
||||
if not SEND_EXTRA_INPUTS:
|
||||
|
||||
@@ -571,7 +571,7 @@ CONFIGS = [
|
||||
),
|
||||
ProcessConfig(
|
||||
proc_name="modeld",
|
||||
pubs=["deviceState", "roadCameraState", "wideRoadCameraState", "liveCalibration", "driverMonitoringState", "carState"],
|
||||
pubs=["deviceState", "roadCameraState", "wideRoadCameraState", "liveCalibration", "driverMonitoringState", "carState", "carControl"],
|
||||
subs=["modelV2", "drivingModelData", "cameraOdometry"],
|
||||
ignore=["logMonoTime", "modelV2.frameDropPerc", "modelV2.modelExecutionTime", "drivingModelData.frameDropPerc", "drivingModelData.modelExecutionTime"],
|
||||
should_recv_callback=ModeldCameraSyncRcvCallback(),
|
||||
|
||||
@@ -1 +1 @@
|
||||
d343af55506b14a4011bfe43b2a49c7e3c387d75
|
||||
465979047295dad5da3a552db9227ed776a26a79
|
||||
@@ -12,10 +12,9 @@ from openpilot.selfdrive.test.process_replay.process_replay import CONFIGS, FAKE
|
||||
check_openpilot_enabled, check_most_messages_valid, get_custom_params_from_lr
|
||||
from openpilot.selfdrive.test.process_replay.vision_meta import DRIVER_CAMERA_FRAME_SIZES
|
||||
from openpilot.selfdrive.test.update_ci_routes import upload_route
|
||||
from openpilot.tools.lib.route import Route
|
||||
from openpilot.tools.lib.framereader import FrameReader, BaseFrameReader, FrameType
|
||||
from openpilot.tools.lib.logreader import LogReader, LogIterable, save_log
|
||||
|
||||
from openpilot.tools.lib.openpilotci import get_url
|
||||
|
||||
class DummyFrameReader(BaseFrameReader):
|
||||
def __init__(self, w: int, h: int, frame_count: int, pix_val: int):
|
||||
@@ -55,45 +54,28 @@ def regen_segment(
|
||||
|
||||
|
||||
def setup_data_readers(
|
||||
route: str, sidx: int, use_route_meta: bool,
|
||||
needs_driver_cam: bool = True, needs_road_cam: bool = True, dummy_driver_cam: bool = False
|
||||
route: str, sidx: int, needs_driver_cam: bool = True, needs_road_cam: bool = True, dummy_driver_cam: bool = False
|
||||
) -> tuple[LogReader, dict[str, Any]]:
|
||||
if use_route_meta:
|
||||
r = Route(route)
|
||||
lr = LogReader(r.log_paths()[sidx])
|
||||
frs = {}
|
||||
if needs_road_cam and len(r.camera_paths()) > sidx and r.camera_paths()[sidx] is not None:
|
||||
frs['roadCameraState'] = FrameReader(r.camera_paths()[sidx])
|
||||
if needs_road_cam and len(r.ecamera_paths()) > sidx and r.ecamera_paths()[sidx] is not None:
|
||||
frs['wideRoadCameraState'] = FrameReader(r.ecamera_paths()[sidx])
|
||||
if needs_driver_cam:
|
||||
if dummy_driver_cam:
|
||||
frs['driverCameraState'] = DummyFrameReader.zero_dcamera()
|
||||
elif len(r.dcamera_paths()) > sidx and r.dcamera_paths()[sidx] is not None:
|
||||
device_type = next(str(msg.initData.deviceType) for msg in lr if msg.which() == "initData")
|
||||
assert device_type != "neo", "Driver camera not supported on neo segments. Use dummy dcamera."
|
||||
frs['driverCameraState'] = FrameReader(r.dcamera_paths()[sidx])
|
||||
else:
|
||||
lr = LogReader(f"{route}/{sidx}/r")
|
||||
frs = {}
|
||||
if needs_road_cam:
|
||||
frs['roadCameraState'] = FrameReader(f"cd:/{route.replace('|', '/')}/{sidx}/fcamera.hevc")
|
||||
if next((True for m in lr if m.which() == "wideRoadCameraState"), False):
|
||||
frs['wideRoadCameraState'] = FrameReader(f"cd:/{route.replace('|', '/')}/{sidx}/ecamera.hevc")
|
||||
if needs_driver_cam:
|
||||
if dummy_driver_cam:
|
||||
frs['driverCameraState'] = DummyFrameReader.zero_dcamera()
|
||||
else:
|
||||
device_type = next(str(msg.initData.deviceType) for msg in lr if msg.which() == "initData")
|
||||
assert device_type != "neo", "Driver camera not supported on neo segments. Use dummy dcamera."
|
||||
frs['driverCameraState'] = FrameReader(f"cd:/{route.replace('|', '/')}/{sidx}/dcamera.hevc")
|
||||
lr = LogReader(f"{route}/{sidx}/r")
|
||||
frs = {}
|
||||
if needs_road_cam:
|
||||
frs['roadCameraState'] = FrameReader(get_url(route, str(sidx), "fcamera.hevc"))
|
||||
if next((True for m in lr if m.which() == "wideRoadCameraState"), False):
|
||||
frs['wideRoadCameraState'] = FrameReader(get_url(route, str(sidx), "ecamera.hevc"))
|
||||
if needs_driver_cam:
|
||||
if dummy_driver_cam:
|
||||
frs['driverCameraState'] = DummyFrameReader.zero_dcamera()
|
||||
else:
|
||||
device_type = next(str(msg.initData.deviceType) for msg in lr if msg.which() == "initData")
|
||||
assert device_type != "neo", "Driver camera not supported on neo segments. Use dummy dcamera."
|
||||
frs['driverCameraState'] = FrameReader(get_url(route, str(sidx), "dcamera.hevc"))
|
||||
|
||||
return lr, frs
|
||||
|
||||
|
||||
def regen_and_save(
|
||||
route: str, sidx: int, processes: str | Iterable[str] = "all", outdir: str = FAKEDATA,
|
||||
upload: bool = False, use_route_meta: bool = False, disable_tqdm: bool = False, dummy_driver_cam: bool = False
|
||||
upload: bool = False, disable_tqdm: bool = False, dummy_driver_cam: bool = False
|
||||
) -> str:
|
||||
if not isinstance(processes, str) and not hasattr(processes, "__iter__"):
|
||||
raise ValueError("whitelist_proc must be a string or iterable")
|
||||
@@ -110,7 +92,7 @@ def regen_and_save(
|
||||
replayed_processes = CONFIGS
|
||||
|
||||
all_vision_pubs = {pub for cfg in replayed_processes for pub in cfg.vision_pubs}
|
||||
lr, frs = setup_data_readers(route, sidx, use_route_meta,
|
||||
lr, frs = setup_data_readers(route, sidx,
|
||||
needs_driver_cam="driverCameraState" in all_vision_pubs,
|
||||
needs_road_cam="roadCameraState" in all_vision_pubs or "wideRoadCameraState" in all_vision_pubs,
|
||||
dummy_driver_cam=dummy_driver_cam)
|
||||
|
||||
@@ -17,7 +17,7 @@ def regen_job(segment, upload, disable_tqdm):
|
||||
sn = SegmentName(segment[1])
|
||||
fake_dongle_id = 'regen' + ''.join(random.choice('0123456789ABCDEF') for _ in range(11))
|
||||
try:
|
||||
relr = regen_and_save(sn.route_name.canonical_name, sn.segment_num, upload=upload, use_route_meta=False,
|
||||
relr = regen_and_save(sn.route_name.canonical_name, sn.segment_num, upload=upload,
|
||||
outdir=os.path.join(FAKEDATA, fake_dongle_id), disable_tqdm=disable_tqdm, dummy_driver_cam=True)
|
||||
relr = '|'.join(relr.split('/')[-2:])
|
||||
return f' ("{segment[0]}", "{relr}"), '
|
||||
|
||||
@@ -44,22 +44,22 @@ source_segments = [
|
||||
|
||||
segments = [
|
||||
("BODY", "regenA67A128BCD8|2024-08-30--02-36-22--0"),
|
||||
("HYUNDAI", "regen9CBD921E93E|2024-08-30--02-38-51--0"),
|
||||
("HYUNDAI", "regenCCD47FEBC0C|2025-03-04--03-21-48--0"),
|
||||
("HYUNDAI2", "regen306779F6870|2024-10-03--04-03-23--0"),
|
||||
("TOYOTA", "regen1CA7A48E6F7|2024-08-30--02-45-08--0"),
|
||||
("TOYOTA", "regen4A5115B248D|2025-03-04--03-21-43--0"),
|
||||
("TOYOTA2", "regen6E484EDAB96|2024-08-30--02-47-37--0"),
|
||||
("TOYOTA3", "regen4CE950B0267|2024-08-30--02-51-30--0"),
|
||||
("HONDA", "regenC8F0D6ADC5C|2024-08-30--02-54-01--0"),
|
||||
("HONDA", "regenB8CABEC09CC|2025-03-04--03-32-55--0"),
|
||||
("HONDA2", "regen4B38A7428CD|2024-08-30--02-56-31--0"),
|
||||
("CHRYSLER", "regenF3DBBA9E8DF|2024-08-30--02-59-03--0"),
|
||||
("RAM", "regenDB02684E00A|2024-08-30--03-02-54--0"),
|
||||
("SUBARU", "regenAA1FF48CF1F|2024-08-30--03-06-45--0"),
|
||||
("SUBARU", "regen5E3347D0A0F|2025-03-04--03-23-55--0"),
|
||||
("GM", "regen720F2BA4CF6|2024-08-30--03-09-15--0"),
|
||||
("GM2", "regen9ADBECBCD1C|2024-08-30--03-13-04--0"),
|
||||
("NISSAN", "regen58464878D07|2024-08-30--03-15-31--0"),
|
||||
("VOLKSWAGEN", "regenED976DEB757|2024-08-30--03-18-02--0"),
|
||||
("MAZDA", "regenACF84CCF482|2024-08-30--03-21-55--0"),
|
||||
("FORD", "regen756F8230C21|2024-11-07--00-08-24--0"),
|
||||
("FORD", "regenA75209BD115|2025-03-04--03-23-53--0"),
|
||||
("RIVIAN", "bc095dc92e101734|000000db--ee9fe46e57--1"),
|
||||
]
|
||||
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import math
|
||||
import json
|
||||
import os
|
||||
import pathlib
|
||||
import psutil
|
||||
import pytest
|
||||
import shutil
|
||||
import subprocess
|
||||
@@ -12,7 +10,7 @@ from collections import Counter, defaultdict
|
||||
from pathlib import Path
|
||||
from tabulate import tabulate
|
||||
|
||||
from cereal import car, log
|
||||
from cereal import log
|
||||
import cereal.messaging as messaging
|
||||
from cereal.services import SERVICE_LIST
|
||||
from openpilot.common.basedir import BASEDIR
|
||||
@@ -23,6 +21,7 @@ from openpilot.selfdrive.test.helpers import set_params_enabled, release_only
|
||||
from openpilot.system.hardware import HARDWARE
|
||||
from openpilot.system.hardware.hw import Paths
|
||||
from openpilot.tools.lib.logreader import LogReader
|
||||
from openpilot.tools.lib.log_time_series import msgs_to_time_series
|
||||
|
||||
"""
|
||||
CPU usage budget
|
||||
@@ -112,6 +111,7 @@ def cputime_total(ct):
|
||||
|
||||
|
||||
@pytest.mark.tici
|
||||
@pytest.mark.skip_tici_setup
|
||||
class TestOnroad:
|
||||
|
||||
@classmethod
|
||||
@@ -119,7 +119,8 @@ class TestOnroad:
|
||||
if "DEBUG" in os.environ:
|
||||
segs = filter(lambda x: os.path.exists(os.path.join(x, "rlog.zst")), Path(Paths.log_root()).iterdir())
|
||||
segs = sorted(segs, key=lambda x: x.stat().st_mtime)
|
||||
cls.lr = list(LogReader(os.path.join(segs[-3], "rlog.zst")))
|
||||
cls.lr = list(LogReader(os.path.join(segs[-1], "rlog.zst")))
|
||||
cls.ts = msgs_to_time_series(cls.lr)
|
||||
return
|
||||
|
||||
# setup env
|
||||
@@ -140,44 +141,31 @@ class TestOnroad:
|
||||
proc = subprocess.Popen(["python", manager_path])
|
||||
|
||||
sm = messaging.SubMaster(['carState'])
|
||||
with Timeout(150, "controls didn't start"):
|
||||
while sm.recv_frame['carState'] < 0:
|
||||
with Timeout(30, "controls didn't start"):
|
||||
while not sm.seen['carState']:
|
||||
sm.update(1000)
|
||||
|
||||
route = None
|
||||
cls.segments = []
|
||||
with Timeout(300, "timed out waiting for logs"):
|
||||
while route is None:
|
||||
route = params.get("CurrentRoute", encoding="utf-8")
|
||||
time.sleep(0.01)
|
||||
route = params.get("CurrentRoute", encoding="utf-8")
|
||||
assert route is not None
|
||||
|
||||
# test car params caching
|
||||
params.put("CarParamsCache", car.CarParams().to_bytes())
|
||||
|
||||
while len(cls.segments) < 1:
|
||||
segs = set()
|
||||
if Path(Paths.log_root()).exists():
|
||||
segs = set(Path(Paths.log_root()).glob(f"{route}--*"))
|
||||
cls.segments = sorted(segs, key=lambda s: int(str(s).rsplit('--')[-1]))
|
||||
time.sleep(0.01)
|
||||
segs = list(Path(Paths.log_root()).glob(f"{route}--*"))
|
||||
assert len(segs) == 1
|
||||
|
||||
time.sleep(TEST_DURATION)
|
||||
|
||||
finally:
|
||||
cls.gpu_procs = {psutil.Process(int(f.name)).name() for f in pathlib.Path('/sys/devices/virtual/kgsl/kgsl/proc/').iterdir() if f.is_dir()}
|
||||
|
||||
if proc is not None:
|
||||
proc.terminate()
|
||||
if proc.wait(60) is None:
|
||||
proc.kill()
|
||||
|
||||
cls.lrs = [list(LogReader(os.path.join(str(s), "rlog.zst"))) for s in cls.segments]
|
||||
|
||||
cls.lr = list(LogReader(os.path.join(str(cls.segments[0]), "rlog.zst")))
|
||||
cls.log_path = cls.segments[0]
|
||||
cls.lr = list(LogReader(os.path.join(str(segs[0]), "rlog.zst")))
|
||||
st = time.monotonic()
|
||||
cls.ts = msgs_to_time_series(cls.lr)
|
||||
print("msgs to time series", time.monotonic() - st)
|
||||
log_path = segs[0]
|
||||
|
||||
cls.log_sizes = {}
|
||||
for f in cls.log_path.iterdir():
|
||||
for f in log_path.iterdir():
|
||||
assert f.is_file()
|
||||
cls.log_sizes[f] = f.stat().st_size / 1e6
|
||||
|
||||
@@ -198,7 +186,7 @@ class TestOnroad:
|
||||
assert len(msgs) >= math.floor(SERVICE_LIST[s].frequency*int(TEST_DURATION*0.8))
|
||||
|
||||
def test_manager_starting_time(self):
|
||||
st = self.msgs['managerState'][0].logMonoTime / 1e9
|
||||
st = self.ts['managerState']['t'][0]
|
||||
assert (st - self.manager_st) < 10, f"manager.py took {st - self.manager_st}s to publish the first 'managerState' msg"
|
||||
|
||||
def test_cloudlog_size(self):
|
||||
@@ -226,7 +214,7 @@ class TestOnroad:
|
||||
result += "-------------- UI Draw Timing ------------------\n"
|
||||
result += "------------------------------------------------\n"
|
||||
|
||||
ts = [m.uiDebug.drawTimeMillis for m in self.msgs['uiDebug']]
|
||||
ts = self.ts['uiDebug']['drawTimeMillis']
|
||||
result += f"min {min(ts):.2f}ms\n"
|
||||
result += f"max {max(ts):.2f}ms\n"
|
||||
result += f"std {np.std(ts):.2f}ms\n"
|
||||
@@ -309,9 +297,6 @@ class TestOnroad:
|
||||
assert np.max(np.diff(mems)) <= 4, "Max memory increase too high"
|
||||
assert np.average(np.diff(mems)) <= 1, "Average memory increase too high"
|
||||
|
||||
def test_gpu_usage(self):
|
||||
assert self.gpu_procs == {"weston", "ui", "camerad", "selfdrive.modeld.modeld", "selfdrive.modeld.dmonitoringmodeld"}
|
||||
|
||||
def test_camera_frame_timings(self, subtests):
|
||||
# test timing within a single camera
|
||||
result = "\n"
|
||||
@@ -319,7 +304,7 @@ class TestOnroad:
|
||||
result += "----------------- SOF Timing ------------------\n"
|
||||
result += "------------------------------------------------\n"
|
||||
for name in ['roadCameraState', 'wideRoadCameraState', 'driverCameraState']:
|
||||
ts = [getattr(m, m.which()).timestampSof for m in self.lr if name in m.which()]
|
||||
ts = self.ts[name]['timestampSof']
|
||||
d_ms = np.diff(ts) / 1e6
|
||||
d50 = np.abs(d_ms-50)
|
||||
result += f"{name} sof delta vs 50ms: min {min(d50):.2f}ms\n"
|
||||
@@ -338,35 +323,51 @@ class TestOnroad:
|
||||
# sanity checks within a single cam
|
||||
for cam in cams:
|
||||
with subtests.test(test="frame_skips", camera=cam):
|
||||
cam_log = [getattr(x, x.which()) for x in self.msgs[cam]]
|
||||
assert set(np.diff([x.frameId for x in cam_log])) == {1, }, "Frame ID skips"
|
||||
assert set(np.diff(self.ts[cam]['frameId'])) == {1, }, "Frame ID skips"
|
||||
|
||||
# EOF > SOF
|
||||
eof_sof_diff = np.array([x.timestampEof - x.timestampSof for x in cam_log])
|
||||
eof_sof_diff = self.ts[cam]['timestampEof'] - self.ts[cam]['timestampSof']
|
||||
assert np.all(eof_sof_diff > 0)
|
||||
assert np.all(eof_sof_diff < 50*1e6)
|
||||
|
||||
fid = {c: [getattr(m, m.which()).frameId for m in self.msgs[c]] for c in cams}
|
||||
first_fid = [min(x) for x in fid.values()]
|
||||
first_fid = {c: min(self.ts[c]['frameId']) for c in cams}
|
||||
if cam.endswith('CameraState'):
|
||||
# camerad guarantees that all cams start on frame ID 0
|
||||
# (note loggerd also needs to start up fast enough to catch it)
|
||||
assert set(first_fid) == {0, }, "Cameras don't start on frame ID 0"
|
||||
assert set(first_fid.values()) == {0, }, "Cameras don't start on frame ID 0"
|
||||
else:
|
||||
# encoder guarantees all cams start on the same frame ID
|
||||
assert len(set(first_fid)) == 1, "Cameras don't start on same frame ID"
|
||||
assert len(set(first_fid.values())) == 1, "Cameras don't start on same frame ID"
|
||||
|
||||
# we don't do a full segment rotation, so these might not match exactly
|
||||
last_fid = [max(x) for x in fid.values()]
|
||||
assert max(last_fid) - min(last_fid) < 10
|
||||
last_fid = {c: max(self.ts[c]['frameId']) for c in cams}
|
||||
assert max(last_fid.values()) - min(last_fid.values()) < 10
|
||||
|
||||
start, end = min(first_fid), min(last_fid)
|
||||
all_ts = [[getattr(m, m.which()).timestampSof for m in self.msgs[c]] for c in cams]
|
||||
start, end = min(first_fid.values()), min(last_fid.values())
|
||||
for i in range(end-start):
|
||||
ts = [round(x[i]/1e6, 1) for x in all_ts]
|
||||
diff = max(ts) - min(ts)
|
||||
ts = {c: round(self.ts[c]['timestampSof'][i]/1e6, 1) for c in cams}
|
||||
diff = (max(ts.values()) - min(ts.values()))
|
||||
assert diff < 2, f"Cameras not synced properly: frame_id={start+i}, {diff=:.1f}ms, {ts=}"
|
||||
|
||||
def test_camera_encoder_matches(self, subtests):
|
||||
# sanity check that the frame metadata is consistent with the encoded frames
|
||||
pairs = [('roadCameraState', 'roadEncodeIdx'),
|
||||
('wideRoadCameraState', 'wideRoadEncodeIdx'),
|
||||
('driverCameraState', 'driverEncodeIdx')]
|
||||
for cam, enc in pairs:
|
||||
with subtests.test(camera=cam, encoder=enc):
|
||||
cam_frames = {fid: (sof, eof) for fid, sof, eof in zip(
|
||||
self.ts[cam]['frameId'],
|
||||
self.ts[cam]['timestampSof'],
|
||||
self.ts[cam]['timestampEof'],
|
||||
strict=True,
|
||||
)}
|
||||
for i, fid in enumerate(self.ts[enc]['frameId']):
|
||||
cam_sof, cam_eof = cam_frames[fid]
|
||||
enc_sof, enc_eof = self.ts[enc]['timestampSof'][i], self.ts[enc]['timestampEof'][i]
|
||||
assert enc_sof == cam_sof, f"SOF mismatch: frameId={fid}, enc_sof={enc_sof}, cam_sof={cam_sof}"
|
||||
assert enc_eof == cam_eof, f"EOF mismatch: frameId={fid}, enc_eof={enc_eof}, cam_eof={cam_eof}"
|
||||
|
||||
def test_mpc_execution_timings(self):
|
||||
result = "\n"
|
||||
result += "------------------------------------------------\n"
|
||||
@@ -438,12 +439,7 @@ class TestOnroad:
|
||||
|
||||
@release_only
|
||||
def test_startup(self):
|
||||
startup_alert = None
|
||||
for msg in self.lrs[0]:
|
||||
# can't use onroadEvents because the first msg can be dropped while loggerd is starting up
|
||||
if msg.which() == "selfdriveState":
|
||||
startup_alert = msg.selfdriveState.alertText1
|
||||
break
|
||||
startup_alert = self.ts['selfdriveState']['alertText1'][0]
|
||||
expected = EVENTS[log.OnroadEvent.EventName.startup][ET.PERMANENT].alert_text_1
|
||||
assert startup_alert == expected, "wrong startup alert"
|
||||
|
||||
|
||||
@@ -47,12 +47,9 @@ translation_sources = [f"#selfdrive/ui/translations/{l}.ts" for l in languages.v
|
||||
translation_targets = [src.replace(".ts", ".qm") for src in translation_sources]
|
||||
lrelease_bin = 'third_party/qt5/larch64/bin/lrelease' if arch == 'larch64' else 'lrelease'
|
||||
|
||||
lupdate = qt_env.Command(translation_sources + ["translations/alerts_generated.h"], qt_src + widgets_src, "selfdrive/ui/update_translations.py")
|
||||
lrelease = qt_env.Command(translation_targets, translation_sources, f"{lrelease_bin} $SOURCES")
|
||||
qt_env.Depends(lrelease, lupdate)
|
||||
qt_env.NoClean(translation_sources)
|
||||
qt_env.Precious(translation_sources)
|
||||
qt_env.NoCache(lupdate)
|
||||
|
||||
# create qrc file for compiled translations to include with assets
|
||||
translations_assets_src = "#selfdrive/assets/translations_assets.qrc"
|
||||
|
||||
@@ -8,6 +8,9 @@
|
||||
#include <QScrollArea>
|
||||
#include <QStackedLayout>
|
||||
#include <QProgressBar>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QTimer>
|
||||
|
||||
FirehosePanel::FirehosePanel(SettingsWindow *parent) : QWidget((QWidget*)parent) {
|
||||
layout = new QVBoxLayout(this);
|
||||
@@ -26,7 +29,7 @@ FirehosePanel::FirehosePanel(SettingsWindow *parent) : QWidget((QWidget*)parent)
|
||||
content_layout->setSpacing(20);
|
||||
|
||||
// Top description
|
||||
QLabel *description = new QLabel(tr("openpilot learns to drive by watching humans, like you, drive.\n\nFirehose Mode allows you to maximize your training data uploads to improve openpilot's driving models. More data means bigger models with better Experimental Mode."));
|
||||
QLabel *description = new QLabel(tr("openpilot learns to drive by watching humans, like you, drive.\n\nFirehose Mode allows you to maximize your training data uploads to improve openpilot's driving models. More data means bigger models, which means better Experimental Mode."));
|
||||
description->setStyleSheet("font-size: 45px; padding-bottom: 20px;");
|
||||
description->setWordWrap(true);
|
||||
content_layout->addWidget(description);
|
||||
@@ -38,41 +41,16 @@ FirehosePanel::FirehosePanel(SettingsWindow *parent) : QWidget((QWidget*)parent)
|
||||
line->setStyleSheet("background-color: #444444; margin-top: 5px; margin-bottom: 5px;");
|
||||
content_layout->addWidget(line);
|
||||
|
||||
enable_firehose = new ParamControl("FirehoseMode", tr("Enable Firehose Mode"), "", "");
|
||||
toggle_label = new QLabel(tr("Firehose Mode: ACTIVE"));
|
||||
toggle_label->setStyleSheet("font-size: 60px; font-weight: bold; color: white;");
|
||||
content_layout->addWidget(toggle_label);
|
||||
|
||||
content_layout->addWidget(enable_firehose);
|
||||
|
||||
// Create progress bar container
|
||||
progress_container = new QFrame();
|
||||
progress_container->hide();
|
||||
QHBoxLayout *progress_layout = new QHBoxLayout(progress_container);
|
||||
progress_layout->setContentsMargins(10, 0, 10, 10);
|
||||
progress_layout->setSpacing(20);
|
||||
|
||||
progress_bar = new QProgressBar();
|
||||
progress_bar->setRange(0, 100);
|
||||
progress_bar->setValue(0);
|
||||
progress_bar->setTextVisible(false);
|
||||
progress_bar->setStyleSheet(R"(
|
||||
QProgressBar {
|
||||
background-color: #444444;
|
||||
border-radius: 10px;
|
||||
height: 20px;
|
||||
}
|
||||
QProgressBar::chunk {
|
||||
background-color: #3498db;
|
||||
border-radius: 10px;
|
||||
}
|
||||
)");
|
||||
progress_bar->setFixedHeight(40);
|
||||
|
||||
// Progress text
|
||||
progress_text = new QLabel(tr("0%"));
|
||||
progress_text->setStyleSheet("font-size: 40px; font-weight: bold; color: white;");
|
||||
|
||||
progress_layout->addWidget(progress_text);
|
||||
|
||||
content_layout->addWidget(progress_container);
|
||||
// Add contribution label
|
||||
contribution_label = new QLabel();
|
||||
contribution_label->setStyleSheet("font-size: 52px; margin-top: 10px; margin-bottom: 10px;");
|
||||
contribution_label->setWordWrap(true);
|
||||
contribution_label->hide();
|
||||
content_layout->addWidget(contribution_label);
|
||||
|
||||
// Add a separator before detailed instructions
|
||||
QFrame *line2 = new QFrame();
|
||||
@@ -83,22 +61,49 @@ FirehosePanel::FirehosePanel(SettingsWindow *parent) : QWidget((QWidget*)parent)
|
||||
|
||||
// Detailed instructions at the bottom
|
||||
detailed_instructions = new QLabel(tr(
|
||||
"Follow these steps to get your device ready:<br>"
|
||||
"\t1. Bring your device inside and connect to a good USB-C adapter<br>"
|
||||
"\t2. Connect to Wi-Fi<br>"
|
||||
"\t3. Enable the toggle<br>"
|
||||
"\t4. Leave it connected for at least 30 minutes<br>"
|
||||
"For maximum effectiveness, bring your device inside and connect to a good USB-C adapter and Wi-Fi weekly.<br>"
|
||||
"<br>"
|
||||
"The toggle turns off once you restart your device. Repeat at least once a week for maximum effectiveness."
|
||||
"<br><br><b>FAQ</b><br>"
|
||||
"<i>Does it matter how or where I drive?</i> Nope, just drive as you normally would.<br>"
|
||||
"<i>What's a good USB-C adapter?</i> Any fast phone or laptop charger should be fine.<br>"
|
||||
"<i>Do I need to be on Wi-Fi?</i> Yes.<br>"
|
||||
"<i>Do I need to bring the device inside?</i> No, you can enable once you're parked, however your uploads will be limited by your car's battery.<br>"
|
||||
"Firehose Mode can also work while you're driving if connected to a hotspot or unlimited SIM card.<br>"
|
||||
"<br><br>"
|
||||
"<b>Frequently Asked Questions</b><br><br>"
|
||||
"<i>Does it matter how or where I drive?</i> Nope, just drive as you normally would.<br><br>"
|
||||
"<i>What's a good USB-C adapter?</i> Any fast phone or laptop charger should be fine.<br><br>"
|
||||
"<i>Does it matter which software I run?</i> Yes, only upstream openpilot (and particular forks) are able to be used for training."
|
||||
));
|
||||
detailed_instructions->setStyleSheet("font-size: 40px; padding: 20px; color: #E4E4E4;");
|
||||
detailed_instructions->setStyleSheet("font-size: 40px; color: #E4E4E4;");
|
||||
detailed_instructions->setWordWrap(true);
|
||||
content_layout->addWidget(detailed_instructions);
|
||||
|
||||
layout->addWidget(content, 1);
|
||||
|
||||
// Set up the API request for firehose stats
|
||||
const QString dongle_id = QString::fromStdString(Params().get("DongleId"));
|
||||
firehose_stats = new RequestRepeater(this, CommaApi::BASE_URL + "/v1/devices/" + dongle_id + "/firehose_stats",
|
||||
"ApiCache_FirehoseStats", 30, true);
|
||||
QObject::connect(firehose_stats, &RequestRepeater::requestDone, [=](const QString &response, bool success) {
|
||||
if (success) {
|
||||
QJsonDocument doc = QJsonDocument::fromJson(response.toUtf8());
|
||||
QJsonObject json = doc.object();
|
||||
int count = json["firehose"].toInt();
|
||||
contribution_label->setText(tr("<b>%1 %2</b> of your driving are in the training dataset so far.").arg(count).arg(count == 1 ? "segment" : "segments"));
|
||||
contribution_label->show();
|
||||
}
|
||||
});
|
||||
|
||||
QObject::connect(uiState(), &UIState::uiUpdate, this, &FirehosePanel::refresh);
|
||||
}
|
||||
|
||||
void FirehosePanel::refresh() {
|
||||
auto deviceState = (*uiState()->sm)["deviceState"].getDeviceState();
|
||||
auto networkType = deviceState.getNetworkType();
|
||||
bool networkMetered = deviceState.getNetworkMetered();
|
||||
|
||||
bool is_active = !networkMetered && (networkType != cereal::DeviceState::NetworkType::NONE);
|
||||
if (is_active) {
|
||||
toggle_label->setText(tr("ACTIVE"));
|
||||
toggle_label->setStyleSheet("font-size: 60px; font-weight: bold; color: #2ecc71;");
|
||||
} else {
|
||||
toggle_label->setText(tr("<span stylesheet='font-size: 60px; font-weight: bold; color: #e74c3c;'>INACTIVE</span>: connect to unmetered network"));
|
||||
toggle_label->setStyleSheet("font-size: 60px;");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,9 +2,8 @@
|
||||
|
||||
#include <QWidget>
|
||||
#include <QVBoxLayout>
|
||||
#include <QProgressBar>
|
||||
#include <QLabel>
|
||||
#include "common/params.h"
|
||||
#include "selfdrive/ui/qt/request_repeater.h"
|
||||
|
||||
#ifdef SUNNYPILOT
|
||||
#include "selfdrive/ui/sunnypilot/ui.h"
|
||||
@@ -26,12 +25,13 @@ public:
|
||||
|
||||
private:
|
||||
QVBoxLayout *layout;
|
||||
|
||||
ParamControl *enable_firehose;
|
||||
QFrame *progress_container;
|
||||
QProgressBar *progress_bar;
|
||||
QLabel *progress_text;
|
||||
|
||||
QLabel *detailed_instructions;
|
||||
|
||||
void updateFirehoseState(bool enabled);
|
||||
QLabel *contribution_label;
|
||||
QLabel *toggle_label;
|
||||
|
||||
RequestRepeater *firehose_stats;
|
||||
|
||||
private slots:
|
||||
void refresh();
|
||||
};
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
|
||||
#include <QLabel>
|
||||
#include <QPainter>
|
||||
#include <QScrollBar>
|
||||
#include <QTransform>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
@@ -12,7 +11,6 @@
|
||||
#include "common/params.h"
|
||||
#include "selfdrive/ui/qt/util.h"
|
||||
#include "selfdrive/ui/qt/widgets/input.h"
|
||||
#include "selfdrive/ui/qt/widgets/scrollview.h"
|
||||
|
||||
TrainingGuide::TrainingGuide(QWidget *parent) : QFrame(parent) {
|
||||
setAttribute(Qt::WA_OpaquePaintEvent);
|
||||
@@ -85,29 +83,25 @@ void TrainingGuide::paintEvent(QPaintEvent *event) {
|
||||
}
|
||||
|
||||
void TermsPage::showEvent(QShowEvent *event) {
|
||||
// late init, building QML widget takes 200ms
|
||||
if (layout()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QVBoxLayout *main_layout = new QVBoxLayout(this);
|
||||
main_layout->setContentsMargins(45, 35, 45, 45);
|
||||
main_layout->setSpacing(0);
|
||||
|
||||
QLabel *title = new QLabel(tr("Terms & Conditions"));
|
||||
title->setStyleSheet("font-size: 90px; font-weight: 600;");
|
||||
main_layout->addWidget(title);
|
||||
QVBoxLayout *vlayout = new QVBoxLayout();
|
||||
vlayout->setContentsMargins(165, 165, 165, 0);
|
||||
main_layout->addLayout(vlayout);
|
||||
|
||||
QLabel *text = new QLabel(this);
|
||||
text->setTextFormat(Qt::RichText);
|
||||
text->setWordWrap(true);
|
||||
text->setText(QString::fromStdString(util::read_file("../assets/offroad/tc.html")));
|
||||
text->setStyleSheet("font-size:50px; font-weight: 200; color: #C9C9C9; background-color:#1B1B1B; padding:50px 50px;");
|
||||
ScrollView *scroll = new ScrollView(text, this);
|
||||
QLabel *title = new QLabel(tr("Welcome to openpilot"));
|
||||
title->setStyleSheet("font-size: 90px; font-weight: 500;");
|
||||
vlayout->addWidget(title, 0, Qt::AlignTop | Qt::AlignLeft);
|
||||
|
||||
main_layout->addSpacing(30);
|
||||
main_layout->addWidget(scroll);
|
||||
main_layout->addSpacing(50);
|
||||
vlayout->addSpacing(90);
|
||||
QLabel *desc = new QLabel(tr("You must accept the Terms and Conditions to use openpilot. Read the latest terms at <span style='color: #465BEA;'>https://comma.ai/terms</span> before continuing."));
|
||||
desc->setWordWrap(true);
|
||||
desc->setStyleSheet("font-size: 80px; font-weight: 300;");
|
||||
vlayout->addWidget(desc, 0);
|
||||
|
||||
vlayout->addStretch();
|
||||
|
||||
QHBoxLayout* buttons = new QHBoxLayout;
|
||||
buttons->setMargin(0);
|
||||
@@ -118,8 +112,7 @@ void TermsPage::showEvent(QShowEvent *event) {
|
||||
buttons->addWidget(decline_btn);
|
||||
QObject::connect(decline_btn, &QPushButton::clicked, this, &TermsPage::declinedTerms);
|
||||
|
||||
accept_btn = new QPushButton(tr("Scroll to accept"));
|
||||
accept_btn->setEnabled(false);
|
||||
accept_btn = new QPushButton(tr("Agree"));
|
||||
accept_btn->setStyleSheet(R"(
|
||||
QPushButton {
|
||||
background-color: #465BEA;
|
||||
@@ -127,23 +120,9 @@ void TermsPage::showEvent(QShowEvent *event) {
|
||||
QPushButton:pressed {
|
||||
background-color: #3049F4;
|
||||
}
|
||||
QPushButton:disabled {
|
||||
background-color: #4F4F4F;
|
||||
}
|
||||
)");
|
||||
buttons->addWidget(accept_btn);
|
||||
QObject::connect(accept_btn, &QPushButton::clicked, this, &TermsPage::acceptedTerms);
|
||||
QScrollBar *scroll_bar = scroll->verticalScrollBar();
|
||||
connect(scroll_bar, &QScrollBar::valueChanged, this, [this, scroll_bar](int value) {
|
||||
if (value == scroll_bar->maximum()) {
|
||||
enableAccept();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void TermsPage::enableAccept() {
|
||||
accept_btn->setText(tr("Agree"));
|
||||
accept_btn->setEnabled(true);
|
||||
}
|
||||
|
||||
void DeclinePage::showEvent(QShowEvent *event) {
|
||||
|
||||
@@ -65,9 +65,6 @@ class TermsPage : public QFrame {
|
||||
public:
|
||||
explicit TermsPage(QWidget *parent = 0) : QFrame(parent) {}
|
||||
|
||||
public slots:
|
||||
void enableAccept();
|
||||
|
||||
private:
|
||||
void showEvent(QShowEvent *event) override;
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ SoftwarePanel::SoftwarePanel(QWidget* parent) : ListWidget(parent) {
|
||||
connect(targetBranchBtn, &ButtonControl::clicked, [=]() {
|
||||
auto current = params.get("GitBranch");
|
||||
QStringList branches = QString::fromStdString(params.get("UpdaterAvailableBranches")).split(",");
|
||||
for (QString b : {current.c_str(), "devel-staging", "devel", "nightly", "nightly-dev", "master-ci", "master"}) {
|
||||
for (QString b : {current.c_str(), "devel-staging", "devel", "nightly", "nightly-dev", "master"}) {
|
||||
auto i = branches.indexOf(b);
|
||||
if (i >= 0) {
|
||||
branches.removeAt(i);
|
||||
|
||||
@@ -26,6 +26,7 @@ void HudRenderer::updateState(const UIState &s) {
|
||||
// Handle older routes where vCruiseCluster is not set
|
||||
set_speed = car_state.getVCruiseCluster() == 0.0 ? controls_state.getVCruiseDEPRECATED() : car_state.getVCruiseCluster();
|
||||
is_cruise_set = set_speed > 0 && set_speed != SET_SPEED_NA;
|
||||
is_cruise_available = set_speed != -1;
|
||||
|
||||
if (is_cruise_set && !is_metric) {
|
||||
set_speed *= KM_TO_MILE;
|
||||
@@ -47,7 +48,9 @@ void HudRenderer::draw(QPainter &p, const QRect &surface_rect) {
|
||||
p.fillRect(0, 0, surface_rect.width(), UI_HEADER_HEIGHT, bg);
|
||||
|
||||
|
||||
drawSetSpeed(p, surface_rect);
|
||||
if (is_cruise_available) {
|
||||
drawSetSpeed(p, surface_rect);
|
||||
}
|
||||
drawCurrentSpeed(p, surface_rect);
|
||||
|
||||
p.restore();
|
||||
|
||||
@@ -25,6 +25,7 @@ protected:
|
||||
float speed = 0;
|
||||
float set_speed = 0;
|
||||
bool is_cruise_set = false;
|
||||
bool is_cruise_available = true;
|
||||
bool is_metric = false;
|
||||
bool v_ego_cluster_seen = false;
|
||||
int status = STATUS_DISENGAGED;
|
||||
|
||||
@@ -69,14 +69,13 @@ class Soundd:
|
||||
for sound in sound_list:
|
||||
filename, play_count, volume = sound_list[sound]
|
||||
|
||||
wavefile = wave.open(BASEDIR + "/selfdrive/assets/sounds/" + filename, 'r')
|
||||
with wave.open(BASEDIR + "/selfdrive/assets/sounds/" + filename, 'r') as wavefile:
|
||||
assert wavefile.getnchannels() == 1
|
||||
assert wavefile.getsampwidth() == 2
|
||||
assert wavefile.getframerate() == SAMPLE_RATE
|
||||
|
||||
assert wavefile.getnchannels() == 1
|
||||
assert wavefile.getsampwidth() == 2
|
||||
assert wavefile.getframerate() == SAMPLE_RATE
|
||||
|
||||
length = wavefile.getnframes()
|
||||
self.loaded_sounds[sound] = np.frombuffer(wavefile.readframes(length), dtype=np.int16).astype(np.float32) / (2**16/2)
|
||||
length = wavefile.getnframes()
|
||||
self.loaded_sounds[sound] = np.frombuffer(wavefile.readframes(length), dtype=np.int16).astype(np.float32) / (2**16/2)
|
||||
|
||||
def get_sound_data(self, frames): # get "frames" worth of data from the current alert sound, looping when required
|
||||
|
||||
|
||||
@@ -2,14 +2,12 @@ import pytest
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import tempfile
|
||||
import xml.etree.ElementTree as ET
|
||||
import string
|
||||
import requests
|
||||
from parameterized import parameterized_class
|
||||
|
||||
from openpilot.selfdrive.ui.update_translations import TRANSLATIONS_DIR, LANGUAGES_FILE, update_translations
|
||||
from openpilot.selfdrive.ui.update_translations import TRANSLATIONS_DIR, LANGUAGES_FILE
|
||||
|
||||
with open(LANGUAGES_FILE) as f:
|
||||
translation_files = json.load(f)
|
||||
@@ -34,16 +32,6 @@ class TestTranslations:
|
||||
assert os.path.exists(os.path.join(TRANSLATIONS_DIR, f"{self.file}.ts")), \
|
||||
f"{self.name} has no XML translation file, run selfdrive/ui/update_translations.py"
|
||||
|
||||
def test_translations_updated(self):
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
shutil.copytree(TRANSLATIONS_DIR, tmpdir, dirs_exist_ok=True)
|
||||
update_translations(translation_files=[self.file], translations_dir=tmpdir)
|
||||
|
||||
cur_translations = self._read_translation_file(TRANSLATIONS_DIR, self.file)
|
||||
new_translations = self._read_translation_file(tmpdir, self.file)
|
||||
assert cur_translations == new_translations, \
|
||||
f"{self.file} ({self.name}) XML translation file out of date. Run selfdrive/ui/update_translations.py to update the translation files"
|
||||
|
||||
@pytest.mark.skip("Only test unfinished translations before going to release")
|
||||
def test_unfinished_translations(self):
|
||||
cur_translations = self._read_translation_file(TRANSLATIONS_DIR, self.file)
|
||||
|
||||
@@ -421,22 +421,30 @@
|
||||
<source>🔥 Firehose Mode 🔥</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Firehose Mode</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>openpilot learns to drive by watching humans, like you, drive.
|
||||
|
||||
Firehose Mode allows you to maximize your training data uploads to improve openpilot's driving models. More data means bigger models with better Experimental Mode.</source>
|
||||
Firehose Mode allows you to maximize your training data uploads to improve openpilot's driving models. More data means bigger models, which means better Experimental Mode.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>0%</source>
|
||||
<translation type="unfinished">5G {0%?}</translation>
|
||||
<source>Firehose Mode: ACTIVE</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Follow these steps to get your device ready:<br> 1. Bring your device inside and connect to a good USB-C adapter<br> 2. Connect to Wi-Fi<br> 3. Enable the toggle<br> 4. Leave it connected for at least 30 minutes<br><br>The toggle turns off once you restart your device. Repeat at least once a week for maximum effectiveness.<br><br><b>FAQ</b><br><i>Does it matter how or where I drive?</i> Nope, just drive as you normally would.<br><i>What's a good USB-C adapter?</i> Any fast phone or laptop charger should be fine.<br><i>Do I need to be on Wi-Fi?</i> Yes.<br><i>Do I need to bring the device inside?</i> No, you can enable once you're parked, however your uploads will be limited by your car's battery.<br></source>
|
||||
<source>For maximum effectiveness, bring your device inside and connect to a good USB-C adapter and Wi-Fi weekly.<br><br>Firehose Mode can also work while you're driving if connected to a hotspot or unlimited SIM card.<br><br><br><b>Frequently Asked Questions</b><br><br><i>Does it matter how or where I drive?</i> Nope, just drive as you normally would.<br><br><i>What's a good USB-C adapter?</i> Any fast phone or laptop charger should be fine.<br><br><i>Does it matter which software I run?</i> Yes, only upstream openpilot (and particular forks) are able to be used for training.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>%1 %2</b> of your driving are in the training dataset so far.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>ACTIVE</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><span stylesheet='font-size: 60px; font-weight: bold; color: #e74c3c;'>INACTIVE</span>: connect to unmetered network</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
@@ -1451,22 +1459,22 @@ This may take up to a minute.</source>
|
||||
</context>
|
||||
<context>
|
||||
<name>TermsPage</name>
|
||||
<message>
|
||||
<source>Terms & Conditions</source>
|
||||
<translation>الشروط والأحكام</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Decline</source>
|
||||
<translation>رفض</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Scroll to accept</source>
|
||||
<translation>قم بالتمرير للقبول</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Agree</source>
|
||||
<translation>أوافق</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Welcome to openpilot</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>You must accept the Terms and Conditions to use openpilot. Read the latest terms at <span style='color: #465BEA;'>https://comma.ai/terms</span> before continuing.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TogglesPanel</name>
|
||||
|
||||
@@ -421,22 +421,30 @@
|
||||
<source>🔥 Firehose Mode 🔥</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Firehose Mode</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>openpilot learns to drive by watching humans, like you, drive.
|
||||
|
||||
Firehose Mode allows you to maximize your training data uploads to improve openpilot's driving models. More data means bigger models with better Experimental Mode.</source>
|
||||
Firehose Mode allows you to maximize your training data uploads to improve openpilot's driving models. More data means bigger models, which means better Experimental Mode.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>0%</source>
|
||||
<translation type="unfinished">5G {0%?}</translation>
|
||||
<source>Firehose Mode: ACTIVE</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Follow these steps to get your device ready:<br> 1. Bring your device inside and connect to a good USB-C adapter<br> 2. Connect to Wi-Fi<br> 3. Enable the toggle<br> 4. Leave it connected for at least 30 minutes<br><br>The toggle turns off once you restart your device. Repeat at least once a week for maximum effectiveness.<br><br><b>FAQ</b><br><i>Does it matter how or where I drive?</i> Nope, just drive as you normally would.<br><i>What's a good USB-C adapter?</i> Any fast phone or laptop charger should be fine.<br><i>Do I need to be on Wi-Fi?</i> Yes.<br><i>Do I need to bring the device inside?</i> No, you can enable once you're parked, however your uploads will be limited by your car's battery.<br></source>
|
||||
<source>For maximum effectiveness, bring your device inside and connect to a good USB-C adapter and Wi-Fi weekly.<br><br>Firehose Mode can also work while you're driving if connected to a hotspot or unlimited SIM card.<br><br><br><b>Frequently Asked Questions</b><br><br><i>Does it matter how or where I drive?</i> Nope, just drive as you normally would.<br><br><i>What's a good USB-C adapter?</i> Any fast phone or laptop charger should be fine.<br><br><i>Does it matter which software I run?</i> Yes, only upstream openpilot (and particular forks) are able to be used for training.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>%1 %2</b> of your driving are in the training dataset so far.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>ACTIVE</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><span stylesheet='font-size: 60px; font-weight: bold; color: #e74c3c;'>INACTIVE</span>: connect to unmetered network</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
@@ -1435,22 +1443,22 @@ This may take up to a minute.</source>
|
||||
</context>
|
||||
<context>
|
||||
<name>TermsPage</name>
|
||||
<message>
|
||||
<source>Terms & Conditions</source>
|
||||
<translation>Benutzungsbedingungen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Decline</source>
|
||||
<translation>Ablehnen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Scroll to accept</source>
|
||||
<translation>Scrolle herunter um zu akzeptieren</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Agree</source>
|
||||
<translation>Zustimmen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Welcome to openpilot</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>You must accept the Terms and Conditions to use openpilot. Read the latest terms at <span style='color: #465BEA;'>https://comma.ai/terms</span> before continuing.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TogglesPanel</name>
|
||||
|
||||
@@ -421,22 +421,30 @@
|
||||
<source>🔥 Firehose Mode 🔥</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Firehose Mode</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>openpilot learns to drive by watching humans, like you, drive.
|
||||
|
||||
Firehose Mode allows you to maximize your training data uploads to improve openpilot's driving models. More data means bigger models with better Experimental Mode.</source>
|
||||
Firehose Mode allows you to maximize your training data uploads to improve openpilot's driving models. More data means bigger models, which means better Experimental Mode.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>0%</source>
|
||||
<translation type="unfinished">5G {0%?}</translation>
|
||||
<source>Firehose Mode: ACTIVE</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Follow these steps to get your device ready:<br> 1. Bring your device inside and connect to a good USB-C adapter<br> 2. Connect to Wi-Fi<br> 3. Enable the toggle<br> 4. Leave it connected for at least 30 minutes<br><br>The toggle turns off once you restart your device. Repeat at least once a week for maximum effectiveness.<br><br><b>FAQ</b><br><i>Does it matter how or where I drive?</i> Nope, just drive as you normally would.<br><i>What's a good USB-C adapter?</i> Any fast phone or laptop charger should be fine.<br><i>Do I need to be on Wi-Fi?</i> Yes.<br><i>Do I need to bring the device inside?</i> No, you can enable once you're parked, however your uploads will be limited by your car's battery.<br></source>
|
||||
<source>For maximum effectiveness, bring your device inside and connect to a good USB-C adapter and Wi-Fi weekly.<br><br>Firehose Mode can also work while you're driving if connected to a hotspot or unlimited SIM card.<br><br><br><b>Frequently Asked Questions</b><br><br><i>Does it matter how or where I drive?</i> Nope, just drive as you normally would.<br><br><i>What's a good USB-C adapter?</i> Any fast phone or laptop charger should be fine.<br><br><i>Does it matter which software I run?</i> Yes, only upstream openpilot (and particular forks) are able to be used for training.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>%1 %2</b> of your driving are in the training dataset so far.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>ACTIVE</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><span stylesheet='font-size: 60px; font-weight: bold; color: #e74c3c;'>INACTIVE</span>: connect to unmetered network</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
@@ -1435,22 +1443,22 @@ Esto puede tardar un minuto.</translation>
|
||||
</context>
|
||||
<context>
|
||||
<name>TermsPage</name>
|
||||
<message>
|
||||
<source>Terms & Conditions</source>
|
||||
<translation>Términos & Condiciones</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Decline</source>
|
||||
<translation>Rechazar</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Scroll to accept</source>
|
||||
<translation>Desliza para aceptar</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Agree</source>
|
||||
<translation>Aceptar</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Welcome to openpilot</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>You must accept the Terms and Conditions to use openpilot. Read the latest terms at <span style='color: #465BEA;'>https://comma.ai/terms</span> before continuing.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TogglesPanel</name>
|
||||
|
||||
@@ -421,22 +421,30 @@
|
||||
<source>🔥 Firehose Mode 🔥</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Firehose Mode</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>openpilot learns to drive by watching humans, like you, drive.
|
||||
|
||||
Firehose Mode allows you to maximize your training data uploads to improve openpilot's driving models. More data means bigger models with better Experimental Mode.</source>
|
||||
Firehose Mode allows you to maximize your training data uploads to improve openpilot's driving models. More data means bigger models, which means better Experimental Mode.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>0%</source>
|
||||
<translation type="unfinished">5G {0%?}</translation>
|
||||
<source>Firehose Mode: ACTIVE</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Follow these steps to get your device ready:<br> 1. Bring your device inside and connect to a good USB-C adapter<br> 2. Connect to Wi-Fi<br> 3. Enable the toggle<br> 4. Leave it connected for at least 30 minutes<br><br>The toggle turns off once you restart your device. Repeat at least once a week for maximum effectiveness.<br><br><b>FAQ</b><br><i>Does it matter how or where I drive?</i> Nope, just drive as you normally would.<br><i>What's a good USB-C adapter?</i> Any fast phone or laptop charger should be fine.<br><i>Do I need to be on Wi-Fi?</i> Yes.<br><i>Do I need to bring the device inside?</i> No, you can enable once you're parked, however your uploads will be limited by your car's battery.<br></source>
|
||||
<source>For maximum effectiveness, bring your device inside and connect to a good USB-C adapter and Wi-Fi weekly.<br><br>Firehose Mode can also work while you're driving if connected to a hotspot or unlimited SIM card.<br><br><br><b>Frequently Asked Questions</b><br><br><i>Does it matter how or where I drive?</i> Nope, just drive as you normally would.<br><br><i>What's a good USB-C adapter?</i> Any fast phone or laptop charger should be fine.<br><br><i>Does it matter which software I run?</i> Yes, only upstream openpilot (and particular forks) are able to be used for training.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>%1 %2</b> of your driving are in the training dataset so far.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>ACTIVE</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><span stylesheet='font-size: 60px; font-weight: bold; color: #e74c3c;'>INACTIVE</span>: connect to unmetered network</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
@@ -1435,22 +1443,22 @@ Cela peut prendre jusqu'à une minute.</translation>
|
||||
</context>
|
||||
<context>
|
||||
<name>TermsPage</name>
|
||||
<message>
|
||||
<source>Terms & Conditions</source>
|
||||
<translation>Termes & Conditions</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Decline</source>
|
||||
<translation>Refuser</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Scroll to accept</source>
|
||||
<translation>Faire défiler pour accepter</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Agree</source>
|
||||
<translation>Accepter</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Welcome to openpilot</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>You must accept the Terms and Conditions to use openpilot. Read the latest terms at <span style='color: #465BEA;'>https://comma.ai/terms</span> before continuing.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TogglesPanel</name>
|
||||
|
||||
@@ -419,24 +419,32 @@
|
||||
<name>FirehosePanel</name>
|
||||
<message>
|
||||
<source>🔥 Firehose Mode 🔥</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Firehose Mode</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>🔥 Firehoseモード 🔥</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>openpilot learns to drive by watching humans, like you, drive.
|
||||
|
||||
Firehose Mode allows you to maximize your training data uploads to improve openpilot's driving models. More data means bigger models with better Experimental Mode.</source>
|
||||
Firehose Mode allows you to maximize your training data uploads to improve openpilot's driving models. More data means bigger models, which means better Experimental Mode.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>0%</source>
|
||||
<translation type="unfinished">5G {0%?}</translation>
|
||||
<source>Firehose Mode: ACTIVE</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Follow these steps to get your device ready:<br> 1. Bring your device inside and connect to a good USB-C adapter<br> 2. Connect to Wi-Fi<br> 3. Enable the toggle<br> 4. Leave it connected for at least 30 minutes<br><br>The toggle turns off once you restart your device. Repeat at least once a week for maximum effectiveness.<br><br><b>FAQ</b><br><i>Does it matter how or where I drive?</i> Nope, just drive as you normally would.<br><i>What's a good USB-C adapter?</i> Any fast phone or laptop charger should be fine.<br><i>Do I need to be on Wi-Fi?</i> Yes.<br><i>Do I need to bring the device inside?</i> No, you can enable once you're parked, however your uploads will be limited by your car's battery.<br></source>
|
||||
<source>For maximum effectiveness, bring your device inside and connect to a good USB-C adapter and Wi-Fi weekly.<br><br>Firehose Mode can also work while you're driving if connected to a hotspot or unlimited SIM card.<br><br><br><b>Frequently Asked Questions</b><br><br><i>Does it matter how or where I drive?</i> Nope, just drive as you normally would.<br><br><i>What's a good USB-C adapter?</i> Any fast phone or laptop charger should be fine.<br><br><i>Does it matter which software I run?</i> Yes, only upstream openpilot (and particular forks) are able to be used for training.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>%1 %2</b> of your driving are in the training dataset so far.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>ACTIVE</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><span stylesheet='font-size: 60px; font-weight: bold; color: #e74c3c;'>INACTIVE</span>: connect to unmetered network</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
@@ -897,7 +905,7 @@ This may take up to a minute.</source>
|
||||
</message>
|
||||
<message>
|
||||
<source>Firehose</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>データ学習</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -1431,22 +1439,22 @@ This may take up to a minute.</source>
|
||||
</context>
|
||||
<context>
|
||||
<name>TermsPage</name>
|
||||
<message>
|
||||
<source>Terms & Conditions</source>
|
||||
<translation>利用規約</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Decline</source>
|
||||
<translation>拒否</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Scroll to accept</source>
|
||||
<translation>スクロールして同意</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Agree</source>
|
||||
<translation>同意</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Welcome to openpilot</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>You must accept the Terms and Conditions to use openpilot. Read the latest terms at <span style='color: #465BEA;'>https://comma.ai/terms</span> before continuing.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TogglesPanel</name>
|
||||
@@ -1606,15 +1614,15 @@ This may take up to a minute.</source>
|
||||
<name>WiFiPromptWidget</name>
|
||||
<message>
|
||||
<source>Open</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>開く</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Maximize your training data uploads to improve openpilot's driving models.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>openpilotの運転モデルを改善するために、大容量の学習データをアップロードして下さい。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><span style='font-family: "Noto Color Emoji";'>🔥</span> Firehose Mode <span style='font-family: Noto Color Emoji;'>🔥</span></source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation><span style='font-family: "Noto Color Emoji";'>🔥</span> Firehoseモード <span style='font-family: Noto Color Emoji;'>🔥</span></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
||||
@@ -121,27 +121,27 @@
|
||||
</message>
|
||||
<message>
|
||||
<source>Longitudinal Maneuver Mode</source>
|
||||
<translation>롱컨 기동 모드</translation>
|
||||
<translation>롱컨 제어 모드</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>openpilot Longitudinal Control (Alpha)</source>
|
||||
<translation type="unfinished">openpilot 가감속 제어 (알파)</translation>
|
||||
<translation>openpilot 가감속 제어 (알파)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB).</source>
|
||||
<translation type="unfinished">경고: openpilot 가감속 제어 알파 기능으로 차량의 자동긴급제동(AEB)을 비활성화합니다.</translation>
|
||||
<translation>경고: openpilot 가감속 제어 알파 기능으로 차량의 자동긴급제동(AEB)을 비활성화합니다.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>On this car, openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha.</source>
|
||||
<translation type="unfinished">이 차량은 openpilot 가감속 제어 대신 기본적으로 차량의 ACC로 가감속을 제어합니다. openpilot의 가감속 제어로 전환하려면 이 기능을 활성화하세요. openpilot 가감속 제어 알파를 활성화하는 경우 실험 모드 활성화를 권장합니다.</translation>
|
||||
<translation>이 차량은 openpilot 가감속 제어 대신 기본적으로 차량의 ACC로 가감속을 제어합니다. openpilot의 가감속 제어로 전환하려면 이 기능을 활성화하세요. openpilot 가감속 제어 알파를 활성화하는 경우 실험 모드 활성화를 권장합니다.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable ADB</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>ADB 사용</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>ADB (Android Debug Bridge) allows connecting to your device over USB or over the network. See https://docs.comma.ai/how-to/connect-to-comma for more info.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>ADB (안드로이드 디버그 브릿지) USB 또는 네트워크를 통해 장치에 연결할 수 있습니다. 자세한 내용은 https://docs.comma.ai/how-to/connect-to-comma를 참조하세요.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Hyundai: Enable Radar Tracks</source>
|
||||
@@ -419,24 +419,32 @@
|
||||
<name>FirehosePanel</name>
|
||||
<message>
|
||||
<source>🔥 Firehose Mode 🔥</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Firehose Mode</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>🔥 파이어호스 모드 🔥</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>openpilot learns to drive by watching humans, like you, drive.
|
||||
|
||||
Firehose Mode allows you to maximize your training data uploads to improve openpilot's driving models. More data means bigger models with better Experimental Mode.</source>
|
||||
Firehose Mode allows you to maximize your training data uploads to improve openpilot's driving models. More data means bigger models, which means better Experimental Mode.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>0%</source>
|
||||
<translation type="unfinished">5G {0%?}</translation>
|
||||
<source>Firehose Mode: ACTIVE</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Follow these steps to get your device ready:<br> 1. Bring your device inside and connect to a good USB-C adapter<br> 2. Connect to Wi-Fi<br> 3. Enable the toggle<br> 4. Leave it connected for at least 30 minutes<br><br>The toggle turns off once you restart your device. Repeat at least once a week for maximum effectiveness.<br><br><b>FAQ</b><br><i>Does it matter how or where I drive?</i> Nope, just drive as you normally would.<br><i>What's a good USB-C adapter?</i> Any fast phone or laptop charger should be fine.<br><i>Do I need to be on Wi-Fi?</i> Yes.<br><i>Do I need to bring the device inside?</i> No, you can enable once you're parked, however your uploads will be limited by your car's battery.<br></source>
|
||||
<source>For maximum effectiveness, bring your device inside and connect to a good USB-C adapter and Wi-Fi weekly.<br><br>Firehose Mode can also work while you're driving if connected to a hotspot or unlimited SIM card.<br><br><br><b>Frequently Asked Questions</b><br><br><i>Does it matter how or where I drive?</i> Nope, just drive as you normally would.<br><br><i>What's a good USB-C adapter?</i> Any fast phone or laptop charger should be fine.<br><br><i>Does it matter which software I run?</i> Yes, only upstream openpilot (and particular forks) are able to be used for training.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>%1 %2</b> of your driving are in the training dataset so far.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>ACTIVE</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><span stylesheet='font-size: 60px; font-weight: bold; color: #e74c3c;'>INACTIVE</span>: connect to unmetered network</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
@@ -897,7 +905,7 @@ This may take up to a minute.</source>
|
||||
</message>
|
||||
<message>
|
||||
<source>Firehose</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>파이어호스</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -1431,22 +1439,22 @@ This may take up to a minute.</source>
|
||||
</context>
|
||||
<context>
|
||||
<name>TermsPage</name>
|
||||
<message>
|
||||
<source>Terms & Conditions</source>
|
||||
<translation>이용약관</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Decline</source>
|
||||
<translation>거절</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Scroll to accept</source>
|
||||
<translation>동의하려면 아래로 스크롤하세요</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Agree</source>
|
||||
<translation>동의</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Welcome to openpilot</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>You must accept the Terms and Conditions to use openpilot. Read the latest terms at <span style='color: #465BEA;'>https://comma.ai/terms</span> before continuing.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TogglesPanel</name>
|
||||
@@ -1606,15 +1614,15 @@ This may take up to a minute.</source>
|
||||
<name>WiFiPromptWidget</name>
|
||||
<message>
|
||||
<source>Open</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>열기</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Maximize your training data uploads to improve openpilot's driving models.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>훈련 데이터 업로드를 최대화하여 오픈파일럿의 주행 모델을 개선하세요.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><span style='font-family: "Noto Color Emoji";'>🔥</span> Firehose Mode <span style='font-family: Noto Color Emoji;'>🔥</span></source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation><span style='font-family: "Noto Color Emoji";'>🔥</span> 파이어호스 모드 <span style='font-family: Noto Color Emoji;'>🔥</span></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
||||
@@ -419,24 +419,32 @@
|
||||
<name>FirehosePanel</name>
|
||||
<message>
|
||||
<source>🔥 Firehose Mode 🔥</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Firehose Mode</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>🔥 Mode Firehose 🔥</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>openpilot learns to drive by watching humans, like you, drive.
|
||||
|
||||
Firehose Mode allows you to maximize your training data uploads to improve openpilot's driving models. More data means bigger models with better Experimental Mode.</source>
|
||||
Firehose Mode allows you to maximize your training data uploads to improve openpilot's driving models. More data means bigger models, which means better Experimental Mode.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>0%</source>
|
||||
<translation type="unfinished">5G {0%?}</translation>
|
||||
<source>Firehose Mode: ACTIVE</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Follow these steps to get your device ready:<br> 1. Bring your device inside and connect to a good USB-C adapter<br> 2. Connect to Wi-Fi<br> 3. Enable the toggle<br> 4. Leave it connected for at least 30 minutes<br><br>The toggle turns off once you restart your device. Repeat at least once a week for maximum effectiveness.<br><br><b>FAQ</b><br><i>Does it matter how or where I drive?</i> Nope, just drive as you normally would.<br><i>What's a good USB-C adapter?</i> Any fast phone or laptop charger should be fine.<br><i>Do I need to be on Wi-Fi?</i> Yes.<br><i>Do I need to bring the device inside?</i> No, you can enable once you're parked, however your uploads will be limited by your car's battery.<br></source>
|
||||
<source>For maximum effectiveness, bring your device inside and connect to a good USB-C adapter and Wi-Fi weekly.<br><br>Firehose Mode can also work while you're driving if connected to a hotspot or unlimited SIM card.<br><br><br><b>Frequently Asked Questions</b><br><br><i>Does it matter how or where I drive?</i> Nope, just drive as you normally would.<br><br><i>What's a good USB-C adapter?</i> Any fast phone or laptop charger should be fine.<br><br><i>Does it matter which software I run?</i> Yes, only upstream openpilot (and particular forks) are able to be used for training.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>%1 %2</b> of your driving are in the training dataset so far.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>ACTIVE</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><span stylesheet='font-size: 60px; font-weight: bold; color: #e74c3c;'>INACTIVE</span>: connect to unmetered network</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
@@ -901,7 +909,7 @@ Isso pode levar até um minuto.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Firehose</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Firehose</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -1435,22 +1443,22 @@ Isso pode levar até um minuto.</translation>
|
||||
</context>
|
||||
<context>
|
||||
<name>TermsPage</name>
|
||||
<message>
|
||||
<source>Terms & Conditions</source>
|
||||
<translation>Termos & Condições</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Decline</source>
|
||||
<translation>Declinar</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Scroll to accept</source>
|
||||
<translation>Role a tela para aceitar</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Agree</source>
|
||||
<translation>Concordo</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Welcome to openpilot</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>You must accept the Terms and Conditions to use openpilot. Read the latest terms at <span style='color: #465BEA;'>https://comma.ai/terms</span> before continuing.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TogglesPanel</name>
|
||||
@@ -1610,15 +1618,15 @@ Isso pode levar até um minuto.</translation>
|
||||
<name>WiFiPromptWidget</name>
|
||||
<message>
|
||||
<source>Open</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Abrir</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Maximize your training data uploads to improve openpilot's driving models.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Maximize seus envios de dados de treinamento para melhorar os modelos de direção do openpilot.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><span style='font-family: "Noto Color Emoji";'>🔥</span> Firehose Mode <span style='font-family: Noto Color Emoji;'>🔥</span></source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation><span style='font-family: "Noto Color Emoji";'>🔥</span> Mode Firehose <span style='font-family: Noto Color Emoji;'>🔥</span></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
||||
@@ -421,22 +421,30 @@
|
||||
<source>🔥 Firehose Mode 🔥</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Firehose Mode</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>openpilot learns to drive by watching humans, like you, drive.
|
||||
|
||||
Firehose Mode allows you to maximize your training data uploads to improve openpilot's driving models. More data means bigger models with better Experimental Mode.</source>
|
||||
Firehose Mode allows you to maximize your training data uploads to improve openpilot's driving models. More data means bigger models, which means better Experimental Mode.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>0%</source>
|
||||
<translation type="unfinished">5G {0%?}</translation>
|
||||
<source>Firehose Mode: ACTIVE</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Follow these steps to get your device ready:<br> 1. Bring your device inside and connect to a good USB-C adapter<br> 2. Connect to Wi-Fi<br> 3. Enable the toggle<br> 4. Leave it connected for at least 30 minutes<br><br>The toggle turns off once you restart your device. Repeat at least once a week for maximum effectiveness.<br><br><b>FAQ</b><br><i>Does it matter how or where I drive?</i> Nope, just drive as you normally would.<br><i>What's a good USB-C adapter?</i> Any fast phone or laptop charger should be fine.<br><i>Do I need to be on Wi-Fi?</i> Yes.<br><i>Do I need to bring the device inside?</i> No, you can enable once you're parked, however your uploads will be limited by your car's battery.<br></source>
|
||||
<source>For maximum effectiveness, bring your device inside and connect to a good USB-C adapter and Wi-Fi weekly.<br><br>Firehose Mode can also work while you're driving if connected to a hotspot or unlimited SIM card.<br><br><br><b>Frequently Asked Questions</b><br><br><i>Does it matter how or where I drive?</i> Nope, just drive as you normally would.<br><br><i>What's a good USB-C adapter?</i> Any fast phone or laptop charger should be fine.<br><br><i>Does it matter which software I run?</i> Yes, only upstream openpilot (and particular forks) are able to be used for training.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>%1 %2</b> of your driving are in the training dataset so far.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>ACTIVE</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><span stylesheet='font-size: 60px; font-weight: bold; color: #e74c3c;'>INACTIVE</span>: connect to unmetered network</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
@@ -1431,22 +1439,22 @@ This may take up to a minute.</source>
|
||||
</context>
|
||||
<context>
|
||||
<name>TermsPage</name>
|
||||
<message>
|
||||
<source>Terms & Conditions</source>
|
||||
<translation>ข้อตกลงและเงื่อนไข</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Decline</source>
|
||||
<translation>ปฏิเสธ</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Scroll to accept</source>
|
||||
<translation>เลื่อนเพื่อตอบรับข้อตกลง</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Agree</source>
|
||||
<translation>ยอมรับ</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Welcome to openpilot</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>You must accept the Terms and Conditions to use openpilot. Read the latest terms at <span style='color: #465BEA;'>https://comma.ai/terms</span> before continuing.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TogglesPanel</name>
|
||||
|
||||
@@ -421,22 +421,30 @@
|
||||
<source>🔥 Firehose Mode 🔥</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Firehose Mode</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>openpilot learns to drive by watching humans, like you, drive.
|
||||
|
||||
Firehose Mode allows you to maximize your training data uploads to improve openpilot's driving models. More data means bigger models with better Experimental Mode.</source>
|
||||
Firehose Mode allows you to maximize your training data uploads to improve openpilot's driving models. More data means bigger models, which means better Experimental Mode.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>0%</source>
|
||||
<translation type="unfinished">5G {0%?}</translation>
|
||||
<source>Firehose Mode: ACTIVE</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Follow these steps to get your device ready:<br> 1. Bring your device inside and connect to a good USB-C adapter<br> 2. Connect to Wi-Fi<br> 3. Enable the toggle<br> 4. Leave it connected for at least 30 minutes<br><br>The toggle turns off once you restart your device. Repeat at least once a week for maximum effectiveness.<br><br><b>FAQ</b><br><i>Does it matter how or where I drive?</i> Nope, just drive as you normally would.<br><i>What's a good USB-C adapter?</i> Any fast phone or laptop charger should be fine.<br><i>Do I need to be on Wi-Fi?</i> Yes.<br><i>Do I need to bring the device inside?</i> No, you can enable once you're parked, however your uploads will be limited by your car's battery.<br></source>
|
||||
<source>For maximum effectiveness, bring your device inside and connect to a good USB-C adapter and Wi-Fi weekly.<br><br>Firehose Mode can also work while you're driving if connected to a hotspot or unlimited SIM card.<br><br><br><b>Frequently Asked Questions</b><br><br><i>Does it matter how or where I drive?</i> Nope, just drive as you normally would.<br><br><i>What's a good USB-C adapter?</i> Any fast phone or laptop charger should be fine.<br><br><i>Does it matter which software I run?</i> Yes, only upstream openpilot (and particular forks) are able to be used for training.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>%1 %2</b> of your driving are in the training dataset so far.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>ACTIVE</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><span stylesheet='font-size: 60px; font-weight: bold; color: #e74c3c;'>INACTIVE</span>: connect to unmetered network</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
@@ -1429,22 +1437,22 @@ This may take up to a minute.</source>
|
||||
</context>
|
||||
<context>
|
||||
<name>TermsPage</name>
|
||||
<message>
|
||||
<source>Terms & Conditions</source>
|
||||
<translation>Şartlar ve Koşullar</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Decline</source>
|
||||
<translation>Reddet</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Scroll to accept</source>
|
||||
<translation>Kabul etmek için kaydırın</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Agree</source>
|
||||
<translation>Kabul et</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Welcome to openpilot</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>You must accept the Terms and Conditions to use openpilot. Read the latest terms at <span style='color: #465BEA;'>https://comma.ai/terms</span> before continuing.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TogglesPanel</name>
|
||||
|
||||
@@ -419,24 +419,32 @@
|
||||
<name>FirehosePanel</name>
|
||||
<message>
|
||||
<source>🔥 Firehose Mode 🔥</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Firehose Mode</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>🔥 训练数据上传模式 🔥</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>openpilot learns to drive by watching humans, like you, drive.
|
||||
|
||||
Firehose Mode allows you to maximize your training data uploads to improve openpilot's driving models. More data means bigger models with better Experimental Mode.</source>
|
||||
Firehose Mode allows you to maximize your training data uploads to improve openpilot's driving models. More data means bigger models, which means better Experimental Mode.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>0%</source>
|
||||
<translation type="unfinished">5G {0%?}</translation>
|
||||
<source>Firehose Mode: ACTIVE</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Follow these steps to get your device ready:<br> 1. Bring your device inside and connect to a good USB-C adapter<br> 2. Connect to Wi-Fi<br> 3. Enable the toggle<br> 4. Leave it connected for at least 30 minutes<br><br>The toggle turns off once you restart your device. Repeat at least once a week for maximum effectiveness.<br><br><b>FAQ</b><br><i>Does it matter how or where I drive?</i> Nope, just drive as you normally would.<br><i>What's a good USB-C adapter?</i> Any fast phone or laptop charger should be fine.<br><i>Do I need to be on Wi-Fi?</i> Yes.<br><i>Do I need to bring the device inside?</i> No, you can enable once you're parked, however your uploads will be limited by your car's battery.<br></source>
|
||||
<source>For maximum effectiveness, bring your device inside and connect to a good USB-C adapter and Wi-Fi weekly.<br><br>Firehose Mode can also work while you're driving if connected to a hotspot or unlimited SIM card.<br><br><br><b>Frequently Asked Questions</b><br><br><i>Does it matter how or where I drive?</i> Nope, just drive as you normally would.<br><br><i>What's a good USB-C adapter?</i> Any fast phone or laptop charger should be fine.<br><br><i>Does it matter which software I run?</i> Yes, only upstream openpilot (and particular forks) are able to be used for training.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>%1 %2</b> of your driving are in the training dataset so far.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>ACTIVE</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><span stylesheet='font-size: 60px; font-weight: bold; color: #e74c3c;'>INACTIVE</span>: connect to unmetered network</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
@@ -897,7 +905,7 @@ This may take up to a minute.</source>
|
||||
</message>
|
||||
<message>
|
||||
<source>Firehose</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>训练上传</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -1431,22 +1439,22 @@ This may take up to a minute.</source>
|
||||
</context>
|
||||
<context>
|
||||
<name>TermsPage</name>
|
||||
<message>
|
||||
<source>Terms & Conditions</source>
|
||||
<translation>条款和条件</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Decline</source>
|
||||
<translation>拒绝</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Scroll to accept</source>
|
||||
<translation>滑动以接受</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Agree</source>
|
||||
<translation>同意</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Welcome to openpilot</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>You must accept the Terms and Conditions to use openpilot. Read the latest terms at <span style='color: #465BEA;'>https://comma.ai/terms</span> before continuing.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TogglesPanel</name>
|
||||
@@ -1606,15 +1614,15 @@ This may take up to a minute.</source>
|
||||
<name>WiFiPromptWidget</name>
|
||||
<message>
|
||||
<source>Open</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>开启</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Maximize your training data uploads to improve openpilot's driving models.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>最大化您的训练数据上传,以改善 openpilot 的驾驶模型。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><span style='font-family: "Noto Color Emoji";'>🔥</span> Firehose Mode <span style='font-family: Noto Color Emoji;'>🔥</span></source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation><span style='font-family: "Noto Color Emoji";'>🔥</span> 训练数据上传模式 <span style='font-family: Noto Color Emoji;'>🔥</span></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
||||
@@ -419,24 +419,32 @@
|
||||
<name>FirehosePanel</name>
|
||||
<message>
|
||||
<source>🔥 Firehose Mode 🔥</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable Firehose Mode</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>🔥 訓練資料上傳模式 🔥</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>openpilot learns to drive by watching humans, like you, drive.
|
||||
|
||||
Firehose Mode allows you to maximize your training data uploads to improve openpilot's driving models. More data means bigger models with better Experimental Mode.</source>
|
||||
Firehose Mode allows you to maximize your training data uploads to improve openpilot's driving models. More data means bigger models, which means better Experimental Mode.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>0%</source>
|
||||
<translation type="unfinished">5G {0%?}</translation>
|
||||
<source>Firehose Mode: ACTIVE</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Follow these steps to get your device ready:<br> 1. Bring your device inside and connect to a good USB-C adapter<br> 2. Connect to Wi-Fi<br> 3. Enable the toggle<br> 4. Leave it connected for at least 30 minutes<br><br>The toggle turns off once you restart your device. Repeat at least once a week for maximum effectiveness.<br><br><b>FAQ</b><br><i>Does it matter how or where I drive?</i> Nope, just drive as you normally would.<br><i>What's a good USB-C adapter?</i> Any fast phone or laptop charger should be fine.<br><i>Do I need to be on Wi-Fi?</i> Yes.<br><i>Do I need to bring the device inside?</i> No, you can enable once you're parked, however your uploads will be limited by your car's battery.<br></source>
|
||||
<source>For maximum effectiveness, bring your device inside and connect to a good USB-C adapter and Wi-Fi weekly.<br><br>Firehose Mode can also work while you're driving if connected to a hotspot or unlimited SIM card.<br><br><br><b>Frequently Asked Questions</b><br><br><i>Does it matter how or where I drive?</i> Nope, just drive as you normally would.<br><br><i>What's a good USB-C adapter?</i> Any fast phone or laptop charger should be fine.<br><br><i>Does it matter which software I run?</i> Yes, only upstream openpilot (and particular forks) are able to be used for training.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>%1 %2</b> of your driving are in the training dataset so far.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>ACTIVE</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><span stylesheet='font-size: 60px; font-weight: bold; color: #e74c3c;'>INACTIVE</span>: connect to unmetered network</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
@@ -897,7 +905,7 @@ This may take up to a minute.</source>
|
||||
</message>
|
||||
<message>
|
||||
<source>Firehose</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>訓練上傳</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -1431,22 +1439,22 @@ This may take up to a minute.</source>
|
||||
</context>
|
||||
<context>
|
||||
<name>TermsPage</name>
|
||||
<message>
|
||||
<source>Terms & Conditions</source>
|
||||
<translation>條款和條件</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Decline</source>
|
||||
<translation>拒絕</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Scroll to accept</source>
|
||||
<translation>滑動至頁尾接受條款</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Agree</source>
|
||||
<translation>接受</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Welcome to openpilot</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>You must accept the Terms and Conditions to use openpilot. Read the latest terms at <span style='color: #465BEA;'>https://comma.ai/terms</span> before continuing.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TogglesPanel</name>
|
||||
@@ -1606,15 +1614,15 @@ This may take up to a minute.</source>
|
||||
<name>WiFiPromptWidget</name>
|
||||
<message>
|
||||
<source>Open</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>開啟</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Maximize your training data uploads to improve openpilot's driving models.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>最大化您的訓練數據上傳,以改善 openpilot 的駕駛模型。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><span style='font-family: "Noto Color Emoji";'>🔥</span> Firehose Mode <span style='font-family: Noto Color Emoji;'>🔥</span></source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation><span style='font-family: "Noto Color Emoji";'>🔥</span> 訓練資料上傳模式 <span style='font-family: Noto Color Emoji;'>🔥</span></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
||||
Reference in New Issue
Block a user