def do_predict(self, args=''): ''' Start prediction Passing received frames through neural network and printing results. Listener should be started before using this command. Use <Ctrl-C> to stop this command. Usage: >> predict ''' if args != '': error('Unknown arguments.') return with self.listening_lock: if not self.listening: error('Listener not started.') return if not self.__model_loaded(): self.model.load() print() with self.predicting_lock: self.predicting = True self.__predict_thread() self.console_queue.get() with self.predicting_lock: self.predicting = False self.model_queue.put(None)
def postloop(self): ''' Take care of any unfinished business. Despite the claims in the Cmd documentation, Cmd.postloop() is not a stub. ''' Cmd.postloop(self) # Clean up command completion print('Exiting...')
def discard_last_sample(self): last_sample = self.get_last_sample(self.gesture) if last_sample is None: print('No files.') return os.remove(last_sample) print('File deleted.')
def __set_file(self): last_sample = self.get_last_sample(self.gesture) if last_sample is None: self.log_file = os.path.join(last_sample, 'sample_1.csv') return save_dir = os.path.dirname(last_sample) last_sample_name = os.path.splitext(last_sample)[0] num = int(os.path.basename(last_sample_name).split('_')[1]) + 1 self.log_file = os.path.join(save_dir, 'sample_' + str(num) + '.csv') print(f'Sample number: {num}')
def do_send(self, args=''): ''' Sending configuration to mmWave Configuring mmWave with given configuration file. All configuration files should be placed in \'mmwave/communication/profiles\' folder. Use <Tab> for autocompletion on available configuration files. All configuration files should have .cfg extension. If no configuration is provided, default configuration file will be used. Usage: >> send >> send profile ''' if args == '': args = self.default_config if len(args.split()) > 1: error('Too many arguments.') return if not self.__is_connected(): error('Not connected.') return cfg = os.path.join(self.config_dir, args + '.cfg') if cfg not in glob.glob(os.path.join(self.config_dir, '*.cfg')): print('Unknown profile.') return mmwave_configured = False cnt = 0 while not mmwave_configured and cnt < 5: mmwave_configured = self.mmwave.configure(cfg) if not mmwave_configured: signal_cnt = 0 while signal_cnt < 5: if not self.console_queue.empty(): self.console_queue.get() return time.sleep(.2) signal_cnt += 1 cnt += 1 if not mmwave_configured: return if os.path.basename(cfg) == 'stop.cfg': self.configured = False else: self.configured = True self.config = cfg
def do_get_model(self, args=''): ''' Get current model type. Usage: >> get_model ''' if args != '': error('Unknown arguments.') return print(f'Current model type: {self.model_type}')
def __mmwave_init(self): self.mmwave = None if self.cli_port is None or self.data_port is None: print('Looking for ports...', end='') ports = mmWave.find_ports() if len(ports) < 2: print(f'{Fore.RED}Ports not found!') print(f'{Fore.YELLOW}Auto-detection is only applicable for', f'{Fore.YELLOW}eval boards with XDS110.') return if len(ports) > 2: print( f'{Fore.YELLOW}Multiple ports detected.', f'{Fore.YELLOW}Selecting ports {ports[0]} and {ports[1]}.') ports = ports[:2] if platform.system() == 'Windows': ports.sort(reverse=True) self.cli_port = ports[0] self.data_port = ports[1] self.mmwave = mmWave(self.cli_port, self.data_port, cli_rate=self.default_cli_rate, data_rate=self.default_data_rate) self.mmwave.connect() if self.mmwave.connected(): self.flasher = Flasher(self.mmwave.cli_port)
def __listen_thread(self): print(f'{Fore.CYAN}=== Listening ===') while True: with self.listening_lock: if not self.listening: return data = self.mmwave.get_data() if data is None: time.sleep(.5) continue self.data_queue.put(data) time.sleep(.05)
def pprint(frame): if frame is None: print(f'{Fore.MAGENTA}Frame: {Fore.RED}None') return print(Fore.CYAN + '='*85) Parser.__pprint_struct(frame) print(Fore.CYAN + '='*85) print()
def do_connect(self, args=''): ''' Manually connecting to mmWave Command will ask you to manualy type ports and baudrates. Use <Tab> for autocompletion on available ports and baudrates. Type \'exit\' for exiting manual connection. If you only press enter on baudrates, console will try to find baudrate automatically. Note that this will work only if connection is already opened from both sides. (On mmWave startup only cli port is open, and data port will open only after \'senstrStart\' command) Look \'autoconnect\' command for automatic connection. Usage: >> connect cli port: /dev/ttyACM0 cli rate: 115200 data port: /dev/ttyACM1 data rate: 921600 ''' if args != '': error('Unknown arguments.') return if self.__is_connected(): self.mmwave.disconnect() print() port = self.__get_user_port('cli') if port is not None: self.cli_port = port self.cli_rate = self.__get_user_rate('cli', port) else: return port = self.__get_user_port('data') if port is not None: self.data_port = port self.data_rate = self.__get_user_rate('data', port) else: return self.__mmwave_init()
def get_all_data(refresh_data=False): X_file = os.path.join(os.path.dirname(__file__), '.X_data') y_file = os.path.join(os.path.dirname(__file__), '.y_data') if refresh_data: X = [] y = [] for gesture in tqdm(GESTURE, desc='Gestures'): for sample in Logger.get_data(gesture): X.append(sample) y.append(gesture.value) pickle.dump(X, open(X_file, 'wb')) pickle.dump(y, open(y_file, 'wb')) else: print('Loading cached data...', end='') X = pickle.load(open(X_file, 'rb')) y = pickle.load(open(y_file, 'rb')) print(f'{Fore.GREEN}Done.') return X, y
def precmd(self, line): ''' This method is called after the line has been input but before it has been interpreted. If you want to modify the input line before execution (for example, variable substitution) do it here. ''' self._hist += [line.strip()] try: info = self.plotter_queues['info'].get(False) if info == 'closed': print(f'{Fore.YELLOW}Plotter closed.\n') with self.plotting_lock: if self.plotting: self.plotting = False except queue.Empty: pass return line
def assemble(self, data): if data is None: return None start_idx = data.find(self.formats.MAGIC_NUMBER) if start_idx == 0: # Save return value, and start capturing new frame frame = deepcopy(self.buffer) self.buffer = bytearray(data) self.sync_time = time.perf_counter() if self.sync is False: print(f'{Fore.GREEN}Sync received!\n') self.sync = True return None return frame elif self.sync is False: if self.sync_time == 0: self.sync_time = time.perf_counter() print(f'{Fore.YELLOW}Waiting for sync...') # Capture long sync time if time.perf_counter() - self.sync_time > self.sync_timeout: print(f'{Fore.RED}No sync received.') print('Please check your board.\n') self.sync_time = 0 else: # Wait for rest of the frame self.buffer.extend(bytearray(data)) # Capture long no data time if data == b'': if time.perf_counter() - self.sync_time > self.sync_timeout: print(f'{Fore.RED}Not receiving data. Resyncing...') self.sync_time = 0 self.sync = False
def __init__(self, plotter_queues): super().__init__() # Connection self.cli_port = None self.cli_rate = None self.data_port = None self.data_rate = None self.default_cli_rate = 115200 self.default_data_rate = 921600 self.firmware_dir = 'firmware/' self.flasher = None self.__mmwave_init() if self.mmwave is None or self.mmwave.connected() is False: print( 'Try connecting manually. Type \'help connect\' for more info.\n' ) # Configuration self.config_dir = 'mmwave/communication/profiles/' self.configured = False self.default_config = 'profile' self.config = None self.logger = Logger() self.model_type = 'lstm' self.__set_model(self.model_type) # Catching signals self.console_queue = Queue() SignalHandler(self.console_queue) # Threading stuff self.listening_lock = Lock() self.printing_lock = Lock() self.plotting_lock = Lock() self.predicting_lock = Lock() self.logging_lock = Lock() self.listening = False self.printing = False self.plotting = False self.predicting = False self.logging = False self.logging_queue = Queue() self.data_queue = Queue() self.model_queue = Queue() self.plotter_queues = plotter_queues self.__set_prompt() print(f'{Fore.GREEN}Init done.\n') print(f'{Fore.MAGENTA}--- mmWave console ---') warning('Type \'help\' for more information.')
def do_start(self, args=''): ''' Start listener, plotter and prediction. If mmWave is not configured, default configuration will be send first. Use <Ctrl-C> to stop this command. Usage: >> start ''' if args != '': error('Unknown arguments.') return if not self.__model_loaded(): self.model.load() print() self.do_send(self.default_config) self.do_listen() self.do_plot() self.do_predict() self.do_stop()
def do_autoconnect(self, args=''): ''' Auto connecting to mmWave Automatically looking for \'XDS\' ports and connecting with default baudrates. Auto-detection is only applicable for eval boards with XDS110. Look \'connect\' command for manual connection. Usage: >> autoconnect ''' if args != '': error('Unknown arguments.') return if self.__is_connected(): warning('Already connected.') print('Reconnecting...') self.cli_port = None self.data_port = None self.__mmwave_init()
def log(self, frame): if not self.logging: self.__set_file() self.logging = True self.detected_time = time.perf_counter() print('Saving...') if (frame is not None and frame.get('tlvs') is not None and frame['tlvs'].get(1) is not None): self.detected_time = time.perf_counter() with open(self.log_file, 'a') as f: if self.frame_num == 0: f.write( 'frame,x,y,range_idx,peak_value,doppler_idx,xyz_q_format\n' ) for obj in frame['tlvs'][1]['values']['objs']: f.write(self.empty_frames) f.write(str(self.frame_num) + ',') f.write(str(obj['x_coord']) + ',') f.write(str(obj['y_coord']) + ',') f.write(str(obj['range_idx']) + ',') f.write(str(obj['peak_value']) + ',') f.write(str(obj['doppler_idx']) + ',') f.write( str(frame['tlvs'][1]['values']['descriptor'] ['xyz_q_format']) + '\n') self.empty_frames = '' self.frame_num += 1 elif self.frame_num != 0: self.empty_frames = (self.empty_frames + str(self.frame_num) + ',') self.empty_frames = (self.empty_frames + 'None, None, None, None, None\n') self.frame_num += 1 if time.perf_counter() - self.detected_time > .5: if os.path.isfile(self.log_file): print('Sample saved.\n') else: print('Nothing to save.\n') self.empty_frames = '' self.logging = False self.frame_num = 0 return True return False
def do_stop(self, args=''): ''' Stopping mmwave, listener and plotter. Possible options: \'mmwave\', \'listen\' and \'plot\'. \'mmwave\': Sending \'sensorStop\' command to mmWave. This option will also stop listener and plotter. \'listen\': Stopping listener and parser threads. This option will also stop plotter. \'plot\': Closing plotter. If nothing is provided as a argument, \'mmwave\' will be used. Usage: >> stop >> stop plot ''' if args == '' or 'mmwave' in args.split(): opts = ['plot', 'listen', 'mmwave'] elif 'listen' in args.split(): opts = ['plot', 'listen'] else: opts = args.split() if 'plot' in opts: with self.plotting_lock: if self.plotting: self.plotting = False print('Plotter stopped.') self.plotter_queues['cli'].put('close') opts.remove('plot') if 'listen' in opts: with self.listening_lock: if self.listening: self.listening = False self.data_queue.put(None) print('Listener stopped.') opts.remove('listen') if 'mmwave' in opts: if self.configured: self.do_send('stop') print('mmWave stopped.') opts.remove('mmwave') for opt in opts: warning(f'Unknown option: {opt}. Skipped.')
def get_stats(X, y): num_of_classes = len(set(y)) print(f'Number of classes: {num_of_classes}') sample_with_max_num_of_frames = max(X, key=lambda sample: len(sample)) max_num_of_frames = len(sample_with_max_num_of_frames) print(f'Maximum number of frames: {max_num_of_frames}') sample_with_max_num_of_objs = max( X, key=lambda sample: [len(frame) for frame in sample]) frame_with_max_num_of_objs = max(sample_with_max_num_of_objs, key=lambda obj: len(obj)) max_num_of_objs = len(frame_with_max_num_of_objs) print(f'Maximum num of objects: {max_num_of_objs}') return max_num_of_frames, max_num_of_objs, num_of_classes
def do_history(self, args): '''Print a list of commands that have been entered''' if args != '': error('Unknown arguments.') return print(self._hist)
def do_eval(self, args=''): ''' Evaluate neural network Command will first load cached X and y data located in \'mmwave/data/.X_data\' and \'mmwave/data/.y_data\' files. This data will be used for the evaluating process. If you want to read raw .csv files, provide \'refresh\' (this will take few minutes). Usage: >> eval >> eval refresh ''' if len(args.split()) > 1: error('Unknown arguments.') return if args == '': refresh_data = False elif args == 'refresh': refresh_data = True else: warning(f'Unknown argument: {args}') return X, y = Logger.get_all_data(refresh_data=refresh_data) Logger.get_stats(X, y) X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=.3, stratify=y, random_state=12) if not self.__model_loaded(): self.model.load() print() print('Eval validation dataset:') self.model.evaluate(X_val, y_val) print() print('Eval train dataset:') self.model.evaluate(X_train, y_train) print() print('Eval full dataset:') self.model.evaluate(X, y) print()
def __header_frame_num_check(self, header, echo=False): if self.frame_num != 0 and self.frame_num + 1 != header['frame_num']: if echo: num_of_missed_frames = header['frame_num'] - self.frame_num - 1 print(f'{Fore.YELLOW}WARNING: Missed {num_of_missed_frames} frames.') self.frame_num = header['frame_num']
def __pprint_struct(frame, indentation='', _recursive_call=False): identetion_marker = '|' + 3*' ' if not _recursive_call: Parser.__pprint_struct.num = 1 for key, value in frame.items(): if isinstance(value, dict): print(indentation, end='') color = Parser.__pprint_get_color(Parser.__pprint_struct.num - 1) print(f'{color}{key}:') indentation += identetion_marker Parser.__pprint_struct.num += 1 Parser.__pprint_struct(value, indentation, True) Parser.__pprint_struct.num -= 1 indentation = indentation[:-4] if key != sorted(frame.keys())[-1]: print(indentation) elif isinstance(value, list): print(indentation, end='') color = Parser.__pprint_get_color(Parser.__pprint_struct.num - 1) print(f'{color}{key}:') indentation += identetion_marker for obj in value: Parser.__pprint_struct.num += 1 Parser.__pprint_struct(obj, indentation, True) Parser.__pprint_struct.num -= 1 if obj != value[-1]: print(indentation) indentation = indentation[:-4] else: if isinstance(value, tuple): print(indentation, end='') color = Parser.__pprint_get_color(Parser.__pprint_struct.num - 1) print(f'{color}{key}:') indentation += identetion_marker with pd.option_context('display.max_rows', 10, 'display.max_columns', 6, 'precision', 2, 'show_dimensions', False): df = pd.DataFrame(value) df = pformat(df) for line_idx, line in enumerate(df.split('\n')): print(indentation, end='') for word_idx, word in enumerate(line.split(' ')): color = '' if word_idx == 0 or line_idx == 0: color = Fore.YELLOW print(f'{color}{word}', end=' ') print() indentation = indentation[:-4] else: print(indentation, end='') color = Parser.__pprint_get_color(Parser.__pprint_struct.num - 1) print(f'{color}{key}: {value}')
def do_flash(self, args=''): ''' Sending .bin files to mmWave Flashing bin files to connected mmWave. It is possible to specify up to 4 meta files. SOP0 and SOP2 have be closed and power reseted before running this command. Look \'connect\' and \'autoconnect\' command for connecting to mmWave. Usage: >> flash xwr16xx_mmw_demo.bin ''' if len(args.split()) > 4: error('Too many arguments.') return if args == '': error('Too few arguments.') return filepaths = [] for arg in args.split(): filepath = os.path.join(self.firmware_dir, arg) if not os.path.isfile(filepath): error(f'File \'{filepath}\' doesn\'t exist.') return filepaths.append(filepath) if not self.__is_connected(): error('Not connected.') return print('Ping mmWave...', end='') response = self.flasher.send_cmd(CMD(OPCODE.PING), resp=False) if response is None: warning('Check if SOP0 and SOP2 are closed, and reset the power.') return print(f'{Fore.GREEN}Done.') print('Get version...', end='') response = self.flasher.send_cmd(CMD(OPCODE.GET_VERSION)) if response is None: return print(f'{Fore.GREEN}Done.') print(f'{Fore.BLUE}Version:', binascii.hexlify(response)) print() self.flasher.flash(filepaths, erase=True) print(f'{Fore.GREEN}Done.')
def __len_check(self, received, expected, echo=False): if received < expected: if echo: print(f'{Fore.RED}ERROR: Corrupted frame.') return False return True