class PygameController: comms = None def __init__(self, serial_name, baud_rate): self.comms = Communication(serial_name, baud_rate) def run(self): # 1. make sure data sending is stopped by ending streaming self.comms.send_message("stop") self.comms.clear() # 2. start streaming orientation data input("Ready to start? Hit enter to begin.\n") self.comms.send_message("start") # 3. Forever collect orientation and send to PyGame until user exits print("Use <CTRL+C> to exit the program.\n") while True: message = self.comms.receive_message() if (message != None): command = None message = int(message) # if message == 0: # command = "FLAT" # if message == 1: # command = "UP" if message == 2: command = "FIRE" elif message == 3: command = "LEFT" elif message == 4: command = "RIGHT" if command is not None: mySocket.send(command.encode("UTF-8"))
def collect_samples(): num_samples = 500 # 10 seconds of data @ 50Hz times = CircularList([], num_samples) ax = CircularList([], num_samples) ay = CircularList([], num_samples) az = CircularList([], num_samples) comms = Communication("/dev/cu.ag-ESP32SPP", 115200) try: comms.clear() # just in case any junk is in the pipes # wait for user to start walking before starting to collect data input("Ready to collect data? Press [ENTER] to begin.\n") sleep(3) comms.send_message("wearable") # begin sending data sample = 0 while (sample < num_samples): message = comms.receive_message() if (message != None): try: (m1, m2, m3, m4) = message.split(',') except ValueError: # if corrupted data, skip the sample continue # add the new values to the circular lists times.add(int(m1)) ax.add(int(m2)) ay.add(int(m3)) az.add(int(m4)) sample += 1 print("Collected {:d} samples".format(sample)) # a single ndarray for all samples for easy file I/O data = np.column_stack([times, ax, ay, az]) except (Exception, KeyboardInterrupt) as e: print(e) # exiting the program due to exception finally: comms.send_message("sleep") # stop sending data comms.close() return data
def collect_samples(): num_samples = 500 # 10 seconds of data @ 50Hz times = CircularList([], num_samples) ppg = CircularList([], num_samples) comms = Communication("/dev/cu.usbserial-1420", 115200) try: comms.clear() # just in case any junk is in the pipes # wait for user and then count down input("Ready to collect data? Press [ENTER] to begin.\n") print("Start measuring in...") for k in range(3,0,-1): print(k) sleep(1) print("Begin!") comms.send_message("wearable") # begin sending data sample = 0 while(sample < num_samples): message = comms.receive_message() if(message != None): try: (m1, _, _, _, m2) = message.split(',') except ValueError: # if corrupted data, skip the sample continue # add the new values to the circular lists times.add(int(m1)) ppg.add(int(m2)) sample += 1 print("Collected {:d} samples".format(sample)) # a single ndarray for all samples for easy file I/O data = np.column_stack([times, ppg]) except(Exception, KeyboardInterrupt) as e: print(e) # exiting the program due to exception finally: comms.send_message("sleep") # stop sending data comms.close() return data
from ECE16Lib.HRMonitor import HRMonitor from ECE16Lib.CircularList import CircularList from matplotlib import pyplot as plt from time import time from time import sleep import numpy as np if __name__ == "__main__": fs = 50 # sampling rate num_samples = 500 # 10 seconds of data @ 50Hz process_time = 1 # compute the heart beat every second MAX_HEART_RATE = 200 hr = HRMonitor(num_samples, 50) comms = Communication("/dev/cu.ag-ESP32SPP", 115200) comms.clear() # just in case any junk is in the pipes comms.send_message("wearable") # begin sending data print("Ready!") hr_plot = CircularList([], num_samples) t = CircularList([], num_samples) # Live data try: previous_time = time() while(True): message = comms.receive_message() if (message != None): try: (m1, _, _, _, m2) = message.split(',') except ValueError: # if corrupted data, skip the sample continue # Collect data in the pedometer hr.add(int(m1)/1e3, int(m2))
from ECE16Lib.Communication import Communication import numpy as np from matplotlib import pyplot as plt if __name__ == "__main__": num_samples = 500 # 10 seconds of data @ 50Hz times = np.zeros((num_samples)) # vectors, not matrices ax = np.zeros((num_samples)) ay = np.zeros((num_samples)) az = np.zeros((num_samples)) comms = Communication("/dev/cu.AkshayBluetooth-ESP32SPP", 115200) comms.clear() # just in case any junk is in the pipes comms.send_message("wearable") # begin sending data try: count = 0 while count < num_samples: message = comms.receive_message() if message != None: (m1, m2, m3, m4) = message.split(',') times[count] = int(m1) ax[count] = int(m2) ay[count] = int(m3) az[count] = int(m4) count += 1 print("Sample:", count, "t:", m1, "ax:", m2, "ay:", m3, "az:", m4) comms.send_message("sleep") # stop sending data comms.close() except(Exception, KeyboardInterrupt) as e:
if __name__ == "__main__": fs = 50 # sampling rate num_samples = 250 # 5 seconds of data @ 50Hz process_time = 1 # compute the step count every second threshold_time = 5 num_steps = 0 ped = Pedometer(num_samples, fs, []) comms = Communication("/dev/cu.ag-ESP32SPP", 115200) low_thresh, high_thresh = calibrate_thresholds() print(low_thresh, high_thresh) ped.set_thresholds(low_thresh, high_thresh) comms.clear() # just in case any junk is in the pipes sleep(3) comms.send_message("wearable") # begin sending data print("Ready!") # Live data try: previous_time = time() while True: message = comms.receive_message() if message != None: try: (m1, m2, m3, m4) = message.split(',') except ValueError: # if corrupted data, skip the sample continue # Collect data in the pedometer ped.add(int(m2), int(m3), int(m4))
if __name__ == "__main__": fs = 50 # sampling rate num_samples = 500 # 10 seconds of data @ 50Hz process_time = 1 # compute the heart beat every second MAX_HEART_RATE = 200 # the maximum heart rate possible initial_period = num_samples / fs # set initial period in seconds hr = HRMonitor(num_samples, fs) hr.train() input("Ready to start monitoring? Press [ENTER] to begin.\n") comms = Communication("/dev/cu.ag-ESP32SPP", 115200) comms.clear() # just in case any junk is in the pipes comms.send_message("wearable") # begin sending data # Used for plotting data t = CircularList([], num_samples) peaks = CircularList([], num_samples) # Live data try: previous_time = time() while True: message = comms.receive_message() if message != None: try: (m1, _, _, _, m2) = message.split(',') except ValueError: # if corrupted data, skip the sample continue
class Processing(): __num_samples = 250 # 2 seconds of data @ 50Hz __refresh_time = 0.5 # update the plot every 0.1s (10 FPS) # Thresholds for idle detection __ax_idle_threshold = 1935 __ay_idle_threshold = 1918 __az_idle_threshold = 2430 """ Initializes the processing object and sets the field variables @:param transformation_method: the type of transformation that will be plotted and computed @:param port_name: The Serial port name used for Serial communication """ def __init__(self, transformation_method, port_name): self.comms = Communication(port_name, 115200) __transform_dict = { "average acceleration": self.__average_value, "sample difference": self.__sample_difference, "L2 norm": self.__l2_norm_calculation, "L1 norm": self.__l1_norm_calculation, "Maximum acceleration:": self.__max_acceleration } # This will keep track of the transformation method to be called self.__transformation_method = __transform_dict[transformation_method] self.transform_x = CircularList([], self.__num_samples) self.transform_y = CircularList([], self.__num_samples) self.transform_z = CircularList([], self.__num_samples) # These will contain the acceleration values read from the accelerometer self.times = CircularList([], self.__num_samples) self.ax = CircularList([], self.__num_samples) self.ay = CircularList([], self.__num_samples) self.az = CircularList([], self.__num_samples) # Set up the plotting fig = plt.figure() self.ax1 = fig.add_subplot(311) self.ax2 = fig.add_subplot(312) self.ax3 = fig.add_subplot(313) self.graph_type = transformation_method # times to keep track of when self.__last_idlecheck_time = 0 self.__idle_state = False self.__last_active_time = 0 """ Updates the plot, displaying the acceeleration values as well as the transformation values """ def __plot(self): # Clears the plots and resets them self.ax1.cla() self.ax2.cla() self.ax3.cla() # Sets the title of the plot self.ax1.set_title("X acceleration (Red) and " + self.graph_type + " (Blue)") self.ax2.set_title("Y acceleration (Red) and " + self.graph_type + " (Blue)") self.ax3.set_title("X acceleration (Red) and " + self.graph_type + " (Blue)") # Plots the acceleration values along with the transformation self.ax1.plot(self.transform_x, 'b', self.ax, 'r') self.ax2.plot(self.transform_y, 'b', self.ay, 'r') self.ax3.plot(self.transform_z, 'b', self.az, 'r') plt.show(block=False) plt.pause(0.0001) """ Determines whether the device is inactive or not @:param average_x: The average x-acceleration @:param average_y: The average y-acceleration @:param average_z: The average z-acceleration @:return: a boolean representing whether the device is inactive or not """ def __is_inactive(self, average_x, average_y, average_z): return average_x <= self.__ax_idle_threshold and average_y <= self.__ay_idle_threshold and average_z <= self.__az_idle_threshold """ Computes the average value for an axis @:param acceleration_list: The acceleration over 5 seconds in either x,y,z direction @:return: A scalar which is the average from the acceleration list """ def __average_value(self, acceleration_list): return np.average(np.array(acceleration_list)) """ Computes the difference between each adjacent indexes @:param acceleration_list: The acceleration over 5 seconds in either x,y,z direction @:return: a numpy array containing the differences between each point """ def __sample_difference(self, acceleration_list): np.diff(np.array(acceleration_list)) return np.diff(np.array(acceleration_list)) """ Computes the euclidean distance for the acceleration list @:param x_acceleration: one sample of the x-acceleration @:param y_acceleration: one sample of the y-acceleration @:param z_acceleration: one sample of the z-acceleration @:return: A scalar which is the square root of the sum of each number in the """ def __l2_norm_calculation(self, x_acceleration, y_acceleration, z_acceleration): return np.linalg.norm( np.array([x_acceleration, y_acceleration, z_acceleration])) """ Computes the L1 norm for the acceleration lsit @:param x_acceleration: one sample of the x-acceleration @:param y_acceleration: one sample of the y-acceleration @:param z_acceleration: one sample of the z-acceleration @:return: The sum of the absolute value of each acceleration value """ def __l1_norm_calculation(self, x_acceleration, y_acceleration, z_acceleration): return np.linalg.norm(np.array( [x_acceleration, y_acceleration, z_acceleration]), ord=1) """ Finds the max acceleration in one of the accelerations @:param: acceleration_list: The acceleration over 5 seconds in either x,y,z direction @:return: The maximum value in the acceleration list """ def __max_acceleration(self, acceleration_list): return int(np.max(np.array(acceleration_list))) """ Records the acceleration and times from the accelerometer @:param time: the time from the Serial monitor @:param x_acceleration: the x-acceleration @:param y_acceleration: the y-acceleration @:param z_acceleration: the z-acceleration """ def __record_acceleration(self, time, x_acceleration, y_acceleration, z_acceleration): # add the new values to the circular lists self.times.add(int(time)) self.ax.add(int(x_acceleration)) self.ay.add(int(y_acceleration)) self.az.add(int(z_acceleration)) """ Records the transformation value based on what transformation type the instance uses @:param x_acceleration: one sample of the x-acceleration @:param y_acceleration: one sample of the y-acceleration @:param z_acceleration: one sample of the z-acceleration """ def __record_transformation(self, x_acceleration, y_acceleration, z_acceleration): # These if statements are used because some of these methods have different parameters and return types if self.__transformation_method == self.__l1_norm_calculation or self.__transformation_method == self.__l2_norm_calculation: norm_number = self.__transformation_method() self.transform_x.add(norm_number) self.transform_y.add(norm_number) self.transform_z.add(norm_number) # sets each transformation method to the sample difference array elif self.__transformation_method == self.__sample_difference: self.transform_x = self.__transformation_method(self.ax) self.transform_y = self.__transformation_method(self.ay) self.transform_z = self.__transformation_method(self.az) # This will either call average_value or maximum_acceleration else: self.transform_x.add(self.__transformation_method(self.ax)) self.transform_y.add(self.__transformation_method(self.ay)) self.transform_z.add(self.__transformation_method(self.az)) """ Checks if the device has been idle for 5 seconds or if it's been active for 1 second. This will either cause the motor to buzz or another message displaying that the person has been active. @:param current_time: The current time the program is at """ def __check_idle(self, current_time): # If it's been 5 seconds since the last time the person has been inactive if current_time - self.__last_idlecheck_time >= 5: # get the average acceleration over 5 seconds average_x = self.__average_value(self.ax) average_y = self.__average_value(self.ay) average_z = self.__average_value(self.az) print(average_x, ",", average_y, ",", average_z) self.__last_idlecheck_time = current_time # if the device has been idle for 5 seconds, buzz the motor if self.__is_inactive(average_x, average_y, average_z): self.__idle_state = True self.comms.send_message("Buzz motor") else: self.__idle_state = False # If the person has been inactive but has become active for 1 second if self.__idle_state and current_time - self.__last_active_time >= 1: self.__last_active_time = current_time # get the average values for the last 1 second average_x = self.__average_value(self.ax[200:]) average_y = self.__average_value(self.ay[200:]) average_z = self.__average_value(self.az[200:]) if not self.__is_inactive(average_x, average_y, average_z): print("Active accelerations: ", average_x, average_y, average_z) self.__last_idlecheck_time = current_time # this ensures that the person must be inactive for 5 seconds after their activity self.comms.send_message("Keep it up!") """ Runs all the processing for the Serial communication, including plotting the acceleration values and checking whether the device has been inactive or not. """ def run(self): self.comms.clear() # just in case any junk is in the pipes self.comms.send_message("wearable") # begin sending data try: previous_time = 0 while (True): message = self.comms.receive_message() if (message != None): try: (m1, m2, m3, m4) = message.split(',') except ValueError: # if corrupted data, skip the sample continue # Record the acceleration and transformation self.__record_acceleration(m1, m2, m3, m4) self.__record_transformation(m2, m3, m4) current_time = time() if current_time - previous_time > self.__refresh_time: previous_time = current_time self.__plot() self.__check_idle(current_time) except (Exception, KeyboardInterrupt) as e: print(e) # Exiting the program due to exception finally: print("Closing Connection") self.comms.send_message("sleep") # stop sending data self.comms.close() sleep(1)
from ECE16Lib.Communication import Communication import time if __name__ == "__main__": comms = Communication("/dev/cu.AkshayBluetooth-ESP32SPP", 115200) comms.clear() try: for i in range(30): message = str(i + 1) + " seconds" comms.send_message(message) time.sleep(1) received_message = comms.receive_message() if received_message != None: print(received_message) except KeyboardInterrupt: print("User stopped the program with CTRL+C input") finally: comms.close()
class PygameController: comms = None filename = "./scores/topscores.csv" def __init__(self, serial_name, baud_rate): self.comms = Communication(serial_name, baud_rate) # Save data to file def save_data(self, filename, data): np.savetxt(filename, data, delimiter=",") # Load data from file def load_data(self, filename): return np.genfromtxt(filename, delimiter=",") """ Receives a message from the server @:return: the message sent from the server """ def receive_from_server(self): game_status = None # Receive game status try: game_status, _ = mySocket.recvfrom(1024) game_status = game_status.decode('utf-8') except: pass return game_status """ Orders the top three scores with the score from the last round @:param top_scores: the last top three scores @:param score: the score from the last round @:return: the new top three scores """ def order_top_scores(self, top_scores, score): top_scores.append( score) # add the score from last round to the top scores top_scores.sort( reverse=True) # sort all the scores from greatest to least return top_scores[:len( top_scores ) - 1] # return the new top scores with the lowest score removed """ Updates the top three scores of the user after their game is zero @:param score: The score the user got in their last game @:return: message send to Arduino which contains the top three scores """ def update_top_scores(self, score): # Load the top three scores from the file and sort them # from greatest to least top_scores = list(self.load_data(self.filename)) top_scores.sort(reverse=True) # Update the top three scores and save them to the file top_scores = self.order_top_scores(top_scores, score) self.save_data(self.filename, np.array(top_scores)) # This is the message that will be sent to the MCU to be displayed on the LED message = "Top Scores:" + "," + "#1: " + str(int( top_scores[0])) + "," + "#2: " + str(int(top_scores[1])) message = message + "," + "#3: " + str(int(top_scores[2])) return message """ Method that only terminates once the game is ready to start """ def wait_until_start(self): # Wait until the user starts the game again while True: game_status = self.receive_from_server() if game_status == "START": print("Game started") self.comms.send_message("start") break """ Checks the current game status, which is sent by the server @:param game_status: a string which represents the game status """ def check_game_status(self, game_status): # If the game ends, we stall sending data until a new game starts if game_status is not None and "GAME OVER" in game_status: # make sure data sending is stopped by ending streaming once game is over self.comms.send_message("stop") self.comms.clear() print("GAME OVER...") score = game_status.split(",")[ 1] # Get the score from the last round message = self.update_top_scores( int(score)) # Update the top three scores print(message) self.comms.send_message( message) # send the top three score to the MCU self.wait_until_start() # If the player has been hit, buzz the motor elif game_status == "BUZZ": print("Player hit!") self.comms.send_message("buzz") def run(self): # 1. make sure data sending is stopped by ending streaming self.comms.send_message("stop") self.comms.clear() # 2. start streaming orientation data input("Ready to start? Hit enter to begin.\n") mySocket.send("CONTROLLER ON".encode('utf-8')) # 3. Forever collect orientation and send to PyGame until user exits print("Waiting for game to start...") self.wait_until_start() print("Use <CTRL+C> to exit the program.\n") while True: message = self.comms.receive_message() if (message != None): command = None message = int(message) if message == -1: self.comms.send_message("LOW BATTERY") command = "QUIT" elif message == 0: command = "FLAT" elif message == 1: command = "UP" elif message == 2: command = "FIRE" elif message == 3: command = "LEFT" elif message == 4: command = "RIGHT" elif message == 5: command = "FIRE LEFT" elif message == 6: command = "FIRE RIGHT" elif message == 10: command = "PAUSE" elif message == 11: command = "PLAY" if command is not None: mySocket.send(command.encode("UTF-8")) print(command) # Check the current game status game_status = self.receive_from_server() self.check_game_status(game_status)
@:param average_x: The average x-acceleration @:param average_y: The average y-acceleration @:param average_z: The average z-acceleration @:return: a boolean representing whether the device is inactive or not """ def is_inactive(average_x, average_y, average_z): return average_x <= ax_idle_threshold and average_y <= ay_idle_threshold and average_z <= az_idle_threshold # Bluetooth port: /dev/cu.AkshayBluetooth-ESP32SPP # Serial port: /dev/cu.usbserial-1410 comms = Communication("/dev/cu.AkshayBluetooth-ESP32SPP", 115200) comms.clear() # just in case any junk is in the pipes comms.send_message("wearable") # begin sending data num_samples = 250 # we want the data to store 5 seconds of data refresh_time = 0.1 # update the plot every 0.1s (10 FPS) # lists to keep track of the acceleration and times = CircularList([], num_samples) ax = CircularList([], num_samples) ay = CircularList([], num_samples) az = CircularList([], num_samples) # the thresholds that determine when the device is idle or noot ax_idle_threshold = 2080 ay_idle_threshold = 2085 az_idle_threshold = 2625 last_idlecheck_time = 0 # variable to keep track of last time for idle check