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.Communication import Communication
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
Beispiel #5
0
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()
Beispiel #7
0
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)