diff --git a/.gitignore b/.gitignore index 9f2e848..6978cc1 100755 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ .DS_Store __pycache__/ +logs/* diff --git a/main.py b/main.py index df325eb..6232a20 100644 --- a/main.py +++ b/main.py @@ -1,6 +1,8 @@ import os -from src.communicator.MultiThread import MultiThread +# Using Multiprocess instead of Multithread to employ all 4 cores of RPI +# from src.communicator.MultiThread import MultiThread +from src.communicator.MultiProcess import MultiProcess # from src.detector.SymbolDetector import SymbolDetector from src.Logger import Logger @@ -9,7 +11,7 @@ def init(): os.system("sudo hciconfig hci0 piscan") try: - multi_thread = MultiThread() + multi_thread = MultiProcess() multi_thread.start() # Currently SymbolDetector seems to be running really slow diff --git a/playgrounds/Multiprocess_comm.py b/playgrounds/Multiprocess_comm.py new file mode 100644 index 0000000..3e81ba7 --- /dev/null +++ b/playgrounds/Multiprocess_comm.py @@ -0,0 +1,68 @@ +from multiprocessing import Process, Queue +import queue +import os +import cv2 as cv +import time + +from src.Logger import Logger +from src.communicator.PC import PC + +log = Logger() + +class MultiThread: + def __init__(self): + log.info('Initializing Multithread Communication') + self.pc = PC() + self.pc.connect() + + self.pc_queue = Queue() + + def start(self): + + read_pc = Process(target=self.read_pc, args=(self.pc_queue,)) + read_pc.start() + + write_pc = Process(target=self.write_pc, args=(self.pc_queue,)) + write_pc.start() + + def end(self): + log.info('Multithread Communication Session Ended') + + def read_pc(self, pc_queue): + print('read read') + while True: + msg = self.pc.read() + if msg is not None: + print('Received: ' + str(msg)) + pc_queue.put_nowait(msg['payload']) + ''' + log.info('Read PC: ' + str(msg['target']) + '; ' + str(msg['payload'])) + if msg['target'] == 'android': + android_queue.put_nowait(msg['payload']) + elif msg['target'] == 'arduino': + arduino_queue.put_nowait(msg['payload']) + elif msg['target'] == 'both': + android_queue.put_nowait(msg['payload']['android']) + arduino_queue.put_nowait(msg['payload']['arduino']) + ''' + + def write_pc(self, pc_queue): + print('write write') + while True: + if not pc_queue.empty(): + msg = pc_queue.get_nowait() + print('Write: ' + str(msg)) + self.pc.write(msg) + log.info('Write PC: ' + str(msg)) + + def detect_symbols(self, android_queue): + while True: + frame = self.detector.get_frame() + symbol_match = self.detector.detect(frame) + if symbol_match is not None: + print('Symbol Match ID: ' + str(symbol_match)) + android_queue.put_nowait('SID|' + str(symbol_match)) + +mp = MultiThread() +mp.start() + diff --git a/playgrounds/Multithread_backup.py b/playgrounds/Multithread_backup.py new file mode 100644 index 0000000..e119f65 --- /dev/null +++ b/playgrounds/Multithread_backup.py @@ -0,0 +1,131 @@ +import _thread +import queue +import os +import cv2 as cv +import time + +from src.Logger import Logger +from src.detector.SymbolDetector import SymbolDetector +from src.communicator.Arduino import Arduino +from src.communicator.PC import PC +from src.communicator.Android import Android + +log = Logger() + +''' +Multithreading essentially refers to running multiple processes in parallel +Communications between Rpi and other devices involve a session, which means +the Rpi will be waiting for a trigger. Hence if single threaded, Rpi can only +do one thing at one time. With multhreading, Rpi can have multiple sessions +simultaneuously. Image Recognition will have to be run as a thread as well, but +it seems to be running really slow at the moment. There's also an occasional +error: Camera component couldn't be enabled: Out of resources. If hit that error +just restart the process, wait a little for the resources to be released, then re +run the main program +''' + +class MultiThread: + def __init__(self): + log.info('Initializing Multithread Communication') + # self.android = Android() + self.arduino = Arduino() + self.pc = PC() + self.detector = SymbolDetector() + + # self.android.connect() + self.arduino.connect() + self.pc.connect() + + self.android_queue = queue.Queue(maxsize= 0) + self.arduino_queue = queue.Queue(maxsize=0) + self.pc_queue = queue.Queue(maxsize=0) + + def start(self): + self.detector.start() + + # _thread.start_new_thread(self.read_android, (self.pc_queue,)) + _thread.start_new_thread(self.read_arduino, (self.pc_queue,)) + _thread.start_new_thread(self.read_pc,(self.android_queue, self.arduino_queue,)) + + # _thread.start_new_thread(self.write_android, (self.android_queue,)) + _thread.start_new_thread(self.write_arduino, (self.arduino_queue,)) + _thread.start_new_thread(self.write_pc, (self.pc_queue,)) + + # _thread.start_new_thread(self.detect_symbols, (self.android_queue,)) + + log.info('Multithread Communication Session Started') + + while True: + pass + + def end(self): + self.detector.end() + log.info('Multithread Communication Session Ended') + + def read_android(self, pc_queue): + while True: + try: + msg = self.android.read() + if msg is not None: + log.info('Read Android:' + str(msg)) + pc_queue.put_nowait(msg) + # if msg == 'SV': + # arduino_queue.put_nowait(msg) + + except Exception as e: + log.error("Android read failed: " + str(e)) + self.android.connect() + + def write_android(self, android_queue): + while True: + if not android_queue.empty(): + try: + msg = android_queue.get_nowait() + self.android.write(msg) + # log.info('Write Android: ' + str(msg)) + except Exception as e: + log.error("Android write failed " + str(e)) + self.android.connect() + + def read_arduino(self, pc_queue): + while True: + msg = self.arduino.read() + if msg is not None and msg != "Connected": + log.info('Read Arduino: ' + str(msg)) + pc_queue.put_nowait(msg) + + def write_arduino(self, arduino_queue): + while True: + if not arduino_queue.empty(): + msg = arduino_queue.get_nowait() + self.arduino.write(msg) + log.info('Write Arduino: ' + str(msg)) + + def read_pc(self, android_queue, arduino_queue): + while True: + msg = self.pc.read() + if msg is not None: + log.info('Read PC: ' + str(msg['target']) + '; ' + str(msg['payload'])) + if msg['target'] == 'android': + android_queue.put_nowait(msg['payload']) + elif msg['target'] == 'arduino': + arduino_queue.put_nowait(msg['payload']) + elif msg['target'] == 'both': + android_queue.put_nowait(msg['payload']['android']) + arduino_queue.put_nowait(msg['payload']['arduino']) + + def write_pc(self, pc_queue): + while True: + if not pc_queue.empty(): + msg = pc_queue.get_nowait() + self.pc.write(msg) + log.info('Write PC: ' + str(msg)) + + def detect_symbols(self, android_queue): + while True: + frame = self.detector.get_frame() + symbol_match = self.detector.detect(frame) + if symbol_match is not None: + print('Symbol Match ID: ' + str(symbol_match)) + android_queue.put_nowait('SID|' + str(symbol_match)) + diff --git a/playgrounds/arduino_command.py b/playgrounds/arduino_command.py index 2e8a4da..5b910eb 100644 --- a/playgrounds/arduino_command.py +++ b/playgrounds/arduino_command.py @@ -10,6 +10,12 @@ print(pc_msg) while True: + try: + msg = arduino.read() + if msg is not None: + print(msg) + except Exception as e: + pass command = input("Enter command to send to Arduino:") if command == 'demo': print('Init demo') diff --git a/playgrounds/multiprocess_test.py b/playgrounds/multiprocess_test.py new file mode 100644 index 0000000..3cced36 --- /dev/null +++ b/playgrounds/multiprocess_test.py @@ -0,0 +1,53 @@ +import _thread +import queue +import os +import time + +from multiprocessing import Process + +''' +Multithreading: _thread.start_new_thread(function, args[, kwargs]) +''' + +def test_thread(name, delay): + while True: + time.sleep(delay) + print('%s Ping' % (name)) + + +class Multiprocess: + def __init__(self): + print('Init Multithread') + self.run = False + + def start(self): + print('Begin Multithread Session') + self.run = True + # _thread.start_new_thread(test_thread, ('Thread 1', 1)) + # _thread.start_new_thread(test_thread, ('Thread 2', 2)) + # _thread.start_new_thread(test_thread, ('Thread 3', 4)) + x1 = Process(target=test_thread, args=('Thread 1', 1)) + x2 = Process(target=test_thread, args=('Thread 2', 2)) + x3 = Process(target=test_thread, args=('Thread 3', 4)) + + x1.start() + x2.start() + x3.start() + + print('Multiprocess Started') + + def end(self): + print('End Multithread Session') + self.run = False + +mp = Multiprocess() +mp.start() + +while mp.run: + try: + pass + except KeyboardInterrupt: + mt.end() + + + diff --git a/playgrounds/multithread_test.py b/playgrounds/multithread_test.py index f1abc27..d8bbc93 100644 --- a/playgrounds/multithread_test.py +++ b/playgrounds/multithread_test.py @@ -24,6 +24,7 @@ def start(self): _thread.start_new_thread(test_thread, ('Thread 1', 1)) _thread.start_new_thread(test_thread, ('Thread 2', 2)) _thread.start_new_thread(test_thread, ('Thread 3', 4)) + print('Multithread Started') def end(self): print('End Multithread Session') diff --git a/playgrounds/pc_command.py b/playgrounds/pc_command.py new file mode 100644 index 0000000..d30e6e7 --- /dev/null +++ b/playgrounds/pc_command.py @@ -0,0 +1,9 @@ +from src.communicator.PC import PC +import time + +pc = PC() +pc.connect() + +while True: + command = input("Enter command to send to PC:") + pc.write(command) diff --git a/src/Logger.py b/src/Logger.py index e94da7b..5e5ff48 100644 --- a/src/Logger.py +++ b/src/Logger.py @@ -11,4 +11,4 @@ def warning(self, msg): logging.warning(msg) def error(self, msg): - logging.error(msg) \ No newline at end of file + logging.error(msg) diff --git a/src/communicator/Arduino.py b/src/communicator/Arduino.py index 65825ae..6a99dbd 100644 --- a/src/communicator/Arduino.py +++ b/src/communicator/Arduino.py @@ -4,6 +4,7 @@ from src.config import SERIAL_PORT from src.config import BAUD_RATE from src.config import LOCALE +from src.communicator.utils import ardMsgParser log = Logger() @@ -57,7 +58,7 @@ def read(self): try: msg = self.connection.readline().strip().decode(LOCALE) if len(msg) > 0: - return msg + return ardMsgParser(msg) return None except Exception as error: log.error('Arduino read failed: ' + str(error)) diff --git a/src/communicator/MultiProcess.py b/src/communicator/MultiProcess.py new file mode 100644 index 0000000..e18e1b4 --- /dev/null +++ b/src/communicator/MultiProcess.py @@ -0,0 +1,129 @@ +import _thread + +from multiprocessing import Process, Queue +import queue +import os +import cv2 as cv +import time + +from src.Logger import Logger +from src.detector.SymbolDetector import SymbolDetector +from src.communicator.Arduino import Arduino +from src.communicator.PC import PC +from src.communicator.Android import Android + +log = Logger() + +''' +Multithreading essentially refers to running multiple processes in parallel +Communications between Rpi and other devices involve a session, which means +the Rpi will be waiting for a trigger. Hence if single threaded, Rpi can only +do one thing at one time. With multhreading, Rpi can have multiple sessions +simultaneuously. Image Recognition will have to be run as a thread as well. +''' + +class MultiProcess: + def __init__(self): + log.info('Initializing Multithread Communication') + # self.android = Android() + self.arduino = Arduino() + self.pc = PC() + self.detector = SymbolDetector() + + # self.android.connect() + self.arduino.connect() + self.pc.connect() + + self.android_queue = Queue() + self.arduino_queue = Queue() + self.pc_queue = Queue() + + def start(self): + # self.detector.start() + + # r_android = Process(target=self.read_android, args=(self.pc_queue,)) + # r_android.start() + # w_android = Process(target=self.write_android, args=(self.android_queue,)) + # w_android.start() + + r_arduino = Process(target=self.read_arduino, args=(self.pc_queue,)) + r_arduino.start() + w_arduino = Process(target=self.write_arduino, args=(self.arduino_queue,)) + w_arduino.start() + + r_pc = Process(target=self.read_pc, args=(self.android_queue, self.arduino_queue,)) + r_pc.start() + w_pc = Process(target=self.write_pc, args=(self.pc_queue,)) + w_pc.start() + + # symbol_detect = Process(target=self.detect_symbols, args=(self.android_queue,)) + + def end(self): + self.detector.end() + log.info('Multithread Communication Session Ended') + + def read_android(self, pc_queue): + while True: + try: + msg = self.android.read() + if msg is not None: + log.info('Read Android:' + str(msg)) + pc_queue.put_nowait(msg) + + except Exception as e: + log.error("Android read failed: " + str(e)) + self.android.connect() + + def write_android(self, android_queue): + while True: + if not android_queue.empty(): + try: + msg = android_queue.get_nowait() + self.android.write(msg) + # log.info('Write Android: ' + str(msg)) + except Exception as e: + log.error("Android write failed " + str(e)) + self.android.connect() + + def read_arduino(self, pc_queue): + while True: + msg = self.arduino.read() + if msg is not None and msg != "Connected": + log.info('Read Arduino: ' + str(msg)) + pc_queue.put_nowait(msg) + + def write_arduino(self, arduino_queue): + while True: + if not arduino_queue.empty(): + msg = arduino_queue.get_nowait() + self.arduino.write(msg) + log.info('Write Arduino: ' + str(msg)) + + def read_pc(self, android_queue, arduino_queue): + while True: + msg = self.pc.read() + if msg is not None: + log.info('Read PC: ' + str(msg['target']) + '; ' + str(msg['payload'])) + if msg['target'] == 'android': + android_queue.put_nowait(msg['payload']) + elif msg['target'] == 'arduino': + arduino_queue.put_nowait(msg['payload']) + elif msg['target'] == 'both': + android_queue.put_nowait(msg['payload']['android']) + arduino_queue.put_nowait(msg['payload']['arduino']) + + def write_pc(self, pc_queue): + while True: + if not pc_queue.empty(): + msg = pc_queue.get_nowait() + self.pc.write(msg) + log.info('Write PC: ' + str(msg)) + + def detect_symbols(self, android_queue): + while True: + frame = self.detector.get_frame() + symbol_match = self.detector.detect(frame) + if symbol_match is not None: + print('Symbol Match ID: ' + str(symbol_match)) + android_queue.put_nowait('SID|' + str(symbol_match)) + diff --git a/src/communicator/MultiThread.py b/src/communicator/MultiThread.py index b5e6425..e119f65 100644 --- a/src/communicator/MultiThread.py +++ b/src/communicator/MultiThread.py @@ -27,12 +27,12 @@ class MultiThread: def __init__(self): log.info('Initializing Multithread Communication') - self.android = Android() + # self.android = Android() self.arduino = Arduino() self.pc = PC() self.detector = SymbolDetector() - self.android.connect() + # self.android.connect() self.arduino.connect() self.pc.connect() @@ -43,11 +43,11 @@ def __init__(self): def start(self): self.detector.start() - _thread.start_new_thread(self.read_android, (self.pc_queue,)) + # _thread.start_new_thread(self.read_android, (self.pc_queue,)) _thread.start_new_thread(self.read_arduino, (self.pc_queue,)) _thread.start_new_thread(self.read_pc,(self.android_queue, self.arduino_queue,)) - _thread.start_new_thread(self.write_android, (self.android_queue,)) + # _thread.start_new_thread(self.write_android, (self.android_queue,)) _thread.start_new_thread(self.write_arduino, (self.arduino_queue,)) _thread.start_new_thread(self.write_pc, (self.pc_queue,)) @@ -69,6 +69,9 @@ def read_android(self, pc_queue): if msg is not None: log.info('Read Android:' + str(msg)) pc_queue.put_nowait(msg) + # if msg == 'SV': + # arduino_queue.put_nowait(msg) + except Exception as e: log.error("Android read failed: " + str(e)) self.android.connect() @@ -87,7 +90,7 @@ def write_android(self, android_queue): def read_arduino(self, pc_queue): while True: msg = self.arduino.read() - if msg is not None: + if msg is not None and msg != "Connected": log.info('Read Arduino: ' + str(msg)) pc_queue.put_nowait(msg) diff --git a/src/communicator/utils.py b/src/communicator/utils.py index b69881b..ba68af1 100644 --- a/src/communicator/utils.py +++ b/src/communicator/utils.py @@ -1,6 +1,20 @@ from src.Logger import Logger log = Logger() +arduino_commands = ['H', 'F', 'S'] +arduino_out = ['SD', 'MC', 'CC', 'EC'] + +''' +Parse messages received from Arduino, essentially filters out +unnecessary messages +''' +def ardMsgParser(msg): + data = msg.split('|') + if data[0] in arduino_out: + return msg + else: + return None + ''' Parse messages received from PC, packages payload into a JSON holding a target and payload @@ -32,6 +46,9 @@ def pcMsgParser(msg): 'android': payload, 'arduino': payload, } + elif command in arduino_commands: + target = 'arduino' + payload = command else: log.error('pcMsgParser unknown command: ' + str(command))