Physio-Go ~ Gamified Physiotherapy Device for Multiple Sclerosis Patients

Designed and prototyped a portable, gamified physiotherapy device to help individuals with Multiple Sclerosis (MS) maintain upper-limb range of motion and therapy consistency at home or while travelling.
Home
Questions?
hero-image

Aleeza Zar

Project Timeline

Jan 2024 - Apr-2024

HighlightS

  • Designed a portable physiotherapy device to support upper-limb range of motion (ROM) for MS patients, informed by direct client consultation.
  • Developed a gamified rehabilitation system using LEDs, photocells, and auditory feedback to improve engagement and adherence to physiotherapy routines.
  • Created an ergonomic, left-hand-specific joystick grip with adjustable straps and removable weights to accommodate reduced grip strength and progressive resistance.
  • Implemented fatigue-aware control logic, automatically ending sessions after inactivity to prevent overexertion.
  • Integrated user-controlled difficulty levels, enabling personalized therapy duration and progression.
  • Built a medium-fidelity functional prototype using laser-cut acrylic, wood housing, and Raspberry Pi-based control.
  • Balanced human-factors design, safety constraints, and manufacturability under tight academic timelines.
  • Led project management tasks, including Gantt chart scheduling, milestone planning, and team coordination.

SKILLS

SolidWorks (CAD & Rendering)
Raspberry Pi
Python (Embedded Control Logic)
Sensor Integration (Photocells)
Rapid Prototyping
Laser Cutting & Fabrication
Electronics Prototyping
Human-Centered Design
Assistive & Rehabilitation Devices
Health & Safety Risk Analysis
Team Leadership & Project Management

Problem Statement

Individuals living with Multiple Sclerosis (MS) often experience progressive motor weakness, spasticity, and reduced range of motion, making consistent upper-limb physiotherapy difficult to maintain. While regular rehabilitation is critical for preserving mobility and functional independence, existing physiotherapy solutions are frequently clinic-dependent, costly, repetitive, or poorly suited to patients’ daily routines—especially for those who travel or experience fatigue easily. As a result, many MS patients struggle with long-term adherence to therapy, leading to further functional decline. There is a need for a safe, affordable, and engaging at-home physiotherapy device that supports range-of-motion exercises, accommodates fluctuating fatigue levels, and empowers patients to independently manage their rehabilitation.

