mirror of
https://github.com/dragonpilot/dragonpilot.git
synced 2026-07-18 11:22:03 +08:00
better live tuning implementation with opEdit
This commit is contained in:
+32
-19
@@ -4,6 +4,7 @@ import json
|
||||
import time
|
||||
import string
|
||||
import random
|
||||
from selfdrive.swaglog import cloudlog
|
||||
from common.travis_checker import travis
|
||||
|
||||
|
||||
@@ -30,6 +31,7 @@ class KeyInfo:
|
||||
live = False
|
||||
has_default = False
|
||||
has_description = False
|
||||
hidden = False
|
||||
|
||||
|
||||
class opParams:
|
||||
@@ -49,7 +51,8 @@ class opParams:
|
||||
|
||||
self.default_params = {'dynamic_follow': {'default': 'relaxed', 'allowed_types': [str], 'description': "Can be: ('traffic', 'relaxed', 'roadtrip'): Left to right increases in following distance.\n"
|
||||
"All profiles support dynamic follow so you'll get your preferred distance while\n"
|
||||
"retaining the smoothness and safety of dynamic follow!", 'live': True},}
|
||||
"retaining the smoothness and safety of dynamic follow!", 'live': True},
|
||||
'op_edit_live_mode': {'default': False, 'description': 'This parameter controls which mode opEdit starts in. It should be hidden from the user with the hide key', 'hide': True}}
|
||||
|
||||
self.params = {}
|
||||
self.params_file = "/data/op_params.json"
|
||||
@@ -126,39 +129,49 @@ class opParams:
|
||||
def get(self, key=None, default=None, force_update=False): # can specify a default value if key doesn't exist
|
||||
self.update_params(key, force_update)
|
||||
if key is None:
|
||||
return self.params
|
||||
return self.get_all()
|
||||
|
||||
if key in self.params:
|
||||
key_info = self.get_key_info(key)
|
||||
key_info = self.key_info(key)
|
||||
if key_info.has_allowed_types:
|
||||
value = self.params[key]
|
||||
allowed_types = self.default_params[key]['allowed_types']
|
||||
valid_type = type(value) in allowed_types
|
||||
if not valid_type:
|
||||
if key_info.has_default: # if value in op_params.json is not correct type, use default
|
||||
value = self.default_params[key]['default']
|
||||
else: # else use a standard value based on type (last resort to keep openpilot running)
|
||||
value = self.value_from_types(allowed_types)
|
||||
if type(value) not in allowed_types:
|
||||
cloudlog.warning('op_params: User\'s value is not valid!')
|
||||
if key_info.has_default: # invalid value type, try to use default value
|
||||
default_value = self.default_params[key]['default']
|
||||
if type(default_value) in allowed_types: # actually check if the default is valid
|
||||
# return default value because user's value of key is not in the allowed_types to avoid crashing openpilot
|
||||
return default_value
|
||||
else: # else use a standard value based on type (last resort to keep openpilot running if user's value is of invalid type)
|
||||
return self.value_from_types(allowed_types)
|
||||
else:
|
||||
return value # all good, returning user's value
|
||||
else:
|
||||
value = self.params[key]
|
||||
else:
|
||||
value = default
|
||||
return self.params[key] # no defined allowed types, returning user's value
|
||||
|
||||
return value
|
||||
return default # not in params
|
||||
|
||||
def get_key_info(self, key):
|
||||
def get_all(self): # returns all non-hidden params
|
||||
return {k: v for k, v in self.params.items() if not self.key_info(k).hidden}
|
||||
|
||||
def key_info(self, key):
|
||||
key_info = KeyInfo()
|
||||
if key is None:
|
||||
return key_info
|
||||
if key in self.default_params:
|
||||
if 'allowed_types' in self.default_params[key]:
|
||||
allowed_types = self.default_params[key]['allowed_types']
|
||||
if isinstance(allowed_types, list) and len(allowed_types) > 0:
|
||||
key_info.has_allowed_types = True
|
||||
if 'live' in self.default_params[key] and self.default_params[key]['live'] is True:
|
||||
key_info.live = True
|
||||
if 'live' in self.default_params[key]:
|
||||
key_info.live = self.default_params[key]['live']
|
||||
if 'default' in self.default_params[key]:
|
||||
key_info.has_default = True
|
||||
if 'description' in self.default_params[key]:
|
||||
key_info.has_description = True
|
||||
if 'hide' in self.default_params[key]:
|
||||
key_info.hidden = self.default_params[key]['hide']
|
||||
return key_info
|
||||
|
||||
def value_from_types(self, allowed_types):
|
||||
@@ -173,8 +186,8 @@ class opParams:
|
||||
return None # unknown type
|
||||
|
||||
def update_params(self, key, force_update):
|
||||
if force_update or self.get_key_info(key).live: # if is a live param, we want to get updates while openpilot is running
|
||||
if not travis and time.time() - self.last_read_time >= self.read_frequency: # make sure we aren't reading file too often
|
||||
if force_update or self.key_info(key).live: # if is a live param, we want to get updates while openpilot is running
|
||||
if not travis and (time.time() - self.last_read_time >= self.read_frequency or force_update): # make sure we aren't reading file too often
|
||||
self.params, read_status = read_params(self.params_file, self.format_default_params())
|
||||
if not read_status:
|
||||
time.sleep(1/100.)
|
||||
@@ -184,4 +197,4 @@ class opParams:
|
||||
def delete(self, key):
|
||||
if key in self.params:
|
||||
del self.params[key]
|
||||
write_params(self.params, self.params_file)
|
||||
write_params(self.params, self.params_file)
|
||||
+23
-32
@@ -9,46 +9,33 @@ class opEdit: # use by running `python /data/openpilot/op_edit.py`
|
||||
self.op_params = opParams()
|
||||
self.params = None
|
||||
self.sleep_time = 1.0
|
||||
self.live_tuning = False
|
||||
self.welcome()
|
||||
|
||||
def welcome(self):
|
||||
print('Welcome to the opParams command line editor!')
|
||||
while True:
|
||||
print('Would you like to enter opEdit\'s live-tuning mode?')
|
||||
choice = input('[Y/n]: ').lower().strip()
|
||||
if choice in ['y', 'ye', 'yes']:
|
||||
self.live_tuning = True
|
||||
self.run_loop()
|
||||
break
|
||||
elif choice in ['n', 'no', '']:
|
||||
self.run_loop()
|
||||
break
|
||||
elif choice in ['e', 'exit']:
|
||||
break
|
||||
self.live_tuning = self.op_params.get('op_edit_live_mode', False)
|
||||
self.run_loop()
|
||||
|
||||
def run_loop(self):
|
||||
if not self.live_tuning:
|
||||
print('Here are your parameters:\n')
|
||||
else:
|
||||
print('Here are your live parameters:\n')
|
||||
print('Welcome to the opParams command line editor!')
|
||||
while True:
|
||||
if not self.live_tuning:
|
||||
print('Here are your parameters:\n')
|
||||
else:
|
||||
print('Here are your live parameters:\n')
|
||||
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.get_key_info(k).live}
|
||||
self.params = {k: v for k, v in self.params.items() if self.op_params.key_info(k).live}
|
||||
|
||||
values_list = [self.params[i] if len(str(self.params[i])) < 20 else '{} ... {}'.format(str(self.params[i])[:30], str(self.params[i])[-15:]) for i in self.params]
|
||||
live = ['(live!)' if self.op_params.get_key_info(i).live else '' for i in self.params]
|
||||
live = ['(live!)' if self.op_params.key_info(i).live else '' for i in self.params]
|
||||
|
||||
to_print = ['{}. {}: {} {}'.format(idx + 1, i, values_list[idx], live[idx]) for idx, i in enumerate(self.params)]
|
||||
to_print.append('\n{}. Add new parameter!'.format(len(self.params) + 1))
|
||||
to_print.append('{}. Delete parameter!'.format(len(self.params) + 2))
|
||||
to_print.append('---\n{}. Add new parameter'.format(len(to_print) + 1))
|
||||
to_print.append('{}. Delete parameter'.format(len(to_print) + 1))
|
||||
to_print.append('{}. Toggle live tuning'.format(len(to_print) + 1))
|
||||
|
||||
print('\n'.join(to_print))
|
||||
print('\nChoose a parameter to explore (by integer index): ')
|
||||
|
||||
choice = input('>> ').strip()
|
||||
parsed, choice = self.parse_choice(choice)
|
||||
parsed, choice = self.parse_choice(choice, len(to_print))
|
||||
if parsed == 'continue':
|
||||
continue
|
||||
elif parsed == 'add':
|
||||
@@ -57,10 +44,13 @@ class opEdit: # use by running `python /data/openpilot/op_edit.py`
|
||||
self.change_parameter(choice)
|
||||
elif parsed == 'delete':
|
||||
self.delete_parameter()
|
||||
elif parsed == 'live':
|
||||
self.live_tuning = not self.live_tuning
|
||||
self.op_params.put('op_edit_live_mode', self.live_tuning) # for next opEdit startup
|
||||
elif parsed == 'error':
|
||||
return
|
||||
|
||||
def parse_choice(self, choice):
|
||||
def parse_choice(self, choice, opt_len):
|
||||
if choice.isdigit():
|
||||
choice = int(choice)
|
||||
choice -= 1
|
||||
@@ -70,22 +60,23 @@ class opEdit: # use by running `python /data/openpilot/op_edit.py`
|
||||
else:
|
||||
self.message('Not an integer!')
|
||||
return 'retry', choice
|
||||
if choice not in range(0, len(self.params) + 2): # three for add/delete parameter
|
||||
if choice not in range(opt_len): # number of options to choose from
|
||||
self.message('Not in range!')
|
||||
return 'continue', choice
|
||||
|
||||
if choice == len(self.params): # add new parameter
|
||||
if choice == opt_len - 3: # add new parameter
|
||||
return 'add', choice
|
||||
|
||||
if choice == len(self.params) + 1: # delete parameter
|
||||
elif choice == opt_len - 2: # delete parameter
|
||||
return 'delete', choice
|
||||
elif choice == opt_len - 1: # live tuning mode
|
||||
return 'live', choice
|
||||
|
||||
return 'change', choice
|
||||
|
||||
def change_parameter(self, choice):
|
||||
while True:
|
||||
chosen_key = list(self.params)[choice]
|
||||
key_info = self.op_params.get_key_info(chosen_key)
|
||||
key_info = self.op_params.key_info(chosen_key)
|
||||
|
||||
old_value = self.params[chosen_key]
|
||||
print('Chosen parameter: {}'.format(chosen_key))
|
||||
|
||||
Reference in New Issue
Block a user