Пример #1
0
    def __init__(self, host):
        rospy.init_node("GUI")

        self.payload = {'image': '','lap': '', 'map': '', 'v':'','w':''}
        self.server = None
        self.client = None
        
        self.host = host

        # Image variable
        self.shared_image = SharedImage("guiimage")
        
        # Get HAL variables
        self.shared_v = SharedValue("velocity")
        self.shared_w = SharedValue("angular")
        
        # Create the lap object
        pose3d_object = ListenerPose3d("/F1ROS/odom")
        self.lap = Lap(pose3d_object)
        self.map = Map(pose3d_object)

        # Event objects for multiprocessing
        self.ack_event = multiprocessing.Event()
        self.cli_event = multiprocessing.Event()

        # Start server thread
        t = threading.Thread(target=self.run_server)
        t.start()
Пример #2
0
    def __init__(self):
        super(ProcessGUI, self).__init__()

        self.host = sys.argv[1]

        # Time variables
        self.time_cycle = SharedValue("gui_time_cycle")
        self.ideal_cycle = SharedValue("gui_ideal_cycle")
        self.iteration_counter = 0
Пример #3
0
    def __init__(self):
        rospy.init_node("HAL")

        # Shared memory variables
        self.shared_image = SharedImage("halimage")
        self.shared_v = SharedValue("velocity")
        self.shared_w = SharedValue("angular")

        # ROS Topics
        self.camera = ListenerCamera("/F1ROS/cameraL/image_raw")
        self.motors = PublisherMotors("/F1ROS/cmd_vel", 4, 0.3)

        # Update thread
        self.thread = ThreadHAL(self.update_hal)
Пример #4
0
class HAL:
    IMG_WIDTH = 320
    IMG_HEIGHT = 240

    def __init__(self):
        rospy.init_node("HAL")

        # Shared memory variables
        self.shared_image = SharedImage("halimage")
        self.shared_v = SharedValue("velocity")
        self.shared_w = SharedValue("angular")

        # ROS Topics
        self.camera = ListenerCamera("/F1ROS/cameraL/image_raw")
        self.motors = PublisherMotors("/F1ROS/cmd_vel", 4, 0.3)

        # Update thread
        self.thread = ThreadHAL(self.update_hal)

    # Function to start the update thread
    def start_thread(self):
        self.thread.start()

    # Get Image from ROS Driver Camera
    def getImage(self):
        image = self.camera.getImage().data
        self.shared_image.add(image)

    # Set the velocity
    def setV(self):
        velocity = self.shared_v.get()
        self.motors.sendV(velocity)

    # Get the velocity
    def getV(self):
        velocity = self.shared_v.get()
        return velocity

    # Get the angular velocity
    def getW(self):
        angular = self.shared_w.get()
        return angular

    # Set the angular velocity
    def setW(self):
        angular = self.shared_w.get()
        self.motors.sendW(angular)

    def update_hal(self):
        self.getImage()
        self.setV()
        self.setW()

    # Destructor function to close all fds
    def __del__(self):
        self.shared_image.close()
        self.shared_v.close()
        self.shared_w.close()
Пример #5
0
class HALFunctions:
    def __init__(self):
        # Initialize image variable
        self.shared_image = SharedImage("halimage")
        self.shared_v = SharedValue("velocity")
        self.shared_w = SharedValue("angular")

    # Get image function
    def getImage(self):
        image = self.shared_image.get()
        return image

    # Send velocity function
    def sendV(self, velocity):
        self.shared_v.add(velocity)

    # Send angular velocity function
    def sendW(self, angular):
        self.shared_w.add(angular)
    def __init__(self, code, exit_signal):
        super(BrainProcess, self).__init__()

        # Initialize exit signal
        self.exit_signal = exit_signal

        # Function definitions for users to use
        self.hal = HALFunctions()
        self.gui = GUIFunctions()

        # Time variables
        self.time_cycle = SharedValue('brain_time_cycle')
        self.ideal_cycle = SharedValue('brain_ideal_cycle')
        self.iteration_counter = 0

        # Get the sequential and iterative code
        # Something wrong over here! The code is reversing
        # Found a solution but could not find the reason for this
        self.sequential_code = code[1]
        self.iterative_code = code[0]
    def __init__(self):
        self.brain_process = None
        self.reload = multiprocessing.Event()
        
        # Time variables
        self.brain_time_cycle = SharedValue('brain_time_cycle')
        self.brain_ideal_cycle = SharedValue('brain_ideal_cycle')
        self.real_time_factor = 0

        self.frequency_message = {'brain': '', 'gui': '', 'rtf': ''}

        # GUI variables
        self.gui_time_cycle = SharedValue('gui_time_cycle')
        self.gui_ideal_cycle = SharedValue('gui_ideal_cycle')
                
        self.server = None
        self.client = None
        self.host = sys.argv[1]

        # Initialize the GUI and HAL behind the scenes
        self.hal = HAL()
