Skip to content

Commit

Permalink
UI Fixes / improvements
Browse files Browse the repository at this point in the history
Improve UI to allow filter in tub manager to be passed through into the trainer.

Fix UI behaviour to better cope with uninitialised widgets when the user has no config or no tub loaded and starts clicking buttons.
  • Loading branch information
DocGarbanzo authored Oct 15, 2022
1 parent 4e6cc64 commit 00c4c03
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 14 deletions.
53 changes: 40 additions & 13 deletions donkeycar/management/kivy_ui.py
Original file line number Diff line number Diff line change
Expand Up @@ -257,16 +257,17 @@ def update_tub(self, event=None):
tub_screen().status(f'Failed loading tub: {str(e)}')
return False
# Check if filter is set in tub screen
expression = tub_screen().ids.tub_filter.filter_expression
# expression = tub_screen().ids.tub_filter.filter_expression
train_filter = getattr(cfg, 'TRAIN_FILTER', None)

# Use filter, this defines the function
def select(underlying):
if not expression:
if not train_filter:
return True
else:
try:
record = TubRecord(cfg, self.tub.base_path, underlying)
res = eval(expression)
res = train_filter(record)
return res
except KeyError as err:
Logger.error(f'Filter: {err}')
Expand All @@ -281,8 +282,6 @@ def select(underlying):
msg = f'Loaded tub {self.file_path} with {self.len} records'
else:
msg = f'No records in tub {self.file_path}'
if expression:
msg += f' using filter {tub_screen().ids.tub_filter.record_filter}'
tub_screen().status(msg)
return True

Expand Down Expand Up @@ -399,9 +398,9 @@ def update(self, record):
self.core_image = CoreImage(bytes_io, ext='png')
self.texture = self.core_image.texture
except KeyError as e:
Logger.error('Record: Missing key:', e)
Logger.error(f'Record: Missing key: {e}')
except Exception as e:
Logger.error('Record: Bad record:', str(e))
Logger.error(f'Record: Bad record: {e}')

def get_image(self, record):
return record.image(cached=False)
Expand All @@ -423,11 +422,15 @@ def start(self, fwd=True, continuous=False):
:param continuous: If we do <<, >> or <, >
:return: None
"""
# this widget it used in two screens, so reference the original location
# of the config which is the config manager in the tub screen
cfg = tub_screen().ids.config_manager.config
hz = cfg.DRIVE_LOOP_HZ if cfg else 20
time.sleep(0.1)
call = partial(self.step, fwd, continuous)
if continuous:
self.fwd = fwd
s = float(self.speed) * tub_screen().ids.config_manager.config.DRIVE_LOOP_HZ
s = float(self.speed) * hz
cycle_time = 1.0 / s
else:
cycle_time = 0.08
Expand All @@ -441,6 +444,9 @@ def step(self, fwd=True, continuous=False, *largs):
:param largs: dummy
:return: None
"""
if self.screen.index is None:
self.screen.status("No tub loaded")
return
new_index = self.screen.index + (1 if fwd else -1)
if new_index >= tub_screen().ids.tub_loader.len:
new_index = 0
Expand Down Expand Up @@ -533,22 +539,33 @@ class TubFilter(PaddedBoxLayout):

def update_filter(self):
filter_text = self.ids.record_filter.text
config = tub_screen().ids.config_manager.config
# empty string resets the filter
if filter_text == '':
self.record_filter = ''
self.filter_expression = ''
rc_handler.data['record_filter'] = self.record_filter
if hasattr(config, 'TRAIN_FILTER'):
delattr(config, 'TRAIN_FILTER')
tub_screen().status(f'Filter cleared')
return
filter_expression = self.create_filter_string(filter_text)
try:
record = tub_screen().current_record
res = eval(filter_expression)
filter_func_text = f"""def filter_func(record):
return {filter_expression}
"""
# creates the function 'filter_func'
ldict = {}
exec(filter_func_text, globals(), ldict)
filter_func = ldict['filter_func']
res = filter_func(record)
status = f'Filter result on current record: {res}'
if isinstance(res, bool):
self.record_filter = filter_text
self.filter_expression = filter_expression
rc_handler.data['record_filter'] = self.record_filter
setattr(config, 'TRAIN_FILTER', filter_func)
else:
status += ' - non bool expression can\'t be applied'
status += ' - press <Reload tub> to see effect'
Expand Down Expand Up @@ -649,8 +666,9 @@ def initialise(self, e):

def on_index(self, obj, index):
""" Kivy method that is called if self.index changes"""
self.current_record = self.ids.tub_loader.records[index]
self.ids.slider.value = index
if index >= 0:
self.current_record = self.ids.tub_loader.records[index]
self.ids.slider.value = index

def on_current_record(self, obj, record):
""" Kivy method that is called if self.current_record changes."""
Expand Down Expand Up @@ -747,7 +765,7 @@ def get_image(self, record):

rgb = (0, 0, 255)
MakeMovie.draw_line_into_image(output[0], output[1], True, img_arr, rgb)
out_record = deepcopy(record)
out_record = copy(record)
out_record.underlying['pilot/angle'] = output[0]
# rename and denormalise the throttle output
pilot_throttle_field \
Expand Down Expand Up @@ -781,6 +799,8 @@ def on_index(self, obj, index):
def on_current_record(self, obj, record):
""" Kivy method that is called when self.current_index changes. Here
we update the images and the control panel entry."""
if not record:
return
i = record.underlying['_index']
self.ids.pilot_control.record_display = f"Record {i:06}"
self.ids.img_1.update(record)
Expand All @@ -806,6 +826,8 @@ def map_pilot_field(self, text):
return rc_handler.data['user_pilot_map'][text]

def set_brightness(self, val=None):
if not self.config:
return
if self.ids.button_bright.state == 'down':
self.config.AUG_MULTIPLY_RANGE = (val, val)
if 'MULTIPLY' not in self.aug_list:
Expand All @@ -816,6 +838,8 @@ def set_brightness(self, val=None):
self.on_aug_list(None, None)

def set_blur(self, val=None):
if not self.config:
return
if self.ids.button_blur.state == 'down':
self.config.AUG_BLUR_RANGE = (val, val)
if 'BLUR' not in self.aug_list:
Expand All @@ -826,11 +850,15 @@ def set_blur(self, val=None):
self.on_aug_list(None, None)

def on_aug_list(self, obj, aug_list):
if not self.config:
return
self.config.AUGMENTATIONS = self.aug_list
self.augmentation = ImageAugmentation(self.config, 'AUGMENTATIONS')
self.on_current_record(None, self.current_record)

def on_trans_list(self, obj, trans_list):
if not self.config:
return
self.config.TRANSFORMATIONS = self.trans_list
self.transformation = ImageAugmentation(self.config, 'TRANSFORMATIONS')
self.on_current_record(None, self.current_record)
Expand Down Expand Up @@ -1088,7 +1116,6 @@ def connected(self, event):
'-o ConnectTimeout=3',
f'{self.config.PI_USERNAME}@{self.config.PI_HOSTNAME}',
'date']
# Logger.info('car check: ' + ' '.join(cmd))
self.connection = Popen(cmd, shell=False, stdout=PIPE,
stderr=STDOUT, text=True,
encoding='utf-8', universal_newlines=True)
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ def package_files(directory, strip_leading):
long_description = fh.read()

setup(name='donkeycar',
version="4.3.22",
version="4.3.23",
long_description=long_description,
description='Self driving library for python.',
url='https://github.com/autorope/donkeycar',
Expand Down

0 comments on commit 00c4c03

Please sign in to comment.