top of page

Final Deliverables

Raspberry Pi Housing

pi housing 1.png
pi housing 2.png

Wearable Device

device 1.png
device 2.png
device 4.png
device 3.png

Engineering Drawings

eng drawing 1.png
eng drawing 3.png
eng drawing 2.png

Computer Program

************************************************************
            ***  Program Implementation - STUDENT CODE BEGINS HERE!  ***
            ************************************************************
            Below this line is where you should IMPLEMENT each of the
            required tasks.
                - DO NOT define any functions in this section!
                - You can liken this to a main() function where you
                  would implement your individual functions in your
                  Lab Mini-Milestones
                - PAY ATTENTION TO YOUR INDENTATIONS!!!!
            '''
            ## Start with indentation aligned with this comment
            
            #Variable/object initializations

            #LED status guide
            #Starting message
            print("Red led - Fall detected")
            print("Green led (solid) - Standby mode")
            print("Green led (flashing) - Charging\n\n\n")

            #Initialize files that the program will write to
            Start_Up_Routine()
            
            #Account login and password for twilio account
            account_sid = "AC7aa58358d003cc3b1b4dd33a53962c8e"
            auth_token = "a907c4305a35e1daa00e9b471e91f06b"

            #Contacts to call upon medical emergency
            priority_contact = "+16479182542" #Dorian's Number
            contacts = [priority_contact]

            #Initializing the twilio object and its client
            Twilio = Twilio_Client(account_sid, auth_token, contacts)
            Twilio.Initialize_Client()

            #Initializing the sensor object
            Sensor = Orientation_Sensor()

            #Initializing the button object and the charging button on pin 21 and pin 26 respectively
            Push_Button = Button(21)
            Charging_Button = Button(26)
            #^^ Is meant to simulate what would happen if the watch was charging. The button doesn't actually exist, it's just for demo purposes

            #Initializing the buzzer object on pin 18
            buzzer = Buzzer(18)

            #Initializing the red and green leds on pins 24 and 12 respectively
            Red_Led = LED(24)
            Green_Led = LED(12)
            
            #Initializing the watch graphical user interface
            Watch = Watchface()

            
            #Getting a buffer of data - prevents an index error later on
            Read_Data(Sensor,5,0.1)

            #Counter to keep count of time, this allows the program to read data from the sensor at set intervals
            counter = 0

            #Insures that the program runs at a set speed
            program_speed_limit = 0.05
            
            

            Green_Led.on()
            
            
            
            while True:
                
                time.sleep(program_speed_limit)
                emergency_flag = False

                #Read data
                if (round(counter,2)%0.75 == 0):
                    Read_Data(Sensor,5,0.1)
                    Calculate_Rolling_Average(10)
                    Calculate_Average_Velocity(2,0.75)
                    Calculate_Average_Acceleration(2,0.75)
                    

                #Flags that determine if a fall has occured
                sudden_movement_flag = Detect_Sudden_Movement()
                flag_rolling_ank, flag_rolling_wr = Detect_Pos_Diff()
                flags = [flag_rolling_ank, flag_rolling_wr, sudden_movement_flag]

                #Based on the flags, did a fall happen?                
                Detect_Fall(flags, Sensor, Watch, Push_Button, Twilio, buzzer, Red_Led, Green_Led)

                #Manual help request
                if (Push_Button.is_pressed):
                    
                    emergency_flag = Manual_Alert(Push_Button, Watch, buzzer, Red_Led, Green_Led)

                #Manual_Alert has registered as true, help is needed
                if (emergency_flag):
                    Twilio.Call_For_Help()

                    #Getting a buffer of data - prevents an index error later on
                    Read_Data(Sensor,10,0.1)
                    Calculate_Rolling_Average(10)
                    Calculate_Average_Velocity(2,0.75)
                    Calculate_Average_Acceleration(2,0.75)

                    Watch.Rectangle_Transition(Watch.colour_bank["black"])

                #Watch is charging
                if (Charging_Button.is_pressed):
                    #Device put to charge, back up files
                    Archiving_Routine()
                    
                    #Getting a buffer of data - prevents an index error later on
                    Read_Data(Sensor,10,0.1)
                    Calculate_Rolling_Average(10)
                    Calculate_Average_Velocity(2,0.75)
                    Calculate_Average_Acceleration(2,0.75)
                    
                    Watch.Charging(Green_Led, Charging_Button)

                #Display the time
                Watch.Display_Time()
                counter+=program_speed_limit

                
            
            
            
            
            '''
            ************************************************************
            ***   Program Implementation - STUDENT CODE ENDS HERE!   ***
            ************************************************************
            '''

        except:
            (type, value, traceback) = sys.exc_info()
            sys.excepthook(type, value, traceback)
            sys.exit(1)
    def stop(self):
        self.is_running = False
        print('stopping thread...')
        self.terminate()


'''
************************************************************
***   Function Definitions - STUDENT CODE BEGINS HERE!   ***
************************************************************
Below this line is where you should DEFINE all functions
    - Any output devices that are used in your functions
      should be defined here as well
    - PAY ATTENTION TO YOUR INDENTATIONS!!!!
