diff --git a/OPEDIT_FEATURES.md b/OPEDIT_FEATURES.md index 750d18811815bc..0ef1a2c1f391e3 100644 --- a/OPEDIT_FEATURES.md +++ b/OPEDIT_FEATURES.md @@ -1,12 +1,15 @@ # opEdit Features: - You can misspell parameter names and opEdit should be able to figure out which parameter you want. Ex. `cmra off` would be parsed as: `camera_offset` - You can also still enter the corresponding parameter index while choosing parameters to edit -- Type `a` to add a parameter, `d` to delete a parameter, or `l` to toggle live tuning only mode +- Type `l` to toggle live tuning only mode, which only shows params that update within a second - Shows a detailed description for each parameter once you choose it - Parameter value type restriction. Ensures a user cannot save an unsupported value type for any parameters, breaking the fork - Remembers which mode you were last in and initializes opEdit with that mode (live tuning or not) -- Case insensitive boolean and NoneType entrance. Type `faLsE` to save `False (bool)`, etc -- **Parameters marked with `(live!)` will have updates take affect within 3 seconds while driving! All other params will require a reboot of your EON/C2 to take effect.** +- Case-insensitive boolean and NoneType entrance. Type `faLsE` to save `False (bool)`, etc + +## ❗NEW❗: +- **Now, any parameter that isn't marked with `(static)` can update while driving and onroad. Only the parameters in the "live" view update within a second, the rest update within 10 seconds. If you enter a parameter, it will tell you its update behavior** +- As before, static parameters will need a reboot of the device, or ignition in some cases. ## To run the opEdit parameter manager: ```python diff --git a/README.md b/README.md index a727d7cad6467b..f65e6996c5dcb3 100644 --- a/README.md +++ b/README.md @@ -126,6 +126,8 @@ python op_edit.py # or ./op_edit.py [**To see what features opEdit has, click me!**](/OPEDIT_FEATURES.md) +πŸ†• All params now update live while driving, and params that are marked with `static` need a reboot of the device, or ignition. + Here are the main parameters you can change with this fork: - **Tuning params**: - `camera_offset` **`(live!)`**: Your camera offset to use in lane_planner.py. Helps fix lane hugging diff --git a/SA_RELEASES.md b/SA_RELEASES.md index 94037ea19c2095..fb3660c5feefb3 100644 --- a/SA_RELEASES.md +++ b/SA_RELEASES.md @@ -7,6 +7,8 @@ Stock Additions v0.6.6 - 2020-02-27 (0.8.2) * Roadtrip profile is now stock longitudinal for smoother road trips * No dynamic follow distance modiciations, all stock * Add color corrections button, PR by ihsakashi + * More parameters now update while driving. + * If the param isn't marked with "static" you no longer have to reboot Stock Additions v0.6.5 - 2020-12-07 (0.8) === diff --git a/common/op_params.py b/common/op_params.py index 650a151cd1066f..763d7aa90dc535 100644 --- a/common/op_params.py +++ b/common/op_params.py @@ -2,30 +2,35 @@ import os import json from common.colors import COLORS +from common.travis_checker import BASEDIR try: from common.realtime import sec_since_boot except ImportError: import time sec_since_boot = time.time -travis = False # replace with travis_checker if you use travis or GitHub Actions - -def warning(msg): print('{}opParams WARNING: {}{}'.format(COLORS.WARNING, msg, COLORS.ENDC)) -def error(msg): print('{}opParams ERROR: {}{}'.format(COLORS.FAIL, msg, COLORS.ENDC)) +warning = lambda msg: print('{}opParams WARNING: {}{}'.format(COLORS.WARNING, msg, COLORS.ENDC)) +error = lambda msg: print('{}opParams ERROR: {}{}'.format(COLORS.FAIL, msg, COLORS.ENDC)) NUMBER = [float, int] # value types NONE_OR_NUMBER = [type(None), float, int] +BASEDIR = os.path.dirname(BASEDIR) +PARAMS_DIR = os.path.join(BASEDIR, 'community', 'params') +IMPORTED_PATH = os.path.join(PARAMS_DIR, '.imported') +OLD_PARAMS_FILE = os.path.join(BASEDIR, 'op_params.json') + class Param: - def __init__(self, default=None, allowed_types=[], description=None, live=False, hidden=False): - self.default = default # value first saved and returned if actual value isn't a valid type + def __init__(self, default, allowed_types=[], description=None, *, static=False, live=False, hidden=False): + self.default_value = default # value first saved and returned if actual value isn't a valid type if not isinstance(allowed_types, list): allowed_types = [allowed_types] self.allowed_types = allowed_types # allowed python value types for opEdit self.description = description # description to be shown in opEdit - self.hidden = hidden # hide this param to user in opEdit? - self.live = live # whether opParams re-reads json file every time this param is .get + self.hidden = hidden # hide this param to user in opEdit + self.live = live # show under the live menu in opEdit + self.static = static # use cached value, never reads to update self._create_attrs() def is_valid(self, value): @@ -37,12 +42,45 @@ def _create_attrs(self): # Create attributes and check Param is valid self.has_allowed_types = isinstance(self.allowed_types, list) and len(self.allowed_types) > 0 self.has_description = self.description is not None self.is_list = list in self.allowed_types + self.read_frequency = None if self.static else (1 if self.live else 10) # how often to read param file (sec) + self.last_read = -1 if self.has_allowed_types: - assert type(self.default) in self.allowed_types, 'Default value type must be in specified allowed_types!' + assert type(self.default_value) in self.allowed_types, 'Default value type must be in specified allowed_types!' if self.is_list: self.allowed_types.remove(list) +def _read_param(key): # Returns None, False if a json error occurs + try: + with open(os.path.join(PARAMS_DIR, key), 'r') as f: + value = json.loads(f.read()) + return value, True + except json.decoder.JSONDecodeError: + return None, False + + +def _write_param(key, value): + tmp = os.path.join(PARAMS_DIR, '.' + key) + with open(tmp, 'w') as f: + f.write(json.dumps(value)) + f.flush() + os.fsync(f.fileno()) + os.rename(tmp, os.path.join(PARAMS_DIR, key)) + os.chmod(os.path.join(PARAMS_DIR, key), 0o777) + + +def _import_params(): + if os.path.exists(OLD_PARAMS_FILE) and not os.path.exists(IMPORTED_PATH): # if opParams needs to import from old params file + try: + with open(OLD_PARAMS_FILE, 'r') as f: + old_params = json.loads(f.read()) + for key in old_params: + _write_param(key, old_params[key]) + open(IMPORTED_PATH, 'w').close() + except: + pass + + class opParams: def __init__(self): """ @@ -50,19 +88,19 @@ def __init__(self): The allowed_types and description args are not required but highly recommended to help users edit their parameters with opEdit safely. - The description value will be shown to users when they use opEdit to change the value of the parameter. - The allowed_types arg is used to restrict what kinds of values can be entered with opEdit so that users can't crash openpilot with unintended behavior. - (setting a param intended to be a number with a boolean, or viceversa for example) + (setting a param intended to be a number with a boolean, or viceversa for example) Limiting the range of floats or integers is still recommended when `.get`ting the parameter. When a None value is allowed, use `type(None)` instead of None, as opEdit checks the type against the values in the arg with `isinstance()`. - - Finally, the live arg tells both opParams and opEdit that it's a live parameter that will change. Therefore, you must place the `op_params.get()` call in the update function so that it can update. + - If you want your param to update within a second, specify live=True. If your param is designed to be read once, specify static=True. + Specifying neither will have the param update every 10 seconds if constantly .get() + If the param is not static, call the .get() function on it in the update function of the file you're reading from to use live updating Here's an example of a good fork_param entry: - self.fork_params = {'camera_offset': Param(default=0.06, allowed_types=NUMBER), live=True} # NUMBER allows both floats and ints + self.fork_params = {'camera_offset': Param(0.06, allowed_types=NUMBER), live=True} # NUMBER allows both floats and ints """ self.fork_params = {'camera_offset': Param(0.06, NUMBER, 'Your camera offset to use in lane_planner.py', live=True), - 'dynamic_follow': Param('auto', str, 'Can be: (\'traffic\', \'relaxed\', \'stock\'): Left to right increases in following distance.\n' - 'All profiles support dynamic follow except stock so you\'ll get your preferred distance while\n' - 'retaining the smoothness and safety of dynamic follow!'), + 'dynamic_follow': Param('auto', str, static=True, hidden=True), 'global_df_mod': Param(1.0, NUMBER, 'The multiplier for the current distance used by dynamic follow. The range is limited from 0.85 to 2.5\n' 'Smaller values will get you closer, larger will get you farther\n' 'This is multiplied by any profile that\'s active. Set to 1. to disable', live=True), @@ -81,136 +119,105 @@ def __init__(self): 'disengage_on_gas': Param(False, bool, 'Whether you want openpilot to disengage on gas input or not'), 'update_behavior': Param('auto', str, 'Can be: (\'off\', \'alert\', \'auto\') without quotes\n' 'off will never update, alert shows an alert on-screen\n' - 'auto will reboot the device when an update is seen'), + 'auto will reboot the device when an update is seen', static=True), 'dynamic_gas': Param(False, bool, 'Whether to use dynamic gas if your car is supported'), 'hide_auto_df_alerts': Param(False, bool, 'Hides the alert that shows what profile the model has chosen'), - 'log_auto_df': Param(False, bool, 'Logs dynamic follow data for auto-df'), + 'log_auto_df': Param(False, bool, 'Logs dynamic follow data for auto-df', static=True), # 'dynamic_camera_offset': Param(False, bool, 'Whether to automatically keep away from oncoming traffic.\n' # 'Works from 35 to ~60 mph (requires radar)'), # 'dynamic_camera_offset_time': Param(3.5, NUMBER, 'How long to keep away from oncoming traffic in seconds after losing lead'), 'support_white_panda': Param(False, bool, 'Enable this to allow engagement with the deprecated white panda.\n' - 'localizer might not work correctly'), - 'disable_charging': Param(30, NUMBER, 'How many hours until charging is disabled while idle'), + 'localizer might not work correctly', static=True), + 'disable_charging': Param(30, NUMBER, 'How many hours until charging is disabled while idle', static=True), 'prius_use_pid': Param(False, bool, 'This enables the PID lateral controller with new a experimental derivative tune\n' - 'False: stock INDI, True: TSS2-tuned PID'), - 'use_lqr': Param(False, bool, 'Enable this to use LQR as your lateral controller over default with any car'), - 'corollaTSS2_use_indi': Param(False, bool, 'Enable this to use INDI for lat with your TSS2 Corolla'), - 'rav4TSS2_use_indi': Param(False, bool, 'Enable this to use INDI for lat with your TSS2 RAV4'), - 'standstill_hack': Param(False, bool, 'Some cars support stop and go, you just need to enable this')} - - self._params_file = '/data/op_params.json' - self._backup_file = '/data/op_params_corrupt.json' - self._last_read_time = sec_since_boot() - self.read_frequency = 3 # max frequency to read with self.get(...) (sec) - self._to_delete = ['steer_rate_fix'] # a list of unused params you want to delete from users' params file - self._to_reset = ['dynamic_gas'] # a list of params you want reset to their default values + 'False: stock INDI, True: TSS2-tuned PID', static=True), + 'use_lqr': Param(False, bool, 'Enable this to use LQR as your lateral controller over default with any car', static=True), + 'corollaTSS2_use_indi': Param(False, bool, 'Enable this to use INDI for lat with your TSS2 Corolla', static=True), + 'rav4TSS2_use_indi': Param(False, bool, 'Enable this to use INDI for lat with your TSS2 RAV4', static=True), + 'standstill_hack': Param(False, bool, 'Some cars support stop and go, you just need to enable this', static=True)} + + self._to_delete = ['steer_rate_fix', 'uniqueID'] # a list of unused params you want to delete from users' params file + self._to_reset = [] # a list of params you want reset to their default values self._run_init() # restores, reads, and updates params def _run_init(self): # does first time initializing of default params # Two required parameters for opEdit self.fork_params['username'] = Param(None, [type(None), str, bool], 'Your identifier provided with any crash logs sent to Sentry.\nHelps the developer reach out to you if anything goes wrong') self.fork_params['op_edit_live_mode'] = Param(False, bool, 'This parameter controls which mode opEdit starts in', hidden=True) - self.params = self._get_all_params(default=True) # start at default values in case file is corrupted - - if travis: - return - - if os.path.isfile(self._params_file): - if self._read(): - to_write = self._add_default_params() # if new default data has been added - to_write |= self._delete_and_reset() # or if old params have been deleted - else: # backup and re-create params file - error("Can't read op_params.json file, backing up to /data/op_params_corrupt.json and re-creating file!") - to_write = True - if os.path.isfile(self._backup_file): - os.remove(self._backup_file) - os.rename(self._params_file, self._backup_file) - else: - to_write = True # user's first time running a fork with op_params, write default params - - if to_write: - self._write() - os.chmod(self._params_file, 0o764) - - def get(self, key=None, force_live=False): # key=None is dict of all params - if key is None: - return self._get_all_params(to_update=force_live) + self.params = self._load_params(can_import=True) + self._add_default_params() # adds missing params and resets values with invalid types to self.params + self._delete_and_reset() # removes old params + + def get(self, key=None, *, force_update=False): # key=None returns dict of all params + if key is None: + return self._get_all_params(to_update=force_update) self._check_key_exists(key, 'get') param_info = self.fork_params[key] - self._update_params(param_info.live or force_live) + rate = param_info.read_frequency # will be None if param is static, so check below + + if (not param_info.static and sec_since_boot() - self.fork_params[key].last_read >= rate) or force_update: + value, success = _read_param(key) + self.fork_params[key].last_read = sec_since_boot() + if not success: # in case of read error, use default and overwrite param + value = param_info.default_value + _write_param(key, value) + self.params[key] = value if param_info.is_valid(value := self.params[key]): return value # all good, returning user's value - - warning('User\'s value type is not valid! Returning default') # somehow... it should always be valid - return param_info.default # return default value because user's value of key is not in allowed_types to avoid crashing openpilot + print(warning('User\'s value type is not valid! Returning default')) # somehow... it should always be valid + return param_info.default_value # return default value because user's value of key is not in allowed_types to avoid crashing openpilot def put(self, key, value): self._check_key_exists(key, 'put') if not self.fork_params[key].is_valid(value): raise Exception('opParams: Tried to put a value of invalid type!') self.params.update({key: value}) - self._write() - - def delete(self, key): # todo: might be obsolete. remove? - if key in self.params: - del self.params[key] - self._write() + _write_param(key, value) + + def _load_params(self, can_import=False): + if not os.path.exists(PARAMS_DIR): + os.makedirs(PARAMS_DIR) + if can_import: + _import_params() # just imports old params. below we read them in + + params = {} + for key in os.listdir(PARAMS_DIR): # PARAMS_DIR is guaranteed to exist + if key.startswith('.') or key not in self.fork_params: + continue + value, success = _read_param(key) + if not success: + value = self.fork_params[key].default_value + _write_param(key, value) + params[key] = value + return params + + def _get_all_params(self, to_update=False): + if to_update: + self.params = self._load_params() + return {k: self.params[k] for k, p in self.fork_params.items() if k in self.params and not p.hidden} def _check_key_exists(self, key, met): if key not in self.fork_params: raise Exception('opParams: Tried to {} an unknown parameter! Key not in fork_params: {}'.format(met, key)) def _add_default_params(self): - added = False for key, param in self.fork_params.items(): if key not in self.params: - self.params[key] = param.default - added = True + self.params[key] = param.default_value + _write_param(key, self.params[key]) elif not param.is_valid(self.params[key]): - warning('Value type of user\'s {} param not in allowed types, replacing with default!'.format(key)) - self.params[key] = param.default - added = True - return added + print(warning('Value type of user\'s {} param not in allowed types, replacing with default!'.format(key))) + self.params[key] = param.default_value + _write_param(key, self.params[key]) def _delete_and_reset(self): - needs_write = False - for param in list(self.params): - if param in self._to_delete: - del self.params[param] - needs_write = True - elif param in self._to_reset and param in self.fork_params: - print('resetting {} to {} from {}'.format(param, self.fork_params[param].default, self.params[param])) - self.params[param] = self.fork_params[param].default - needs_write = True - return needs_write - - def _get_all_params(self, default=False, return_hidden=False, to_update=False): - self._update_params(to_update) - if default: - return {k: p.default for k, p in self.fork_params.items()} - return {k: self.params[k] for k, p in self.fork_params.items() if k in self.params and (not p.hidden or return_hidden)} - - def _update_params(self, to_update): - if not travis and sec_since_boot() - self._last_read_time >= self.read_frequency and to_update: # make sure we aren't reading file too often - if self._read(): - self._last_read_time = sec_since_boot() - - def __getitem__(self, s): # can also do op_params['param_name'] - return self.get(s) - - def _read(self): - try: - with open(self._params_file, "r") as f: - self.params = json.loads(f.read()) - return True - except Exception as e: - error(e) - return False - - def _write(self): - if not travis: - with open(self._params_file, "w") as f: - f.write(json.dumps(self.params, indent=2)) # can further speed it up by remove indentation but makes file hard to read + for key in list(self.params): + if key in self._to_delete: + del self.params[key] + os.remove(os.path.join(PARAMS_DIR, key)) + elif key in self._to_reset and key in self.fork_params: + self.params[key] = self.fork_params[key].default_value + _write_param(key, self.params[key]) diff --git a/common/travis_checker.py b/common/travis_checker.py index 74f2d256d07d43..2eba1689e66c70 100644 --- a/common/travis_checker.py +++ b/common/travis_checker.py @@ -1,2 +1,3 @@ -from common.basedir import BASEDIR +import os +BASEDIR = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), "../")) travis = BASEDIR.strip('/').split('/')[0] != 'data' diff --git a/op_edit.py b/op_edit.py index 39b8763946cc66..bf7ff7a60e79cd 100755 --- a/op_edit.py +++ b/op_edit.py @@ -24,36 +24,38 @@ def __init__(self): def run_init(self): if self.username is None: - self.success('\nWelcome to the opParams command line editor!', sleep_time=0) - self.prompt('Parameter \'username\' is missing! Would you like to add your Discord username for easier crash debugging?') + self.success('\nWelcome to the {}opParams{} command line editor!'.format(COLORS.CYAN, COLORS.SUCCESS), sleep_time=0) + self.prompt('Would you like to add your Discord username for easier crash debugging for the fork owner?') + self.prompt('Your username is only used for reaching out if a crash occurs.') username_choice = self.input_with_options(['Y', 'n', 'don\'t ask again'], default='n')[0] if username_choice == 0: - self.prompt('Please enter your Discord username so the developers can reach out if a crash occurs:') + self.prompt('Enter a unique identifer/Discord username:') username = '' while username == '': username = input('>> ').strip() - self.success('Thanks! Saved your Discord username\n' - 'Edit the \'username\' parameter at any time to update', sleep_time=1.0) self.op_params.put('username', username) self.username = username + self.success('Thanks! Saved your username\n' + 'Edit the \'username\' parameter at any time to update', sleep_time=1.5) elif username_choice == 2: self.op_params.put('username', False) self.info('Got it, bringing you into opEdit\n' 'Edit the \'username\' parameter at any time to update', sleep_time=1.0) else: - self.success('\nWelcome to the opParams command line editor, {}!'.format(self.username), sleep_time=0) + self.success('\nWelcome to the {}opParams{} command line editor, {}!'.format(COLORS.CYAN, COLORS.SUCCESS, self.username), sleep_time=0) self.run_loop() def run_loop(self): while True: if not self.live_tuning: - self.info('Here are your parameters:', end='\n', sleep_time=0) + self.info('Here are all your parameters:', sleep_time=0) + self.info('(non-static params update while driving)', end='\n', sleep_time=0) else: self.info('Here are your live parameters:', sleep_time=0) - self.info('(changes take effect within {} seconds)'.format(self.op_params.read_frequency), end='\n', sleep_time=0) - self.params = self.op_params.get(force_live=True) + self.info('(changes take effect within a second)', end='\n', sleep_time=0) + self.params = self.op_params.get(force_update=True) if self.live_tuning: # only display live tunable params self.params = {k: v for k, v in self.params.items() if self.op_params.fork_params[k].live} @@ -70,12 +72,12 @@ def run_loop(self): v = '{} ... {}'.format(str(v)[:30], str(v)[-15:]) values_list.append(v) - live = [COLORS.INFO + '(live!)' + COLORS.ENDC if self.op_params.fork_params[k].live else '' for k in self.params] + static = [COLORS.INFO + '(static)' + COLORS.ENDC if self.op_params.fork_params[k].static else '' for k in self.params] to_print = [] blue_gradient = [33, 39, 45, 51, 87] for idx, param in enumerate(self.params): - line = '{}. {}: {} {}'.format(idx + 1, param, values_list[idx], live[idx]) + line = '{}. {}: {} {}'.format(idx + 1, param, values_list[idx], static[idx]) if idx == self.last_choice and self.last_choice is not None: line = COLORS.OKGREEN + line else: @@ -83,7 +85,7 @@ def run_loop(self): line = COLORS.BASE(_color) + line to_print.append(line) - extras = {'l': ('Toggle live tuning', COLORS.WARNING), + extras = {'l': ('Toggle live params', COLORS.WARNING), 'e': ('Exit opEdit', COLORS.PINK)} to_print += ['---'] + ['{}. {}'.format(ext_col + e, ext_txt + COLORS.ENDC) for e, (ext_txt, ext_col) in extras.items()] @@ -137,14 +139,18 @@ def change_parameter(self, choice): param_info = self.op_params.fork_params[chosen_key] old_value = self.params[chosen_key] - if param_info.live: + if not param_info.static: self.info2('Chosen parameter: {}{} (live!)'.format(chosen_key, COLORS.BASE(207)), sleep_time=0) else: - self.info2('Chosen parameter: {}'.format(chosen_key), sleep_time=0) + self.info2('Chosen parameter: {}{} (static)'.format(chosen_key, COLORS.BASE(207)), sleep_time=0) to_print = [] if param_info.has_description: to_print.append(COLORS.OKGREEN + '>> Description: {}'.format(param_info.description.replace('\n', '\n > ')) + COLORS.ENDC) + if param_info.static: + to_print.append(COLORS.WARNING + '>> A reboot is required for changes to this parameter!' + COLORS.ENDC) + if not param_info.static and not param_info.live: + to_print.append(COLORS.WARNING + '>> Changes take effect within 10 seconds for this parameter!' + COLORS.ENDC) if param_info.has_allowed_types: to_print.append(COLORS.RED + '>> Allowed types: {}'.format(', '.join([at.__name__ for at in param_info.allowed_types])) + COLORS.ENDC) @@ -175,7 +181,7 @@ def change_parameter(self, choice): self.error('The type of data you entered ({}) is not allowed with this parameter!'.format(type(new_value).__name__)) continue - if param_info.live: # stay in live tuning interface + if not param_info.static: # stay in live tuning interface self.op_params.put(chosen_key, new_value) self.success('Saved {} with value: {}! (type: {})'.format(chosen_key, new_value, type(new_value).__name__)) else: # else ask to save and break diff --git a/selfdrive/car/interfaces.py b/selfdrive/car/interfaces.py index 5abcca435dae83..b730393b45f502 100644 --- a/selfdrive/car/interfaces.py +++ b/selfdrive/car/interfaces.py @@ -23,7 +23,7 @@ class CarInterfaceBase(): def __init__(self, CP, CarController, CarState): self.CP = CP self.VM = VehicleModel(CP) - self.disengage_on_gas = opParams().get('disengage_on_gas') + self.op_params = opParams() self.frame = 0 self.low_speed_alert = False @@ -108,7 +108,7 @@ def create_common_events(self, cs_out, extra_gears=[], gas_resume_speed=-1, pcm_ events.add(EventName.wrongCarMode) if cs_out.espDisabled: events.add(EventName.espDisabled) - if cs_out.gasPressed and self.disengage_on_gas: + if cs_out.gasPressed and self.op_params.get('disengage_on_gas'): events.add(EventName.gasPressed) if cs_out.stockFcw: events.add(EventName.stockFcw) @@ -127,7 +127,7 @@ def create_common_events(self, cs_out, extra_gears=[], gas_resume_speed=-1, pcm_ # Disable on rising edge of gas or brake. Also disable on brake when speed > 0. # Optionally allow to press gas at zero speed to resume. # e.g. Chrysler does not spam the resume button yet, so resuming with gas is handy. FIXME! - if (self.disengage_on_gas and cs_out.gasPressed and (not self.CS.out.gasPressed) and cs_out.vEgo > gas_resume_speed) or \ + if (self.op_params.get('disengage_on_gas') and cs_out.gasPressed and (not self.CS.out.gasPressed) and cs_out.vEgo > gas_resume_speed) or \ (cs_out.brakePressed and (not self.CS.out.brakePressed or not cs_out.standstill)): events.add(EventName.pedalPressed) diff --git a/selfdrive/car/toyota/interface.py b/selfdrive/car/toyota/interface.py index 6e1eb0a5709894..92cf6b0db46ffd 100755 --- a/selfdrive/car/toyota/interface.py +++ b/selfdrive/car/toyota/interface.py @@ -7,11 +7,6 @@ from selfdrive.car.interfaces import CarInterfaceBase from common.op_params import opParams -op_params = opParams() -use_lqr = op_params.get('use_lqr') -prius_use_pid = False # op_params.get('prius_use_pid') -corollaTSS2_use_indi = False # op_params.get('corollaTSS2_use_indi') -rav4TSS2_use_indi = op_params.get('rav4TSS2_use_indi') EventName = car.CarEvent.EventName @@ -22,6 +17,12 @@ def compute_gb(accel, speed): @staticmethod def get_params(candidate, fingerprint=gen_empty_fingerprint(), has_relay=False, car_fw=[]): # pylint: disable=dangerous-default-value + op_params = opParams() + use_lqr = op_params.get('use_lqr') + prius_use_pid = False # op_params.get('prius_use_pid') + corollaTSS2_use_indi = False # op_params.get('corollaTSS2_use_indi') + rav4TSS2_use_indi = op_params.get('rav4TSS2_use_indi') + ret = CarInterfaceBase.get_std_params(candidate, fingerprint, has_relay) ret.carName = "toyota" diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py index eba44f0ef0b6db..11ddd466fea2e6 100755 --- a/selfdrive/controls/controlsd.py +++ b/selfdrive/controls/controlsd.py @@ -77,8 +77,7 @@ def __init__(self, sm=None, pm=None, can_sock=None): 'laneSpeed', 'dynamicCameraOffset', 'modelLongButton']) self.op_params = opParams() - self.df_manager = dfManager(self.op_params) - self.hide_auto_df_alerts = self.op_params.get('hide_auto_df_alerts') + self.df_manager = dfManager() self.support_white_panda = self.op_params.get('support_white_panda') self.last_model_long = False @@ -318,7 +317,7 @@ def add_stock_additions_alerts(self, CS): df_alert = 'dfButtonAlert' if df_out.is_auto and df_out.last_is_auto: # only show auto alert if engaged, not hiding auto, and time since lane speed alert not showing - if CS.cruiseState.enabled and not self.hide_auto_df_alerts: + if CS.cruiseState.enabled and not self.op_params.get('hide_auto_df_alerts'): df_alert += 'Silent' self.AM.SA_add(df_alert, extra_text_1=df_out.model_profile_text + ' (auto)') return diff --git a/selfdrive/controls/lib/dynamic_follow/__init__.py b/selfdrive/controls/lib/dynamic_follow/__init__.py index 9bec1aaea9b22b..2fbe4719ea8e7b 100644 --- a/selfdrive/controls/lib/dynamic_follow/__init__.py +++ b/selfdrive/controls/lib/dynamic_follow/__init__.py @@ -58,7 +58,7 @@ def __init__(self, mpc_id): self.mpc_id = mpc_id self.op_params = opParams() self.df_profiles = dfProfiles() - self.df_manager = dfManager(self.op_params) + self.df_manager = dfManager() self.dmc_v_rel = DistanceModController(k_i=0.042, k_d=0.08, x_clip=[-1, 0, 0.66], mods=[1.15, 1., 0.95]) self.dmc_a_rel = DistanceModController(k_i=0.042 * 1.05, k_d=0.08, x_clip=[-1, 0, 0.33], mods=[1.15, 1., 0.98]) # a_lead loop is 5% faster diff --git a/selfdrive/controls/lib/dynamic_follow/df_manager.py b/selfdrive/controls/lib/dynamic_follow/df_manager.py index ac98932f32b3b1..093f71dddf855e 100644 --- a/selfdrive/controls/lib/dynamic_follow/df_manager.py +++ b/selfdrive/controls/lib/dynamic_follow/df_manager.py @@ -1,4 +1,5 @@ import cereal.messaging as messaging +from common.op_params import opParams from selfdrive.controls.lib.dynamic_follow.support import dfProfiles from common.realtime import sec_since_boot @@ -14,9 +15,8 @@ class dfReturn: class dfManager: - def __init__(self, op_params, is_df=False): - self.op_params = op_params - self.is_df = is_df + def __init__(self): + self.op_params = opParams() self.df_profiles = dfProfiles() self.sm = messaging.SubMaster(['dynamicFollowButton', 'dynamicFollowData']) self.button_updated = False diff --git a/selfdrive/controls/lib/lateral_planner.py b/selfdrive/controls/lib/lateral_planner.py index 98285009b31634..f39925c8a00b05 100644 --- a/selfdrive/controls/lib/lateral_planner.py +++ b/selfdrive/controls/lib/lateral_planner.py @@ -66,8 +66,6 @@ def __init__(self, CP): self.y_pts = np.zeros(TRAJECTORY_SIZE) self.op_params = opParams() - self.alca_nudge_required = self.op_params.get('alca_nudge_required') - self.alca_min_speed = self.op_params.get('alca_min_speed') * CV.MPH_TO_MS def setup_mpc(self): self.libmpc = libmpc_py.libmpc @@ -107,7 +105,7 @@ def update(self, sm, CP, VM): # Lane change logic one_blinker = sm['carState'].leftBlinker != sm['carState'].rightBlinker - below_lane_change_speed = v_ego < self.alca_min_speed + below_lane_change_speed = v_ego < self.op_params.get('alca_min_speed') * CV.MPH_TO_MS if sm['carState'].leftBlinker: self.lane_change_direction = LaneChangeDirection.left @@ -121,7 +119,7 @@ def update(self, sm, CP, VM): torque_applied = sm['carState'].steeringPressed and \ ((sm['carState'].steeringTorque > 0 and self.lane_change_direction == LaneChangeDirection.left) or (sm['carState'].steeringTorque < 0 and self.lane_change_direction == LaneChangeDirection.right)) - if not self.alca_nudge_required: + if not self.op_params.get('alca_nudge_required'): torque_applied = True blindspot_detected = ((sm['carState'].leftBlindspot and self.lane_change_direction == LaneChangeDirection.left) or diff --git a/selfdrive/controls/lib/longcontrol.py b/selfdrive/controls/lib/longcontrol.py index 3ca4ddc21f903e..361a657b2ea5ca 100644 --- a/selfdrive/controls/lib/longcontrol.py +++ b/selfdrive/controls/lib/longcontrol.py @@ -68,7 +68,6 @@ def __init__(self, CP, compute_gb, candidate): self.last_output_gb = 0.0 self.op_params = opParams() - self.enable_dg = self.op_params.get('dynamic_gas') self.dynamic_gas = DynamicGas(CP, candidate) def reset(self, v_pid): @@ -82,7 +81,7 @@ def update(self, active, CS, v_target, v_target_future, a_target, CP, extras): gas_max = interp(CS.vEgo, CP.gasMaxBP, CP.gasMaxV) brake_max = interp(CS.vEgo, CP.brakeMaxBP, CP.brakeMaxV) - if self.enable_dg: + if self.op_params.get('dynamic_gas'): gas_max = self.dynamic_gas.update(CS, extras) # Update state machine diff --git a/selfdrive/controls/lib/pid.py b/selfdrive/controls/lib/pid.py index a9437271c62610..633fca449b944b 100644 --- a/selfdrive/controls/lib/pid.py +++ b/selfdrive/controls/lib/pid.py @@ -109,7 +109,6 @@ def update(self, setpoint, measurement, speed=0.0, check_saturation=True, overri class LongPIDController: def __init__(self, k_p, k_i, k_d, k_f=1., pos_limit=None, neg_limit=None, rate=100, sat_limit=0.8, convert=None): self.op_params = opParams() - self.enable_long_derivative = self.op_params.get('enable_long_derivative') self._k_p = k_p # proportional gain self._k_i = k_i # integral gain self._k_d = k_d # derivative gain @@ -186,7 +185,7 @@ def update(self, setpoint, measurement, speed=0.0, check_saturation=True, overri not freeze_integrator: self.id = i - if self.enable_long_derivative: + if self.op_params.get('enable_long_derivative'): if abs(setpoint - self.last_setpoint) / self.rate < self.max_accel_d: # if setpoint isn't changing much d = self.k_d * (error - self.last_error) if (self.id > 0 and self.id + d >= 0) or (self.id < 0 and self.id + d <= 0): # if changing integral doesn't make it cross zero diff --git a/selfdrive/loggerd/uploader.py b/selfdrive/loggerd/uploader.py index a0cc62583b201c..393bc722adc462 100644 --- a/selfdrive/loggerd/uploader.py +++ b/selfdrive/loggerd/uploader.py @@ -25,7 +25,7 @@ allow_sleep = bool(os.getenv("UPLOADER_SLEEP", "1")) force_wifi = os.getenv("FORCEWIFI") is not None fake_upload = os.getenv("FAKEUPLOAD") is not None -upload_on_hotspot = opParams().get('upload_on_hotspot') +op_params = opParams() def get_directory_sort(d): @@ -226,7 +226,7 @@ def uploader_fn(exit_event): d = None on_hotspot = is_on_hotspot() - if (on_hotspot and upload_on_hotspot) or not on_hotspot: + if (on_hotspot and op_params.get('upload_on_hotspot')) or not on_hotspot: d = uploader.next_file_to_upload(with_raw=allow_raw_upload and on_wifi and offroad) if d is None: # Nothing to upload