diff --git a/README.md b/README.md index b62ce1a..f4cece3 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ We use a facial recognition system to facilitate user logins and registrations t Real-time feedback is delivered via a vibrating mousepad, which reminds the user to sit up straight if they are not sitting correctly. Current-session feedback can be viewed via the SDG's monitor to show the user how their posture has progressed over the current session, as well as via the physical growth of the potted plant. -For developers, see [Project Overview](#project-overview). For users setting up a Raspberry Pi for use in the SDG, see [Raspberry Pi Setup](#raspberry-pi-setup). +For developers, see [Project Overview](#project-overview). For users setting up a Raspberry Pi for use in the SDG, see [Deployment](#deployment). --- @@ -25,15 +25,18 @@ For developers, see [Project Overview](#project-overview). For users setting up - [Project Overview](#project-overview) - [Directory Structure](#directory-structure) - [Dependencies](#dependencies) + - [Deployment](#deployment) + - [Single command all-in-one](#single-command-all-in-one) + - [Pi Environment Set-up](#pi-environment-set-up) + - [Deploy codebase](#deploy-codebase) + - [Run Program](#run-program) - [Development](#development) - [Installation](#installation) - [Dependencies](#dependencies-1) - [Testing](#testing) - [Code Styling](#code-styling) - [Documentation](#documentation) - - [Raspberry Pi Setup](#raspberry-pi-setup) - - [Environment](#environment) - - [Deployment](#deployment) + ## Project Overview ### Directory Structure @@ -53,6 +56,36 @@ The main project dependencies are specified in [pyproject.toml](./pyproject.toml - [piicodev](https://pypi.org/project/piicodev/) provides modules for interfacing with Raspberry Pi peripherals. - [face-recognition](https://pypi.org/project/face-recognition/) provides the face rceognition model. +## Deployment +### Single command all-in-one +To set up the Pi's environment, deploy the code base, and start the program follow the following steps. +1. Flash an SD card with a fresh installation of the 64bit Raspberry Pi OS using the [official imager](https://www.raspberrypi.com/software/). When imaging the SD card you must turn on the SSH connections in the edit OS settings menu. +2. Plug the SD card into the Pi and turn it on. Wait for the green light to stop flashing before going to step 3. +3. Clone this git directory to your computer. +4. From the base directory of the project run, +` +./run.sh [Pi Hostname/IP] [Pi Username] +`. If you do not have sshpass installed this may prompt for the Pi's password many times. +5. The above command will take a while. +### Pi Environment Set-up +You can set up the Pi's environment by following steps 1,2, and 3 of the above instructions. and then running. +```bash +scripts/bootstrap.sh [Pi Hostname/IP] [Pi Username] +``` +### Deploy codebase +You can deploy the codebase by running +```bash +cd scripts +./deploy.sh ../deploypaths.txt [Pi Hostname/IP] [Pi Username] +``` + +### Run Program +You can start up the program by running +```bash +cd scripts +./ssh [Pi Username]@[Pi Hostname/IP] 'bash -s' < run_garden.sh +``` + ## Development ### Installation @@ -150,25 +183,3 @@ This spins up a local server which serves the documentation pages, and also hot- You can build the documentation (without spinning up a server) with `make docs`, and clean the documentation output with `make docs-clean`. -## Raspberry Pi Setup -### Environment -Flash up your Raspberry Pi Model 3 B with a fresh install of Raspberry Pi OS (64-bit). Turn on the Raspberry Pi and record its IP address `[Target IP]`. -On your personal machine, clone into this Git repository. From the base directory, run the following command. -```bash -cd bootstrap && ./bootstrap.sh [Target IP] [Username] -``` -This will install python3.10 to the Pi and the dependencies for the project. -### Deployment -To deploy a build to the Raspberry Pi, turn it on and run the `deploy.sh` script from your personal machine. This script will create a tarball of file listed in a text file, transfer it to -a specified hostname and untar it there. - -To use the script execute it in the project's root directory with, -```bash -./deploy.sh [pathfile] [hostname] [username] -``` -For example, to deploy the files listed in `deploypaths.txt` to the target IP `testpi` (using username raspberry) the command would be -```bash -./deploy.sh deploypaths.txt testpi raspberry -``` -The pathname file should contain a path to a file or directory on each line. If a directory is listed `deploy.sh` will copy the entire contents over. -You can use the `#` character at the start of a line to leave comments. diff --git a/client/overlord_overlord.py b/client/overlord_overlord.py index 009a658..89f4634 100644 --- a/client/overlord_overlord.py +++ b/client/overlord_overlord.py @@ -14,11 +14,11 @@ def spawn_camera_overlord(): - subprocess.run([PYTHON_CAMERA, "drivers/camera_overlord.py"]) + subprocess.run([PYTHON_CAMERA, "client/drivers/camera_overlord.py"]) def spawn_pi_overlord(no_posture_model): - cmd = [PYTHON_DEFAULT, "drivers/main.py"] + cmd = [PYTHON_DEFAULT, "client/drivers/main.py"] if no_posture_model: cmd.append("--no-posture-model") subprocess.run(cmd) @@ -29,6 +29,7 @@ def main(): parser = argparse.ArgumentParser() parser.add_argument("--no-posture-model", action="store_true") args = parser.parse_args() + logger.info(args) # Spawn a new process to run the camera indefinitely camera_overlord = multiprocessing.Process(target=spawn_camera_overlord, args=()) diff --git a/scripts/async_posture.py b/demos/async_posture.py similarity index 100% rename from scripts/async_posture.py rename to demos/async_posture.py diff --git a/scripts/face_unlock.py b/demos/face_unlock.py similarity index 100% rename from scripts/face_unlock.py rename to demos/face_unlock.py diff --git a/scripts/test-database-tools.py b/demos/test-database-tools.py similarity index 100% rename from scripts/test-database-tools.py rename to demos/test-database-tools.py diff --git a/scripts/test-posture-tracker.py b/demos/test-posture-tracker.py similarity index 100% rename from scripts/test-posture-tracker.py rename to demos/test-posture-tracker.py diff --git a/deploypaths.txt b/deploypaths.txt index f43685e..c4d0206 100644 --- a/deploypaths.txt +++ b/deploypaths.txt @@ -2,6 +2,5 @@ # deploy.sh will preserve the source directory layout so imports between files # should still work if all files are copied in client/ -scripts/ pyproject.toml poetry.lock diff --git a/run.sh b/run.sh new file mode 100755 index 0000000..a94d2ef --- /dev/null +++ b/run.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +WARN="[\033[1;33mWARN\033[0m]" +INFO="[\033[1;32mINFO\033[0m]" +ERROR="[\033[1;31mERROR\033[0m]" + +SSHTARGET=$1 +SSHUSER=$2 + +# Ready to rock +cd scripts + +echo -e $INFO Bootstrapping the Pi +if ! ./bootstrap.sh $SSHTARGET $SSHUSER; then + exit 1; +fi + +echo -e $INFO Deploying codebase +if ! ./deploy.sh ../deploypaths.txt $SSHTARGET $SSHUSER; then + exit 1; +fi + +echo -e $INFO +ssh $SSHUSER@$SSHTARGET 'bash -s' < run-garden.sh diff --git a/bootstrap/bootstrap.sh b/scripts/bootstrap.sh similarity index 73% rename from bootstrap/bootstrap.sh rename to scripts/bootstrap.sh index 3900acf..802370a 100755 --- a/bootstrap/bootstrap.sh +++ b/scripts/bootstrap.sh @@ -1,8 +1,8 @@ #!/bin/bash -WARN="[\033[1;33mWARN\033[0m]" -INFO="[\033[1;32mINFO\033[0m]" -ERROR="[\033[1;31mERROR\033[0m]" +WARN="bootstrap[\033[1;33mWARN\033[0m]" +INFO="bootstrap[\033[1;32mINFO\033[0m]" +ERROR="bootstrap[\033[1;31mERROR\033[0m]" SSHTARGET=$1 SSHUSER=$2 @@ -29,6 +29,12 @@ fi SSH_GO="$SSH_PREFIX ssh $SSHUSER@$SSHTARGET" +echo -e $INFO Increasing Swapfile Size +if ! $SSH_GO 'bash -s' < increase_swap.sh; then + echo -e $ERROR Something went wrong... please check above. + exit 1 +fi + echo -e $INFO Installing and Compiling Python if $SSH_GO 'command -v python3.10 > /dev/null'; then echo -e "$INFO It appears Python3.10 already exists on target. I won't compile it again." @@ -40,6 +46,12 @@ else echo -e $INFO Python3.10 installed fi +echo -e $INFO Installing dlib +if ! $SSH_GO 'bash -s' < face_rec_install.sh; then + echo -e $ERROR dlib installation failed. + exit 1 +fi + echo -e $INFO Installing uv if $SSH_GO 'test -f ~/.cargo/bin/uv'; then echo -e "$INFO uv already installed" @@ -52,9 +64,9 @@ else fi echo -e $INFO Copying Dependency Data -$SSH_PREFIX scp ../{pyproject.toml,README.md} ./apt_packages.txt $SSHUSER@$SSHTARGET:~/ +$SSH_PREFIX scp ../{pyproject.toml,README.md} $SSHUSER@$SSHTARGET:~/ echo -e $INFO Installing apt packages echo -e $INFO Compiling dependencies $SSH_GO "~/.cargo/bin/uv pip compile pyproject.toml -o requirements.txt" -echo -e $INFO Installing dependencies +echo -e "$INFO Installing dependencies" $SSH_GO "sudo ~/.cargo/bin/uv pip install --system --python 3.10 -r requirements.txt" diff --git a/deploy.sh b/scripts/deploy.sh similarity index 90% rename from deploy.sh rename to scripts/deploy.sh index 6706efa..b31e996 100755 --- a/deploy.sh +++ b/scripts/deploy.sh @@ -1,9 +1,9 @@ #!/bin/bash -WARN="[\033[1;33mWARN\033[0m]" -INFO="[\033[1;32mINFO\033[0m]" -ERROR="[\033[1;31mERROR\033[0m]" +WARN="deploy[\033[1;33mWARN\033[0m]" +INFO="deploy[\033[1;32mINFO\033[0m]" +ERROR="deploy[\033[1;31mERROR\033[0m]" PATHFILE=$1 TEMPDIRPATH='package_temp' @@ -101,8 +101,10 @@ fi echo -e "$INFO Downloading Models" $SSH_GO "mkdir build/client/models/resources && curl -o build/client/models/resources/pose_landmarker_lite.task \ -https://storage.googleapis.com/mediapipe-models/pose_landmarker/pose_landmarker_lite/float16/latest/pose_landmarker_lite.task -" +https://storage.googleapis.com/mediapipe-models/pose_landmarker/pose_landmarker_lite/float16/latest/pose_landmarker_lite.task" + +echo -e $INFO Installing the package +$SSH_GO "cd build && pip install -e . && cd .." echo -e "$INFO Deployed Successfully" cleanup diff --git a/scripts/face_rec_install.sh b/scripts/face_rec_install.sh new file mode 100644 index 0000000..00a81a7 --- /dev/null +++ b/scripts/face_rec_install.sh @@ -0,0 +1,32 @@ +#!/bin/bash +ERROR="deploy[\033[1;31mERROR\033[0m]" + +sudo apt-get install build-essential \ + cmake \ + gfortran \ + git \ + wget \ + curl \ + graphicsmagick \ + libgraphicsmagick1-dev \ + libatlas-base-dev \ + libavcodec-dev \ + libavformat-dev \ + libboost-all-dev \ + libgtk2.0-dev \ + libjpeg-dev \ + liblapack-dev \ + libswscale-dev \ + pkg-config \ + python3-dev \ + python3-numpy \ + python3-pip \ + zip + +mkdir -p dlib +git clone https://github.com/davisking/dlib.git dlib/ +cd ./dlib +if ! sudo python3.10 setup.py install --compiler-flags "-O3"; then + echo -e "$ERROR Error building dlib" + exit 1; +fi \ No newline at end of file diff --git a/scripts/increase_swap.sh b/scripts/increase_swap.sh new file mode 100644 index 0000000..2a11aa8 --- /dev/null +++ b/scripts/increase_swap.sh @@ -0,0 +1,23 @@ +#!/bin/bash +WARN="bootstrap[\033[1;33mWARN\033[0m]" +INFO="bootstrap[\033[1;32mINFO\033[0m]" +ERROR="bootstrap[\033[1;31mERROR\033[0m]" + +if ! sudo swapoff /var/swap; then + echo -e $WARN Error with swapoff +fi + +if ! sudo fallocate -l 2G /var/swap; then + echo -e $ERROR Error with fallocate + exit 1 +fi + +if ! sudo mkswap /var/swap; then + echo -e $ERROR Error with mkswap + exit 1 +fi + +if ! sudo swapon /var/swap; then + echo -e $ERROR Error with swapon + exit 1 +fi \ No newline at end of file diff --git a/bootstrap/python_install.sh b/scripts/python_install.sh similarity index 100% rename from bootstrap/python_install.sh rename to scripts/python_install.sh diff --git a/scripts/run-garden.sh b/scripts/run-garden.sh new file mode 100755 index 0000000..faa22be --- /dev/null +++ b/scripts/run-garden.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +# Usage: ./run.sh [--no-posture-model] + +ERROR="[\033[1;31mERROR\033[0m]" + +cd build/ + +if ! type -P python3.10 >/dev/null 2>&1; then + echo -e "$ERROR python3.10 not found" + exit 2 +fi + +if ! type -P python3.11 >/dev/null 2>&1; then + echo -e "$ERROR python3.11 not found" + exit 2 +fi + +if [ -n "$1" ]; then + if [ $1 = "--no-posture-model" ]; then + python3.10 client/overlord_overlord.py --no-posture-model + else + echo -e "$ERROR Unrecognised first argument: $1" + exit 1 + fi +else + python3.10 client/overlord_overlord.py +fi