class Template:
    # Initialize class variables
    # self.time_cycle to run an execution for atleast 1 second
    # self.process for the current running process
    def __init__(self):
        self.brain_process = None
        self.reload = multiprocessing.Event()
        
        # Time variables
        self.brain_time_cycle = SharedValue('brain_time_cycle')
        self.brain_ideal_cycle = SharedValue('brain_ideal_cycle')
        self.real_time_factor = 0

        self.frequency_message = {'brain': '', 'gui': '', 'rtf': ''}

        # GUI variables
        self.gui_time_cycle = SharedValue('gui_time_cycle')
        self.gui_ideal_cycle = SharedValue('gui_ideal_cycle')
                
        self.server = None
        self.client = None
        self.host = sys.argv[1]

        # Initialize the GUI and HAL behind the scenes
        self.hal = HAL()
        
    # Function for saving   
    def save_code(self, source_code):
    	with open('code/academy.py', 'w') as code_file:
    		code_file.write(source_code)
    
    # Function for loading		
    def load_code(self):
    	with open('code/academy.py', 'r') as code_file:
    		source_code = code_file.read()
    		
    	return source_code

    # Function to parse the code
    # A few assumptions: 
    # 1. The user always passes sequential and iterative codes
    # 2. Only a single infinite loop
    def parse_code(self, source_code):
    	# Check for save/load
    	if(source_code[:5] == "#save"):
    		source_code = source_code[5:]
    		self.save_code(source_code)
    		
    		return "", ""
    	
    	elif(source_code[:5] == "#load"):
    		source_code = source_code + self.load_code()
    		self.server.send_message(self.client, source_code)
    
    		return "", ""

        elif(source_code[:5] == "#resu"):
                restart_simulation = rospy.ServiceProxy('/gazebo/unpause_physics', Empty)
                restart_simulation()

                return "", ""

        elif(source_code[:5] == "#paus"):
                pause_simulation = rospy.ServiceProxy('/gazebo/pause_physics', Empty)
                pause_simulation()

                return "", ""
    		
    	elif(source_code[:5] == "#rest"):
    		reset_simulation = rospy.ServiceProxy('/gazebo/reset_world', Empty)
    		reset_simulation()
    		return "", ""
    		
    	else:
    		sequential_code, iterative_code = self.seperate_seq_iter(source_code)
    		return iterative_code, sequential_code
    
    # Function to seperate the iterative and sequential code
    def seperate_seq_iter(self, source_code):
    	if source_code == "":
            return "", ""

        # Search for an instance of while True
        infinite_loop = re.search(r'[^ \t]while\(True\):|[^ \t]while True:', source_code)

        # Seperate the content inside while True and the other
        # (Seperating the sequential and iterative part!)
        try:
            start_index = infinite_loop.start()
            iterative_code = source_code[start_index:]
            sequential_code = source_code[:start_index]

            # Remove while True: syntax from the code
            # And remove the the 4 spaces indentation before each command
            iterative_code = re.sub(r'[^ ]while\(True\):|[^ ]while True:', '', iterative_code)
            iterative_code = re.sub(r'^[ ]{4}', '', iterative_code, flags=re.M)

        except:
            sequential_code = source_code
            iterative_code = ""
            
        return sequential_code, iterative_code
    
    # Function to maintain thread execution
    def execute_thread(self, source_code):
        # Keep checking until the thread is alive
        # The thread will die when the coming iteration reads the flag
        if(self.brain_process != None):
            while self.brain_process.is_alive():
                pass

        # Turn the flag down, the iteration has successfully stopped!
        self.reload.clear()
        # New thread execution
        code = self.parse_code(source_code)
        if code[0] == "" and code[1] == "":
            return
            
        self.brain_process = BrainProcess(code, self.reload)
        self.brain_process.start()

    # Function to read and set frequency from incoming message
    def read_frequency_message(self, message):
        frequency_message = json.loads(message)

        # Set brain frequency
        frequency = float(frequency_message["brain"])
        self.brain_time_cycle.add(1000.0 / frequency)

        # Set gui frequency
        frequency = float(frequency_message["gui"])
        self.gui_time_cycle.add(1000.0 / frequency)

        return

    # Function to track the real time factor from Gazebo statistics
    # https://stackoverflow.com/a/17698359
    # (For reference, Python3 solution specified in the same answer)
    def track_stats(self):
        args=["gz", "stats", "-p"]
        # Prints gz statistics. "-p": Output comma-separated values containing-
        # real-time factor (percent), simtime (sec), realtime (sec), paused (T or F)
        stats_process = subprocess.Popen(args, stdout=subprocess.PIPE, bufsize=1)
        # bufsize=1 enables line-bufferred mode (the input buffer is flushed 
        # automatically on newlines if you would write to process.stdin )
        with stats_process.stdout:
            for line in iter(stats_process.stdout.readline, b''):
                stats_list = [x.strip() for x in line.split(',')]
                self.real_time_factor = stats_list[0]     


    # Function to generate and send frequency messages
    def send_frequency_message(self):
        # This function generates and sends frequency measures of the brain and gui
        brain_frequency = 0; gui_frequency = 0
        try:
            brain_frequency = round(1000 / self.brain_ideal_cycle.get(), 1)
        except ZeroDivisionError:
            brain_frequency = 0

        try:
            gui_frequency = round(1000 / self.gui_ideal_cycle.get(), 1)
        except ZeroDivisionError:
            gui_frequency = 0

        self.frequency_message["brain"] = brain_frequency
        self.frequency_message["gui"] = gui_frequency
        self.frequency_message["rtf"] = self.real_time_factor

        message = "#freq" + json.dumps(self.frequency_message)
        self.server.send_message(self.client, message)


    # The websocket function
    # Gets called when there is an incoming message from the client
    def handle(self, client, server, message):
        if(message[:5] == "#freq"):
            frequency_message = message[5:]
            self.read_frequency_message(frequency_message)
            self.send_frequency_message()
            return
        
        try:
            # Once received turn the reload flag up and send it to execute_thread function
            code = message
            # print(repr(code))
            self.reload.set()
            self.execute_thread(code)
        except:
            pass

    # Function that gets called when the server is connected
    def connected(self, client, server):
    	self.client = client
    	# Start the HAL update thread
        self.hal.start_thread()

        # Start real time factor tracker thread
        self.stats_thread = threading.Thread(target=self.track_stats)
        self.stats_thread.start()

        # Initialize the ping message
        self.send_frequency_message()
    	
    	print(client, 'connected')
    	
    # Function that gets called when the connected closes
    def handle_close(self, client, server):
    	print(client, 'closed')
    	
    def run_server(self):
    	self.server = WebsocketServer(port=1905, host=self.host)
    	self.server.set_fn_new_client(self.connected)
    	self.server.set_fn_client_left(self.handle_close)
    	self.server.set_fn_message_received(self.handle)
    	self.server.run_forever()