'''
#imports
import os
from twilio.rest import Client
import matplotlib.pyplot as plt
import numpy as np
import pygame
import math
from datetime import datetime as dt

 

 

class Twilio_Client:
    def __init__(self, ID, auth, contacts, your_number="+16145023894"):
        self.ID = ID
        self.auth = auth
        self.contacts = contacts
        self.your_number = your_number

 

    def Call_For_Help(self):

        for contact in self.contacts:
            #Text the priority contact
            message = self.client.messages.create(
                to=contact,
                from_= self.your_number,
                body="This is an automated message from Team-13. Your loved one has fallen and needs urgent medical care.")

            #The api does one command a second therefore there needs to be a delay
            time.sleep(2) 
            
            #Call the priority contact
            call = self.client.calls.create(
                url = 'http://demo.twilio.com/docs/voice.xml',
                to=contact,
                from_= self.your_number,
            )

        #Archive and wipe files
        Archiving_Routine()

 

    def Initialize_Client(self):
        #Creates the twilio client to permit calling/texting
        self.client = Client(self.ID, self.auth)

    

class Watchface:
    def __init__(self):
        #Initializations
        pygame.init()
        pygame.display.init()
        pygame.font.init()

        #Colour bank
        self.colour_bank = {"red":(255,0,0),
                            "blue":(0,0,255),
                            "green":(0,255,0),
                            "white":(255,255,255),
                            "black":(0,0,0),
                            "yellow":(255,255,0),
                            "turquoise":(64,224,208),
                            "magenta":(255,0,255),
                            "teal":(0,128,128)}

        #Default font
        self.font_style = pygame.font.match_font("arial")

        #Initializing screen
        self.length = 640
        self.width = 480
        self.dimensions = (self.length,self.width)
        self.screen = pygame.display.set_mode(self.dimensions)

        #Allows the watch to keep track of how many milliseconds have passed since initialization
        self.timer = 0

 

    def Automatic_Help_Request(self,message,time=0):
                
        #Get countdown time as integer
        time_left = int((60-time)//1)

        if (round(time,2)%2==0):
            #Shell update within an if statement to limit program lag
            Combined_Information()


        if time_left < 0:
            #Because of floating point errors the time will appear as negative at zero
            time_left = 0

        time_left = str(time_left)        
        self.screen.fill(self.colour_bank["red"])

        #Message will be written in two lines, initializing variables
        line1 = ""
        line2 = ""

        #Finding desired message
        if message == 1:
            line1 = "Help sequence"
            line2 = "Initialized"
        elif message == 2:
            line1 = "Help sequence"
            line2 = "Aborted"
        elif message == 3:
            line1 = "Help is"
            line2 = "On the way"
        elif message == 4:
            line1 = "Fall detected"
            line2 = "Press button"
            time_left = "to cancel" #"to cancel" isn't the time left but should be written in the same spot as "time left" would be written in

        #Draw circle
        center = (self.length//2,self.width//2)
        pygame.draw.circle(self.screen,self.colour_bank["turquoise"],center,abs(int((self.length/3)-20*math.sin(self.timer/500))))

        #Write message to screen
        self.Text_To_Screen(line1,50,self.colour_bank["black"],self.length/2,3*self.width/8)
        self.Text_To_Screen(line2,50,self.colour_bank["black"],self.length/2,4*self.width/8)
        self.Text_To_Screen(time_left,50,self.colour_bank["black"],self.length/2,5*self.width/8)

        #Update display
        self.Update_Screen()
        
    def Charging(self,Green_Led, Charging_Button):
        counter = 0
        self.Rectangle_Transition(self.colour_bank["teal"])
       
        while Charging_Button.is_pressed:
            if (round(counter,2)%1==0):
                #Shell update within an if statement to limit program lag
                Combined_Information()
            
            #Background
            self.screen.fill(self.colour_bank["teal"])

            #Draw circle and text
            center = (self.length//2,self.width//2)
            pygame.draw.circle(self.screen,self.colour_bank["black"],center,abs(int((self.length/3)-20*math.sin(self.timer/500))))
            self.Text_To_Screen("Charging",50,self.colour_bank["white"],self.length/2,self.width/2)

            self.Update_Screen()

            #Flash LED every 3 seconds
            if ((self.timer//1000)%6 == 0):
                Green_Led.off()
            elif ((self.timer//1000)%3 == 0):
                Green_Led.on()

            time.sleep(0.05)
            counter += 0.05

        #Charging has stopped
        Green_Led.off()
        self.Rectangle_Transition(self.colour_bank["black"])
        
    def Display_Time(self):
        #Shell update
        Combined_Information()
        
        #Fetch current time
        time = Get_Current_Time()

        #Update screen to have black background with the time and message displayed
        self.screen.fill(self.colour_bank["black"])
        self.Text_To_Screen(time,100,self.colour_bank["white"],self.length/2,2*self.width/5)
        message = "Push button for 10 seconds for EMS"
        self.Text_To_Screen(message,20,self.colour_bank["white"],self.length/2,3*self.width/4-10*math.sin(self.timer/500)) #The sin function is for animating the text
        self.Update_Screen()

    

    def Manual_Help_Request(self,time,message):
        if (round(time,2)%2==0):
            #Shell update within an if statement to limit program lag
            Combined_Information()
        
        #Get countdown time as integer and cast as string
        time_left = int((10-time)//1)

        if time_left < 0:
            #Because of floating point errors the time will appear as negative at zero
            time_left = 0

        time_left = str(time_left)
        self.screen.fill(self.colour_bank["white"])

        #Message will be written in two lines, initializing variables
        line1 = ""
        line2 = ""

        #Finding desired message
        if message == 1:
            line1 = "Help sequence"
            line2 = "Initialized"
        elif message == 2:
            line1 = "Help sequence"
            line2 = "Aborted"
        elif message == 3:
            line1 = "Help is"
            line2 = "On the way"

        
        #Draw circle
        center = (self.length//2,self.width//2)
        pygame.draw.circle(self.screen,self.colour_bank["turquoise"],center,abs(int((self.length/3)-20*math.sin(self.timer/500))))

        #Write message to screen
        self.Text_To_Screen(line1,50,self.colour_bank["black"],self.length/2,3*self.width/8)
        self.Text_To_Screen(line2,50,self.colour_bank["black"],self.length/2,4*self.width/8)
        self.Text_To_Screen(time_left,50,self.colour_bank["black"],self.length/2,5*self.width/8)

        #Update display
        self.Update_Screen()

 

    def Rectangle_Transition(self,colour):
        #General info: this method is the animation between different watch screens

        #The dimensions of the drawn on rectangles
        final_rect_len = self.length
        final_rect_width = self.width//2

        #The rectangles will increase in size, starting from zero
        curr_rect_width = 0
        
        for i in range(2,10):
            #Using the harmonic series to reduce the change in size of rectangles that will be on screen
            curr_rect_width += final_rect_width * (1/i)

            #Rectangle from top
            
            #Dimensions(left, top, length, width)
            dimensions_top = (0,0,self.length,curr_rect_width)

            pygame.draw.rect(self.screen,colour,dimensions_top)
            
            
            #Rectangle from bottom
            top_coord = self.width - curr_rect_width 

            dimensions_bottom = (0,top_coord,self.length,curr_rect_width)
            pygame.draw.rect(self.screen, colour,dimensions_bottom)

            #Update screen
            self.Update_Screen()
            time.sleep(0.1)


        
    def Text_To_Screen(self,text,size,colour,x,y):
        #Setting the specific font and size for the desired text
        text_font = pygame.font.Font(self.font_style,size)

        #Pygame can't write directly onto the screen therefore the font must be "rendered" onto a new surface
        text_surface = text_font.render(text, True, colour)

        #Find how big the new surface is 
        text_rect = text_surface.get_rect()

        #Setting where the middle of the top bar will be placed on the screen
        text_rect.center = (x,y)

        #Paste the text to the screen
        self.screen.blit(text_surface, text_rect)

 

    def Update_Screen(self):
        #Updates screen and internal clock
        pygame.display.flip()
        self.timer = pygame.time.get_ticks() 

 


def Alert_User(Sensor, Watch, Push_Button, Twilio, buzzer, Red_Led, Green_Led):
    #Setting initial value to trigger the while loop
    acc = -1

    #Other variable initalizations
    increment = 0.1 #seconds
    threshold = 70 #degrees
    time_limit = 60 #seconds
    message = 4
    counter = 0
    emergency_flag = True

    #Updating the GUI
    Watch.Rectangle_Transition(Watch.colour_bank["red"])
    Green_Led.off()
    Red_Led.on()

    #Turn on buzzer to alert the user
    buzzer.on()
    
    while acc != 0:
        #Waiting to the fall to complete. When fall is finished, acceleration will be zero

        #Display that a fall was detected
        Watch.Automatic_Help_Request(message)

        #Flags
        wrist_zero = False
        ankle_zero = False
        
        #Continue recording data
        time.sleep(0.25)
        Read_Data(Sensor,5,0.1)
        Calculate_Rolling_Average(10)
        Calculate_Average_Velocity(2,0.75)
        Calculate_Average_Acceleration(2,0.75)

        #read wrist data from acceleration file
        accel_file = open('average_acceleration_wr.txt','r')
        last_line = accel_file.readlines()[-1].split()

        yaw_accel = float(last_line[0])
        roll_accel = float(last_line[1])
        pitch_accel = float(last_line[2])

        yaw_zero = False
        roll_zero = False
        pitch_zero = False

        #Deadzoning - in real life the acceleration values will never be zero so as long as they're within a range we'll be good to continue
        if(abs(yaw_accel) < 0.5):
            yaw_zero = True
        if(abs(roll_accel)<0.5):
            roll_zero = True
        if(abs(pitch_accel)<0.5):
            pitch_zero = True

        if (yaw_zero and roll_zero and pitch_zero):
            wrist_zero = True

 

        #read ankle data from acceleration file
        accel_file = open('average_acceleration_ank.txt','r')
        last_line = accel_file.readlines()[-1].split()

        yaw_accel = float(last_line[0])
        roll_accel = float(last_line[1])
        pitch_accel = float(last_line[2])

        yaw_zero = False
        roll_zero = False
        pitch_zero = False

        #Deadzoning - in real life the acceleration values will never be zero so as long as they're within a range we'll be good to continue
        if(abs(yaw_accel) < 0.5):
            yaw_zero = True
        if(abs(roll_accel)<0.5):
            roll_zero = True
        if(abs(pitch_accel)<0.5):
            pitch_zero = True

        if (yaw_zero and roll_zero and pitch_zero):
            ankle_zero = True

        

        if (Push_Button.is_pressed):
            emergency_flag = False
            message = 2

            #Update GUI, let the user know that the sequence has been aborted
            Watch.Automatic_Help_Request(message)

            #Turn off buzzer and LED
            buzzer.off()
            Red_Led.off()
            Green_Led.on()
            
            #Extra time to read message
            time.sleep(2)
            Watch.Rectangle_Transition(Watch.colour_bank["black"])
            break

        if (ankle_zero and wrist_zero):
            acc = 0
            #Give the user time to read the message
            time.sleep(1)
        
        

    #Read initial position values
    reference_wr = open('rolling_average_wr.txt', 'r') 
    reference_value_wr = reference_wr.readlines()[-1].split()
    reference_wr.close()

    reference_ank = open('rolling_average_ank.txt', 'r') 
    reference_value_ank = reference_ank.readlines()[-1].split()
    reference_ank.close()

    #Split up the values 
    first_roll_wr = float(reference_value_wr[1])
    first_pitch_wr = float(reference_value_wr[2])

    first_roll_ank = float(reference_value_ank[1])
    first_pitch_ank = float(reference_value_ank[2])

    message = 1
    while emergency_flag:
        time.sleep(increment)
        counter += increment
        
        if Push_Button.is_pressed: #The user has cancelled the alert
            emergency_flag = False
            message = 2

            #Turn off buzzer and LED
            buzzer.off()
            Red_Led.off()
            Green_Led.on()

            #Update the GUI, let them know that the help sequence has been aborted
            Watch.Automatic_Help_Request(message,counter)
            
            #Give user time to read message
            time.sleep(2)
            Watch.Rectangle_Transition(Watch.colour_bank["black"])
            break
        
        else:
            #Update GUI, let them know how much time is left until help arrives
            Watch.Automatic_Help_Request(message,counter)

        #Time limit expired, exit loop and call for help
        if counter >= time_limit:
            #Turn off buzzer and LED
            buzzer.off()
            Red_Led.off()
            Green_Led.on()
            break

    if emergency_flag == True:

        #Read new position
        Read_Data(Sensor,5,0.1)
        Calculate_Rolling_Average(5)

        #Get current position
        reference_new_wr = open('rolling_average_wr.txt', 'r')
        ref_new_wr = reference_new_wr.readlines()[-1].split()
        reference_new_wr.close()

        reference_new_ank = open('rolling_average_ank.txt', 'r')
        ref_new_ank = reference_new_ank.readlines()[-1].split()
        reference_new_ank.close()

        second_roll_wr = float(ref_new_wr[1])
        second_pitch_wr = float(ref_new_wr[2])

        second_roll_ank = float(ref_new_ank[1])
        second_pitch_ank = float(ref_new_ank[2])


        #Initializing flags
        wrist_unresponsive = False
        ankle_unresponsive = False

        #Check if both the ankle and wrist have moved drastically from original position in the y and z axis. If so, the user has likely gotten up and is ok
        if (abs(first_roll_wr - second_roll_wr)< threshold and abs(first_pitch_wr - second_pitch_wr)<threshold):
            wrist_unresponsive = True

        if (abs(first_roll_ank - second_roll_ank)< threshold and abs(first_pitch_ank - second_pitch_ank)<threshold):
            ankle_unresponsive = True

        
        #If the user has moved both ankle and wrist above the threshold, they are most likely and haven't canceled the alert
        if (wrist_unresponsive and ankle_unresponsive):

            #Update the GUI
            message = 3
            Watch.Automatic_Help_Request(message,counter)
            
            #Let user read message
            time.sleep(2)
            Watch.Rectangle_Transition(Watch.colour_bank["yellow"])
            Twilio.Call_For_Help()

            #Getting a buffer of data - prevents an index error later on
            Read_Data(Sensor,10,0.1)
            Calculate_Rolling_Average(10)
            Calculate_Average_Velocity(2,0.75)
            Calculate_Average_Acceleration(2,0.75)

            Watch.Rectangle_Transition(Watch.colour_bank["black"])

        else:
            #person is okay and up
            message = 2

            #Update the GUI to notify that the sequence has been aborted
            Watch.Automatic_Help_Request(message,counter)

            #Give user time to read message
            time.sleep(2)

            Watch.Rectangle_Transition(Watch.colour_bank["black"])
            

 

def Archiving_Routine():
    #Move all files to the archive folder
    dst_path = "/home/pi/Emulator/Archive/"
    src_path = "/home/pi/Emulator/"
    current_time = Get_Current_Time_In_Seconds()
    file_suffix = current_time + ".txt"
    
    #Rolling average files
    
    file_prefix = "rolling_average"

    os.replace(src_path+"rolling_average_wr.txt",dst_path+file_prefix+"_wr_"+file_suffix)
    os.replace(src_path+"rolling_average_ank.txt",dst_path+file_prefix+"_ank_"+file_suffix)

    #Average velocity files
    file_prefix = "average_velocity"

    os.replace(src_path+"average_velocity_wr.txt",dst_path+file_prefix+"_wr_"+file_suffix)
    os.replace(src_path+"average_velocity_ank.txt",dst_path+file_prefix+"_ank_"+file_suffix)

    #Average acceleration files
    file_prefix = "average_acceleration"

    os.replace(src_path+"average_acceleration_wr.txt",dst_path+file_prefix+"_wr_"+file_suffix)
    os.replace(src_path+"average_acceleration_ank.txt",dst_path+file_prefix+"_ank_"+file_suffix)

        
    #wipe files clean
    file = open("raw_data_wr.txt",'w')
    file.close()
    file = open("raw_data_ank.txt",'w')
    file.close()
    file = open("rolling_average_wr.txt",'w')
    file.close()
    file = open("rolling_average_ank.txt",'w')
    file.close()
    file = open("average_velocity_wr.txt",'w')
    file.close()
    file = open("average_velocity_ank.txt",'w')
    file.close()
    file = open("average_acceleration_wr.txt",'w')
    file.close()
    file = open("average_acceleration_ank.txt",'w')
    file.close()

 

def Calculate_Average_Acceleration(data_size,input_interval):

    #Average acceleration for wrist

    #Initializing variables
    yaw_difference = 0
    roll_difference = 0
    pitch_difference = 0

    #Open average velocity file and calculate the average acceleration
    with open("average_velocity_wr.txt",'r') as rolling_average_v:

        #Calculate the average rate of change by using the current data and the data x lines in the past
        all_lines = rolling_average_v.readlines()
        last_lines = all_lines[-data_size:]

        initial_position = last_lines[0].split()
        final_position = last_lines[-1].split()

        #Calculate the difference in yaw roll and pitch from the last and first data point
        yaw_difference = float(final_position[0]) - float(initial_position[0])
        roll_difference = float(final_position[1]) - float(initial_position[1])
        pitch_difference = float(final_position[2]) - float(initial_position[2])
        
    #Open a separate file and write the average acceleration                    
    with open("average_acceleration_wr.txt", 'a') as average_acceleration:

        #Calculating the average acceleration
        ayaw_average = yaw_difference/(data_size*input_interval)
        aroll_average = roll_difference/(data_size*input_interval)
        apitch_average = pitch_difference/(data_size*input_interval)

        #Formatting and writing the string
        average = [str(ayaw_average),"\t",str(aroll_average),"\t",str(apitch_average),"\n"]
        average_acceleration.writelines(average)

 

    #Average acceleration for ankle


    #Initializing variables
    yaw_difference = 0
    roll_difference = 0
    pitch_difference = 0

    #Open average velocity file and calculate the average acceleration
    with open("average_velocity_ank.txt",'r') as rolling_average_v:

        #Calculate the average rate of change by using the current data and the data x lines in the past
        all_lines = rolling_average_v.readlines()
        last_lines = all_lines[-data_size:]

        initial_position = last_lines[0].split()
        final_position = last_lines[-1].split()

        #Calculate the difference in yaw roll and pitch from the last and first data point
        yaw_difference = float(final_position[0]) - float(initial_position[0])
        roll_difference = float(final_position[1]) - float(initial_position[1])
        pitch_difference = float(final_position[2]) - float(initial_position[2])
        
    #Open a separate file and write the average acceleration                    
    with open("average_acceleration_ank.txt", 'a') as average_acceleration:

        #Calculating the average acceleration
        ayaw_average = yaw_difference/(data_size*input_interval)
        aroll_average = roll_difference/(data_size*input_interval)
        apitch_average = pitch_difference/(data_size*input_interval)

        #Formatting and writing the string
        average = [str(ayaw_average),"\t",str(aroll_average),"\t",str(apitch_average),"\n"]
        average_acceleration.writelines(average)

 

def Calculate_Average_Velocity(data_size,input_interval):

    #Average velocity for wrist

    
    #Initializing variables
    yaw_difference = 0
    roll_difference = 0
    pitch_difference = 0

    #Open rolling average file and calculate the average velocity
    with open("rolling_average_wr.txt",'r') as rolling_average:

        #Calculate the average rate of change by using the current data and the data x lines in the past
        all_lines = rolling_average.readlines()
        last_lines = all_lines[-data_size:]

        initial_position = last_lines[0].split()
        final_position = last_lines[-1].split()

        #Calculate the difference in yaw roll and pitch from the last and first data point
        yaw_difference = float(final_position[0]) - float(initial_position[0])
        roll_difference = float(final_position[1]) - float(initial_position[1])
        pitch_difference = float(final_position[2]) - float(initial_position[2])
        
    #Open a separate file and write the average velocity        
    with open("average_velocity_wr.txt", 'a') as average_velocity:

        #Calculating the average velocity
        vyaw_average = yaw_difference/(data_size*input_interval)
        vroll_average = roll_difference/(data_size*input_interval)
        vpitch_average = pitch_difference/(data_size*input_interval)

        #Formatting and writing the string
        average = [str(vyaw_average),"\t",str(vroll_average),"\t",str(vpitch_average),"\n"]
        average_velocity.writelines(average)

 

    #Average velocity for ankle
        

    
    #Initializing variables
    yaw_difference = 0
    roll_difference = 0
    pitch_difference = 0

    #Open rolling average file and calculate the average velocity
    with open("rolling_average_ank.txt",'r') as rolling_average:

        #Calculate the average rate of change by using the current data and the data x lines in the past
        all_lines = rolling_average.readlines()
        last_lines = all_lines[-data_size:]

        initial_position = last_lines[0].split()
        final_position = last_lines[-1].split()

        #Calculate the difference in yaw roll and pitch from the last and first data point
        yaw_difference = float(final_position[0]) - float(initial_position[0])
        roll_difference = float(final_position[1]) - float(initial_position[1])
        pitch_difference = float(final_position[2]) - float(initial_position[2])
        
    #Open a separate file and write the average velocity        
    with open("average_velocity_ank.txt", 'a') as average_velocity:

        #Calculating the average velocity
        vyaw_average = yaw_difference/(data_size*input_interval)
        vroll_average = roll_difference/(data_size*input_interval)
        vpitch_average = pitch_difference/(data_size*input_interval)

        #Formatting and writing the string
        average = [str(vyaw_average),"\t",str(vroll_average),"\t",str(vpitch_average),"\n"]
        average_velocity.writelines(average)

 

def Calculate_Rolling_Average(data_size):

    #Rolling average for wrist
    
    #Initializing variables
    yaw_total = 0
    roll_total = 0
    pitch_total = 0

    #Read 10 latest data points for pitch roll and yaw
    with open("raw_data_wr.txt",'r') as file1:
        all_lines = file1.readlines()

        #Retreive the last x lines of data
        last_lines = all_lines[-data_size:]

        #iterate through each line in the dataset and find the sum
        for i in range(len(last_lines)):
            line_buffer = last_lines[i]
            line_buffer = line_buffer.split()
            yaw_total += float(line_buffer[0])
            roll_total += float(line_buffer[1])
            pitch_total += float(line_buffer[2])

    #Calculate the average of the last x data points and write to file
    with open("rolling_average_wr.txt",'a') as file2:
        yaw_average = round(yaw_total/data_size,2)
        roll_average = round(roll_total/data_size,2)
        pitch_average = round(pitch_total/data_size,2)
        average = [str(yaw_average),"\t",str(roll_average),"\t",str(pitch_average),"\n"]
        file2.writelines(average)

 

    #Rolling average for ankle

 

    #Initializing variables
    yaw_total = 0
    roll_total = 0
    pitch_total = 0

    #Read 10 latest data points for pitch roll and yaw
    with open("raw_data_ank.txt",'r') as file1:
        all_lines = file1.readlines()

        #Retreive the last x lines of data
        last_lines = all_lines[-data_size:]

        #iterate through each line in the dataset and find the sum
        for i in range(len(last_lines)):
            line_buffer = last_lines[i]
            line_buffer = line_buffer.split()
            yaw_total += float(line_buffer[0])
            roll_total += float(line_buffer[1])
            pitch_total += float(line_buffer[2])

    #Calculate the average of the last x data points and write to file
    with open("rolling_average_ank.txt",'a') as file2:
        yaw_average = yaw_total/data_size
        roll_average = roll_total/data_size
        pitch_average = pitch_total/data_size
        average = [str(yaw_average),"\t",str(roll_average),"\t",str(pitch_average),"\n"]
        file2.writelines(average)

 

def Combined_Information():
    #This function is exclusively to display the current state of all of the output devices and the sensor data

    raw_data_file_wr = open("raw_data_wr.txt",'r')
    raw_data_file_ank = open("raw_data_ank.txt",'r')
    rolling_average_file_wr = open("rolling_average_wr.txt",'r')
    rolling_average_file_ank = open("rolling_average_ank.txt",'r')

    raw_data_wr = raw_data_file_wr.readlines()[-1]
    raw_data_ank = raw_data_file_ank.readlines()[-1]

    average_pos_wr = rolling_average_file_wr.readlines()[-1]
    average_pos_ank = rolling_average_file_ank.readlines()[-1]

    #Determines if the output devices are in the on or off state
    red_status = "On" if led6State_var else "Off"
    green_status = "On" if led4State_var else "Off"
    buzzer_status = "On" if buzzer1State_var else "Off"

    #Shell update
    print(raw_data_wr.split()[0],raw_data_wr.split()[1],raw_data_wr.split()[2],"\t\t",
          raw_data_ank.split()[0],raw_data_ank.split()[1],raw_data_ank.split()[2],"\t",
          average_pos_wr.split()[0],average_pos_wr.split()[1],average_pos_wr.split()[2],"\t",
          average_pos_ank.split()[0],average_pos_ank.split()[1],average_pos_ank.split()[2],"\t",
          buzzer_status,"\t\t",red_status,"\t\t",green_status)
          
    
    #Writing all this information to a file
    processed_information_file = open("Processed_info.txt",'a')

    processed_information_file.writelines(["\n",raw_data_wr.split()[0]," ",raw_data_wr.split()[1]," ",raw_data_wr.split()[2],"\t\t",
          raw_data_ank.split()[0]," ",raw_data_ank.split()[1]," ",raw_data_ank.split()[2],"\t",
          average_pos_wr.split()[0]," ",average_pos_wr.split()[1]," ",average_pos_wr.split()[2],"\t",
          average_pos_ank.split()[0]," ",average_pos_ank.split()[1]," ",average_pos_ank.split()[2],"\t",
          buzzer_status,"\t\t",red_status,"\t\t",green_status])

 


    

def Detect_Fall(flags, Sensor, Watch, Push_Button, Twilio, buzzer, Red_Led, Green_Led):
    #If fall has been detected, alert user
    if flags[0] == True and flags[1] == True and flags[2] == True:
        Alert_User(Sensor, Watch, Push_Button, Twilio, buzzer, Red_Led, Green_Led)

 

def Detect_Pos_Diff():

    #Initialize flags/variables
    flag_rolling_wr = False
    flag_rolling_ank = False
    threshold = 30

    #Retreive the last two lines in the rolling_average file and separate into initial and final values for wrist
    file_rolling_av_wr = open("rolling_average_wr.txt", 'r')
    rolling_av_wr = file_rolling_av_wr.readlines()

    last_lines_wr = rolling_av_wr[-2:]
    initial_position_wr = last_lines_wr[0].split()
    final_position_wr = last_lines_wr[-1].split()

    #Retreive the last two lines in the rolling_average file and separate into initial and final values for ankle
    file_rolling_av_ank = open("rolling_average_ank.txt", 'r')
    rolling_av_ank = file_rolling_av_ank.readlines()

    last_lines_ank = rolling_av_ank[-2:]
    initial_position_ank = last_lines_ank[0].split()
    final_position_ank = last_lines_ank[-1].split()

    wrist_roll_difference = abs(float(final_position_wr[1]) - float(initial_position_wr[1]))
    wrist_pitch_difference = abs(float(final_position_wr[2]) - float(initial_position_wr[2]))
    ankle_roll_difference = abs(float(final_position_ank[1]) - float(initial_position_ank[1]))
    ankle_pitch_difference = abs(float(final_position_ank[2]) - float(initial_position_ank[2]))

  
    #Check to see if threshold has been crossed
    if wrist_roll_difference >= threshold:
        flag_rolling_wr = True
    if wrist_pitch_difference >= threshold:
        flag_rolling_wr = True
    if ankle_roll_difference >= threshold:
        flag_rolling_ank = True
    if ankle_pitch_difference >= threshold:
        flag_rolling_ank = True
    else:
        pass

    return flag_rolling_ank, flag_rolling_wr


        
def Detect_Sudden_Movement():

    #If acceleration is above 7 deg/s^2 the threshold will be crossed
    threshold = 7
    
    #Set the flag to false by default
    sudden_movement_detected = False
    sudden_movement_detected_wr = False
    sudden_movement_detected_ank = False

    #Read the average acceleration and check to see if the threshold was passed for the wrist
    with open("average_acceleration_wr.txt",'r') as accel:

        #Isolating the last line
        everything = accel.readlines()
        average_accel = everything[-1].split()

        #Isolating roll and pitch from the string list
        roll = float(average_accel[1])
        pitch = float(average_accel[2])

        #Check to see if the acceleration has passed the threshold
        if (abs(pitch) >= threshold):
            sudden_movement_detected_wr = True
        elif (abs(roll) >= threshold):
            sudden_movement_detected_wr = True

    #Read the average acceleration and check to see if the threshold was passed for the ankle
    with open("average_acceleration_ank.txt",'r') as accel:

        #Isolating the last line
        everything = accel.readlines()
        average_accel = everything[-1].split()

        #Isolating roll and pitch from the string list
        roll = float(average_accel[1])
        pitch = float(average_accel[2])

        #Check to see if the acceleration has passed the threshold
        if (abs(pitch) >= threshold):
            sudden_movement_detected_ank = True
        elif (abs(roll) >= threshold):
            sudden_movement_detected_ank = True

    if (sudden_movement_detected_wr and sudden_movement_detected_ank):
        sudden_movement_detected = True
        
    #Return the flag
    return sudden_movement_detected

 

def Get_Current_Time():
    return dt.now().strftime("%H:%M")

 

def Get_Current_Time_In_Seconds():
    return dt.now().strftime("%H:%M:%S")

 


def Manual_Alert(Push_Button, Watch, buzzer, Red_Led, Green_Led):
    #If button is pushed to call for help
    Green_Led.off()
    Red_Led.on()
    
    #Initializing variables
    message = 1
    time_interval = 0.1
    counter = 0

    emergency_flag = True

    #Updating GUI
    Watch.Rectangle_Transition(Watch.colour_bank["white"])

    #Turn on buzzer to alert the user
    buzzer.on()
    
    while counter < 10:
        if Push_Button.is_pressed:
            

            #Show how much time is left before help is called
            counter += time_interval
            Watch.Manual_Help_Request(counter,message)
            
        else: #Button has been released, help sequence aborted
            #Turn off buzzer and LED
            buzzer.off()
            Red_Led.off()
            Green_Led.on()
            
            #Update GUI, show that help sequence has been aborted
            message = 2
            Watch.Manual_Help_Request(counter,message)

            #Time out the program for 1 second
            time.sleep(1.5)            
            emergency_flag = False
            Watch.Rectangle_Transition(Watch.colour_bank["black"])
            
            break
        
        time.sleep(time_interval)

    if emergency_flag:
        #Call for help
        message = 3
        buzzer.off()
        Red_Led.off()
        Green_Led.on()
        Watch.Manual_Help_Request(10,message)

    return emergency_flag

 

def Read_Data(Sensor,data_size,speed):
    #Reads data from orientation sensor and writes in file
    file_wr = open("raw_data_wr.txt",'a')
    file_ank = open("raw_data_ank.txt",'a')

    for i in range(data_size):
        time.sleep(speed)
        data_tuple = Sensor.euler_angles()        
        data_str = [str(data_tuple[0]),"\t",str(data_tuple[1]),"\t",str(data_tuple[2]),"\n"]
        file_wr.writelines(data_str)
        file_ank.writelines(data_str)

    file_wr.close()
    file_ank.close()

    #Yes, it is a bit redundant, the same data is being written to two files
    #Our design necessitates two distinct sensors, one for the wrist and one of the ankle
    #Because of the limitations of the emulator we can only have one orientation sensor
    #If we were able to run two orientation sensors, the data being written to both files would be different
    #To showcase how the code would work right now we're just writing the same set of data to both files
    
def Start_Up_Routine():
    #Initialize files
    file = open("raw_data_wr.txt",'w')
    file.close()
    file = open("raw_data_ank.txt",'w')
    file.close()
    file = open("rolling_average_wr.txt",'w')
    file.close()
    file = open("rolling_average_ank.txt",'w')
    file.close()
    file = open("average_velocity_wr.txt",'w')
    file.close()
    file = open("average_velocity_ank.txt",'w')
    file.close()
    file = open("average_acceleration_wr.txt",'w')
    file.close()
    file = open("average_acceleration_ank.txt",'w')
    file.close()

    #Purely to staisfy the DP-3 project requirements, not actually needed for functionality
    file = open("Processed_info.txt",'w')
    file.writelines(["|Wr raw pos (x,z,y)|","\t","|Ank raw pos|","\t","|Avg pos Wr|","\t","|Avg pos Ank|","\t","|Buzzer|","\t","|Red LED|","\t","|Green LED|"])
    file.close()

    #shell header
    print("|Wr raw pos (x,z,y)|","\t","|Ank raw pos|","\t",
          "|Avg pos Wr|","\t","|Avg pos Ank|","\t",
          "|Buzzer|","\t","|Red LED|","\t","|Green LED|")

 

 

'''
************************************************************
***   Function Definitions - STUDENT CODE ENDS HERE!   ***
************************************************************
'''

 


if __name__ == "__main__":
    global mainObj
    mainObj = MainWindow_EXEC()
 

Emulator 

program shell.png
output devices.png
fall detected.png
program 2.png
program.png
bottom of page