Abhilash Jai Gudivada
Published © GPL3+

Posture correction program

A simple tool to remind you every time your posture falters.

BeginnerWork in progress12 hours423
Posture correction program

Things used in this project

Hardware components

Raspberry Pi 3 Model B
Raspberry Pi 3 Model B
Raspberry Pi with breadboard and jumper wires
×1
Buzzer
Buzzer
Passive buzzer
×1
Camera Module
Raspberry Pi Camera Module
Didn't really use the raspi camera because I use my laptop more, but everything still works with the raspi camera as well.
×1

Software apps and online services

Visual Studio 2015
Microsoft Visual Studio 2015

Story

Read more

Schematics

Simple perfboard schematic

Extremely simple circuit schematic I drew on a printer paper

Simple circuit diagram

Circuit diagram I created to showcase how the electricity flows

Code

Server side code

Python
Code used to run the Raspberry Pi side of things
import sys
import RPi.GPIO as GPIO
import time
import socket

password = "1234"

server = socket.socket()
print("Server created")

server.bind(("192.168.1.55", 21985))
server.listen(3)
print("Waiting for clients")

client, address = server.accept()
print("A client has accepted!")

client.send(bytes("What is the password?", "utf-8"))
msg = client.recv(1024).decode()

triggerPIN = 21
GPIO.setmode(GPIO.BCM)
GPIO.setup(triggerPIN, GPIO.OUT)
buzzer = GPIO.PWM

if msg == password:
  client.send(bytes("Your password guess was correct!", "utf-8"))
  
  while True:
    message = client.recv(1024).decode()
    
    if message == "1":
      #stop the beep
      buzzer.stop()
      
    if message == "2":
      buzzer.start(10)
      
    if message == "stop":
      break
    
GPIO.cleanup()
sys.exit

Client side code

Python
Code used by the laptop or main computer
import cv2
import mediapipe as mp
import numpy as np
import socket

mp_drawing = mp.solutions.drawing_utils
mp_drawing_styles = mp.solutions.drawing_styles
mp_pose = mp.solutions.pose

class Ergonomy:
	def __init__(self):
		self.neck_angle=0

	def update_joints(self, landmarks_3d):
		#update all needed joints based on landmarks_3d.landmark from mp
		try:
			# media pipe joints (BlazePose GHUM 3D)
			left_shoulder = np.array([landmarks_3d.landmark[11].x, landmarks_3d.landmark[11].y, landmarks_3d.landmark[11].z])
			right_shoulder = np.array([landmarks_3d.landmark[12].x, landmarks_3d.landmark[12].y, landmarks_3d.landmark[12].z])
			left_mouth = np.array([landmarks_3d.landmark[9].x, landmarks_3d.landmark[9].y, landmarks_3d.landmark[9].z])
			right_mouth = np.array([landmarks_3d.landmark[10].x, landmarks_3d.landmark[10].y, landmarks_3d.landmark[10].z])
			left_hip = np.array([landmarks_3d.landmark[23].x, landmarks_3d.landmark[23].y, landmarks_3d.landmark[23].z])
			right_hip = np.array([landmarks_3d.landmark[24].x, landmarks_3d.landmark[24].y, landmarks_3d.landmark[24].z])
			#left_knee = np.array([landmarks_3d.landmark[25].x, landmarks_3d.landmark[25].y, landmarks_3d.landmark[25].z])
			#right_knee = np.array([landmarks_3d.landmark[26].x, landmarks_3d.landmark[26].y, landmarks_3d.landmark[26].z])
			
			# helper joints
			mid_shoulder = (left_shoulder + right_shoulder) / 2
			mid_hip = (left_hip + right_hip) / 2
			mid_mouth = (left_mouth + right_mouth) / 2
			#mid_knee = (left_knee + right_knee) / 2

			# angles
			self.neck_angle = self.get_angle(mid_hip, mid_shoulder, mid_mouth, mid_shoulder, adjust=True)

		except:
			# could not retrieve all needed joints
			pass

	def get_angle(self, a, b, c, d, adjust):
		"""return the angle between two vectors"""
		vec1 = a - b
		vec2 = c - d

		cosine_angle = np.dot(vec1, vec2) / (np.linalg.norm(vec1) * np.linalg.norm(vec2))
		angle = np.arccos(cosine_angle)

		# adjust angle by substracting 180 deg if needed 
		if (adjust):
			angle_adjusted = abs(np.degrees(angle) - 180)
			return int(angle_adjusted)
		else:
			return int(abs(np.degrees(angle)))

	def get_neck_color(self):
		#returns (B,G,R) colors for visualization
		if self.neck_angle < 35:
			print("1")
			client_socket.send("1".encode())
			return (0,255,0)
		elif self.neck_angle <= 50:
			print("2")
			client_socket.send("2".encode())
			return (0,255,255)
		else:
			print("3")
			client_socket.send("2".encode())
			return (0,0,255)


if __name__ == '__main__':
	MyErgonomy = Ergonomy()
	
	try:
		host = (("192.168.1.55", 21985))
		client_socket = socket.socket()
		client_socket.connect(host)
		
		print(client_socket.recv(1024).decode())
		message = input()
		client_socket.send(message.encode())
		print(client_socket.recv(1024).decode())

		cap = cv2.VideoCapture(0)  # webcam input
		with mp_pose.Pose(
			model_complexity=1,
			smooth_landmarks=True,
			min_detection_confidence=0.3,
			min_tracking_confidence=0.3) as pose:
			while cap.isOpened():
				success, image = cap.read()
				if not success:
					print("Ignoring empty camera frame.")
					continue

				image.flags.writeable = False
				image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
				results = pose.process(image)
				landmarks_3d = results.pose_world_landmarks

				# draw the pose annotation on the image.
				image.flags.writeable = True
				image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
				mp_drawing.draw_landmarks(
					image,
					results.pose_landmarks,
					mp_pose.POSE_CONNECTIONS,
					landmark_drawing_spec=mp_drawing_styles.get_default_pose_landmarks_style())

				MyErgonomy.update_joints(landmarks_3d)
    
				# visualization: text + HP bar
				age = cv2.putText(image, text="neck angle: "+str(MyErgonomy.neck_angle), 
				org=(5,60), fontFace=cv2.FONT_HERSHEY_SIMPLEX, fontScale=1, color=MyErgonomy.get_neck_color(), thickness=3)
				image = cv2.rectangle(image, (5,5), (145*2, 30), color=(255,255,255), thickness=-1)
				image = cv2.rectangle(image, (5,5), (145*2-(MyErgonomy.neck_angle * 2), 30), color=MyErgonomy.get_neck_color(), thickness=-1)
			
				cv2.imshow('MediaPipe Pose Demo', image)

				if cv2.waitKey(5) & 0xFF == 27:
					break
		cap.release()
  
	except KeyboardInterrupt:
		goodbye = "stop"
		client_socket.send(goodbye.encode())

Ergonomy

Base code for standing posture that I edited

Credits

Abhilash Jai Gudivada
1 project • 0 followers
Just a high schooler trying to make cool projects

Comments