Пример #9
0
 def __init__(self):
     # Initialize image variable
     self.shared_image = SharedImage("halimage")
     self.shared_v = SharedValue("velocity")
     self.shared_w = SharedValue("angular")
class BrainProcess(multiprocessing.Process):
    def __init__(self, code, exit_signal):
        super(BrainProcess, self).__init__()

        # Initialize exit signal
        self.exit_signal = exit_signal

        # Function definitions for users to use
        self.hal = HALFunctions()
        self.gui = GUIFunctions()

        # Time variables
        self.time_cycle = SharedValue('brain_time_cycle')
        self.ideal_cycle = SharedValue('brain_ideal_cycle')
        self.iteration_counter = 0

        # Get the sequential and iterative code
        # Something wrong over here! The code is reversing
        # Found a solution but could not find the reason for this
        self.sequential_code = code[1]
        self.iterative_code = code[0]

    # Function to run to start the process
    def run(self):
        # Two threads for running and measuring
        self.measure_thread = threading.Thread(target=self.measure_frequency)
        self.thread = threading.Thread(target=self.process_code)

        self.measure_thread.start()
        self.thread.start()

        print("Brain Process Started!")

        self.exit_signal.wait()

    # The process function
    def process_code(self):
        # Redirect information to console
        start_console()

        # Reference Environment for the exec() function
        iterative_code, sequential_code = self.iterative_code, self.sequential_code

        # print(sequential_code)
        # print(iterative_code)

        # Whatever the code is, first step is to just stop!
        self.hal.sendV(0)
        self.hal.sendW(0)

        # The Python exec function
        # Run the sequential part
        gui_module, hal_module = self.generate_modules()
        if sequential_code != "":
            reference_environment = {"GUI": gui_module, "HAL": hal_module}
            exec(sequential_code, reference_environment)

        # Run the iterative part inside template
        # and keep the check for flag
        while not self.exit_signal.is_set():
            start_time = datetime.now()

            # Execute the iterative portion
            if iterative_code != "":
                exec(iterative_code, reference_environment)

            # Template specifics to run!
            finish_time = datetime.now()
            dt = finish_time - start_time
            ms = (dt.days * 24 * 60 * 60 +
                  dt.seconds) * 1000 + dt.microseconds / 1000.0

            # Keep updating the iteration counter
            if (iterative_code == ""):
                self.iteration_counter = 0
            else:
                self.iteration_counter = self.iteration_counter + 1

            # The code should be run for atleast the target time step
            # If it's less put to sleep
            # If it's more no problem as such, but we can change it!
            time_cycle = self.time_cycle.get()

            if (ms < time_cycle):
                time.sleep((time_cycle - ms) / 1000.0)

        close_console()
        print("Current Thread Joined!")

    # Function to generate the modules for use in ACE Editor
    def generate_modules(self):
        # Define HAL module
        hal_module = imp.new_module("HAL")
        hal_module.HAL = imp.new_module("HAL")
        hal_module.HAL.motors = imp.new_module("motors")

        # Add HAL functions
        hal_module.HAL.getImage = self.hal.getImage
        hal_module.HAL.motors.sendV = self.hal.sendV
        hal_module.HAL.motors.sendW = self.hal.sendW

        # Define GUI module
        gui_module = imp.new_module("GUI")
        gui_module.GUI = imp.new_module("GUI")

        # Add GUI functions
        gui_module.GUI.showImage = self.gui.showImage

        # Adding modules to system
        # Protip: The names should be different from
        # other modules, otherwise some errors
        sys.modules["HAL"] = hal_module
        sys.modules["GUI"] = gui_module

        return gui_module, hal_module

    # Function to measure the frequency of iterations
    def measure_frequency(self):
        previous_time = datetime.now()
        # An infinite loop
        while not self.exit_signal.is_set():
            # Sleep for 2 seconds
            time.sleep(2)

            # Measure the current time and subtract from the previous time to get real time interval
            current_time = datetime.now()
            dt = current_time - previous_time
            ms = (dt.days * 24 * 60 * 60 +
                  dt.seconds) * 1000 + dt.microseconds / 1000.0
            previous_time = current_time

            # Get the time period
            try:
                # Division by zero
                self.ideal_cycle.add(ms / self.iteration_counter)
            except:
                self.ideal_cycle.add(0)

            # Reset the counter
            self.iteration_counter = 0
