Line 125: |
Line 125: |
| ====Laptop Code for Robot/Laptop Base Communication ==== | | ====Laptop Code for Robot/Laptop Base Communication ==== |
| <source lang="Python"> | | <source lang="Python"> |
− | # -*- coding: utf-8 -*- | + | #!/usr/bin/python3 |
− | #author: joel.martin
| + | |
− | #import the modules required here
| + | |
| + | import queue |
| + | import threading |
| + | import time |
| + | import itertools |
| import PySimpleGUI as sg | | import PySimpleGUI as sg |
| import socket | | import socket |
| | | |
− | GRAPH_SIZE = (500,400)
| + | def worker_thread1(thread_name, gui_queue): |
− | GRAPH_STEP_SIZE = 1
| + | """ |
| + | A worker thread that communicates with the GUI |
| + | These threads can call functions that block without affecting the GUI (a good thing) |
| + | Note that this function is the code started as each thread. |
| + | This thread recieves data from the BOT. |
| + | """ |
| + | while True: |
| + | message_from_bot = (client.recv(4096)).decode() |
| + | gui_queue.put(message_from_bot) |
| + | #print (message_from_bot) |
| + | #if message_from_bot == "RxAck:Engaging Robot Shutdown" : escape = False |
| | | |
− | sg.change_look_and_feel('GreenMono') # give our window a spiffy set of colors
| + | def worker_thread2(thread_name, run_freq, gui_queue): |
− | # ------ GetFile Window Definition ------ #
| + | gui_queue.put('{} - {}'.format(thread_name)) |
− | | + | |
− | # ------ Menu Definition ------ #
| + | def worker_thread3(thread_name, run_freq, gui_queue): |
− | menu_def = [['&File', ['&Open Text File to Transmit', '---', 'Properties', '---','H&alt Everything']],
| + | gui_queue.put('{} - {}'.format(thread_name)) |
− | ['&Help', '&About...'], ]
| |
− | # ------ Column Definition ------ #
| |
− | col1 = [
| |
− | [sg.Text('Bot Message response', size=(30, 1))],
| |
− | [sg.Output(size=(40, 20), font=('Mono 8'))],
| |
− | [sg.Text('Bot Command Single Entry', size=(30, 1))],
| |
− | [sg.InputText(size=(30, 0), key='-QUERY-')],
| |
− | [sg.Button('Send Command',size=(20,1), button_color=(sg.YELLOWS[0], sg.GREENS[0]), bind_return_key=True)],
| |
− | ]
| |
− | col2 = [
| |
− | [sg.Text('Bot Jitter Test',font=('Mono 9'), justification="center", size=(48, 1))],
| |
− | [sg.Button('<<CCW',size=(10,1),font=('Mono 9'), button_color=(sg.YELLOWS[0], sg.GREENS[0])),
| |
− | sg.Button('S2S-F2B',size=(10,1),font=('Mono 9'), button_color=(sg.YELLOWS[0], sg.GREENS[0])),
| |
− | sg.Button('Combo',size=(10,1),font=('Mono 9'), button_color=(sg.YELLOWS[0], sg.GREENS[0])),
| |
− | sg.Button('CW>>',size=(10,1),font=('Mono 9'), button_color=(sg.YELLOWS[0], sg.GREENS[0]))],
| |
− |
| |
− | [sg.Text('Bot Rotation',font=('Mono 9'), justification="center", size=(48, 1))],
| |
− | [sg.Button('<<180 CCW',size=(10,1),font=('Mono 9'), button_color=(sg.YELLOWS[0], sg.GREENS[0])),
| |
− | sg.Button('<180 CCW',size=(10,1),font=('Mono 9'), button_color=(sg.YELLOWS[0], sg.GREENS[0])),
| |
− | sg.Button('180 CW>',size=(10,1),font=('Mono 9'), button_color=(sg.YELLOWS[0], sg.GREENS[0])),
| |
− | sg.Button('180 CW>>',size=(10,1),font=('Mono 9'), button_color=(sg.YELLOWS[0], sg.GREENS[0])),],
| |
− |
| |
− | [sg.Button('<<Input CCW',size=(15,1),font=('Mono 9'), button_color=(sg.YELLOWS[0], sg.GREENS[0])),
| |
− | sg.InputText(size=(11, 0), justification="center", key='-Rotate-'),
| |
− | sg.Button('Input CW>>',size=(15,1),font=('Mono 9'), button_color=(sg.YELLOWS[0], sg.GREENS[0])),
| |
− | ],
| |
− |
| |
− | [sg.Text('IMU',font=('Mono 9'), justification="center", size=(48, 1))],
| |
− | [sg.Button('Zero to North',size=(16,1),font=('Mono 9'), button_color=(sg.YELLOWS[0], sg.GREENS[0])),
| |
− | sg.Button('South',size=(8,1),font=('Mono 9'), button_color=(sg.YELLOWS[0], sg.GREENS[0])),
| |
− | sg.Button('East',size=(8,1),font=('Mono 9'), button_color=(sg.YELLOWS[0], sg.GREENS[0])),
| |
− | sg.Button('West',size=(8,1),font=('Mono 9'), button_color=(sg.YELLOWS[0], sg.GREENS[0])),],
| |
− |
| |
− | [sg.Text('Linear Movement',font=('Mono 9'), justification="center", size=(48, 1))],
| |
− | [sg.Text('Bot Angle:',font=('Mono 9'), justification="Left", size=(10, 1)),
| |
− | sg.InputText(size=(5, 0), justification="center", key='-BotAngle-'),
| |
− | sg.Text('Line of Bearing:',font=('Mono 9'), justification="Left", size=(15, 1)),
| |
− | sg.InputText(size=(5, 0), justification="center", key='-Bearing-'),],
| |
− | [sg.Text('Speed:',font=('Mono 9'), justification="Left", size=(8, 1)),
| |
− | sg.Slider(range=(1,255),key='speed', default_value=127, size=(22,15), orientation='horizontal', font=('Helvetica', 12)),],
| |
− | [sg.Button('Execute Move',size=(15,1),font=('Mono 9'), button_color=(sg.YELLOWS[0], sg.GREENS[0])),
| |
− | sg.Button('Execute Move with Spin',size=(30,1),font=('Mono 9'), button_color=(sg.YELLOWS[0], sg.GREENS[0])),],
| |
− | ]
| |
− | col3 = [
| |
− | [sg.Graph(GRAPH_SIZE, (0,0), GRAPH_SIZE, key='-GRAPH-', background_color='lightblue')
| |
− | ],
| |
| | | |
− | ]
| + | def the_gui(gui_queue): |
− | layout = [ | + | GRAPH_SIZE = (400,400) |
| + | GRAPH_STEP_SIZE = 1 |
| + | sg.change_look_and_feel('GreenMono') # give our window a spiffy set of colors |
| + | # ------ GetFile Window Definition ------ # |
| + | |
| + | # ------ Menu Definition ------ # |
| + | menu_def = [['&File', ['&Open Text File to Transmit', '---', 'Properties', '---','H&alt Everything']], |
| + | ['&Help', '&About...'], ] |
| + | # ------ Column Definition ------ # |
| + | col1 = [ |
| + | [sg.Text('Bot Message response', size=(30, 1))], |
| + | [sg.Output(size=(40, 20), font=('Mono 8'))], |
| + | [sg.Text('Bot Command Single Entry', size=(30, 1))], |
| + | [sg.InputText(size=(30, 0), key='-QUERY-')], |
| + | [sg.Button('Send Command',size=(20,1), button_color=(sg.YELLOWS[0], sg.GREENS[0]), bind_return_key=True)], |
| + | ] |
| + | col2 = [ |
| + | [sg.Text('Bot Jitter Test',font=('Mono 9'), justification="center", size=(48, 1))], |
| + | [sg.Button('<<CCW',size=(10,1),font=('Mono 9'), button_color=(sg.YELLOWS[0], sg.GREENS[0])), |
| + | sg.Button('S2S-F2B',size=(10,1),font=('Mono 9'), button_color=(sg.YELLOWS[0], sg.GREENS[0])), |
| + | sg.Button('Combo',size=(10,1),font=('Mono 9'), button_color=(sg.YELLOWS[0], sg.GREENS[0])), |
| + | sg.Button('CW>>',size=(10,1),font=('Mono 9'), button_color=(sg.YELLOWS[0], sg.GREENS[0]))], |
| + | |
| + | [sg.Text('Bot Rotation',font=('Mono 9'), justification="center", size=(48, 1))], |
| + | [sg.Button('<<180 CCW',size=(10,1),font=('Mono 9'), button_color=(sg.YELLOWS[0], sg.GREENS[0])), |
| + | sg.Button('<180 CCW',size=(10,1),font=('Mono 9'), button_color=(sg.YELLOWS[0], sg.GREENS[0])), |
| + | sg.Button('180 CW>',size=(10,1),font=('Mono 9'), button_color=(sg.YELLOWS[0], sg.GREENS[0])), |
| + | sg.Button('180 CW>>',size=(10,1),font=('Mono 9'), button_color=(sg.YELLOWS[0], sg.GREENS[0])),], |
| + | |
| + | [sg.Button('<<Input CCW',size=(15,1),font=('Mono 9'), button_color=(sg.YELLOWS[0], sg.GREENS[0])), |
| + | sg.InputText(size=(11, 0), justification="center", key='-Rotate-'), |
| + | sg.Button('Input CW>>',size=(15,1),font=('Mono 9'), button_color=(sg.YELLOWS[0], sg.GREENS[0])), |
| + | ], |
| + | |
| + | [sg.Text('IMU',font=('Mono 9'), justification="center", size=(48, 1))], |
| + | [sg.Button('Zero to North',size=(16,1),font=('Mono 9'), button_color=(sg.YELLOWS[0], sg.GREENS[0])), |
| + | sg.Button('South',size=(8,1),font=('Mono 9'), button_color=(sg.YELLOWS[0], sg.GREENS[0])), |
| + | sg.Button('East',size=(8,1),font=('Mono 9'), button_color=(sg.YELLOWS[0], sg.GREENS[0])), |
| + | sg.Button('West',size=(8,1),font=('Mono 9'), button_color=(sg.YELLOWS[0], sg.GREENS[0])),], |
| + | |
| + | [sg.Text('Linear Movement',font=('Mono 9'), justification="center", size=(48, 1))], |
| + | [sg.Text('Bot Angle:',font=('Mono 9'), justification="Left", size=(10, 1)), |
| + | sg.InputText(size=(5, 0), justification="center", key='-BotAngle-'), |
| + | sg.Text('Line of Bearing:',font=('Mono 9'), justification="Left", size=(15, 1)), |
| + | sg.InputText(size=(5, 0), justification="center", key='-Bearing-'),], |
| + | [sg.Text('Speed:',font=('Mono 9'), justification="Left", size=(8, 1)), |
| + | sg.Slider(range=(1,255),key='speed', default_value=127, size=(22,15), orientation='horizontal', font=('Helvetica', 12)),], |
| + | [sg.Button('Execute Move',size=(15,1),font=('Mono 9'), button_color=(sg.YELLOWS[0], sg.GREENS[0])), |
| + | sg.Button('Execute Move with Spin',size=(30,1),font=('Mono 9'), button_color=(sg.YELLOWS[0], sg.GREENS[0])),], |
| + | ] |
| + | col3 = [ |
| + | [sg.Graph(GRAPH_SIZE, (0,0), GRAPH_SIZE, key='-GRAPH-', background_color='lightblue')], |
| + | ] |
| + | col4 = [ |
| + | [sg.Button('Gyroscope',size=(15,1),font=('Mono 9'), button_color=(sg.YELLOWS[0], sg.GREENS[0]))], |
| + | [sg.Text('X',font=('Mono 9'), justification="center", size=(5, 1)), |
| + | sg.Text('Y',font=('Mono 9'), justification="center", size=(5, 1)), |
| + | sg.Text('Z',font=('Mono 9'), justification="center", size=(5, 1))], |
| + | ] |
| + | layout = [ |
| [sg.Menu(menu_def, tearoff=True)], | | [sg.Menu(menu_def, tearoff=True)], |
| [sg.Column(col1, pad=((1,1),(1,1)), justification="left", background_color = None), | | [sg.Column(col1, pad=((1,1),(1,1)), justification="left", background_color = None), |
| sg.Column(col2, pad=((1,1),(1,1)), justification="left", background_color = None), | | sg.Column(col2, pad=((1,1),(1,1)), justification="left", background_color = None), |
| sg.Column(col3, pad=((1,1),(1,1)), justification="left", background_color = None), | | sg.Column(col3, pad=((1,1),(1,1)), justification="left", background_color = None), |
| + | sg.Column(col4, pad=((1,1),(1,1)), justification="left", background_color = None), |
| ]] | | ]] |
| | | |
− | | + | |
− | main_window = sg.Window('Crawler Bot Window Control', layout, font=('Helvetica', ' 11'), default_button_element_size=(8, 2)) | + | main_window = sg.Window('Crawler Bot Window Control', layout, font=('Helvetica', ' 11'), default_button_element_size=(8, 2)) |
− | | + | # --------------------- EVENT LOOP --------------------- |
− | #start executing main here --------------------------------------- | |
− | if __name__ == '__main__':
| |
− | #sg.Popup('Data!')
| |
− | message_from_bot = ''
| |
− | #client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
| |
− | #client.connect(('192.168.1.132', 13000))
| |
| escape = True | | escape = True |
− | | + | message_to_bot = '' |
− | while escape == True: | + | while True and escape == True: |
− | message_from_bot ='' | + | # wait for up to 100 ms for a GUI event |
− | #----------------process all the window events -------------------------- | + | event, values = main_window.read(timeout=100) |
− | event, value = main_window.read() | + | if event in (None, 'Exit'): |
| + | break |
| if event == 'Open Text File to Transmit': | | if event == 'Open Text File to Transmit': |
| text = sg.PopupGetFile("Open the file to transmit", | | text = sg.PopupGetFile("Open the file to transmit", |
Line 218: |
Line 241: |
| #transmit line by line to the bot | | #transmit line by line to the bot |
| print ("Transmitting Message") | | print ("Transmitting Message") |
− | #client.send(message_to_bot.encode()) | + | client.send(message_to_bot.encode()) |
| if event == 'Halt Everything': | | if event == 'Halt Everything': |
| message_to_bot = "SRS" | | message_to_bot = "SRS" |
− | #client.send(message_to_bot.encode()) | + | client.send(message_to_bot.encode()) |
| break | | break |
| + | if event == 'Gyroscope': |
| + | message_to_bot = "GYR" |
| + | client.send(message_to_bot.encode()) |
| + | if event == '<<CCW': |
| + | message_to_bot = "TST" |
| + | client.send(message_to_bot.encode()) |
| if event == 'Send Command': | | if event == 'Send Command': |
| message_to_bot = value['-QUERY-'].rstrip() | | message_to_bot = value['-QUERY-'].rstrip() |
− | #client.send(message_to_bot.encode()) | + | client.send(message_to_bot.encode()) |
− | #------------------------------------------------------------------------- | + | # --------------- Loop through all messages coming in from threads --------------- |
− | #message_from_bot = (client.recv(4096)).decode() | + | while True: # loop executes until runs out of messages in Queue |
− | print (message_from_bot)
| + | try: # see if something has been posted to Queue |
− | if message_from_bot == "RxAck:Engaging Robot Shutdown" : escape = False
| + | message = gui_queue.get_nowait() |
− |
| + | except queue.Empty: # get_nowait() will get exception when Queue is empty |
| + | break # break from the loop if no more messages are queued up |
| + | # if message received from queue, display the message in the Window |
| + | if message: |
| + | #main_window['-QUERY-'].update(message) |
| + | # do a refresh because could be showing multiple messages before next Read |
| + | main_window.refresh() |
| + | print(message) |
| + | if message == "RxAck:Engaging Robot Shutdown" : escape = False |
| + | # if user exits the window, then close the window and exit the GUI func |
| main_window.close() | | main_window.close() |
− | #client.close() | + | |
| + | if __name__ == '__main__': |
| + | client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) |
| + | client.connect(('192.168.1.132', 13000)) |
| + | # -- Create a Queue to communicate with GUI -- |
| + | # queue used to communicate between the gui and the threads |
| + | gui_queue = queue.Queue() |
| + | # -- Start threads, each taking a different amount of time |
| + | threading.Thread(target=worker_thread1, args=( |
| + | 'Thread 1', gui_queue,), daemon=True).start() |
| + | #threading.Thread(target=worker_thread2, args=( |
| + | # 'Thread 2', 200, gui_queue,), daemon=True).start() |
| + | #threading.Thread(target=worker_thread3, args=( |
| + | # 'Thread 3', 1000, gui_queue,), daemon=True).start() |
| + | # -- Start the GUI passing in the Queue -- |
| + | the_gui(gui_queue) |
| + | |
| + | client.close() |
| print ("You ended the Robot Server Session") | | print ("You ended the Robot Server Session") |
| </source> | | </source> |