Control & Game Logic (Python, Raspberry Pi

PYTHON
from sensor_library import *
m gpiozero import *
import time
import sys
import random

# Define GPIO pin numbers for buttons, LEDs, buzzer and photocells
button1 = Button(21)
button2 = Button(20)

led1 = LED(26)
led2 = LED(19)
led3 = LED(13)
led4 = LED(6)

buzzer = Buzzer(10)

photocell1 = Force_Sensing_Resistor(0)
photocell2 = Force_Sensing_Resistor(1)
photocell3 = Force_Sensing_Resistor(2)
photocell4 = Force_Sensing_Resistor(3)


# This function turns all LEDs on and prompts the user to start a session by pressing the "game" button.
def device_on():
led1.on()
led2.on()
led3.on()
led4.on()
print("Welcome! Press the 'game' button to start your session.")

# When this button is pressed, it will execute the device_on function.
button1.when_pressed = device_on

# This function starts the game by prompting the user to type in a level, turns on random LEDs, and tracks the number of lights turned off for a set time interval.
def start_game(level):
start_time = 0
threshold = 80
light = 0
start = time.time()
elapsed_time = 0
stop = 15

# Prompting the user to input a level corresponding to how long they would like their time session to be.
level = int(input("Type number of level (30-second session is level 1, 60-second session is level 2, etc.) or type 0 to quit:"))

# if zero is inpuutted, the game turns off.
if level == 0:
print("Game turning off...")
print("Goodbye.")


else:
# Depending on the level inputted, the start time (initalized at 0) will increase by an interval of 30 seconds, modifying the session time interval.
for i in range(level):
start_time += 30

# While the time passed is less than the time interval of the session, a random number is called between 1-4, corresponding to a specific LED turning on.
while elapsed_time < start_time:
broken = False
call = random.randint(1,4)

# if 1 is called, LED 1 turns on and the corresponding photocell is monitored.
if call == 1:
while photocell1.force_raw() >= threshold:

value = photocell1.force_raw()

led1.on()
led2.off()
led3.off()
led4.off()

elapsed_time = time.time()-start

# If the photocell resistance (value) is less than the set threshold, the light will turn off, trigger the buzzer to beep, the light and elapsed time are recorded and displayed.
if value < threshold:

buzzer.on()
time.sleep(0.1)
buzzer.off()
time.sleep(0.1)
buzzer.on()
time.sleep(0.1)
buzzer.off()

led1.off()

light+=1
stop += elapsed_time

print("Elapsed time:", round(elapsed_time,2))
print(round(stop,2))
print("light hit:", round(light,2))

# If the resistance value is consistently greater than the threshold for more than the initialized buffer time (15 secs), the loop breaks and level is not complete the level.
elif value >= threshold and elapsed_time >= stop:
broken = True
print ("Sorry, you did not complete this level. Take a break and come again later.")
led1.off()
break
if broken == True:
break

# This process is repeated for other three LEDs

elif call == 2:
while photocell2.force_raw() >= threshold:

value = photocell2.force_raw()

led2.on()
led1.off()
led3.off()
led4.off()

elapsed_time = time.time()-start

if value < threshold:

buzzer.on()
time.sleep(0.1)
buzzer.off()
time.sleep(0.1)
buzzer.on()
time.sleep(0.1)
buzzer.off()

led2.off()

light+=1
stop += elapsed_time

print("Elapsed time:", round(elapsed_time,2))
print(round(stop,2))
print("light hit:", round(light,2))

elif value >= threshold and elapsed_time >= stop:
broken = True
print ("Sorry, you did not complete this level. Take a break and come again later.")
led2.off()
break
if broken == True:
break

elif call == 3:
while photocell3.force_raw() >= threshold:

value = photocell3.force_raw()

led3.on()
led1.off()
led2.off()
led4.off()

elapsed_time = time.time()-start

if value < threshold:

buzzer.on()
time.sleep(0.1)
buzzer.off()
time.sleep(0.1)
buzzer.on()
time.sleep(0.1)
buzzer.off()

led3.off()

light+=1
stop += elapsed_time

print("Elapsed time:", round(elapsed_time,2))
print(round(stop,2))
print("light hit:", round(light,2))

elif value >= threshold and elapsed_time >= stop:
broken = True
print ("Sorry, you did not complete this level. Take a break and come again later.")
led3.off()
break
if broken == True:
break

elif call == 4:
while photocell4.force_raw() >= threshold:

value = photocell4.force_raw()

led4.on()
led1.off()
led2.off()
led3.off()

elapsed_time = time.time()-start

if value < threshold:

buzzer.on()
time.sleep(0.1)
buzzer.off()
time.sleep(0.1)
buzzer.on()
time.sleep(0.1)
buzzer.off()

led4.off()

light+=1

stop += elapsed_time

print("Elapsed time:", round(elapsed_time,2))
print(round(stop,2))
print("light hit:", round(light,2))

elif value >= threshold and elapsed_time >= stop:
broken = True
print ("Sorry, you did not complete this level. Take a break and come again later.")
led4.off()
break
if broken == True:
break

# When the time of level is completed, the user is congratulated and told how many lights they've hit.
# Prompts the user to start the next level.
if elapsed_time >= start_time and broken == False:
print("Congrats! You succesfully completed level", level, "! You hit", light, "lights!")
start_time += 30
print ("Your next session is a", start_time, "-second interval. Press and hold the 'game' button to start:")
music()

# the LEDs blink after the game is complete.
while button2.is_pressed == False:

led1.on()
led2.on()
led3.on()
led4.on()

time.sleep(0.5)

led1.off()
led2.off()
led3.off()
led4.off()

time.sleep(0.5)


# when the "game" button is pressed, the start_game function is called.
button2.when_pressed = start_game

# This function makes the buzzer chime three times and is called when level is completed to indicate the user.
def music():
buzzer.on()
time.sleep(0.2)
buzzer.off()
time.sleep(0.05)
buzzer.on()
time.sleep(0.2)
buzzer.off()
time.sleep(0.05)
buzzer.on()
time.sleep(0.2)
buzzer.off()