Пример #11
0
class GUI:
    # Initialization function
    # The actual initialization
    def __init__(self, host):
        rospy.init_node("GUI")

        self.payload = {'image': '','lap': '', 'map': '', 'v':'','w':''}
        self.server = None
        self.client = None
        
        self.host = host

        # Image variable
        self.shared_image = SharedImage("guiimage")
        
        # Get HAL variables
        self.shared_v = SharedValue("velocity")
        self.shared_w = SharedValue("angular")
        
        # Create the lap object
        pose3d_object = ListenerPose3d("/F1ROS/odom")
        self.lap = Lap(pose3d_object)
        self.map = Map(pose3d_object)

        # Event objects for multiprocessing
        self.ack_event = multiprocessing.Event()
        self.cli_event = multiprocessing.Event()

        # Start server thread
        t = threading.Thread(target=self.run_server)
        t.start()

    # Function to prepare image payload
    # Encodes the image as a JSON string and sends through the WS
    def payloadImage(self):
        image = self.shared_image.get()
        payload = {'image': '', 'shape': ''}
    	
    	shape = image.shape
        frame = cv2.imencode('.JPEG', image)[1]
        encoded_image = base64.b64encode(frame)
        
        payload['image'] = encoded_image.decode('utf-8')
        payload['shape'] = shape
        
        return payload

    # Function to get the client
    # Called when a new client is received
    def get_client(self, client, server):
        self.client = client
        self.cli_event.set()

        print(client, 'connected')
        
    # Update the gui
    def update_gui(self):
        # Payload Image Message
        payload = self.payloadImage()
        self.payload["image"] = json.dumps(payload)
        
        # Payload Lap Message
        lapped = self.lap.check_threshold()
        self.payload["lap"] = ""
        if(lapped != None):
            self.payload["lap"] = str(lapped)
            
        # Payload Map Message
        pos_message = str(self.map.getFormulaCoordinates())
        self.payload["map"] = pos_message

        # Payload V Message
        v_message = str(self.shared_v.get())
        self.payload["v"] = v_message

        # Payload W Message
        w_message = str(self.shared_w.get())
        self.payload["w"] = w_message
        
        message = "#gui" + json.dumps(self.payload)
        self.server.send_message(self.client, message)
            
    # Function to read the message from websocket
    # Gets called when there is an incoming message from the client
    def get_message(self, client, server, message):
        # Acknowledge Message for GUI Thread
        if(message[:4] == "#ack"):
            # Set acknowledgement flag
            self.ack_event.set()
        # Pause message
        elif(message[:5] == "#paus"):
            self.lap.pause()
        # Unpause message
        elif(message[:5] == "#resu"):
            self.lap.unpause()
        # Reset message
        elif(message[:5] == "#rest"):
            self.reset_gui()

    	
    # Function that gets called when the connected closes
    def handle_close(self, client, server):
        print(client, 'closed')

    # Activate the server
    def run_server(self):
        self.server = WebsocketServer(port=2303, host=self.host)
        self.server.set_fn_new_client(self.get_client)
        self.server.set_fn_message_received(self.get_message)
        self.server.set_fn_client_left(self.handle_close)
        self.server.run_forever()

    # Function to reset
    def reset_gui(self):
        self.lap.reset()
        self.map.reset()
Пример #12
0
class ProcessGUI(multiprocessing.Process):
    def __init__(self):
        super(ProcessGUI, self).__init__()

        self.host = sys.argv[1]

        # Time variables
        self.time_cycle = SharedValue("gui_time_cycle")
        self.ideal_cycle = SharedValue("gui_ideal_cycle")
        self.iteration_counter = 0

    # Function to initialize events
    def initialize_events(self):
        # Events
        self.ack_event = self.gui.ack_event
        self.cli_event = self.gui.cli_event
        self.exit_signal = multiprocessing.Event()

    # Function to start the execution of threads
    def run(self):
        # Initialize GUI
        self.gui = GUI(self.host)
        self.initialize_events()

        # Wait for client before starting
        self.cli_event.wait()

        self.measure_thread = threading.Thread(target=self.measure_thread)
        self.thread = threading.Thread(target=self.run_gui)

        self.measure_thread.start()
        self.thread.start()

        print("GUI Process Started!")

        self.exit_signal.wait()

    # The measuring thread to measure frequency
    def measure_thread(self):
        previous_time = datetime.now()
        while(True):
            # Sleep for 2 seconds
            time.sleep(2)

            # Measure the current time and subtract from previous time to get real time interval
            current_time = datetime.now()
            dt = current_time - previous_time
            ms = (dt.days * 24 * 60 * 60 + dt.seconds) * 1000 + dt.microseconds / 1000.0
            previous_time = current_time

            # Get the time period
            try:
                # Division by zero
                self.ideal_cycle.add(ms / self.iteration_counter)
            except:
                self.ideal_cycle.add(0)

            # Reset the counter
            self.iteration_counter = 0

    # The main thread of execution
    def run_gui(self):
        while(True):
            start_time = datetime.now()
            # Send update signal
            self.gui.update_gui()

            # Wait for acknowldege signal
            self.ack_event.wait()
            self.ack_event.clear()
            
            finish_time = datetime.now()
            self.iteration_counter = self.iteration_counter + 1
            
            dt = finish_time - start_time
            ms = (dt.days * 24 * 60 * 60 + dt.seconds) * 1000 + dt.microseconds / 1000.0
            
            time_cycle = self.time_cycle.get()

            if(ms < time_cycle):
                time.sleep((time_cycle-ms) / 1000.0)

        self.exit_signal.set()

    # Functions to handle auxillary GUI functions
    def reset_gui():
        self.gui.reset_gui()
    
    def lap_pause():
        self.gui.lap.pause()
    
    def lap_unpause():
        self.gui.lap.unpause()