Compare commits

...

95 Commits

Author SHA1 Message Date
Luca Warmenhoven
13fca50d6f Updated .gitignore 2024-05-17 14:56:20 +02:00
Luca Warmenhoven
7442d1fca4 Added fitness activity switching 2024-05-17 14:53:45 +02:00
Luca Warmenhoven
cfcbe7d51c Added Gson for JSON parsing, added Exercise retriever 2024-05-17 13:25:50 +02:00
Luca Warmenhoven
3edab82535 Added example exercises 2024-05-17 12:42:10 +02:00
Luca Warmenhoven
3fe90ce547 Merge remote-tracking branch 'origin/main' 2024-05-17 12:32:59 +02:00
Luca Warmenhoven
59c374eb02 Added sport activity abstraction classes 2024-05-17 12:32:54 +02:00
03b056811d Name change 2024-05-15 17:03:32 +02:00
58f1b14ab6 Merge branch 'main' of https://gitlab.fdmci.hva.nl/propedeuse-hbo-ict/onderwijs/2023-2024/out-a-se-ti/blok-4/muupooviixee66 2024-05-15 17:03:07 +02:00
ab73c5012b java class explanation 2024-05-15 17:03:02 +02:00
Luca Warmenhoven
a4a01ae9ef fixed issues 2024-05-15 16:50:22 +02:00
Luca Warmenhoven
5b5934d985 g 2024-05-15 16:44:25 +02:00
Luca Warmenhoven
b89dab7792 Merge remote-tracking branch 'origin/main'
# Conflicts:
#	code/src/Fitbot/app/src/main/AndroidManifest.xml
#	code/src/Fitbot/app/src/main/java/com/example/fitbot/ui/activities/MainActivity.java
2024-05-15 16:44:07 +02:00
SebasKoedam
32020ce801 feat: Add Java build configuration update to .vscode/settings.json 2024-05-15 16:42:21 +02:00
SebasKoedam
4d169a5e74 Merge branch 'main' of ssh://gitlab.fdmci.hva.nl/propedeuse-hbo-ict/onderwijs/2023-2024/out-a-se-ti/blok-4/muupooviixee66 2024-05-15 16:42:11 +02:00
SebasKoedam
3ca982c36f feat: Add Bluetooth permissions and location permission to AndroidManifest.xml 2024-05-15 16:41:32 +02:00
Luca Warmenhoven
ce5f50439a fixed 2024-05-15 16:40:35 +02:00
Luca Warmenhoven
37ef0aa118 Merge branch 'refs/heads/35-als-gebruiker-wil-ik-live-mijn-bewegingen-doen-zodat-ik-kan-inzien-of-ik-het-goed-doe'
# Conflicts:
#	code/src/Fitbot/app/src/main/AndroidManifest.xml
#	code/src/Fitbot/app/src/main/java/com/example/fitbot/ui/activities/MainActivity.java
2024-05-15 16:35:40 +02:00
Luca Warmenhoven
af9138b1ea store changes 2024-05-15 16:34:17 +02:00
Luca Warmenhoven
9107d5d9f7 Merge remote-tracking branch 'origin/35-als-gebruiker-wil-ik-live-mijn-bewegingen-doen-zodat-ik-kan-inzien-of-ik-het-goed-doe'
# Conflicts:
#	code/src/Fitbot/app/src/main/AndroidManifest.xml
#	code/src/Fitbot/app/src/main/java/com/example/fitbot/ui/activities/MainActivity.java
2024-05-15 16:32:56 +02:00
Luca Warmenhoven
612b1c8a7c bread 2024-05-15 16:32:38 +02:00
Luca Warmenhoven
606a05aa13 Updated path math, started with 3d path to 2d screen space projection 2024-05-15 16:32:33 +02:00
Luca Warmenhoven
8224327a01 bread 2024-05-15 16:29:22 +02:00
Luca Warmenhoven
cf429f993e Merge remote-tracking branch 'origin/main' 2024-05-15 15:48:18 +02:00
Luca Warmenhoven
86a96740e5 Updated onderzoek-voorbeeld.md & motion-tracking-system-analysis.md 2024-05-15 15:47:52 +02:00
3a7d1cb72c Merge branch 'main' of https://gitlab.fdmci.hva.nl/propedeuse-hbo-ict/onderwijs/2023-2024/out-a-se-ti/blok-4/muupooviixee66 2024-05-15 13:45:16 +02:00
92a1c2b650 Repaired the websocket connector
for some reason it doesnt wannar in a class
2024-05-15 13:45:13 +02:00
Luca Warmenhoven
5ff813c35c Merge remote-tracking branch 'origin/main' 2024-05-15 13:38:43 +02:00
Luca Warmenhoven
552436b993 Updated onderzoek-voorbeeld.md and motion-tracking-system-analysis.md 2024-05-15 13:38:38 +02:00
SebasKoedam
c5c0e871e8 feat: Implement position tracking with Wii Fit Board 2024-05-15 12:36:57 +02:00
SebasKoedam
307a06e53f feat: Add FitnessActivity for fitness tracking functionality 2024-05-15 12:36:50 +02:00
Luca Warmenhoven
7fba504e90 Renamed files, added motion-tracking-system-analysis.md 2024-05-15 12:04:36 +02:00
Luca Warmenhoven
20a2f3b6d5 Merge remote-tracking branch 'origin/main'
# Conflicts:
#	code/src/Fitbot/app/src/main/java/com/example/fitbot/MainActivity.java
#	code/src/Fitbot/app/src/main/java/com/example/fitbot/ui/activities/MainActivity.java
#	code/src/Fitbot/app/src/main/java/com/example/fitbot/util/processing/MotionProcessor.java
2024-05-15 10:44:11 +02:00
Luca Warmenhoven
0c4b4d3d0b Updated onderzoek-voorbeeld.md 2024-05-15 10:42:08 +02:00
Luca Warmenhoven
3e9385bb46 onderzoek-voorbeeld.md 2024-05-15 01:27:32 +02:00
Luca Warmenhoven
11489682eb Updated path math, started with 3d path to 2d screen space projection 2024-05-15 01:10:51 +02:00
Niels
6608f361aa Onderzoeks opdracht 2024-05-14 22:21:17 +02:00
Niels
44138ee916 inleidign betoog 2024-05-14 19:39:49 +02:00
1c39bf9153 cleanup + serial communication for setting zeropoint and put wifi in its own class 2024-05-14 16:01:41 +02:00
SebasKoedam
7bc97e93c2 optimized file structure 2024-05-14 14:34:02 +02:00
Luca Warmenhoven
490a97ae78 Updated PersonalMotionPreviewElement (previously SportPreviewCanvas) 2024-05-14 14:15:12 +02:00
Luca Warmenhoven
b7459f531b Added SportPreviewActivity and SportPreviewCanvas 2024-05-14 13:40:59 +02:00
Luca Warmenhoven
714a8a1c51 Merge remote-tracking branch 'origin/main' 2024-05-14 12:58:44 +02:00
Luca Warmenhoven
a276b6fcb1 Updated motion processing and WebSocket code. 2024-05-14 12:58:38 +02:00
SebasKoedam
58613e5c5d chore: Update button IDs in activity_main.xml 2024-05-14 12:58:24 +02:00
Luca Warmenhoven
98d30d6bc4 Updated motion processing and WebSocket code. 2024-05-14 12:57:29 +02:00
Luca Warmenhoven
59e1cfab94 Updated motion processing and WebSocket code. 2024-05-14 12:57:25 +02:00
Luca Warmenhoven
a16bd22e99 Updated error function calculation to be more efficient 2024-05-14 12:57:10 +02:00
Luca Warmenhoven
8bbf5750f6 Added error calculations for GesturePath :: MotionProcessor.averageError, MotionProcessor.getErrors, GesturePath::getError 2024-05-14 12:56:51 +02:00
Luca Warmenhoven
8db4e8a208 Updated math behind path error calculation, fixed WebSocket not starting. 2024-05-14 12:56:27 +02:00
Luca Warmenhoven
d533ce97bb Added motion processing, fixed WebSocket packet processing, added Vector math to process motion data 2024-05-14 12:55:54 +02:00
Luca Warmenhoven
c5b08a4907 Added basic WebSocket functionality (no decoding yet) 2024-05-14 12:55:54 +02:00
Luca Warmenhoven
7936137912 Merge remote-tracking branch 'refs/remotes/origin/44-als-gebruiker-wil-ik-dat-ik-feedback-krijg-als-mijn-bewegingen-niet-optimaal-zijn-zodat-ik-weet'
# Conflicts:
#	code/src/Fitbot/app/src/main/java/com/example/fitbot/MainActivity.java
#	code/src/Fitbot/app/src/main/java/com/example/fitbot/MainScreen.java
2024-05-14 12:15:19 +02:00
SebasKoedam
8993d8eed6 added database docs to pages 2024-05-14 11:39:03 +02:00
SebasKoedam
2570d4320f added mariadb nodejs apache and phpmyadmin to pages 2024-05-14 11:37:06 +02:00
SebasKoedam
db78a11747 Added database erd eerd and infrastucture docs 2024-05-14 11:32:32 +02:00
SebasKoedam
955c05ae40 added inhoudsopgave 2024-05-14 10:03:36 +02:00
SebasKoedam
d1f81982da added onderzoek ethiek opdracht 3 2024-05-14 10:01:05 +02:00
SebasKoedam
d8236d474d Merge branch 'main' of ssh://gitlab.fdmci.hva.nl/propedeuse-hbo-ict/onderwijs/2023-2024/out-a-se-ti/blok-4/muupooviixee66 2024-05-14 09:23:57 +02:00
SebasKoedam
62eaba9318 added daily tasks 2024-05-14 09:23:56 +02:00
3484e16edb Betoog literatuur onderzoek 2024-05-13 19:58:58 +02:00
0278842145 Merge branch 'main' of https://gitlab.fdmci.hva.nl/propedeuse-hbo-ict/onderwijs/2023-2024/out-a-se-ti/blok-4/muupooviixee66 2024-05-13 16:50:05 +02:00
c59dcb3d01 Betoog 2024-05-13 16:50:00 +02:00
SebasKoedam
a28f7a28e5 Add ERD, EERD, and infrastructure documentation 2024-05-13 15:07:08 +02:00
SebasKoedam
45d211c71b Add darkred_button_gradient.xml and red_button_gradient.xml drawables 2024-05-13 15:07:00 +02:00
7cd7ed1545 Websocket server (stolen from last project) 2024-05-12 19:14:18 +02:00
1f7f4dcdbe send data in json format 2024-05-12 18:59:35 +02:00
c7c3ebe1c2 wifi and websocket connection added 2024-05-12 18:42:40 +02:00
Niels
29ed7e57c7 added white 2024-05-10 13:23:00 +02:00
Luca Warmenhoven
2d2f1a7be3 Added more code documentation (Vector3, WebSocket) 2024-05-10 12:44:58 +02:00
Luca Warmenhoven
c9422db59f Updated documentation 2024-05-10 12:30:12 +02:00
Luca Warmenhoven
f0a02d93a4 Merge remote-tracking branch 'origin/main' 2024-05-10 12:21:42 +02:00
Luca Warmenhoven
f74faa9d42 Added documentation (robot_motion_tracking_system.md and MotionProcessor.md) 2024-05-10 12:21:34 +02:00
Niels Gras
aef59c8b88 added black 2024-05-08 16:30:58 +02:00
4c80c69312 Merge branch 'main' of https://gitlab.fdmci.hva.nl/propedeuse-hbo-ict/onderwijs/2023-2024/out-a-se-ti/blok-4/muupooviixee66 2024-05-08 16:22:48 +02:00
ca34413fd7 Added wifi 2024-05-08 16:22:44 +02:00
Niels Gras
96c1a9e6b2 Merge branch 'main' of ssh://gitlab.fdmci.hva.nl/propedeuse-hbo-ict/onderwijs/2023-2024/out-a-se-ti/blok-4/muupooviixee66 2024-05-08 15:57:04 +02:00
Niels Gras
22c9239920 added orange 2024-05-08 15:57:02 +02:00
Luca Warmenhoven
b2d145f030 Merge remote-tracking branch 'origin/main' 2024-05-08 15:53:58 +02:00
Luca Warmenhoven
2ff4d8937a Added comment to incoming_request_handlers.js 2024-05-08 15:53:46 +02:00
SebasKoedam
a70e973c35 Merge branch 'main' of ssh://gitlab.fdmci.hva.nl/propedeuse-hbo-ict/onderwijs/2023-2024/out-a-se-ti/blok-4/muupooviixee66 2024-05-08 15:52:50 +02:00
SebasKoedam
5c333454bb chore: Update NodeJs and MariaDB setup documentation navigation 2024-05-08 15:52:49 +02:00
Luca Warmenhoven
bc3ee24de1 Merge remote-tracking branch 'origin/main' 2024-05-08 15:47:45 +02:00
Luca Warmenhoven
b1db3b5612 Added basic server files for RaspBerry Pi 2024-05-08 15:47:41 +02:00
Niels Gras
ffebd69d29 Add color research findings to documentation 2024-05-08 15:27:04 +02:00
2c51596996 changed measuring datatype to quanternions and convert them to radials and degrees 2024-05-08 15:12:49 +02:00
c7951c3d9f Merge branch 'main' of https://gitlab.fdmci.hva.nl/propedeuse-hbo-ict/onderwijs/2023-2024/out-a-se-ti/blok-4/muupooviixee66 2024-05-08 14:09:44 +02:00
ed7fdb5b1c start documentation pvb 2024-05-08 14:09:39 +02:00
6a20c8f16d class and script creation 2024-05-08 14:09:03 +02:00
21f1a844ba Update personal docs 2024-05-08 14:08:46 +02:00
SebasKoedam
7769e7f84d chore: Update NodeJs and MariaDB setup documentation navigation 2024-05-08 12:54:16 +02:00
SebasKoedam
cde3e1c580 chore: Update NodeJs Setup and MariaDB Setup navigation in documentation 2024-05-08 12:41:20 +02:00
SebasKoedam
d349a1a5ec chore: Update Raspberry Pi and NodeJs navigation in documentation 2024-05-08 12:37:35 +02:00
SebasKoedam
c777ca738e chore: Update navigation structure in documentation 2024-05-08 12:32:54 +02:00
Niels
65282cc57a added red and yellow to research 2024-05-07 18:41:37 +02:00
Niels
6fe9d1fb4f added more research 2024-05-07 18:18:45 +02:00
107 changed files with 2952 additions and 987 deletions

108
.idea/workspace.xml generated
View File

@@ -14,15 +14,9 @@
</configurations>
</component>
<component name="ChangeListManager">
<list default="true" id="00599d5b-7eb5-44da-ad7f-98bf42384c16" name="Changes" comment="Final update onderzoek-formulier.md">
<change afterPath="$PROJECT_DIR$/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/server/WebSocketConnection.java" afterDir="false" />
<list default="true" id="00599d5b-7eb5-44da-ad7f-98bf42384c16" name="Changes" comment="Updated onderzoek-voorbeeld.md &amp; motion-tracking-system-analysis.md">
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/processing/MotionData.java" beforeDir="false" afterPath="$PROJECT_DIR$/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/processing/MotionData.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/processing/MotionInputStream.java" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/processing/MotionProcessor.java" beforeDir="false" afterPath="$PROJECT_DIR$/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/processing/MotionProcessor.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/server/IWebSocketHandler.java" beforeDir="false" afterPath="$PROJECT_DIR$/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/server/IWebSocketHandler.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/server/WebSocket.java" beforeDir="false" afterPath="$PROJECT_DIR$/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/server/WebSocket.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/server/WebSocketConnectionHandler.java" beforeDir="false" afterPath="$PROJECT_DIR$/code/src/Fitbot/app/src/main/java/com/example/fitbot/util/server/WebSocketConnectionHandler.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/docs/documentation/research-questions/motion-tracking-system-analysis.md" beforeDir="false" afterPath="$PROJECT_DIR$/docs/documentation/research-questions/motion-tracking-system-analysis.md" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
@@ -32,7 +26,6 @@
<component name="ClangdSettings">
<option name="formatViaClangd" value="false" />
</component>
<component name="ExecutionTargetManager" SELECTED_TARGET="device_and_snapshot_combo_box_target[]" />
<component name="ExternalProjectsData">
<projectState path="$PROJECT_DIR$">
<ProjectState />
@@ -62,6 +55,11 @@
<option name="BRANCH" value="origin/main" />
</component>
<component name="Git.Settings">
<option name="RECENT_BRANCH_BY_REPOSITORY">
<map>
<entry key="$PROJECT_DIR$" value="44-als-gebruiker-wil-ik-dat-ik-feedback-krijg-als-mijn-bewegingen-niet-optimaal-zijn-zodat-ik-weet" />
</map>
</option>
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
</component>
<component name="GitSEFilterConfiguration">
@@ -87,22 +85,22 @@
<option name="hideEmptyMiddlePackages" value="true" />
<option name="showLibraryContents" value="true" />
</component>
<component name="PropertiesComponent"><![CDATA[{
"keyToString": {
"RunOnceActivity.OpenProjectViewOnStart": "true",
"RunOnceActivity.ShowReadmeOnStart": "true",
"git-widget-placeholder": "44-als-gebruiker-wil-ik-dat-ik-feedback-krijg-als-mijn-bewegingen-niet-op…-weet",
"kotlin-language-version-configured": "true",
"last_opened_file_path": "/Users/lucawarm/Jetbrains/Android Studio/muupooviixee66",
"node.js.detected.package.eslint": "true",
"node.js.detected.package.tslint": "true",
"node.js.selected.package.eslint": "(autodetect)",
"node.js.selected.package.tslint": "(autodetect)",
"nodejs_package_manager_path": "npm",
"settings.editor.selected.configurable": "preferences.pluginManager",
"vue.rearranger.settings.migration": "true"
<component name="PropertiesComponent">{
&quot;keyToString&quot;: {
&quot;RunOnceActivity.OpenProjectViewOnStart&quot;: &quot;true&quot;,
&quot;RunOnceActivity.ShowReadmeOnStart&quot;: &quot;true&quot;,
&quot;git-widget-placeholder&quot;: &quot;main&quot;,
&quot;kotlin-language-version-configured&quot;: &quot;true&quot;,
&quot;last_opened_file_path&quot;: &quot;/Users/lucawarm/Jetbrains/Android Studio/muupooviixee66&quot;,
&quot;node.js.detected.package.eslint&quot;: &quot;true&quot;,
&quot;node.js.detected.package.tslint&quot;: &quot;true&quot;,
&quot;node.js.selected.package.eslint&quot;: &quot;(autodetect)&quot;,
&quot;node.js.selected.package.tslint&quot;: &quot;(autodetect)&quot;,
&quot;nodejs_package_manager_path&quot;: &quot;npm&quot;,
&quot;settings.editor.selected.configurable&quot;: &quot;preferences.pluginManager&quot;,
&quot;vue.rearranger.settings.migration&quot;: &quot;true&quot;
}
}]]></component>
}</component>
<component name="RecentsManager">
<key name="MoveFile.RECENT_KEYS">
<recent name="$PROJECT_DIR$/code/src/app/src/main/java/com/fitbot" />
@@ -142,6 +140,13 @@
<method v="2" />
</configuration>
</component>
<component name="SharedIndexes">
<attachedChunks>
<set>
<option value="bundled-js-predefined-1d06a55b98c1-91d5c284f522-JavaScript-WS-241.15989.105" />
</set>
</attachedChunks>
</component>
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
<component name="TaskManager">
<task active="true" id="Default" summary="Default task">
@@ -155,6 +160,12 @@
<workItem from="1713814327036" duration="4920000" />
<workItem from="1713863377053" duration="634000" />
<workItem from="1713960463274" duration="353000" />
<workItem from="1715686350378" duration="91000" />
<workItem from="1715687332786" duration="822000" />
<workItem from="1715724270673" duration="5481000" />
<workItem from="1715765990621" duration="8538000" />
<workItem from="1715777647522" duration="725000" />
<workItem from="1715779408605" duration="3840000" />
</task>
<task id="LOCAL-00001" summary="Changes">
<created>1713528225837</created>
@@ -208,7 +219,47 @@
<option name="project" value="LOCAL" />
<updated>1713858768333</updated>
</task>
<option name="localTasksCounter" value="8" />
<task id="LOCAL-00008" summary="onderzoek-voorbeeld.md">
<option name="closed" value="true" />
<created>1715729252488</created>
<option name="number" value="00008" />
<option name="presentableId" value="LOCAL-00008" />
<option name="project" value="LOCAL" />
<updated>1715729252488</updated>
</task>
<task id="LOCAL-00009" summary="Updated onderzoek-voorbeeld.md">
<option name="closed" value="true" />
<created>1715762530473</created>
<option name="number" value="00009" />
<option name="presentableId" value="LOCAL-00009" />
<option name="project" value="LOCAL" />
<updated>1715762530473</updated>
</task>
<task id="LOCAL-00010" summary="Renamed files, added motion-tracking-system-analysis.md">
<option name="closed" value="true" />
<created>1715767477412</created>
<option name="number" value="00010" />
<option name="presentableId" value="LOCAL-00010" />
<option name="project" value="LOCAL" />
<updated>1715767477412</updated>
</task>
<task id="LOCAL-00011" summary="Updated onderzoek-voorbeeld.md and motion-tracking-system-analysis.md">
<option name="closed" value="true" />
<created>1715773120402</created>
<option name="number" value="00011" />
<option name="presentableId" value="LOCAL-00011" />
<option name="project" value="LOCAL" />
<updated>1715773120402</updated>
</task>
<task id="LOCAL-00012" summary="Updated onderzoek-voorbeeld.md &amp; motion-tracking-system-analysis.md">
<option name="closed" value="true" />
<created>1715780873394</created>
<option name="number" value="00012" />
<option name="presentableId" value="LOCAL-00012" />
<option name="project" value="LOCAL" />
<updated>1715780873394</updated>
</task>
<option name="localTasksCounter" value="13" />
<servers />
</component>
<component name="TypeScriptGeneratedFilesManager">
@@ -234,6 +285,11 @@
<MESSAGE value="Added 'onderzoek.md' &amp; 'onderzoek-formulier.md'" />
<MESSAGE value="Updated 'onderzoek-formulier.md'" />
<MESSAGE value="Final update onderzoek-formulier.md" />
<option name="LAST_COMMIT_MESSAGE" value="Final update onderzoek-formulier.md" />
<MESSAGE value="onderzoek-voorbeeld.md" />
<MESSAGE value="Updated onderzoek-voorbeeld.md" />
<MESSAGE value="Renamed files, added motion-tracking-system-analysis.md" />
<MESSAGE value="Updated onderzoek-voorbeeld.md and motion-tracking-system-analysis.md" />
<MESSAGE value="Updated onderzoek-voorbeeld.md &amp; motion-tracking-system-analysis.md" />
<option name="LAST_COMMIT_MESSAGE" value="Updated onderzoek-voorbeeld.md &amp; motion-tracking-system-analysis.md" />
</component>
</project>

3
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,3 @@
{
"java.configuration.updateBuildConfiguration": "interactive"
}

View File

@@ -0,0 +1,23 @@
#include "Connectivity.h"
void Connectivity::connectWiFi(char* ssid, char* pass){
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, pass);
while (WiFi.status() != WL_CONNECTED) {
Serial.println("connecting to wifi");
delay(1000);
}
Serial.println(WiFi.localIP());
}
void Connectivity::websocketSetup(char* ip, uint16_t port, char* adress){
//ws server address, port and URL
webSocket.begin(ip , port, adress);
// try every 500 again if connection has failed
webSocket.setReconnectInterval(500);
}
void Connectivity::sendData(float roll, float pitch, float yaw){
String message = "{\"Sensor\": 1, \"roll\":\"" + String(roll) + "\",\"pitch\":\"" + String(pitch) + "\",\"yaw\":\"" + String(yaw) + "\"}";
webSocket.sendTXT(message);
}

View File

@@ -0,0 +1,30 @@
#ifndef Connectivity_h
#define Connectivity_h
#include "Arduino.h"
#include <WebSocketsClient.h>
#include <ArduinoWiFiServer.h>
#include <ESP8266WiFi.h>
#include <ESP8266WiFiGeneric.h>
#include <ESP8266WiFiGratuitous.h>
#include <ESP8266WiFiMulti.h>
#include <ESP8266WiFiSTA.h>
#include <ESP8266WiFiScan.h>
#include <ESP8266WiFiType.h>
#include <WiFiClient.h>
#include <WiFiServer.h>
#include <WiFiServerSecure.h>
#include <WiFiUdp.h>
class Connectivity {
public:
void connectWiFi(char* ssid, char* pass);
void websocketSetup(char* ip, uint16_t port, char* adress);
void sendData(float roll, float pitch, float yaw);
private:
ESP8266WiFiMulti wifi;
WebSocketsClient webSocket;
};
#endif

View File

@@ -0,0 +1,62 @@
#include "headerFile.h"
SensorManager::Rotation offset;
void setup() {
Serial.begin(9600);
Serial.println("startup");
connectivity.connectWiFi(ssid, pass);
sensorManager.sensorSetup();
//ws server address, port and URL
webSocket.begin("145.3.245.22", 8001, "");
// try every 500 again if connection has failed
webSocket.setReconnectInterval(500);
}
void loop() {
SensorManager::Rotation rotation = sensorManager.readLoop();
// Subtract offset
rotation.i -= offset.i;
rotation.j -= offset.j;
rotation.k -= offset.k;
rotation.w -= offset.w;
// Convert quaternion to Euler angles in radians
float roll = atan2(2.0f * (rotation.w * rotation.i + rotation.j * rotation.k), 1.0f - 2.0f * (rotation.i * rotation.i + rotation.j * rotation.j));
float pitch = asin(2.0f * (rotation.w * rotation.j - rotation.k * rotation.i));
float yaw = atan2(2.0f * (rotation.w * rotation.k + rotation.i * rotation.j), 1.0f - 2.0f * (rotation.j * rotation.j + rotation.k * rotation.k));
// Convert to degrees
float rollDegrees = roll * 180.0f / PI;
float pitchDegrees = pitch * 180.0f / PI;
float yawDegrees = yaw * 180.0f / PI;
Serial.print(roll);
Serial.print(" ");
Serial.print(pitch);
Serial.print(" ");
Serial.print(yaw);
sendData(roll, pitch, yaw);
Serial.println();
webSocket.loop();
if (Serial.available()) {
String command = Serial.readStringUntil('\n');
command.trim(); // remove any trailing whitespace
if (command == "setZeroPoint") {
setZeroPoint();
}
}
}
void setZeroPoint() {
offset = sensorManager.readLoop();
}
void sendData(float roll, float pitch, float yaw){
String message = "{\"Sensor\": 1, \"roll\":\"" + String(roll) + "\",\"pitch\":\"" + String(pitch) + "\",\"yaw\":\"" + String(yaw) + "\"}";
webSocket.sendTXT(message);
}

View File

@@ -0,0 +1,51 @@
#include "SensorManager.h"
#include <Wire.h>
SensorManager::SensorManager() {}
void SensorManager::sensorSetup() {
Wire.setClockStretchLimit(150000L); // Default stretch limit 150mS
Wire.begin();
//wait for the sensor to start before continue
if (myIMU.begin() == false) {
delay(1000);
Serial.println(".");
}
//start sensorfunction and start autocalibration
//once calibration is enabled it attempts to every 5 min
Wire.setClock(400000); //Increase I2C data rate to 400kHz
myIMU.calibrateAll(); //Turn on cal for Accel, Gyro, and Mag
myIMU.enableGyroIntegratedRotationVector(100); //send data every 100ms
myIMU.enableMagnetometer(100); //Send data update every 100ms
myIMU.saveCalibration(); //Saves the current dynamic calibration data (DCD) to memory
myIMU.requestCalibrationStatus(); //Sends command to get the latest calibration status
if (myIMU.calibrationComplete() == true) {
Serial.println("Calibration data successfully stored");
}
Serial.println(F("magnetometer rotation enabled"));
}
SensorManager::Rotation SensorManager::readLoop() {
if (myIMU.dataAvailable() == true) {
float i = myIMU.getQuatI();
float j = myIMU.getQuatJ();
float k = myIMU.getQuatK();
float w = myIMU.getQuatReal();
Rotation rotation = { i, j, k, w };
return rotation;
}
else {
float i = myIMU.getQuatI();
float j = myIMU.getQuatJ();
float k = myIMU.getQuatK();
float w = myIMU.getQuatReal();
Rotation rotation = { i, j, k, w };
return rotation;
}
}

View File

@@ -0,0 +1,22 @@
#ifndef SensorManager_h
#define SensorManager_h
#include "Arduino.h"
#include "SparkFun_BNO080_Arduino_Library.h"
class SensorManager {
public:
SensorManager();
void sensorSetup();
struct Rotation {
float i;
float j;
float k;
float w;
};
Rotation readLoop();
private:
BNO080 myIMU;
};
#endif

View File

@@ -0,0 +1,13 @@
//classes
#include "SensorManager.h"
#include "Connectivity.h"
//define
SensorManager sensorManager;
Connectivity connectivity;
WebSocketsClient webSocket;
#define USE_SERIAL Serial
#define ssid "1235678i"
#define pass "12345678"

View File

@@ -0,0 +1,28 @@
# testscript for websocket server
# stolen from Sam's last project
import websockets
import asyncio
connected = set()
async def handler(websocket):
# Register.
connected.add(websocket)
try:
while True:
message = await websocket.recv()
print(message)
except websockets.ConnectionClosedOK:
print("Client disconnected")
finally:
connected.remove(websocket)
async def main():
async with websockets.serve(handler, "0.0.0.0", 8001):
await asyncio.Future() # run forever
if __name__ == "__main__":
asyncio.run(main())
#https://websockets.readthedocs.io/en/stable/reference/sync/server.html#websockets.sync.server.serve

View File

@@ -13,3 +13,5 @@
.externalNativeBuild
.cxx
local.properties
.idea
.vscode

View File

@@ -7,9 +7,22 @@
<entry key="..\:/Users/31687/muupooviixee66-1/code/src/Fitbot/app/src/main/res/layout/activity_bicepvideo.xml" value="0.2015625" />
<entry key="..\:/Users/31687/muupooviixee66-1/code/src/Fitbot/app/src/main/res/layout/activity_main.xml" value="0.2015625" />
<entry key="..\:/Users/31687/muupooviixee66-1/code/src/Fitbot/app/src/main/res/layout/activity_main_screen.xml" value="0.358695652173913" />
<entry key="..\:/Users/sebas/Documents/HvA/Reposetories/muupooviixee66/code/src/Fitbot/app/src/main/res/drawable-v24/ic_launcher_foreground.xml" value="0.25" />
<entry key="..\:/Users/sebas/Documents/HvA/Reposetories/muupooviixee66/code/src/Fitbot/app/src/main/res/drawable/darkred_button_gradient.xml" value="0.346" />
<entry key="..\:/Users/sebas/Documents/HvA/Reposetories/muupooviixee66/code/src/Fitbot/app/src/main/res/drawable/ic_baseline_home_48.xml" value="0.25" />
<entry key="..\:/Users/sebas/Documents/HvA/Reposetories/muupooviixee66/code/src/Fitbot/app/src/main/res/drawable/ic_baseline_settings_48.xml" value="0.25" />
<entry key="..\:/Users/sebas/Documents/HvA/Reposetories/muupooviixee66/code/src/Fitbot/app/src/main/res/drawable/ic_baseline_star_rate_48.xml" value="0.25" />
<entry key="..\:/Users/sebas/Documents/HvA/Reposetories/muupooviixee66/code/src/Fitbot/app/src/main/res/drawable/ic_launcher_background.xml" value="0.25" />
<entry key="..\:/Users/sebas/Documents/HvA/Reposetories/muupooviixee66/code/src/Fitbot/app/src/main/res/drawable/red_button_gradient.xml" value="0.346" />
<entry key="..\:/Users/sebas/Documents/HvA/Reposetories/muupooviixee66/code/src/Fitbot/app/src/main/res/layout/activity_bicepvideo.xml" value="0.22826086956521738" />
<entry key="..\:/Users/sebas/Documents/HvA/Reposetories/muupooviixee66/code/src/Fitbot/app/src/main/res/layout/activity_main.xml" value="0.1" />
<entry key="..\:/Users/sebas/Documents/HvA/Reposetories/muupooviixee66/code/src/Fitbot/app/src/main/res/layout/activity_main.xml" value="0.176" />
<entry key="..\:/Users/sebas/Documents/HvA/Reposetories/muupooviixee66/code/src/Fitbot/app/src/main/res/layout/activity_main_screen.xml" value="0.1" />
<entry key="..\:/Users/sebas/Documents/HvA/Reposetories/muupooviixee66/code/src/Fitbot/app/src/main/res/layout/activity_power_screen.xml" value="0.1" />
<entry key="..\:/Users/sebas/Documents/HvA/Reposetories/muupooviixee66/code/src/Fitbot/app/src/main/res/layout/activity_sport_item.xml" value="0.1" />
<entry key="..\:/Users/sebas/Documents/HvA/Reposetories/muupooviixee66/code/src/Fitbot/app/src/main/res/layout/activity_sport_menu.xml" value="0.1" />
<entry key="..\:/Users/sebas/Documents/HvA/Reposetories/muupooviixee66/code/src/Fitbot/app/src/main/res/layout/header.xml" value="0.125" />
<entry key="..\:/Users/sebas/Documents/HvA/Reposetories/muupooviixee66/code/src/Fitbot/app/src/main/res/layout/toolbar.xml" value="0.125" />
<entry key="app/src/main/res/layout/activity_fitness.xml" value="0.23550724637681159" />
<entry key="app/src/main/res/layout/activity_main.xml" value="0.1" />
<entry key="app/src/main/res/layout/activity_sport_item.xml" value="0.2341485507246377" />
<entry key="app/src/main/res/layout/activity_sport_menu.xml" value="0.22056159420289856" />

View File

@@ -34,7 +34,12 @@ dependencies {
implementation 'com.android.support.constraint:constraint-layout:2.0.4'
implementation 'com.android.support:cardview-v7:28.0.0'
implementation 'com.android.support:design:28.0.0'
implementation 'org.joml:joml:1.10.5'
implementation 'com.google.code.gson:gson:2.8.6'
testImplementation 'junit:junit:4.13.2'
testImplementation 'org.junit.jupiter:junit-jupiter'
testImplementation 'org.junit.jupiter:junit-jupiter'
testImplementation 'org.junit.jupiter:junit-jupiter'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
implementation 'com.aldebaran:qisdk:1.7.5'

View File

@@ -4,6 +4,10 @@
<uses-feature android:name="com.softbank.hardware.pepper" />
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
@@ -12,23 +16,10 @@
android:supportsRtl="true"
android:theme="@style/Theme.Fitbot" >
<activity
android:name=".Completion_Screen"
android:exported="false" />
<activity
android:name=".ui.SportMenuActivity"
android:exported="true">
</activity>
<activity
android:name=".BicepVideo"
android:exported="false" />
<activity
android:name=".PowerScreen"
android:exported="false" />
<activity
android:name=".MainActivity"
android:name=".ui.activities.FitnessActivity"
android:exported="true" />
<activity
android:name=".MainScreen"
android:name=".ui.activities.MainActivity"
android:exported="true" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />

View File

@@ -1,6 +1,7 @@
package com.example.fitbot;
import android.support.v7.app.AppCompatActivity;
import com.aldebaran.qi.sdk.QiContext;
import com.aldebaran.qi.sdk.builder.AnimateBuilder;
import com.aldebaran.qi.sdk.builder.AnimationBuilder;

View File

@@ -1,59 +0,0 @@
package com.example.fitbot;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.Button;
import android.widget.MediaController;
import android.widget.VideoView;
import com.aldebaran.qi.sdk.QiContext;
import com.aldebaran.qi.sdk.builder.AnimateBuilder;
import com.aldebaran.qi.sdk.builder.AnimationBuilder;
import com.aldebaran.qi.sdk.object.actuation.Animate;
import com.aldebaran.qi.sdk.object.actuation.Animation;
public class BicepVideo extends AppCompatActivity {
// private QiContext qiContext;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_bicepvideo);
setupButtons();
}
public void Video(QiContext qiContext) {
VideoView videoView = findViewById(R.id.videoView);
videoView.setVideoURI(Uri.parse("android.resource://" + getPackageName() + "/" + R.raw.bicepvideo));
MediaController mediaController = new MediaController(this);
videoView.setMediaController(mediaController);
videoView.setOnCompletionListener(mp -> videoView.start());
videoView.start();
Animation animation = AnimationBuilder.with(qiContext)
.withResources(R.raw.bicepcurl)
.build();
Animate animate = AnimateBuilder.with(qiContext)
.withAnimation(animation)
.build();
animate.async().run();
}
private void setupButtons() {
Button backButton = findViewById(R.id.buttonback);
backButton.setOnClickListener(v -> finish());
Button completeButton = findViewById(R.id.buttoncomplete);
completeButton.setOnClickListener(v -> {
Intent intent = new Intent(BicepVideo.this, Completion_Screen.class);
startActivity(intent);
});
}
}

View File

@@ -1,13 +0,0 @@
package com.example.fitbot;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
public class Completion_Screen extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_completion_screen);
}
}

View File

@@ -1,80 +0,0 @@
package com.example.fitbot;
import android.os.Bundle;
import com.aldebaran.qi.sdk.QiContext;
import com.aldebaran.qi.sdk.QiSDK;
import com.aldebaran.qi.sdk.RobotLifecycleCallbacks;
import com.aldebaran.qi.sdk.builder.SayBuilder;
import com.aldebaran.qi.sdk.design.activity.RobotActivity;
import com.aldebaran.qi.sdk.object.conversation.Phrase;
import com.aldebaran.qi.sdk.object.conversation.Say;
import com.aldebaran.qi.sdk.object.locale.Language;
import com.aldebaran.qi.sdk.object.locale.Locale;
import com.aldebaran.qi.sdk.object.locale.Region;
public class MainActivity extends RobotActivity implements RobotLifecycleCallbacks {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Register the RobotLifecycleCallbacks to this Activity.
QiSDK.register(this, this);
}
@Override
protected void onDestroy() {
// Unregister the RobotLifecycleCallbacks for this Activity.
QiSDK.unregister(this, this);
super.onDestroy();
}
@Override
public void onRobotFocusGained(QiContext qiContext) {
Locale locale = new Locale(Language.DUTCH, Region.NETHERLANDS);
// Create a new say action.
Say say = SayBuilder.with(qiContext) // Create the builder with the context.
.withText("Hallo hoe gaat het?") // Set the text to say.
.build(); // Build the say action.
String locationName = ("de hogeschool van amsterdam");
String locationDescription = ("0 bitches");
Phrase namePhrase = new Phrase("Deze locatie is " + locationName);
Say sayName = SayBuilder.with(qiContext)
.withPhrase(namePhrase)
.withLocale(locale)
.build();
Phrase descriptionPhrase = new Phrase(locationDescription);
Say sayDescription = SayBuilder.with(qiContext)
.withPhrase(descriptionPhrase)
.withLocale(locale)
.build();
sayName.run();
sayDescription.run();
// Create a new BicepVideo with the qiContext
// BicepVideo BicepVideo = new BicepVideo();
//
// // Call the videoPlayer method
// BicepVideo.Video(qiContext);
// Execute the action.
say.run();
}
@Override
public void onRobotFocusLost() {
// Nothing here.
}
@Override
public void onRobotFocusRefused(String reason) {
// The robot focus is refused.
}
}

View File

@@ -1,43 +0,0 @@
package com.example.fitbot;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.ImageButton;
public class PowerScreen extends AppCompatActivity {
ImageButton openBicepVideo;
ImageButton openSquatVideo;
ImageButton openTricepVideo;
ImageButton goToHome;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_power_screen);
openBicepVideo = findViewById(R.id.open_BicepVideo);
openSquatVideo = findViewById(R.id.open_SquatVideo);
openTricepVideo = findViewById(R.id.open_TricepVideo);
goToHome = findViewById(R.id.GoToHome);
openBicepVideo.setOnClickListener(v -> {
Intent intent = new Intent(PowerScreen.this, BicepVideo.class);
startActivity(intent);
});
// openSquatVideo.setOnClickListener(v -> {
// Intent intent = new Intent(PowerScreen.this, SquatVideo.class);
// startActivity(intent);
// });
//
// openTricepVideo.setOnClickListener(v -> {
// Intent intent = new Intent(PowerScreen.this, TricepVideo.class);
// startActivity(intent);
// });
goToHome.setOnClickListener(v -> {
Intent intent = new Intent(PowerScreen.this, MainActivity.class);
startActivity(intent);
});
}
}

View File

@@ -0,0 +1,104 @@
package com.example.fitbot.exercise;
import android.util.Log;
import com.example.fitbot.util.path.GesturePath;
import com.example.fitbot.util.server.IWebSocketHandler;
import com.example.fitbot.util.server.WebSocket;
import java.util.Objects;
public abstract class AbstractExercise implements IWebSocketHandler {
private EMuscleGroup muscleGroup;
private GesturePath path;
// Static fields.
private static WebSocket webSocket;
private static AbstractExercise currentExercise = null;
/**
* Constructor for the AbstractExercise class.
*
* @param muscleGroup The muscle group of the exercise.
* @param path The path of the exercise.
*/
public AbstractExercise(EMuscleGroup muscleGroup, GesturePath path) {
this.muscleGroup = muscleGroup;
this.path = path;
}
/**
* Start the exercise.
* This method starts a WebSocket server
*/
public final void startExercise() {
// Ensure no other exercise is active.
if (currentExercise != null && currentExercise != this) {
currentExercise.__stopExercise();
Log.i("Exercises", "Another exercise was started when another was still running.");
}
// If a WebSocket server is already running, change the event handler to be this class.
if (webSocket != null && webSocket.isConnected()) {
webSocket.setEventHandler(this);
}
try {
webSocket = WebSocket.createServer();
Objects.requireNonNull(webSocket, "WebSocket server could not be created.");
webSocket.startListening();
webSocket.setEventHandler(this);
currentExercise = this;
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Method for ending this exercise and returning the grade of the performance
* of this activity.
*/
public final double finishExercise() {
this.__stopExercise();
// TODO: Implement grade calculation
return 0.0;
}
/**
* Stop the exercise.
* This method stops the WebSocket server.
*/
private void __stopExercise() {
if (webSocket != null && webSocket.isConnected()) {
webSocket.stop();
webSocket = null;
}
currentExercise = null;
}
/**
* Check if the current exercise is the current activity.
*/
public final boolean isCurrentActivity() {
return currentExercise == this;
}
/**
* Get the muscle group of the exercise.
*/
public EMuscleGroup getMuscleGroup() {
return muscleGroup;
}
/**
* Get the path of the exercise.
*/
public GesturePath getPath() {
return path;
}
}

View File

@@ -0,0 +1,30 @@
package com.example.fitbot.exercise;
public enum EMuscleGroup {
// TODO: Implement
TORSO(0),
ARMS(1),
LEGS(2),
BALANCE(3);
int muscleGroupIdentifier;
EMuscleGroup(int identifier) {
this.muscleGroupIdentifier = identifier;
}
public int getIdentifier() {
return this.muscleGroupIdentifier;
}
public static EMuscleGroup parse(int identifier) {
for (EMuscleGroup muscleGroup : EMuscleGroup.values()) {
if (muscleGroup.getIdentifier() == identifier) {
return muscleGroup;
}
}
return null;
}
}

View File

@@ -0,0 +1,53 @@
package com.example.fitbot.exercise;
/**
* The ExerciseUser class represents a user of the exercise application.
* This contains all necessary information of the current user.
*/
public class ExerciseUser {
public float upperArmLength;
public float lowerArmLength;
public float upperLegLength;
public float lowerLegLength;
public float height;
/**
* Constructor for the ExerciseUser class.
* @param upperArmLength The length of the upper arm.
* @param lowerArmLength The length of the lower arm.
* @param height The height of the user.
* @param upperLegLength The length of the upper leg.
* @param lowerLegLength The length of the lower leg.
*/
public ExerciseUser(float upperArmLength, float lowerArmLength, float height, float upperLegLength, float lowerLegLength) {
this.upperArmLength = upperArmLength;
this.lowerArmLength = lowerArmLength;
this.upperLegLength = upperLegLength;
this.lowerLegLength = lowerLegLength;
this.height = height;
}
/**
* Constructor for the ExerciseUser class.
* @param height The height of the user.
*/
public ExerciseUser(float height) {
this.height = height;
this.upperArmLength = height * 0.2f;
this.lowerArmLength = height * 0.2f;
this.upperLegLength = height * 0.3f;
this.lowerLegLength = height * 0.3f;
}
/**
* Default constructor for the ExerciseUser class.
* This sets the default height to 180.0f. (1.80m)
*/
public ExerciseUser() {
this(180.0f);
}
}

View File

@@ -0,0 +1,113 @@
package com.example.fitbot.exercise;
import com.example.fitbot.util.path.GesturePath;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import org.joml.Vector3f;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Constructor;
import java.net.URL;
import java.net.URLConnection;
public class FitnessManager {
private static final String HOST_ADDRESS = "http://145.92.8.132";
private static final String PROPERTY_DESC = "description";
private static final String PROPERTY_VECTORS = "vector_data";
private static final String PROPERTY_NAME = "name";
private static final String PROPERTY_MUSCLE_GROUP = "muscle_group";
private static String sendHTTP(String url, String method, String contentType, String body) {
try {
URLConnection connection = new URL(url).openConnection();
connection.addRequestProperty("Content-Type", contentType);
connection.addRequestProperty("Request-Method", method);
connection.getOutputStream().write(body.getBytes());
connection.connect();
InputStream stream = connection.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
StringBuilder builder = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
builder.append(line);
}
return builder.toString();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
/**
* Function for retrieving an exercise from the Raspberry Pi Database.
*
* @param uniqueIdentifier The unique identifier of the exercise
* @return The exercise, if it exists on the server. Otherwise null.
*/
public static <T extends AbstractExercise> AbstractExercise acquireExercise(String uniqueIdentifier, Class<T> referenceClass) {
String response = sendHTTP(
HOST_ADDRESS + "/acquire", "GET", "application/json", "{\"kind\":\"" + uniqueIdentifier + "\"}"
);
// Validate the response
if (response != null) {
try {
JsonObject content = JsonParser.parseString(response).getAsJsonObject();
Constructor<T> constructor = referenceClass.getConstructor(referenceClass);
T instance = null;
try {
instance = constructor.newInstance(
EMuscleGroup.parse(content.get(PROPERTY_MUSCLE_GROUP).getAsInt()),
gesturePathFromString(content.get(PROPERTY_VECTORS).getAsString())
);
} catch (Exception e) {
e.printStackTrace();
}
return instance;
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
}
/**
* Function for converting a string to a GesturePath object.
* The input string bytes will be directly converted into 3d vectors.
* Every coordinate is composed of 32 bits, so four characters per coordinate.
*
* @param input The string to convert
* @return The GesturePath object
*/
private static GesturePath gesturePathFromString(String input) {
byte[] bytes = input.getBytes();
// Check if the input string contains a valid amount of bytes (12 bytes per vector)
if (input.length() % 12 != 0) {
throw new IllegalArgumentException("Invalid input string length");
}
GesturePath.Builder builder = new GesturePath.Builder();
float[] xyz = new float[3];
for (int i = 0; i < bytes.length; i += 12) {
for (int j = 0; j < 3; j++) {
xyz[j] = Float.intBitsToFloat(
(bytes[i + j * 4] & 0xFF) << 24 |
(bytes[i + j * 4 + 1] & 0xFF) << 16 |
(bytes[i + j * 4 + 2] & 0xFF) << 8 |
(bytes[i + j * 4 + 3] & 0xFF)
);
}
builder.addVector(new Vector3f(
xyz[0], xyz[1], xyz[2]
));
}
return builder.build();
}
}

View File

@@ -1,18 +0,0 @@
package com.example.fitbot.sports;
public enum ESportType {
FITNESS("Fitness"),
POWER("Krachttrening");
private final String name;
ESportType(String name) {
this.name = name;
}
public String getName() {
return name;
}
}

View File

@@ -0,0 +1,4 @@
package com.example.fitbot.ui.activities;
public class CompletionActivity {
}

View File

@@ -0,0 +1,29 @@
package com.example.fitbot.ui.activities;
import android.os.Bundle;
import com.aldebaran.qi.sdk.QiContext;
import com.aldebaran.qi.sdk.RobotLifecycleCallbacks;
import com.aldebaran.qi.sdk.design.activity.RobotActivity;
public class FitnessActivity extends RobotActivity implements RobotLifecycleCallbacks {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public void onRobotFocusGained(QiContext qiContext) {
// Implement your logic when the robot focus is gained
}
@Override
public void onRobotFocusLost() {
// Implement your logic when the robot focus is lost
}
@Override
public void onRobotFocusRefused(String reason) {
// Implement your logic when the robot focus is refused
}
}

View File

@@ -1,6 +1,7 @@
package com.example.fitbot;
package com.example.fitbot.ui.activities;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.os.Bundle;
import android.support.design.widget.NavigationView;
import android.support.v4.view.GravityCompat;
@@ -9,55 +10,36 @@ import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.widget.Button;
import com.example.fitbot.util.processing.GesturePath;
import com.example.fitbot.util.processing.MotionData;
import com.example.fitbot.util.processing.MotionProcessor;
import com.example.fitbot.util.processing.Vector3;
import com.example.fitbot.R;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
public class MainScreen extends AppCompatActivity {
public class MainActivity extends AppCompatActivity {
//Variables
DrawerLayout drawerLayout;
NavigationView navigationView;
Toolbar toolbar;
Button startButton;
@SuppressLint("WrongViewCast")
@Override
protected void onCreate (Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setContentView(R.layout.activity_main );
/*---Hooks---*/
drawerLayout = findViewById(R.id.drawer_layout);
navigationView = findViewById(R.id.nav_view);
toolbar = findViewById(R.id.toolbar);
startButton = findViewById(R.id.startButton);
MotionProcessor motionProcessor = new MotionProcessor();
GesturePath.Builder builder = new GesturePath.Builder();
motionProcessor.setMotionDataEventHandler((data -> {
Log.i("MotionProcessor", "Current position: " + data.toString());
}));
List<Vector3> relativePath = new ArrayList<>();
double y, dy;
Function<Double, Double> F = (x) -> 4.0 + 0.125D * x * x;
Function<Double, Double> d2F = (x) -> 0.25D;
for ( double x = -50; x < 10; x += 0.125D ) {
builder.addVector(new Vector3(0, F.apply(x), 0));
motionProcessor.addMotionData(new MotionData(new Vector3(0, d2F.apply(x), 0), Vector3.zero()));
}
motionProcessor.logStatistics(builder.build());
startButton.setOnClickListener(v -> {
// Switch to fitness activity
Log.i("MainActivity", "Switching to FitnessActivity");
Intent intent = new Intent(MainActivity.this, FitnessActivity.class);
startActivity(intent);
});
/*---Tool Bar---*/
// setSupportActionBar(toolbar);
@@ -66,7 +48,7 @@ public class MainScreen extends AppCompatActivity {
navigationView.bringToFront();
ActionBarDrawerToggle toggle=new
ActionBarDrawerToggle(this,drawerLayout,toolbar,R.string.navigation_drawer_open,R.string.navigation_drawer_close);
ActionBarDrawerToggle(this,drawerLayout,toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawerLayout.addDrawerListener(toggle);
toggle.syncState();
}

View File

@@ -0,0 +1,172 @@
package com.example.fitbot.ui.components;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.Log;
import android.view.View;
import com.example.fitbot.util.path.GesturePath;
import com.example.fitbot.util.path.PathSegment;
import com.example.fitbot.util.processing.MotionData;
import com.example.fitbot.util.processing.MotionProcessor;
import org.joml.Matrix4f;
import org.joml.Vector2f;
import org.joml.Vector3f;
import org.joml.Vector4f;
public class PersonalMotionPreviewElement extends View {
private GesturePath path;
private double pathTime = 0.0D; // The timestamp at which the path is currently at.
private MotionProcessor motionProcessor;
private Path referencePath, performingPath;
private Paint referencePaint, performingPaint;
private Paint backgroundColor = new Paint();
/**
* Constants for the preview path projection.
*/
private final float FOV = 70.0f; // The field of view of the preview path
private final float Z_NEAR = 0.1f; // The near clipping plane
private final float Z_FAR = 1000.0f; // The far clipping plane
private Vector3f cameraPosition = new Vector3f(0.0f, 0.0f, 0.0f); // The position of the camera
private Vector2f screenDimensions = new Vector2f(); // Width and height dimensions of the screen
private Vector2f rotation = new Vector2f(); // Rotation vector (yaw, pitch)
/**
* Constructor for the PersonalMotionPreviewElement class.
*
* @param context The context in which this element is created.
* @param path The gesture path that will be drawn on the canvas.
*/
public PersonalMotionPreviewElement(Context context, GesturePath path) {
super(context);
Log.i("PersonalMotionPreviewElement", "Creating new PersonalMotionPreviewElement.");
this.backgroundColor = new Paint();
this.backgroundColor.setColor(0xFF000000); // Black
this.path = path;
this.motionProcessor = new MotionProcessor();
this.motionProcessor.startListening();
this.motionProcessor.setMotionDataEventHandler((processed, preprocessed, sampleIndex, sampleRate) -> {
// TODO: Implement the calculation of the `performingPath` based on the motion data
});
this.referencePath = getDrawablePath(path.getSegments());
this.performingPath = new Path();
this.referencePaint = new Paint();
this.referencePaint.setColor(-1); // White
this.referencePaint.setStyle(Paint.Style.STROKE);
this.referencePaint.setStrokeWidth(5.0f);
this.performingPaint = new Paint();
this.performingPaint.setColor(0xFF0000FF); // Blue
this.performingPaint.setStyle(Paint.Style.STROKE);
this.performingPaint.setStrokeWidth(5.0f);
}
/**
* Method that calculates the path that will be drawn on the
* canvas. This method will be called every time new motion data is received.
*/
private void calculateDrawingPath(Vector3f transformedVector, MotionData motionData, int sampleIndex, double sampleRate) {
// Recalculate the personal path based on the new motion data
}
/**
* Method for setting the gesture path that will be drawn on the canvas.
*
* @param path The gesture path to draw.
*/
public void setGesturePath(GesturePath path) {
this.path = path;
this.referencePath = getDrawablePath(path.getSegments());
}
/**
* Method for setting the rotation of the preview path.
*
* @param yaw The yaw rotation of the preview path.
* @param pitch The pitch rotation of the preview path.
*/
public void setRotation(float yaw, float pitch) {
this.rotation.set(Math.toRadians(yaw), Math.toRadians(pitch));
}
/**
* Method for projecting a 3D point onto the screen.
* This method converts the 3D point to 2D space using a Model-View-Projection matrix transformation.
*
* @param point The point to cast to the screen.
* @param virtualWidth The width of the virtual screen.
* This is used to normalize the screen coordinates.
* @param virtualHeight The height of the virtual screen.
* @return The transformed vector in screen coordinates ranging from (0, 0) to (virtualWidth, virtualHeight).
*/
private Vector2f projectVertex(Vector3f point, int virtualWidth, int virtualHeight) {
Matrix4f modelViewMatrix = new Matrix4f()
.rotateX((float) Math.toRadians(rotation.x))
.rotateY((float) Math.toRadians(rotation.y))
.translate(cameraPosition);
Matrix4f projectionMatrix = new Matrix4f()
.perspective((float) Math.toRadians(FOV), (float) virtualWidth / virtualHeight, Z_NEAR, Z_FAR);
// Calculate Model-View-Projection matrix
Matrix4f MVP = new Matrix4f()
.set(projectionMatrix)
.mul(modelViewMatrix);
// Convert to screen coordinates
Vector4f screenCoordinates = new Vector4f(point, 1.0f)
.mul(MVP);
// Normalize screen coordinates from (-1, 1) to (0, virtualWidth) and (0, virtualHeight)
float normalizedX = (screenCoordinates.x / screenCoordinates.w + 1.0f) * 0.5f * virtualWidth;
float normalizedY = (1.0f - screenCoordinates.y / screenCoordinates.w) * 0.5f * virtualHeight;
return new Vector2f(normalizedX, normalizedY);
}
/**
* Method that converts a sequence of vectors to a Path object.
* This path is a set of bezier curves that will be drawn on the canvas.
*
* @param segments The path segments in the path.
* These segments will be connected by bezier curves, which
* all have unique curvature values.
* @return The generated path object.
*/
private Path getDrawablePath(PathSegment... segments) {
Path calculatedPath = new Path();
// Starting point
Vector2f origin = projectVertex(segments[0].getStart(), getWidth(), getHeight());
calculatedPath.moveTo(origin.x, origin.y);
// Draw the path segments
for (PathSegment segment : segments) {
Vector2f startProjected = projectVertex(segment.getStart(), getWidth()/2, getHeight());
Vector2f endProjected = projectVertex(segment.getEnd(), getWidth()/2, getHeight());
calculatedPath.lineTo(startProjected.x, startProjected.y);
calculatedPath.lineTo(endProjected.x, endProjected.y);
}
return calculatedPath;
}
@Override
public void onDraw(Canvas canvas) {
canvas.drawRect(0, 0, getWidth(), getHeight(), backgroundColor);
// Draw the sport preview canvas
canvas.drawPath(referencePath, referencePaint);
canvas.drawPath(performingPath, performingPaint);
}
}

View File

@@ -0,0 +1,121 @@
package com.example.fitbot.util.path;
import org.joml.Vector3f;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class GesturePath {
// The vectors that make up the path.
private final PathSegment[] segments;
public GesturePath(Vector3f[] vectors) {
this(vectors, 0.0D);
}
/**
* Create a new gesture path with a given set of vectors and curvature.
*
* @param vectors The vectors that make up the path.
* @param curvature The curvature of the path.
*/
public GesturePath(Vector3f[] vectors, double curvature)
{
if ( vectors.length < 2)
throw new IllegalArgumentException("A path must have at least two points.");
this.segments = new PathSegment[vectors.length - 1];
for ( int i = 0; i < vectors.length - 1; i++)
segments[i] = new PathSegment(vectors[i], vectors[i + 1]);
}
/**
* Constructor for a GesturePath with provided PathSegments.
* @param segments The PathSegments to initialize the path with.
*/
public GesturePath(PathSegment... segments) {
this.segments = segments;
}
/**
* Getter method for retrieving the path segments of this GesturePath.
*
* @return The path segments.
*/
public PathSegment[] getSegments() {
return segments;
}
/**
* Method for retrieving the closest path segment to a reference point.
*
* @param reference The reference point to find the closest path segment to.
* @return The closest path segment to the reference point.
*/
public PathSegment closest(Vector3f reference) {
// If there's only one segment, return that one.
if ( segments.length == 1)
return segments[0];
return Arrays
.stream(segments)
.reduce(segments[0], (a, b) -> PathSegment.closer(a, b, reference));
}
/**
* Get the error between an arbitrary path segment and the reference point.
*
* @param referencePoint The reference point to calculate the error of.
* @return The error offset between the path and the reference point.
*/
public double getError(Vector3f referencePoint) {
return closest(referencePoint).difference(referencePoint); // Get the closest segment and calculate the error.
}
// Builder class for the GesturePath object.
public static class Builder {
// List of vectors to add to the GesturePath object.
private final List<Vector3f> vectors;
/**
* Constructor for the Builder object.
*
* @param vectors The list of vectors to add.
*/
public Builder(List<Vector3f> vectors) {
this.vectors = vectors;
}
/**
* Default constructor for the Builder object.
*/
public Builder() {
this.vectors = new ArrayList<>();
}
/**
* Adds a vector to the GesturePath object.
*
* @param vector The vector to add.
* @return The Builder object.
*/
public Builder addVector(Vector3f vector) {
vectors.add(vector);
return this;
}
/**
* Builds the GesturePath object.
*
* @return The GesturePath object.
*/
public GesturePath build() {
return new GesturePath(vectors.toArray(new Vector3f[0]));
}
}
}

View File

@@ -0,0 +1,105 @@
package com.example.fitbot.util.path;
import org.joml.Vector3f;
public class PathSegment {
private final Vector3f start, end;
private final double distance;
/**
* Constructor for creating a PathSegment of two lines, with the normal vector
* pointing straight upwards relative to the line, with a curvature of 0.0.
*
* @param start The starting point of the line segment
* @param end The end point of the line segment.
*/
public PathSegment(Vector3f start, Vector3f end) {
this.start = start;
this.end = end;
this.distance = start.distance(end);
}
/**
* Method that interpolates between the start and end points of the path segment,
* depending on the curvature of the curve. If the curvature is unset, or set to 0
* then this method will use linear interpolation. Otherwise, it will use a curve.
*
* @param t The interpolation value between 0 and 1.
*/
public Vector3f interpolate(double t) {
return new Vector3f(this.start)
.lerp(this.end, (float) Math.min(1.0F, Math.max(0.0F, t)));
}
/**
* Method for calculating the difference between the provided vector and the
* path segment, depending on the normal vector and the curvature.
* If the provided vector does not lie on the path segment, this method will return
* the linear distance to the path.
*
* @param other The vector to calculate the difference to.
* @return The difference between the vector and the path segment.
*/
public double difference(Vector3f other) {
if (this.distance == 0)
return this.start.distance(other);
double t = ((other.x - this.start.x) * (this.end.x - this.start.x) +
(other.y - this.start.y) * (this.end.y - this.start.y) +
(other.z - this.start.z) * (this.end.z - this.start.z)) / distance;
t = Math.max(0, Math.min(1, t));
return other.distance(new Vector3f(
(float) (this.start.x + t * (this.end.x - this.start.x)),
(float) (this.start.y + t * (this.end.y - this.start.y)),
(float) (this.start.z + t * (this.end.z - this.start.z))
));
}
/**
* Get the normal vector of the path segment.
*
* @return The normal vector of the path segment.
*/
public Vector3f getStart() {
return start;
}
/**
* Get the end point of the path segment.
*
* @return The end point of the path segment.
*/
public Vector3f getEnd() {
return end;
}
/**
* Method for returning the distance to the closest point on the path segment.
*
* @param reference The reference point to calculate the distance to.
* @return The distance to the closest point on the path segment.
*/
public double distance(Vector3f reference) {
if ( this.start.distanceSquared(reference) > this.end.distanceSquared(reference))
return this.end.distance(reference);
return this.start.distance(reference);
}
/**
* Function for returning the closest path segment to a reference point.
*
* @param first The first path segment to compare.
* @param second The second path segment to compare.
* @param referencePoint The reference point to compare to.
* @return The closest path segment to the reference point.
*/
public static PathSegment closer(PathSegment first, PathSegment second, Vector3f referencePoint) {
if (first.distance(referencePoint) < second.distance(referencePoint))
return first;
return second;
}
}

View File

@@ -1,104 +0,0 @@
package com.example.fitbot.util.processing;
import java.util.ArrayList;
import java.util.List;
public class GesturePath {
// The vectors that make up the path.
private final Vector3[] vectors;
public GesturePath(Vector3[] vectors) {
this.vectors = vectors;
}
/**
* Get the error between an arbitrary path segment and the reference point.
*
* @param referencePoint The reference point to calculate the error of.
* @return The error offset between the path and the reference point.
*/
public double getError(Vector3 referencePoint) {
// If there are no vectors, return 0.
if ( vectors.length == 0)
return 0;
// If there's only one vector, return the distance to that vector.
if ( vectors.length == 1)
return vectors[0].distance(referencePoint);
double distance = Double.MAX_VALUE;
double currentDistSq, nextDistSq;
int closestVectorIdx = 0;
// Acquire two closest points to the reference point.
for ( int i = 0; i < vectors.length - 1; i++) {
currentDistSq = vectors[i].distanceSq(referencePoint);
nextDistSq = vectors[i + 1].distanceSq(referencePoint);
if ( currentDistSq < distance) {
distance = currentDistSq;
closestVectorIdx = i;
} else if ( nextDistSq < distance) {
distance = nextDistSq;
closestVectorIdx = i + 1;
i++; // Skip the next iteration; this point is already closer.
}
}
// Calculate the error between the two closest points.
Vector3 pointB = (closestVectorIdx == vectors.length - 1) ?
vectors[closestVectorIdx - 1] : // If the closest point is the last point, use the 1 to last one
(closestVectorIdx > 0 && // Find the closer point between the surrounding points.
(vectors[closestVectorIdx - 1].distanceSq(referencePoint) < vectors[closestVectorIdx + 1].distanceSq(referencePoint))) ?
vectors[closestVectorIdx - 1] :
vectors[closestVectorIdx + 1];
return referencePoint.distanceToLine(vectors[closestVectorIdx], pointB);
}
// Builder class for the GesturePath object.
public static class Builder {
// List of vectors to add to the GesturePath object.
private final List<Vector3> vectors;
/**
* Constructor for the Builder object.
*
* @param vectors The list of vectors to add.
*/
public Builder(List<Vector3> vectors) {
this.vectors = vectors;
}
/**
* Default constructor for the Builder object.
*/
public Builder() {
this.vectors = new ArrayList<>();
}
/**
* Adds a vector to the GesturePath object.
*
* @param vector The vector to add.
* @return The Builder object.
*/
public Builder addVector(Vector3 vector) {
vectors.add(vector);
return this;
}
/**
* Builds the GesturePath object.
*
* @return The GesturePath object.
*/
public GesturePath build() {
return new GesturePath(vectors.toArray(new Vector3[0]));
}
}
}

View File

@@ -0,0 +1,16 @@
package com.example.fitbot.util.processing;
import org.joml.Vector3f;
public interface IMotionDataConsumer {
/**
* Function for accepting motion data and the transformed vector.
* @param transformedVector The transformed vector.
* @param motionData The input motion data.
* @param sampleIndex The index of the current sample
* @param sampleRate The sample rate.
*/
void accept(Vector3f transformedVector, MotionData motionData, int sampleIndex, double sampleRate);
}

View File

@@ -1,11 +1,13 @@
package com.example.fitbot.util.processing;
import org.joml.Vector3f;
import java.util.Objects;
public class MotionData {
// Data of the motion sensor
public Vector3 acceleration, rotation;
public Vector3f acceleration, rotation;
// Delimiter for the data received from the motion sensor
private static final String DATA_DELIMITER = ";";
@@ -20,9 +22,9 @@ public class MotionData {
* @param rotationY The rotation in the Y axis in degrees.
* @param rotationZ The rotation in the Z axis in degrees.
*/
public MotionData(double accelerationX, double accelerationY, double accelerationZ, double rotationX, double rotationY, double rotationZ) {
this.acceleration = new Vector3(accelerationX, accelerationY, accelerationZ);
this.rotation = new Vector3(rotationX, rotationY, rotationZ);
public MotionData(float accelerationX, float accelerationY, float accelerationZ, float rotationX, float rotationY, float rotationZ) {
this.acceleration = new Vector3f(accelerationX, accelerationY, accelerationZ);
this.rotation = new Vector3f(rotationX, rotationY, rotationZ);
}
/**
@@ -31,7 +33,7 @@ public class MotionData {
* @param acceleration The acceleration vector in m/s^2.
* @param rotation The rotation vector in degrees.
*/
public MotionData(Vector3 acceleration, Vector3 rotation) {
public MotionData(Vector3f acceleration, Vector3f rotation) {
this.acceleration = acceleration;
this.rotation = rotation;
}
@@ -52,12 +54,12 @@ public class MotionData {
return null;
return new MotionData(
Double.parseDouble(parts[0]),
Double.parseDouble(parts[1]),
Double.parseDouble(parts[2]),
Double.parseDouble(parts[3]),
Double.parseDouble(parts[4]),
Double.parseDouble(parts[5])
Float.parseFloat(parts[0]),
Float.parseFloat(parts[1]),
Float.parseFloat(parts[2]),
Float.parseFloat(parts[3]),
Float.parseFloat(parts[4]),
Float.parseFloat(parts[5])
);
}
}

View File

@@ -2,14 +2,15 @@ package com.example.fitbot.util.processing;
import android.util.Log;
import com.example.fitbot.util.path.GesturePath;
import com.example.fitbot.util.server.IWebSocketHandler;
import com.example.fitbot.util.server.WebSocket;
import org.jetbrains.annotations.NotNull;
import org.joml.Vector3f;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import java.util.stream.Collectors;
public class MotionProcessor {
@@ -17,10 +18,11 @@ public class MotionProcessor {
public static final String DELIMITER = ";";
private final List<MotionData> preprocessedData = new ArrayList<>(); // Preprocessed motion data
private final List<Vector3> relativePath = new ArrayList<>(); // Relative path of the motion data
private Vector3 ZERO = new Vector3(0, 0, 0);
private double sampleRate = 1.0D; // samples/second
private Consumer<Vector3> motionDataConsumer = (data) -> {};
private final List<Vector3f> relativePath = new ArrayList<>(); // Relative path of the motion data
private Vector3f ZERO = new Vector3f(0, 0, 0);
private float sampleRate = 1.0F; // samples/second
private IMotionDataConsumer motionDataConsumer = (p1, p2, p3, p4) -> {};
private GesturePath path;
private WebSocket socket;
@@ -78,14 +80,14 @@ public class MotionProcessor {
// Otherwise check if it starts with 'calibrate', this is the ZERO point.
} else if ( data.startsWith("zero")) { // message to calibrate device
String[] vectorData = data.split(" ")[1].split(DELIMITER);
ZERO = new Vector3(
ZERO = new Vector3f(
Float.parseFloat(vectorData[0]),
Float.parseFloat(vectorData[1]),
Float.parseFloat(vectorData[2])
);
Log.i("MotionProcessor", "Device calibrated at " + ZERO.toString());
} else if ( data.startsWith("sampleRate")) {
this.sampleRate = Double.parseDouble(data.split(" ")[1]);
this.sampleRate = Float.parseFloat(data.split(" ")[1]);
}
}
@@ -105,10 +107,10 @@ public class MotionProcessor {
*/
public void addMotionData(MotionData data) {
preprocessedData.add(data);
Vector3 previous = this.relativePath.isEmpty() ? ZERO : this.relativePath.get(this.relativePath.size() - 1);
Vector3 relativeVector = getRelativeVector(data).add(previous);
Vector3f previous = this.relativePath.isEmpty() ? ZERO : this.relativePath.get(this.relativePath.size() - 1);
Vector3f relativeVector = getRelativeVector(data).add(previous);
this.relativePath.add(relativeVector);
motionDataConsumer.accept(relativeVector);
motionDataConsumer.accept(relativeVector, data, this.relativePath.size(), this.sampleRate);
}
/**
@@ -116,7 +118,7 @@ public class MotionProcessor {
*
* @param relativePath The new relative path.
*/
public void setRelativePath(List<Vector3> relativePath) {
public void setRelativePath(List<Vector3f> relativePath) {
this.relativePath.clear();
this.relativePath.addAll(relativePath);
}
@@ -125,7 +127,7 @@ public class MotionProcessor {
* Function for setting the motion data receiver.
* @param consumer The consumer to set.
*/
public void setMotionDataEventHandler(Consumer<Vector3> consumer) {
public void setMotionDataEventHandler(IMotionDataConsumer consumer) {
if ( consumer != null)
this.motionDataConsumer = consumer;
}
@@ -139,15 +141,17 @@ public class MotionProcessor {
* @param motionData The motion data to calculate the relative vector for.
* @return The relative vector of the motion data.
*/
public Vector3 getRelativeVector(MotionData motionData) {
public Vector3f getRelativeVector(MotionData motionData) {
// Rotate the acceleration vector back by the rotation vector to make it
// perpendicular to the gravity vector, then apply double integration to get the relative position.
// s = 1/2 * a * t^2
return motionData.acceleration
.rotate(motionData.rotation.negate())
.divide(2)
.multiply(sampleRate * sampleRate);
.rotateX(-motionData.rotation.x)
.rotateY(-motionData.rotation.y)
.rotateZ(-motionData.rotation.z)
.div(2)
.mul(sampleRate * sampleRate);
}
/**
@@ -186,7 +190,7 @@ public class MotionProcessor {
* @param referencePoint The reference point to compare the motion data to.
* @return The error of the motion data compared to the reference path.
*/
public double getError(GesturePath path, Vector3 referencePoint)
public double getError(GesturePath path, Vector3f referencePoint)
{
return path.getError(referencePoint);
}
@@ -198,7 +202,7 @@ public class MotionProcessor {
* @param referencePoint The reference point to compare the path data to.
* @return The error of the motion data compared to the reference path.
*/
public double getError(Vector3 referencePoint) {
public double getError(Vector3f referencePoint) {
if ( path == null)
return 0;
return path.getError(referencePoint);
@@ -241,6 +245,5 @@ public class MotionProcessor {
Log.i("MotionProcessor", "Path length: " + relativePath.size());
Log.i("MotionProcessor", "Sample rate: " + sampleRate);
Log.i("MotionProcessor", "Calibration point: " + ZERO.toString());
}
}

View File

@@ -1,258 +0,0 @@
package com.example.fitbot.util.processing;
import java.util.Arrays;
import java.util.Comparator;
public class Vector3 {
public double x, y, z;
/**
* Constructor for creating a new vector.
*
* @param x The X component of the vector.
* @param y The Y component of the vector.
* @param z The Z component of the vector.
*/
public Vector3(double x, double y, double z) {
this.x = x;
this.y = y;
this.z = z;
}
/**
* Copy the vector.
*
* @return A new vector with the same values.
*/
public Vector3 copy() {
return new Vector3(this.x, this.y, this.z);
}
/**
* Get the zero vector.
*
* @return The zero vector.
*/
public static Vector3 zero() {
return new Vector3(0, 0, 0);
}
/**
* Get the magnitude of the vector.
*
* @return The magnitude of the vector.
*/
public double magnitude() {
return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);
}
/**
* Normalize the vector.
*
* @return The normalized vector.
*/
public Vector3 normalize() {
double mag = this.magnitude();
if (mag == 0) throw new IllegalArgumentException("Cannot normalize the zero vector.");
return new Vector3(this.x / mag, this.y / mag, this.z / mag);
}
/**
* Subtract the vector from another vector.
*
* @param other The other vector to subtract.
* @return The new vector.
*/
public Vector3 subtract(Vector3 other) {
return new Vector3(this.x - other.x, this.y - other.y, this.z - other.z);
}
/**
* Add the vector to another vector.
*
* @param other The other vector to add.
* @return The new vector.
*/
public Vector3 add(Vector3 other) {
return new Vector3(this.x + other.x, this.y + other.y, this.z + other.z);
}
/**
* Multiply the vector by a scalar.
*
* @param scalar The scalar to multiply by.
* @return The multiplied vector.
*/
public Vector3 multiply(double scalar) {
return new Vector3(this.x * scalar, this.y * scalar, this.z * scalar);
}
/**
* Divide the vector by a scalar.
*
* @param scalar The scalar to divide by.
* @return The divided vector.
*/
public Vector3 divide(double scalar) {
if (scalar == 0) throw new IllegalArgumentException("Cannot divide by zero.");
return new Vector3(this.x / scalar, this.y / scalar, this.z / scalar);
}
/**
* Negate the vector.
*
* @return The negated vector.
*/
public Vector3 negate() {
return new Vector3(-this.x, -this.y, -this.z);
}
/**
* Rotate the vector around the X, Y, and Z axes.
*
* @param radX Rotation around the X axis in radians.
* @param radY Rotation around the Y axis in radians.
* @param radZ Rotation around the Z axis in radians.
* @return The rotated vector.
*/
public Vector3 rotate(double radX, double radY, double radZ) {
double cosX = Math.cos(radX);
double cosY = Math.cos(radY);
double cosZ = Math.cos(radZ);
double sinX = Math.sin(radX);
double sinY = Math.sin(radY);
double sinZ = Math.sin(radZ);
double newX = x * cosY * cosZ + y * cosY * sinZ - z * sinY;
double newY = x * (sinX * sinY * cosZ - cosX * sinZ) + y * (sinX * sinY * sinZ + cosX * cosZ) + z * sinX * cosY;
double newZ = x * (cosX * sinY * cosZ + sinX * sinZ) + y * (cosX * sinY * sinZ - sinX * cosZ) + z * cosX * cosY;
return new Vector3(newX, newY, newZ);
}
/**
* Rotate the vector around the X, Y, and Z axes.
*
* @param rotation The rotation vector.
* @return The rotated vector.
*/
public Vector3 rotate(Vector3 rotation) {
return rotate(rotation.x, rotation.y, rotation.z);
}
/**
* Rotate the vector around the X axis.
*
* @param angle Rotation around the X axis in radians.
* @return The rotated vector.
*/
public Vector3 rotateX(double angle) {
double sinTheta = Math.sin(angle);
double cosTheta = Math.cos(angle);
return new Vector3(
x,
y * cosTheta - z * sinTheta,
y * sinTheta + z * cosTheta
);
}
/**
* Rotate the vector around the Y axis.
*
* @param angle Rotation around the Y axis in radians.
* @return The rotated vector.
*/
public Vector3 rotateY(double angle) {
double sinTheta = Math.sin(angle);
double cosTheta = Math.cos(angle);
return new Vector3(
x * cosTheta + z * sinTheta,
y,
-x * sinTheta + z * cosTheta
);
}
/**
* Rotate the vector around the Z axis.
*
* @param angle Rotation around the Z axis in radians.
* @return The rotated vector.
*/
public Vector3 rotateZ(double angle) {
double sinTheta = Math.sin(angle);
double cosTheta = Math.cos(angle);
return new Vector3(
x * cosTheta - y * sinTheta,
x * sinTheta + y * cosTheta,
z
);
}
/**
* Get the squared distance between this vector and another vector.
*
* @param compare The other vector.
* @return The squared distance between the two vectors.
*/
public double distanceSq(Vector3 compare) {
return Math.pow(compare.x - x, 2) + Math.pow(compare.y - y, 2) + Math.pow(compare.z - z, 2);
}
/**
* Get the distance between this vector and another vector.
*
* @param compare The other vector.
* @return The distance between the two vectors.
*/
public double distance(Vector3 compare) {
return Math.sqrt(distanceSq(compare));
}
/**
* Calculate the distance to a line defined by two points.
*
* @param lineStart The starting point of the line.
* @param lineEnd The ending point of the line.
* @return The distance to the line.
*/
public double distanceToLine(Vector3 lineStart, Vector3 lineEnd) {
double lineDistance = lineStart.distanceSq(lineEnd);
if (lineDistance == 0)
return this.distanceSq(lineStart);
double t = ((this.x - lineStart.x) * (lineEnd.x - lineStart.x) +
(this.y - lineStart.y) * (lineEnd.y - lineStart.y) +
(this.z - lineStart.z) * (lineEnd.z - lineStart.z)) / lineDistance;
t = Math.max(0, Math.min(1, t));
return this.distanceSq(new Vector3(
lineStart.x + t * (lineEnd.x - lineStart.x),
lineStart.y + t * (lineEnd.y - lineStart.y),
lineStart.z + t * (lineEnd.z - lineStart.z))
);
}
/**
* Retrieve the closest vector to this one given a list of vectors.
*
* @param vectors The list of vectors to compare.
* @return The closest vector.
*/
public Vector3 closest(Vector3 ... vectors) {
return Arrays.stream(vectors).min(Comparator.comparingDouble(this::distanceSq)).orElse(null);
}
public Vector3 map(VectorMapFunction function) {
return function.apply(this);
}
public interface VectorMapFunction {
Vector3 apply(Vector3 vector);
}
@Override
public String toString()
{
return "Vector3(" + this.x + ", " + this.y + ", " + this.z + ")";
}
}

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<corners
android:radius="20dp"
/>
<gradient
android:startColor="#660000"
android:endColor="#990000"
android:angle="90"/>
</shape>

View File

@@ -5,8 +5,8 @@
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillColor="#3DDC84"
android:pathData="M0,0h108v108h-108z" />
android:fillColor="#FF0000"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<corners
android:radius="30dp"
/>
<gradient
android:startColor="#990000"
android:endColor="#FF0000"
android:angle="90"/>
</shape>

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

View File

@@ -1,58 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".BicepVideo">
<VideoView
android:id="@+id/videoView"
android:layout_width="1142dp"
android:layout_height="515dp"
android:layout_marginTop="64dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0" />
<Button
android:id="@+id/buttonback"
android:layout_width="88dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="10dp"
android:text="back"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/buttoncomplete"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="6dp"
android:text="complete"
app:layout_constraintBottom_toTopOf="@+id/videoView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.093" />
<TextView
android:id="@+id/textView"
android:layout_width="1074dp"
android:layout_height="197dp"
android:layout_marginStart="122dp"
android:layout_marginTop="7dp"
android:layout_marginEnd="122dp"
android:layout_marginBottom="16dp"
android:text="Uitleg text"
android:textSize="32sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/videoView" />
</android.support.constraint.ConstraintLayout>

View File

@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".Completion_Screen">
</android.support.constraint.ConstraintLayout>

View File

@@ -0,0 +1,25 @@
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#232323"
android:fitsSystemWindows="true"
tools:context=".ui.activities.FitnessActivity"
tools:openDrawer="start">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.example.fitbot.ui.components.PersonalMotionPreviewElement
android:id="@+id/personalMotionPreviewElement"
android:visibility="visible"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
</android.support.v4.widget.DrawerLayout>

View File

@@ -1,17 +1,87 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#232323"
android:fitsSystemWindows="true"
tools:context=".MainActivity"
tools:context=".ui.activities.MainActivity"
tools:openDrawer="start">
<include
android:id="@+id/toolbar"
layout="@layout/toolbar" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include
android:id="@+id/toolbar"
layout="@layout/toolbar" />
<TextView
android:id="@+id/textView2"
android:layout_width="524dp"
android:layout_height="77dp"
android:layout_marginStart="378dp"
android:layout_marginTop="80dp"
android:text="@string/welkom_bij_fitbot"
android:textColor="@color/white"
android:textSize="64sp" />
<TextView
android:id="@+id/textView3"
android:layout_width="510dp"
android:layout_height="39dp"
android:layout_marginStart="385dp"
android:layout_marginTop="0dp"
android:text="@string/robot_helpt"
android:textColor="@color/white"
android:textSize="32sp" />
<Button
android:id="@+id/startButton"
android:layout_width="300dp"
android:layout_height="150dp"
android:layout_marginStart="490dp"
android:layout_marginTop="100dp"
android:text="@string/start"
android:textColor="@color/white"
android:textSize="80sp"
android:textAllCaps="false"
android:background="@drawable/red_button_gradient"/>
<Button
android:id="@+id/helpButton"
android:layout_width="160dp"
android:layout_height="80dp"
android:layout_marginStart="560dp"
android:layout_marginTop="20dp"
android:text="@string/help"
android:textColor="@color/white"
android:textSize="40sp"
android:textAllCaps="false"
android:background="@drawable/darkred_button_gradient"/>
<ImageView
android:id="@+id/imageView2"
android:layout_width="375dp"
android:layout_height="375dp"
android:layout_marginStart="0dp"
android:layout_marginTop="-180dp"
app:srcCompat="@drawable/robot_logo_inverted"
android:contentDescription="@string/todo" />
<!-- <Button-->
<!-- android:id="@+id/menu_switch_btn"-->
<!-- android:layout_width="200dp"-->
<!-- android:layout_height="50dp"-->
<!-- android:clickable="true"-->
<!-- android:text="Go to Sport Menu"-->
<!-- app:layout_constraintBottom_toBottomOf="parent"-->
<!-- app:layout_constraintLeft_toLeftOf="parent"-->
<!-- android:focusable="true" />-->
</LinearLayout>
<android.support.design.widget.NavigationView
android:id="@+id/nav_view"
@@ -19,17 +89,6 @@
android:layout_height="match_parent"
android:layout_gravity="start"
app:headerLayout="@layout/header"
app:menu="@menu/main_menu" />
<Button
android:id="@+id/menu_switch_btn"
android:layout_width="200dp"
android:layout_height="50dp"
android:clickable="true"
android:text="Go to Sport Menu"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
android:focusable="true" />
</android.support.v4.widget.DrawerLayout>

View File

@@ -1,84 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".PowerScreen">
<!-- <Button-->
<!-- android:id="@+id/open_BicepVideo"-->
<!-- android:layout_width="215dp"-->
<!-- android:layout_height="64dp"-->
<!-- android:layout_marginStart="108dp"-->
<!-- android:layout_marginTop="341dp"-->
<!-- android:layout_marginEnd="108dp"-->
<!-- android:layout_marginBottom="342dp"-->
<!-- android:text="Bicep Oefening"-->
<!-- app:layout_constraintBottom_toBottomOf="parent"-->
<!-- app:layout_constraintEnd_toEndOf="parent"-->
<!-- app:layout_constraintStart_toStartOf="parent"-->
<!-- app:layout_constraintTop_toTopOf="parent"-->
<!-- app:layout_constraintVertical_bias="1.0" />-->
<ImageButton
android:id="@+id/open_BicepVideo"
android:layout_width="330dp"
android:layout_height="300dp"
android:layout_marginStart="120dp"
android:layout_marginTop="60dp"
android:layout_marginEnd="190dp"
android:layout_marginBottom="40dp"
app:layout_constraintBottom_toTopOf="@+id/open_SquatVideo"
app:layout_constraintEnd_toStartOf="@+id/open_TricepVideo"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/noun_bicep_499185"
android:contentDescription="Open bicep exercise video" />
<ImageButton
android:id="@+id/open_SquatVideo"
android:layout_width="330dp"
android:layout_height="300dp"
android:layout_marginStart="120dp"
android:layout_marginTop="40dp"
android:layout_marginEnd="190dp"
android:layout_marginBottom="60dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/GoToHome"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/open_BicepVideo"
app:srcCompat="@drawable/squatlogo"
android:contentDescription="Open squad exercise video" />
<ImageButton
android:id="@+id/open_TricepVideo"
android:layout_width="330dp"
android:layout_height="300dp"
android:layout_marginStart="190dp"
android:layout_marginTop="60dp"
android:layout_marginEnd="120dp"
android:layout_marginBottom="40dp"
app:layout_constraintBottom_toTopOf="@+id/GoToHome"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/open_BicepVideo"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/triceplogo"
android:contentDescription="Open tricep exercise video" />
<ImageButton
android:id="@+id/GoToHome"
android:layout_width="330dp"
android:layout_height="300dp"
android:layout_marginStart="190dp"
android:layout_marginTop="40dp"
android:layout_marginEnd="120dp"
android:layout_marginBottom="60dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/open_SquatVideo"
app:layout_constraintTop_toBottomOf="@+id/open_TricepVideo"
app:srcCompat="@drawable/house_3"
android:contentDescription="Go to Home Screen" />
</android.support.constraint.ConstraintLayout>

View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
</android.support.constraint.ConstraintLayout>

View File

@@ -1,16 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:context=".ui.SportMenuActivity">
<com.example.fitbot.ui.SportMenuItem
android:id="@+id/sportMenuItem1"
android:layout_width="300dp"
android:layout_height="300dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>

View File

@@ -4,4 +4,9 @@
<string name="navigation_drawer_open">Open navigation drawer</string>
<string name="navigation_drawer_close">Open navigation close</string>
<string name="welkom_bij_fitbot">Welkom bij FitBot</string>
<string name="robot_helpt">de robot die helpt om fit te blijven</string>
<string name="start">Start</string>
<string name="help">Help</string>
<string name="todo">TODO</string>
</resources>

View File

@@ -0,0 +1,37 @@
package com.example.fitbot;
import static org.junit.Assert.assertEquals;
import com.example.fitbot.util.path.GesturePath;
import com.example.fitbot.util.path.PathSegment;
import org.joml.Vector3f;
import org.junit.Test;
public class PathSegmentTest {
@Test
public void testPathSegment() {
// Test the PathSegment class
Vector3f[] vectors = new Vector3f[2];
vectors[0] = new Vector3f(0, 0, 0);
vectors[1] = new Vector3f(1, 1, 1);
GesturePath path = new GesturePath(vectors);
PathSegment[] segments = path.getSegments();
assertEquals(1, segments.length);
assertEquals(new Vector3f(0, 0, 0), segments[0].getStart());
assertEquals(new Vector3f(1, 1, 1), segments[0].getEnd());
assertEquals(new Vector3f(0.5f, 0.5f, 0.5f), segments[0].interpolate(0.5));
}
@Test
public void test_pathSegmentInterpolation() {
Vector3f start = new Vector3f(0, 0, 0);
Vector3f end = new Vector3f(1, 1, 1);
PathSegment segment = new PathSegment(start, end);
assertEquals(new Vector3f(0.5f, 0.5f, 0.5f), segment.interpolate(0.5));
}
}

View File

View File

@@ -0,0 +1,11 @@
// Om iets met de database te doen, is het handig om een functie te maken
// die een `app` parameter en een `pool` parameter accepteert.
// Deze moet dan geëxporteerd worden om deze te kunnen gebruiken in `server.js`.
// Dit is een voorbeeld van hoe je dat zou kunnen doen:
// module.exports = function(app, pool) { ... }

25
code/web/server.js Normal file
View File

@@ -0,0 +1,25 @@
const mariadb = require('mariadb');
const express = require('express');
const app = express();
const serverPort = 3000;
const databaseCredentials = {
host: 'localhost',
user: 'fitbot',
password: 'fitbot123',
database: 'fitbot',
connectionLimit: 5,
allowUnauthorized: true
}
// Create connection pool
const pool = mariadb.createPool(databaseCredentials);
// Register incoming HTTP request handlers
require('incoming_request_handlers')(app, pool);
// Start server
app.listen(port, () => {
console.log(`Server running on port ${serverPort}`);
})

View File

@@ -14,15 +14,34 @@ nav:
- Pepper: documentation/robots/pepper
- Little Endian: documentation/robots/little-endian
- 📚 Documentation:
- 🧠 Brianstorm:
- Ideas: documentation/brainstorm/ideas
- 📱 Android:
- Android Studio: documentation/android/androidStudio
- app setup: documentation/android/appSetup
- video view: documentation/android/Videoview
- 🧠 Brianstorm:
- Ideas: documentation/brainstorm/ideas
- 🗄️ Database:
- EERD: documentation/database/EERD
- ERD: documentation/database/ERD
- Infrastructure: documentation/database/infrastructure
- 📦 Hardware:
- Hardware: documentation/hardware/sensors
- 🤖 Pepper:
- Pepper Setup: documentation/pepper/pepperSetup
- Pepper movement: documentation/android/robotmovement
- 👷‍♀️ Hardware:
- Hardware: documentation/hardware/sensors
- 🍓 Raspberry Pi:
- Raspberry Pi: documentation/raspberryPi/raspberryPiSetup
- Apache:
- Apache: documentation/raspberryPi/apache/apache
- Apache Setup: documentation/raspberryPi/apache/apacheSetup
- MariaDB:
- MariaDB: documentation/raspberryPi/mariaDB/mariaDB
- MariaDB Setup: documentation/raspberryPi/mariaDB/mariaDBSetup
- NodeJs:
- NodeJs: documentation/raspberryPi/nodeJs/nodeJs
- NodeJs Setup: documentation/raspberryPi/nodeJs/nodeJsSetup
- phpMyAdmin:
- phpMyAdmin: documentation/raspberryPi/phpMyAdmin/phpMyAdmin
- phpMyAdmin Setup: documentation/raspberryPi/phpMyAdmin/phpMyAdminSetup

View File

@@ -0,0 +1,86 @@
## Class Implementation - MotionProcessor
---
#### Methods
Creates a WebSocket server and starts listening for incoming MotionData messages
```java
public void startListening() { ... }
```
Stops the WebSocket server and stops listening for incoming MotionData messages
```java
public void stopListening() { ... }
```
Parses an incoming WebSocket message packet and processes the data.
The data that is accepted is a string that can be of the following formats:
```java
// Sending data
"data accelerationX;accelerationY;accelerationZ;rotationX;rotationY;rotationZ" // all values are floats
// Changing the sample rate
"sampleRate rate" // rate is an integer
// Calibrating the zero point
"zero x;y;z" // x, y, z are floats
```
```java
public void parsePacket(@NotNull String message) { ... }
```
Processes the provided MotionData object, uses it as a relative path point, and calls the
motionDataEventHandler with the calculated vector.
```java
public void addMotionData(MotionData data) { ... }
```
Sets the gesture path to the provided path.
```java
public void setGesturePath(GesturePath gesturePath) { ... }
```
Updates the relative path to the provided path.
```java
public void setRelativePath(List<Vector3> relativePath) { ... }
```
Sets the motionDataEventHandler to the provided handler.
```java
public void setMotionDataEventHandler(Consumer<Vector3> consumer) { ... }
```
Calculate the relative vector given a MotionData object.
This converts relative acceleration and rotation to a vector, taking the
sample rate into account.
```java
public Vector3 getRelativeVector(MotionData motionData) { ... }
```
Get a list of error values given the provided GesturePath.
This compares the relative path (calibrated) to the provided path segments,
and returns the offsets.
```java
public List<Double> getErrors(GesturePath referencePath) { ... }
public List<Double> getErrors() { ... } // Using pre-set path
```
Get the error offset of the provided vector to the provided path, or with the
set path.
This compares a given vector to the provided GesturePath object.
```java
public double getError(GesturePath path, Vector3 referencePoint) { ... }
public double getError(Vector3 referencePoint) { ... } // Using pre-set path
```
Get the average error offset of the relative path and the provided GesturePath object.
```java
public double getAverageError(GesturePath referencePath) { ... }
public double getAverageError() { ... } // Using pre-set path
```
Logs statistics to the console
```java
public void logStatistics(GesturePath referencePath) { ... }
```

View File

@@ -0,0 +1,87 @@
# Vector3
This class represents a 3D vector with x, y, and z components.
## public Vector3(double x, double y, double z)
Constructor for creating a new vector.
## public Vector3 copy()
This method returns a new vector with the same values as the current vector.
## public static Vector3 zero()
This static method returns a new vector with all components set to zero.
## public double magnitude(): double
This method returns the magnitude of the vector.
## public Vector3 normalize()
This method returns the normalized vector. It throws an `IllegalArgumentException` if the vector is the zero vector.
## public Vector3 subtract(Vector3 other)
This method subtracts another vector from the current vector and returns the result as a new vector.
## public Vector3 add(Vector3 other)
This method adds another vector to the current vector and returns the result as a new vector.
## public Vector3 multiply(double scalar)
This method multiplies the vector by a scalar and returns the result as a new vector.
## public Vector3 divide(double scalar)
This method divides the vector by a scalar and returns the result as a new vector. It throws an `IllegalArgumentException` if the scalar is zero.
## public Vector3 negate()
This method negates the vector and returns the result as a new vector.
## public Vector3 rotate(double radX, double radY, double radZ)
This method rotates the vector around the X, Y, and Z axes by the specified angles in radians and returns the result as a new vector.
## public Vector3 rotate(Vector3 rotation)
This method rotates the vector around the X, Y, and Z axes.
## public Vector3 rotateX(double angle)
This method rotates the vector around the X axis by the specified angle in radians and returns the result as a new vector.
## public Vector3 rotateY(double angle)
This method rotates the vector around the Y axis by the specified angle in radians and returns the result as a new vector.
## public Vector3 rotateZ(double angle)
This method rotates the vector around the Z axis by the specified angle in radians and returns the result as a new vector.
## public double distanceSq(Vector3 compare)
This method returns the squared distance between the current vector and another vector.
## public double distance(Vector3 compare)
This method returns the distance between the current vector and another vector.
## public double distanceToLine(Vector3 lineStart, Vector3 lineEnd)
This method calculates the distance from the current vector to a line defined by two points and returns the result.
## public Vector3 closest(Vector3 ... vectors)
This method returns the closest vector to the current vector from a list of vectors.
## public Vector3 map(VectorMapFunction function)
This method applies a `VectorMapFunction` to the current vector and returns the result.
## public String toString()
This method returns a string representation of the vector.

View File

@@ -0,0 +1,64 @@
# WebSocket
This class represents a WebSocket server.
## private WebSocket()
Constructor for creating a new WebSocket server.
## public static WebSocket createServer()
Function for creating a new WebSocket server. Due to Android security restrictions,
the server must be created both in a separate thread and with a non-predefined port.
The port will be selected by the system.
## public void startListening()
Method for listening for incoming connections.
This creates a new thread for the server.
## public void stop()
Method for stopping the WebSocket server.
## public void setEventHandler(IWebSocketHandler handler)
Method for setting the event handler for this WebSocket server.
This event handler accepts all WebSocket events, such as:
- onConnected(Socket socket)
- onMessageReceived(WebSocket.Message message, WebSocket.MessageReply replier)
- onDisconnected(Socket socket)
- onError(Socket socket, String error)
## public ServerSocket getSocket()
Method for getting the ServerSocket connection.
## public boolean isConnected()
Method for checking whether this WebSocket connection is connected.
---
# WebSocket.Message
Class representing a message received from a WebSocket connection.
### Fields
- `WebSocketConnection connection`: The connection from which the message was received.
- `String message`: The message content.
## Opcode decode(byte opcode)
Method for decoding the opcode of a message.
## public Message(WebSocketConnection connection, String message)
Constructor for a WebSocket message.
# MessageReply
Interface for a message reply.
This can be used for sending back a response to the client, by calling
`reply(String message)`.

View File

@@ -0,0 +1,109 @@
# Java class modifiers
## How are classes build in java?
There are a lot of classes with a lot of parameters
A class always begins with either the public or default or abstract access modifier. Then comes the class name
Example:
```java
public class MyClass {
//methods and atributes
}
```
Then in a class you can have Methods or Atributes where the actual code is.
```mermaid
flowchart
a[Access Modifiers] --> b[class] --> c[Class name]
```
## Constructor
A constructor in Java is a special method that is used to initialize objects. The constructor is called when an object of a class is created. It can be used to set initial values for object attributes.
The constructor Method is the first method that is called when a class is created. It has the same name as the class and no return type. It is automaticly called when a class is created.
### Methods
A method is a block of code which only runs when it is called. You can pass data, known as parameters, into a method. Methods are used to perform certain actions, and they are also known as functions.
Methods are build like this
```mermaid
flowchart
A[Access Modifiers] --> B[Method Modifier] --> C[Return Type] --> D[Method Name] --> E[Parameters] --> F[Method Body]
```
Example:
```java
public class MyClass {
// Method
static void myMethod() {
// print Hello World!
System.out.println("Hello World!");
}
// Main method
//access modifier, Method Modifier, return type, method name, parameters, method body
public static void main(String[] args) {
// Call the method
myMethod();
}
}
```
### Atributes
Attributes are variables within a class. When an object is created from a class, the object will have these attributes.
Example:
```java
public class MyClass {
int x = 5;
}
```
## Classes
### Class modifiers
#### Non-access modifiers
| Modifier | Description | | | |
|---|---|---|---|---|
| final | The class cannot be inherited by other classes (You will learn more about inheritance in the Inheritance chapter) | | | |
| abstract | The class cannot be used to create objects (To access an abstract class, it must be inherited from another class. You will learn more about inheritance and abstraction in the Inheritance and Abstraction chapters) | | | |
||||
#### Access modifiers
| Modifier | Description | | | |
|---|---|---|---|---|
| public | The code is accessible for all classes | | | |
| private | The code is only accessible within the declared class | | | |
| default | The code is only accessible in the same package. This is used when you don't specify a modifier. You will learn more about packages in the Packages chapter | | | |
| protected | The code is accessible in the same package and subclasses. You will learn more about subclasses and superclasses in the Inheritance chapter | | | |
| | | | | |
## Methods and attributes
#### non access modifiers
| Modifier | Description | | | |
|---|---|---|---|---|
| final | Attributes and methods cannot be overridden/modified | | | |
| static | Attributes and methods belongs to the class, rather than an object. You don't really wanna use this one. | | | |
| abstract | Can only be used in an abstract class, and can only be used on methods. The method does not have a body, for example abstract void run();. The body is provided by the subclass (inherited from). You will learn more about inheritance and abstraction in the Inheritance and Abstraction chapters | | | |
| transient | Attributes and methods are skipped when serializing the object containing them | | | |
| synchronized | Methods can only be accessed by one thread at a time | | | |
| volatile | The value of an attribute is not cached thread-locally, and is always read from the "main memory" | | | |
||||
#### Access modifiers
| Modifier | Description | | | |
|---|---|---|---|---|
| public | The code is accessible for all classes | | | |
| private | The code is only accessible within the declared class | | | |
| default | The code is only accessible in the same package. This is used when you don't specify a modifier. You will learn more about packages in the Packages chapter | | | |
| protected | The code is accessible in the same package and subclasses. You will learn more about subclasses and superclasses in the Inheritance chapter | | | |
| | | | | |
## Sources
* https://www.w3schools.com/java/java_modifiers.asp

View File

@@ -0,0 +1,108 @@
## Motion Tracking System
---
To capture the user's motion with the sensing devices, we'll need to use a tracking system that calculates the
path the user makes to be able to determine the user's position and orientation, and therefore whether the movement
that was made correlates to the provided path.
This is done by some calculations in the `MotionProcessor` class. To get started, create an instance of the `MotionProcessor` class and call the `processMotion` method with the `MotionData` object as a parameter. This will return a `MotionResult` object that contains the calculated path.
```java
// create the motion processor
MotionProcessor motionProcessor = new MotionProcessor();
```
To start listening for input, one must call the following method:
```java
// start listening for input
motionProcessor.startListening();
```
Calling this function creates a WebSocket server, which the sensing devices can connect to.
The `MotionProcessor` class will then start listening for a set of messages that start with specified kind of keywords.
The messages always start with the keyword, separated by a space, and then the data is sent.
The default data separator is `;`.
An example of the message format is shown below:
```java
// Sending data
"data accelerationX;accelerationY;accelerationZ;rotationX;rotationY;rotationZ" // all values are floats
// Changing the sample rate
"sampleRate rate" // rate is an integer
// Calibrating the zero point
"zero x;y;z" // x, y, z are floats
```
To add a custom message received handler, one can simply call the following method:
```java
// Add a custom message handler
motionProcessor.setMotionDataEventHandler((Vector3 vector) -> { ... });
```
*Note: The message handler provides a vector as a parameter; this vector is already converted from relative acceleration and rotation.*
### Error checking
To check whether the made movements correlate with a given path, one must check for their differences.
This can be done by a few implemented methods:
***Get the error of a vector compared to a path***
```java
GesturePath path = new GesturePath.Builder()
.addVector(...)
.build();
Vector3 referencePoint = new Vector3(...);
double error = motionProcessor.getError(path, referencePoint);
```
***Get the average error of a computed path to a `GesturePath`***
```java
GesturePath path = new GesturePath.Builder()
.addVector(...)
.build();
double error = motionProcessor.getAverageError(path);
```
***Get a list of error values from a computed path to a `GesturePath`***
```java
GesturePath path = new GesturePath.Builder()
.addVector(...)
.build();
List<Double> errorList = motionProcessor.getErrors(path);
```
### Example
An example of how to use a motion tracking system is shown below:
```java
// create the motion processor
MotionProcessor motionProcessor = new MotionProcessor();
// Create a gesture path
GesturePath.Builder pathBuilder = new GesturePath.Builder();
for ( int i = 0; i < 100; i++ )
pathBuilder.addVector(new Vector3(i, i, i));
GesturePath path = pathBuilder.build();
// Set the path
for ( int i = 0; i < 100; i++ ) {
motionProcessor.addMotionData(new MotionData(i, i, i, i, i, i));
}
// Get error values
List<Double> errorList = motionProcessor.getErrors(path);
// Get average error
double averageError = motionProcessor.getAverageError(path);
// Now you can do whatever you want with these results.
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 863 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 944 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -5,14 +5,69 @@ As we become older, our vision worsens. We need to keep this in mind because our
![contrast](contrastcolors.png)
This image shows what elderly people may experience while reading or using an app. We must keep this in mind as we design our app.
### color psychology
Colors can be an effective way to influence emotions and feelings. They may influence you without your knowledge. We can use this to influence those who use our app. Colors have a powerful ability to influence emotions. Every color has a unique effect on our minds. For example, blue has a calming and trustworthy effect on our minds. While blue may not be appropriate for our project, it may prove useful when using a more serious app. We can see PayPal using this trend because it is a banking app that must be trusted. Because blue influences those who use PayPal, it will have a positive impact on their customers. We also want to positively influence our people.
Here are some examples of how colors can be used in a fitness app for elderly people. First we need to sort out what kind of emotions we want to stimulate. For starting and doing the excersize we need to boost excitement, energy and strenght. We need to boost these emotions to get the most out of people. We hope by using these colors we are stimulating people to get more out of there work out. The reason of boosting emotions trough color is that is is seamless and that makes it powerfull. If you dont know that you are being influenced it has the best effect. Lets discuss some colors
<span style="color:red">
<strong> RED: </strong>
</span>
Red is an interesting color because it increases excitement, activity, aggression, bravery, and youthfulness. People associate the color red with boldness, fire, competition, love, energy, speed, power, youth, and so much more. These emotions are useful when developing a fitness app, but even a different shade of red affects emotions and effectiveness. Lighter shades highlight the energetic qualities of red. Darker shades emphasize power. This makes red a powerful color and for us and an interesting option because Strava, a fitness app focused on running, uses the same colors.
![palettes of red](redpalette.png)
<span style="color:ORANGE">
<strong> ORANGE: </strong>
</span>
Orange is a warm color that is a combination of red and yellow, making it a good middle ground between the two. Orange is an interesting color for our project because it promotes emotions like playful, warm, friendly, social, gregarious, cheerful, vibrant, confident, and successful. As we can see, there is a good balance of red and yellow emotions. People associate the color orange with extroversion, adventure, celebration, courage, confidence, good health, friendship, and success. This makes it a suitable choice for our project because it triggers most of the emotions we wanted. It is not as aggressive as red, but it basically has the same effect. Deeper oranges are warmer, while lighter tints make it feel more like yellow. We should consider orange for our app because it stimulates the desired emotions.
![palettes of orange](orangepalette.png)
<span style="color:yellow">
<strong> YELLOW: </strong>
</span>
Yellow belongs in the same park as red because they are both warm colors. Yellow boosts emotions such as warmth, cheerfulness, happiness, energy, clarity, and attention, making it a good choice for us to look at. People associate the color or yellow with. Sunshine, creativity, imagination, hope, joy, the future, and spirituality. The various shades affect yellow in different ways, and bright sharp yellows can be tiring and cause headaches. Lighter shades appeal to the happiness aspect, reminding users of summer and the sun. Darker shades, such as gold, add weight. This makes yellow an interesting color option for our app.
![palettes of yellow](yellowpalette.png)
<span style="color:green">
<strong> GREEN: </strong>
</span>
Green is on the opposite side of the spectrum from red and yellow. Green is a colder color, which gives it a different effect. Green enhances emotions such as restful, natural, stable, healthy, and prosperity. This can make it a viable option, especially because it gives people a sense of good health. People associate color green with. Freshness, ecology, nature, health, balance, fertility, growth, renewal, healing, money, and good luck. This is interesting because it not only provides people with the feeling of being healthy, but also of being outside in nature, which may help elderly people feel less isolated. However, the shades of green also make people feel different. Pale greens are soothing. Dark greens can improve concentration. However, because we do not rely on concetration, it will have little impact on our project.
![palletes of green](greenpalette.png)
<span style="color:BLUE">
<strong> BLUE: </strong>
</span>
Blue is also a colder color, so it takes the same path as green, giving it a more calming effect. However, it is not comparable to green because they influnce other emotions. Blue enhances emotions like calm, security, peace, patience, loyalty, trust, and sadness. It has the same soothing effect as green, but it does not give people the feeling of being healthy. It gives people trust and peace, which are interesting emotions, but they are not beneficial to us. People associate the color blue with stability, protection, trust, loyalty, patience, perseverance, security, peace, loyalty, sadness and depression, and masculinity. This further confirms that blue gives people a sense of security, which is not important for us because we want people to start exercising. Pale blue is cooling and relaxing, but it should not be used inappropriately because it can make people feel sad and depressed. Indigo is useful in situations where fear prevents activity. Indigo may be useful for a cool-down exercise or if someone is afraid of exercising.
![palletes of blue](bluepalette.png)
<span style="color:Black">
<strong> BLACK: </strong>
</span>
Black is not a color but we can use this as the main tone for our app. However since old people tend to have issues when there isnt much light and black is the absence of light we are not very likely to sue it. Black boost emotions like Mysterious, elegant, sophisticated, worldly, powerful, strength, and intelligence. This makes black not that interesting for us since we want to make a simple app that everyone can understand. People associate the color black with Authority, sophistication, simplicity, protection, formality, elegance, night, power, and mystery. This is very intersting but not for our project since we do not desire people to associate our project with these emotions. If we tone the color black we get gray and white of which i will discuss the color white seperatly. Too much black can be frightening. Depressing unless used with other colors.
![palletes of black](blackpalette.png)
<span style="color:White">
<strong> WHITE: </strong>
</span>
White is not a color so it has the same purpose as black being a main tone to our app. White is a light tone which may cause it to glare. This means that you do not what to use the brightest types of screen with white. We do not have this issue so we can use white as much as wel like. White gives people the emotions of: fresh, pure, clear, easy, receptive, modern, neat, and precise. Since we are designing a simple app white is a nice main tone for our app. People associate white with Goodness, innocence, purity, cleanliness, calmness, freshness, healthiness, and precision. This further confirms that white is a good option for our app. However as i said Too bright white can produce eyestrain and headaches. Escpecially elderdly people are extra sensetive for this. So if we use white we need to be a little bit carefull whit it
![palletes of white](whitepalette.png)
### Conclusion
We decided to go for
# Source
https://eldertech.org/color-in-designing-technology-for-seniors/
https://eldertech.org/color-in-designing-technology-for-seniors/
https://decode.agency/article/choose-color-palette-for-apps/

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -0,0 +1,15 @@
# EERD
EERD stands for Extended Entity Relationship Diagram, which is an extended version of the Entity Relationship Diagram (ERD). An EERD is often used to visualize the structure and relationships between entities in a database.
In an EERD, different symbols are used to represent the different elements of a database. Two important symbols are the Primary Key (PK) and the Foreign Key (FK).
Primary Key (PK): A Primary Key is a unique identifier for an entity in a database. It is used to identify and distinguish rows in a table. In an EERD, a PK is usually indicated with an underscored attribute or a special symbol, such as a Key icon.
Foreign Key (FK): A Foreign Key is an attribute in a table that refers to the Primary Key of another table. It is used to define relationships between tables. In an EERD, an FK is usually indicated with a dotted line pointing to the PK of another entity.
Here is an example to clarify the concept of PK and FK:
Suppose we have a database with two tables: "Orders" and "Customers". The "Orders" table has a PK called "order_id", while the "Customers" table has a PK called "customer_id". To define the relationship between these two tables, we can add an FK called "customer_id" to the "Orders" table, which refers to the PK "customer_id" in the "Customers" table. This allows us to link the orders of each customer to the correct customer information.
![EERD](../assets/EERD.png)

View File

@@ -0,0 +1,16 @@
# ERD
Entity Relationship Diagram (ERD)
To design a relational database, you first create an Entity Relationship Diagram. In this, you model the data that the user wants to store, without looking at the technical implementation. The following concepts play a role in an ERD:
* Entity: a type of "thing" about which the user wants to store data, for example a user, an order, or a student.
* Attribute: properties of an entity. For a user, this could be: username, email, and password.
* Relationships: connection between entities, for example the fact that one customer can place multiple orders.
* Instances: an example of an entity, for example the order with order number 239741.
* 1-to-many (1: N): one instance can belong to multiple instances of another entity. For example: a customer can place multiple orders, but an order belongs to only one customer.
* many-to-many (N: M): one instance can belong to multiple instances of another entity, but the reverse is also true. For example: an order can contain multiple products and conversely a product can appear on multiple orders.
* 1-to-1 (1:1): one instance belongs to a maximum of one instance of another entity. For example: an employee can have one lease car and a lease car is from one employee.
![ERD](../assets/ERD.png)

View File

@@ -0,0 +1,19 @@
# Infrastructure
The infrastructure of the database is composed of the following components:
- User
- Pepper
- Interface
- Robot
- Raspberry Pi
- Database
- MariaDB
- Server
- Apache
- phpMyAdmin
- Node.js
User interacts with Pepper through the interface. The interface sends the user input to the robot. The robot processes the input (java) and sends the output (xml) back to the interface. The interface displays the output to the user. The Raspberry Pi hosts the server and database. The database stores the data and the server hosts the website. The server runs Apache, phpMyAdmin, and Node.js. The interface makes a request to the server (HTTP GET) to retrieve the data in the database. The server processes the request (HTTP GET) and retrieves (SQL) the data from the database. The interface displays the data to the user.
![Application Architecture Diagram](../diagrams/assets/appDiagram.png)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 99 KiB

After

Width:  |  Height:  |  Size: 114 KiB

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,24 @@
# PCB
## Headerpins
```
#define PIN_IMU_SDA D2
#define PIN_IMU_SCL D1
#define PIN_IMU_INT D5
#define PIN_IMU_INT_2 D6
```
## What does the pcb do
The pcb on itself is a espd1mini with no sensors or battery. You need to manual solder a battery and sensor of your choice to the pcb.
## Original usage
These pcb's where originally designed for virtual reality fullbody tracking. They are basicly movement trackers that can be used to track the movement of the body. We can also use this really well for our project.
## Why did we choose this pcb
We chose this pcb because its really small and it has a socket for a sensor and it also has a build in bms for the battery.
## Usage in our project
We are going to rotational data from the sensor and use that to give feedback to the user based on how well they did the exercise.
![alt text](../assets/pcbImage.png)
### Sources
* https://github.com/Sorakage033/SlimeVR-CheeseCake

View File

@@ -0,0 +1 @@
# Apache

View File

@@ -0,0 +1,47 @@
# Apache Setup on Raspberry Pi
Apache is a popular open-source web server that is widely used to serve web content. It is a powerful and flexible server that can be used to host websites, web applications, and more. In this guide, we will show you how to set up Apache on your Raspberry Pi. This will allow you to host your own websites and serve content to users on your local network or the internet.
## Prerequisites
Before you begin, you will need the following:
- A Raspberry Pi with Raspbian installed
- Access to the terminal on your Raspberry Pi
## Installation
### Step 1: Update the Package List
The first step is to update the package list on your Raspberry Pi. This will ensure that you have the latest information about available packages.
Run the following command to update the package list:
```bash
sudo apt update
```
### Step 2: Install Apache
Next, you will need to install the Apache web server on your Raspberry Pi. You can do this by running the following command:
```bash
sudo apt install apache2
```
During the installation process, you may be prompted to confirm that you want to install the packages. Type `Y` and press `Enter` to continue.
### Step 3: Verify the Installation
To verify that Apache has been installed correctly, you can open a web browser on your computer and enter the IP address of your Raspberry Pi in the address bar. If Apache has been installed successfully, you should see the default Apache web page.
For example, if the IP address of your Raspberry Pi is `145.92.8.132`, you would enter `http://145.92.8.132` in the address bar.
## Conclusion
You have successfully set up Apache on your Raspberry Pi. You can now host your own websites and serve content to users on your local network or the internet. If you have any questions or run into any issues, feel free to refer to the [Apache documentation](https://httpd.apache.org/docs/) for more information.
```

View File

@@ -0,0 +1,57 @@
# MariaDB create database
In this guide, we will show you how to create a new database in MariaDB. This will allow you to store and manage data in a structured way.
## Prerequisites
Before you begin, you will need the following:
- A Raspberry Pi with Raspbian installed
- Access to the terminal on your Raspberry Pi
- MariaDB installed on your Raspberry Pi
If you have not already installed MariaDB, you can follow our guide on [how to install MariaDB on your Raspberry Pi](../mariaDB/mariaSetup.md).
## Step 1: Access the MariaDB Shell
The first step is to access the MariaDB shell. You can do this by running the following command in the terminal:
```bash
sudo mysql -u root -p
```
You will be prompted to enter the root password that you set during the MariaDB installation process.
## Step 2: Create a New Database
Once you are in the MariaDB shell, you can create a new database by running the following command:
```sql
CREATE DATABASE database_name;
```
Replace `database_name` with the name that you want to give to your new database.
For example, to create a database called `mydatabase`, you would run the following command:
```sql
CREATE DATABASE mydatabase;
```
## Step 3: Verify the Database Creation
To verify that the database has been created successfully, you can run the following command in the MariaDB shell:
```sql
SHOW DATABASES;
```
This will display a list of all the databases on your MariaDB server, including the one that you just created.
## Conclusion
You have successfully created a new database in MariaDB. You can now start adding tables and data to your database to store and manage information. If you have any questions or run into any issues, feel free to refer to the [MariaDB documentation](https://mariadb.com/kb/en/) for more information.

View File

@@ -0,0 +1,70 @@
# MariaDB Setup on Raspberry Pi
MariaDB is a fork of MySQL and is a popular choice for database management systems. It is open-source and is widely used in web applications. MariaDB is a community-driven project and is developed by the original developers of MySQL. It is designed to be fully compatible with MySQL, meaning that it can be used as a drop-in replacement for MySQL.
In this guide, we will show you how to install MariaDB on your Raspberry Pi. This will allow you to create and manage databases on your device.
## Prerequisites
Before you begin, you will need the following:
- A Raspberry Pi with Raspbian installed
- Access to the terminal on your Raspberry Pi
## Installation
### Step 1: Update the Package List
The first step is to update the package list on your Raspberry Pi. This will ensure that you have the latest information about available packages.
Run the following command to update the package list:
```bash
sudo apt update
```
### Step 2: Install MariaDB
Next, you will need to install the MariaDB server on your Raspberry Pi. You can do this by running the following command:
```bash
sudo apt install mariadb-server
```
During the installation process, you will be prompted to set a root password for the MariaDB server. Enter a secure password and remember it, as you will need it to access the database server.
### Step 3: Secure the MariaDB Installation
After installing MariaDB, you should secure the installation by running the `mysql_secure_installation` script. This script will guide you through the process of securing your MariaDB installation by setting a root password, removing anonymous users, disallowing remote root login, and removing the test database.
Run the following command to start the `mysql_secure_installation` script:
```bash
sudo mysql_secure_installation
```
Follow the prompts to secure your MariaDB installation.
### Step 4: Access the MariaDB Shell
Once you have secured the MariaDB installation, you can access the MariaDB shell by running the following command:
```bash
sudo mysql -u root -p
```
Enter the root password that you set during the installation process. You should now be logged into the MariaDB shell.
## Conclusion
You have successfully installed MariaDB on your Raspberry Pi. You can now create and manage databases using MariaDB on your device. If you have any questions or run into any issues, feel free to refer to the [MariaDB documentation](https://mariadb.com/kb/en/) for more information.
---

View File

@@ -0,0 +1,3 @@
# NodeJs
NodeJs is a JavaScript runtime that is built on Chrome's V8 JavaScript engine. It is designed to be lightweight and efficient, making it perfect for running on the Raspberry Pi. This is a file that

View File

@@ -0,0 +1,96 @@
# NodeJs Setup on Raspberry Pi
## Prerequisites
Before you begin, you will need the following:
- A Raspberry Pi with Raspbian installed
- Access to the terminal on your Raspberry Pi
## Installation
### Step 1: Update the Package List
The first step is to update the package list on your Raspberry Pi. This will ensure that you have the latest information about available packages.
Run the following command to update the package list:
```bash
sudo apt update
```
### Step 2: Install Node.js
Next, you will need to install Node.js on your Raspberry Pi. You can do this by running the following command:
```bash
sudo apt install nodejs
```
### Step 3: Install npm
After installing Node.js, you will also need to install npm, which is the Node.js package manager. You can do this by running the following command:
```bash
sudo apt install npm
```
### Step 4: Verify the Installation
To verify that Node.js and npm have been installed correctly, you can check the versions of both tools by running the following commands:
```bash
node -v
npm -v
```
If the installation was successful, you should see the version numbers of Node.js and npm displayed in the terminal.
### Step 5: Create a Test File
To test that Node.js is working correctly on your Raspberry Pi, you can create a simple test file. Create a new file called `test.js` by running the following command:
```bash
nano test.js
```
In the text editor, add the following code:
```javascript
console.log('Hello, World!');
```
Save and exit the text editor by pressing `Ctrl + X`, then `Y`, and finally `Enter`.
### Step 6: Run the Test File
To run the test file, use the following command:
```bash
node test.js
```
If Node.js is working correctly, you should see `Hello, World!` displayed in the terminal.
Congratulations! You have successfully installed Node.js on your Raspberry Pi. You can now start developing applications using Node.js on your device.
If you have any questions or run into any issues, feel free to refer to the [Node.js documentation](https://nodejs.org/en/docs/) for more information.
## Conclusion
You have successfully installed Node.js and npm on your Raspberry Pi. You can now use these tools to develop and run Node.js applications on your device. If you have any questions or run into any issues, feel free to refer to the [Node.js documentation](https://nodejs.org/en/docs/) for more information.

View File

@@ -0,0 +1 @@
# phpMyAdmin

View File

@@ -0,0 +1,100 @@
# phpMyAdmin setup on Raspberry Pi
phpMyAdmin is a free and open-source tool written in PHP that allows you to manage MySQL and MariaDB databases through a web interface. It provides an easy-to-use graphical interface for performing database operations such as creating, editing, and deleting databases, tables, and records.
In this guide, we will show you how to set up phpMyAdmin on your Raspberry Pi. This will allow you to manage your MySQL and MariaDB databases through a web browser.
## Prerequisites
Before you begin, you will need the following:
- A Raspberry Pi with Raspbian installed
- Access to the terminal on your Raspberry Pi
- MySQL or MariaDB installed on your Raspberry Pi
If you have not already installed MySQL or MariaDB, you can follow our guides on [how to install MySQL on your Raspberry Pi](../mysql/mysqlSetup.md) or [how to install MariaDB on your Raspberry Pi](../mariaDB/mariaSetup.md).
## Installation
### Step 1: Install phpMyAdmin
The first step is to install phpMyAdmin on your Raspberry Pi. You can do this by running the following command:
```bash
sudo apt install phpmyadmin
```
During the installation process, you will be prompted to select the web server that you are using. If you are using Apache, select `apache2` by pressing the `Space` key, then press `Tab` to select `OK` and press `Enter` to continue.
You will also be prompted to configure the database for phpMyAdmin. Select `Yes` and enter the root password for your MySQL or MariaDB server when prompted.
### Step 2: Configure phpMyAdmin
After installing phpMyAdmin, you will need to configure it to work with your web server. You can do this by running the following command:
```bash
sudo dpkg-reconfigure phpmyadmin
```
During the configuration process, you will be prompted to select the web server that you are using. If you are using Apache, select `apache2` by pressing the `Space` key, then press `Tab` to select `OK` and press `Enter` to continue.
You will also be prompted to configure the database for phpMyAdmin. Select `Yes` and enter the root password for your MySQL or MariaDB server when prompted.
### Step 3: Access phpMyAdmin
Once you have installed and configured phpMyAdmin, you can access it through a web browser. Open a web browser on your computer and enter the IP address of your Raspberry Pi followed by `/phpmyadmin` in the address bar.
For example, if the IP address of your Raspberry Pi is `145.92.8.132/phpmyadmin`, you would enter `http://145.92.8.132/phpmyadmin` in the address bar.
You will be prompted to enter the username and password for your MySQL or MariaDB server. Enter `root` as the username and the root password that you set during the installation process.
You should now see the phpMyAdmin login page, where you can log in and start managing your databases. If not, you may need to restart the Apache web server by running the following command:
```bash
sudo systemctl restart apache2
```
Check phpMyAdmin Configuration: Ensure that phpMyAdmin is correctly configured in Apache2. There should be a phpMyAdmin configuration file in the /etc/apache2/conf-enabled/ directory named phpmyadmin.conf. If it's not there, you can create a symbolic link to it with:
```bash
sudo ln -s /etc/phpmyadmin/apache.conf /etc/apache2/conf-enabled/phpmyadmin.conf
```
### Step 4: Log in to phpMyAdmin
Once you have restarted the Apache web server, you can log in to phpMyAdmin using the username `root` and the root password that you set during the installation process.
You should now see the phpMyAdmin dashboard, where you can manage your MySQL or MariaDB databases through a web interface.
If not you may need to change the port number in the phpMyAdmin configuration file. You can do this by editing the `config.inc.php` file located in the `/etc/phpmyadmin` directory:
```bash
sudo nano /etc/phpmyadmin/config.inc.php
```
Find the line that starts with `$cfg['Servers'][$i]['host']` and add the port number after the host name. For example, if your MySQL or MariaDB server is running on port `3306`, the line should look like this:
```php
$cfg['Servers'][$i]['host'] = 'localhost:3306';
```
Save the file and restart the Apache web server by running the following command:
```bash
sudo systemctl restart apache2
```
You should now be able to log in to phpMyAdmin using the username `root` and the root password that you set during the installation process.
## Conclusion
You have successfully set up phpMyAdmin on your Raspberry Pi. You can now use phpMyAdmin to manage your MySQL or MariaDB databases through a web interface. If you have any questions or run into any issues, feel free to refer to the [phpMyAdmin documentation](https://docs.phpmyadmin.net/en/latest/) for more information.

View File

@@ -0,0 +1,3 @@
# Raspberry Pi Setup
To setup the Raspberry Pi, follow the guide in the this [link](https://knowledgebase.hbo-ict-hva.nl/1_beroepstaken/infrastructuur/realiseren/edge_computing/raspberry_pi/respberry_pi_installation/).

View File

@@ -0,0 +1,50 @@
## Analysis for Motion Tracking System on the Pepper Robot.
---
For our project, we want our users to be able to see the movement they're making, so they can
see whether they're executing the fitness task correctly. For a tracking system as such, we'll need to use quite
some mathematics.
Our current approach is defining the required path by a set of vertices; points in 3d space.
These points define along which path the user has to move their limbs to, depending on what the activity is
and where they've placed the tracking devices.
A path can look like the following
<img height="128" src="../assets/motion-path-example-vertices.png" width="128" alt="Path Point Example"/>
To be able to measure the position of our tracking device, we'll have to use sensors that allow us
to retrieve useful information that can provide us with either position or velocity. The device will have
to be calibrated initially, of course, due to position being relative.
To acquire our measurements, we've chosen for the following configuration for the tracking device:
- ESP8266 (Wi-Fi only)
- Accelerometer / Gyroscope combination (BNO085)
We've chosen for this configuration due to the fact that it delivers all of our needs, with the smallest form factor,
whilst also delivering quality measurements.
This sadly does come at the cost that the ESP8266 does not have a dedicated Bluetooth chip, therefore making
connectivity to our robot a little more complicated.
The calculations behind the tracking system will be done in the following steps:
1. Acquire calibration point (zero point)
2. Convert relative acceleration and rotation to position, relative to the calibration point
3. Generate a path object that can be compared to the correct one
4. Calculate the difference of the path at every measurement sample
At first, to get the calibration point, the user will have to stand still for a moment without moving.
This can be sensed by the device, which will then be sent to the Pepper robot.
We've decided to send this data using Wi-Fi using a HTTP WebSocket connection, due to the fact that our
ESP8266 does not have a Bluetooth chip present, and due to the fact that a WebSocket connection allows us
for a both fast and secure data transfer.
Second, to convert our relative acceleration rotation to a useful position, we'll have to first convert the
acceleration vector `A(x, y, z)` and rotation vector `R(x, y, z)` to an acceleration vector that is
perpendicular to the normal vector of the earth. This is because the acceleration vector of the device
is relative to its own axes, and not to the earth's normal vector.
To convert this, we'll have to multiply the acceleration vector `A(x, y, z)` by the rotation matrix
with negative angles, to rotate it back to be perpendicular with the normal of the earth.
After this transformation

View File

@@ -0,0 +1,89 @@
# Position Tracking with Embedded Systems
## Introduction
For this project we want to design an embedded system that can track a users position. We want to track their current position on the ground and see how they are shifting their weight. This system will be used to track their position to determine if a user is doing the exercises correctly.
## Objectives
- Design an embedded system that can track user position.
- Develop an algorithm to process the data from the Wii Fit Board and determine the user's position.
## Research and Analysis
### Choosing the Wii Fit Board
For this project we have chosen the Wii Fit Board as our primary sensor. The Wii Fit Board is a balance board that can measure a user's weight and center of balance. It is a low-cost sensor that is easy to interface with a microcontroller. The Wii Fit Board communicates over Bluetooth, which makes it easy to connect to a microcontroller with Bluetooth capabilities.
### Alternative Solutions
There are other sensors that can be used for position tracking, such as pressure sensors or accelerometers. However, these sensors are more expensive and may require additional processing to determine the user's position. The Wii Fit Board provides a simple and cost-effective solution for position tracking.
Example of other sensors that can be used for position tracking:
Pressure sensors:
- Description: Pressure sensors can be used to measure the force applied by the user on the ground. By measuring the pressure distribution, the user's position can be determined.
- Pros: High accuracy, can measure force applied by the user.
- Cons: Expensive, will require additional hardware for data transfer.
- Cost: ~ 33 euros (https://www.antratek.nl/flexiforce-a401-sensor-25lbs?gad_source=1&gclid=CjwKCAjwupGyBhBBEiwA0UcqaMMrIXGafsF2oE-15JaTPT5tDhfCyDHz2D2gSghyPvg11okv_QIFThoCw5oQAvD_BwE)
Accelerometers:
- Description: Accelerometers can be used to measure the user's acceleration and orientation. By integrating the acceleration data, the user's position can be determined.
- Pros: Can measure acceleration and orientation, cheap.
- Cons: Will require additional hardware for data transfer.
- Cost: ~ 5 euros (https://www.amazon.nl/versnellingsmeter-gyroscoop-versnellingssensor-converter-gegevensuitgang/dp/B07BVXN2GP/ref=asc_df_B07BVXN2GP/?tag=nlshogostdde-21&linkCode=df0&hvadid=430548884871&hvpos=&hvnetw=g&hvrand=5187253011954678898&hvpone=&hvptwo=&hvqmt=&hvdev=c&hvdvcmdl=&hvlocint=&hvlocphy=1010543&hvtargid=pla-928293154057&psc=1&mcid=43bf111afa7b3ba593f4a49321683352)
### System Requirements
To be added
## System Design
### Hardware
The hardware of the system will consist of the following components:
- Wii Fit Board: The primary sensor for position tracking.
- Pepper: The controller that will process the data from the Wii Fit Board.
### Software
The software of the system will consist of the following:
- Wiiboard-simple: A library that will be used to transfer data from the Wii Fit Board to pepper.
- Position Tracking Algorithm: An algorithm that will process the sensor data and determine the user's position.
### Integration
The Wii Fit Board will be connected to Pepper using the Wiiboard-simple library. The library will be used to read the sensor data from the Wii Fit Board and transfer it to Pepper. The position tracking algorithm will process the sensor data and determine the user's position.
Challenge:
- Connecting to the wii fit board. It is not possible to connect directly to the Wii Fit Board, it is necessary to use a library that can interpret the data sent by the Wii Fit Board.
- The Wii Fit Balance Board sends data in a specific format. To interpret this data, it's necessary to understand the format and how to convert it to a usable format.
- The Wii Fit Balance Board uses Bluetooth 2.0 to communicate. Pepper uses Bluetooth 4.0 this means that there might be compatibility issues/latancy issues.
## Implementation
### Prototyping
To start the implementation of the system, we will create a prototype that will read the sensor data from the Wii Fit Board and send it to your computer. Once we have the data, we will develop the position tracking algorithm to determine the user's position. After that, the algorithm will be integrated with pepper.
### Testing and Validation
Tests:
- Test the prototype to ensure that it can read the sensor data from the Wii Fit Board.
- Test the position tracking algorithm to ensure that it can determine the user's position accurately.
- Test the integrated system to ensure that it can track the user's position in real-time.
## Conclusion
To be added
## References
[Wiiboard lib](https://code.google.com/archive/p/wiiboard-simple/wikis/Documentation.wiki)
https://advanti-lab.sb.dfki.de/?page_id=64
https://github.com/paulburton/fitscales
https://github.com/micromu/WiiRemoteJ
## Appendices
To be added

View File

@@ -0,0 +1,68 @@
# Literatuuronderzoek Luca Warmenhoven
## Hoe kunnen we voorkomen dat de privacy van ouderen wordt geschonden bij het inzetten van kunstmatige intelligentie om eenzaamheid te bestrijden?
---
### Inhoudsopgave
1. [Inleiding](#inleiding)
2. [Hoe ontstaat eenzaamheid onder ouderen?](#hoe-ontstaat-eenzaamheid-onder-ouderen)
3. [Kan kunstmatige intelligentie ingezet worden om dit te verhelpen?](#op-welke-manier-kunnen-we-kunstmatige-intelligentie-inzetten-om-eenzaamheid-onder-ouderen-te-bestrijden)
4. [Hoe kunnen we ervoor zorgen dat de privacy van ouderen niet wordt geschonden?](#hoe-kunnen-we-ervoor-zorgen-dat-dit-gedaan-kan-worden-zonder-de-privacy-van-ouderen-te-schenden)
5. [Conclusie](#conclusie)
6. [Bronnen](#bronnen)
---
### Inleiding
Door de vergrijzing van de bevolking neemt het aantal ouderen in Nederland toe. Dit zorgt ervoor dat er steeds meer ouderen terecht komen in de verzorgingstehuizen.
Met een stijgende hoeveelheid ouderen in de verzorgingstehuizen zou je denken dat de eenzaamheid onder hen afneemt, maar dit is echter niet het geval.
Een manier om dit probleem op te lossen is door het inzetten van robots. Om deze robots nog capabeler te maken wordt er tegenwoordig ook gebruik gemaakt van kunstmatige
intelligentie. Dit komt echter ook met nadelen, zo kan het dat er informatie gedeeld wordt met de makers van de robots.
In dit onderzoek zal er gekeken worden of het mogelijk is om kunstmatige intelligentie toe te passen zonder dat dit ten koste gaat van de privacy van de ouderen.
### Wat zijn de belangrijkste factoren die bijdragen aan eenzaamheid onder ouderen?
Om te begrijpen hoe we eenzaamheid kunnen aanpakken is het noodzakelijk om te begrijpen waar het vandaan komt. Hierbij is het belangrijk om te kijken
naar wat voor factoren er meespelen in de levens van de ouderen die hieraan kunnen bijdragen. Eenzaamheid kan zowel fysiek als mentaal zijn, dit betekent
dat hoewel het persoon omringt kan zijn met mensen, hij/zij nog steeds gevoelens van eenzaamheid kan ervaren. De oorzaak van emotionele eenzaamheid verschilt
per persoon, en valt niet zo gemakkelijk te verklaren, als te verhelpen. Bij fysieke eenzaamheid is het echter makkelijker om te zien waar het vandaan komt.
Hierbij kunnen er andere omgevingsfactoren meespelen die ervoor zorgen dat het persoon zich eenzaam voelt,
denk hierbij aan het verlies van een partner of vrienden, familieproblematiek of acute verandering van levensstijl ([1. SCP 2018](#bronnen)).
Door dit soort veranderingen kan het zijn dat het persoon in een depressie raakt, wat er weer voor kan zorgen dat het persoon zich eenzaam voelt,
en dat het persoon zich nog meer terugtrekt van de buitenwereld. Dit is een vicieuze cirkel die moeilijk te doorbreken is.
Daarom is het belangrijk om te kijken of er ook methoden zijn om hierbij te helpen, zowel binnen als buitenhuis.
Doordat robots de laatste decennia steeds geavanceerder zijn geworden, is het mogelijk om te overwegen deze toe te passen
in de ouderenzorg om te helpen bij het eenzaamheidsprobleem. Robots worden de afgelopen jaren al steeds meer ingezet om ouderen te helpen
bij bepaalde dagelijkse problemen, zoals het wassen van ouderen in het bad, of het helpen bij eten consumeren ([3. University of Japan, 2017](#bronnen)).
Door de verbeteringen van technologie over de afgelopen jaren heeft K.I. ook een drastische verbetering ondergaan. Hierdoor valt er te overwegen
om deze toe te passen om te helpen met het eenzaamheidsprobleem bij ouderen.
### Op welke manier kunnen we kunstmatige intelligentie inzetten om eenzaamheid onder ouderen te bestrijden?
Zoals al eerder was vermeld worden robots al langer gebruikt bij het helpen van ouderen met huishoudelijke taken die voor hen te zwaar zijn.
Daarom valt het idee ook te overwegen om robots in te zetten om ouderen te helpen met het bestrijden van eenzaamheid. Hiervoor kan er
gebruik gemaakt worden van kunstmatige intelligentie. Kunstmatige intelligentie kan gebruikt worden om de robot te leren hoe het om moet gaan met
de gebruiker, om zowel te horen wat de gebruiker zegt, inhoudelijke reacties te geven op de gebruiker of om de gebruiker te helpen met bepaalde taken als ernaar
gevraagd wordt. Dit kan ervoor zorgen dat de ouderen zich minder eenzaam voelen, en dat ze zich meer op hun gemak voelen in hun eigen huis.
### Hoe kunnen we ervoor zorgen dat dit gedaan kan worden zonder de privacy van ouderen te schenden?
### Conclusie
### Bronnen
1. [Eenzaamheid ouderen](https://repository.scp.nl/bitstream/handle/publications/393/Kwetsbaar%20en%20eenzaam.pdf?sequence=1&isAllowed=y)
2. [Cijfers eenzaamheid onder ouderen](https://www.cbs.nl/nl-nl/nieuws/2023/38/bijna-70-procent-van-ouderen-heeft-minstens-elke-week-contact-met-de-buren)
3. [Inzetten robots in de ouderenzorg](https://digitcult.lim.di.unimi.it/index.php/dc/article/view/54)
4. [Effectiviteit robots in de ouderenzorg](https://essay.utwente.nl/92446/1/Watford-Spence_MA_Behavioural%2C%20Management%20and%20Social%20sciences.pdf)
5. [AI, Privacy and Security](https://www.frontiersin.org/articles/10.3389/frai.2022.826737/full)
6. [Problematic Interactions between AI and Health Privacy](https://heinonline.org/HOL/LandingPage?handle=hein.journals/utahlr2021&div=25&id=&page=)

View File

@@ -0,0 +1,91 @@
**A. ONDERWERP Het thema/vraagstuk van het onderzoek is:**
Ethiek binnen de ICT bij ouderenzorg
**B. AANLEIDING De aanleiding en/of context van het thema/vraagstuk is:**
omdat wij niet weten hoe we met nieuwe technologie om moeten gaan. Dit kan voor veel problemen zorgen als er niet goed over wordt nagedacht. Er is nu nog veel onduidelijkheid over dit onderwerp
**C. AFBAKENING Binnen dit thema beperk ik mij tot het aspect:**
Ouderenzorg en Robotica
**D. DOELSTELLING Het onderzoek levert het volgende op (bijv. kennis die er nu nog niet is in de vorm van een voorstel/ontwerp, of een diagnose van het probleem):**
Ik wil weten of de opdracht waarmee we bezig zijn een ethisch probleem kan vormen.
**C. ETHISCH/MAATSCHAPPELIJK ISSUE Het voor mijn publiek interessante issue dat op het gebied van het afgebakende thema speelt is:**
Is het wel ethisch verantwoord om ouderen in contact te brengen met robots
**G. VRAAGSTELLING 1 - De Hoofdvraag van mijn onderzoek is:**
Welke ethische dilemma's kunnen er vormen bij het gebruik van robotica in de ouderenzorg.
**H. BEGRIPSOMSCHRIJVING De volgende begrippen uit mijn vraagstelling definieer ik als:**
**I. VRAAGSTELLING 2 - De deelvragen van mijn onderzoek zijn:**
# Hoofdvraag
Welke ethische dilemma's kunnen er vormen bij het gebruik van robotica in de ouderenzorg.
# Deelvragen
Wat zijn de mogelijke effecten van robots op het emotionele en sociale welzijn van ouderen?
Kan het gebruik van robots in de ouderenzorg leiden tot een gevoel van dehumanisering of verminderde menselijke interactie voor ouderen?
Welke risico's zijn er op het gebied van veiligheid en privacy voor ouderen bij het gebruik van robots in de zorg?
# Bronnen
Design issues for assistive robotics for the elderly
https://www.sciencedirect.com/science/article/abs/pii/S1474034605000923
|
Socially Assistive Robots in Elderly Care: A Systematic Review into Effects and Effectiveness
https://www.sciencedirect.com/science/article/abs/pii/S1525861010003476
Older adults experiences with and perceptions of the use of socially assistive robots in aged care: A systematic review of quantitative evidence
https://www.sciencedirect.com/science/article/abs/pii/S0167494321000613
The ethical issues of social assistive robotics: A critical literature review
https://www.sciencedirect.com/science/article/pii/S0160791X21002013
Enabling Security Services in Socially Assistive Robot Scenarios for Healthcare Applications
https://www.ncbi.nlm.nih.gov/pmc/articles/PMC8541011/
The concept of social dignity as a yardstick to delimit ethical use of robotic assistance in the care of older persons
https://www.ncbi.nlm.nih.gov/pmc/articles/PMC8614079/
Socially facilitative robots for older adults to alleviate social isolation: A participatory design workshop approach in the US and Japan
https://www.frontiersin.org/journals/psychology/articles/10.3389/fpsyg.2022.904019/full
Ethical Design and Use of Robotic Care of the Elderly
https://www.ncbi.nlm.nih.gov/pmc/articles/PMC8936033/
# inleiding
De vergrijzing van de samenleving zet druk op de ouderenzorg. Er is een tekort aan zorgverleners, terwijl de vraag naar zorg toeneemt. Robotica wordt gezien als een mogelijke oplossing om dit probleem optelossen. Robots kunnen taken overnemen van verpleegsters, zoals medicatie toedienen, lichaamsverzorging en gezelschap bieden. Maar de inzet van robots in de ouderenzorg roept ook ethische dilemma's op. Ik ga onderzoeken welke etische dillemas er kunnen ontstaan in de zorg. Om dit doel te bereiken, zullen we de volgende deelvragen beantwoorden:
- Wat zijn de mogelijke effecten van het gebruik van robots op het emotionele en sociale welzijn van ouderen?
- Leidt robotisering in de ouderenzorg tot onpersoonlijke en mechanische zorg?
- Welke risico's zijn er over de veiligheid en privacy voor ouderen bij het gebruik van robots in de zorg?
Deze vragen behandelen allerei verschillende aspecten van robotica in de ouderzorg. na het beantwoorden van de deelvragen kunnen wij een concusie trekken en kijken naar welke dillemas er kunnen ontstaan.
## Wat zijn de mogelijke effecten van het gebruik van robots op het emotionele en sociale welzijn van ouderen?
Het sociale welzijn van ouderen is een belangrijk onderwerp. Ouderen kunnen zich vaak enzaam of afgesloten voelen van de samenleving. Dit is een groot probleem binnen in de ouderzorg omdat je niet wilt dat ouderen zich nog eenzamer gaan voelen nadat zij worden verzorgd door een robot. Daarom wil ik weten wat de effecten zijn van het gebruik van robotica in de ouderzorg, Zodat ik daaruit kan bepalen wat voor een dillema het met zich mee zou brengen.
Er zijn al veel onderzoeken geweest naar dit onderwerp. Onderzoek wijst uit dat robots zowel positieve als negatieve effecten kunnen hebben. Een postief effect ervan is dat ouderen zich minder eenzaam voelen. 17 onderzoeken met 4 verschillende type robots wijsen erop dat Uit de meeste onderzoeken bleek dat gezelschapsrobots een positieve invloed hadden op (socio)psychologische (bijv. humeur, eenzaamheid, sociale connecties en communicatie) en fysiologische (bijv. stressverlaging) variabelen. De methodologische kwaliteit van de studies was over het algemeen laag.[1] Dit laat zien dat het helpt om eenzaamheid bij ouderen tegentegaan. Ze kunnen ook worden gebruikt om ouderen te helpen in contact te blijven met vrienden en familie. Dit is handig iets omdat ouderen dan dichter bij hun familie zijn wat voor de meeste ouderen heel belangrijk is om eenzaamheid tegen te gaan. Bovendien kunnen robots worden gebruikt om ouderen te motiveren om actief en betrokken te blijven bij hun leven. Fitness is niet alleen iets om fit te blijven maar brengt ook socialen aspecten met zich mee. Ik ben nu persoonlijk bezig met een project waarmee wij ouderen willen stimuleren meer te bewegen zodat zij ook wat vaker naar buiten kunnen en potentieel ook samen workouts kunnen doen.
Over het algemeen zijn de mogelijke effecten van robots op het emotionele en sociale welzijn van ouderen complex. Er zijn zowel mogelijke Voordelen en nadelen, en de impact van robots zal waarschijnlijk van persoon tot persoon verschillen. Het is belangrijk om deze factoren zorgvuldig af te wegen bij het beslissen of robots wel of niet in de ouderzorg te implementeren.
## Kan het gebruik van robots in de ouderenzorg leiden tot een gevoel van dehumanisering of verminderde menselijke interactie voor ouderen?
(Socially Assistive Robots in Elderly Care: A Systematic Review into Effects and Effectiveness https://www.sciencedirect.com/science/article/abs/pii/S1525861010003476)[1]

View File

@@ -0,0 +1,40 @@
# Betoog
Hoofdvraag: Hoe beïnvloedt de opkomst van robots in de ouderenzorg de kwaliteit van leven en menselijke interactie van ouderen
Deelvraag: Wat zijn de taken die robots kunnen overnemen in de ouderenzorg, en hoe verschilt dat met mensenlijke interactie?
Deelvraag: Hoe ervaren ouderen communicatie en interactie met robots en wat zijn de voor en nadelen.
Deelvraag: Welke ethische vragen komen naar boven bij het vervangen van menselijke interactie door robots in de ouderenzorg.
## Inleiding
Dit literatuur onderzoek gaat over de opkomst van robots in de ouderenzorg en de invloed die dit heeft op de ouderen die er mee te maken krijgen. De vraag naar ouderenzorg word veel groter, waardoor de vraag naar personeel ook stijgt. Daarnaast is er ook nog sprake van vergrijzing waardoor de vraag nog meer toeneemd. Omdat er niet genoeg personeel is om de grote vraag te vervullen worden er robots ingezet om de taken van het personeel over te nemen. Wat voor effect heeft deze verandering op de ouderen en is het wel verantwoord om robots in te zetten in de ouderenzorg?
## Taken van robots in de ouderenzorg
Robots kunnen ouderen helpen bij hun dagelijkse activiteiten. Blijkt uit het literatuuroverzicht van [(Pouyan Asgharian)](https://www.mdpi.com/2218-6581/11/6/127). Volgens de schrijvers kunnen deze robots herinneringen, huishoudelijke taken, veiligheid en gezondheidsmonitoring ondersteunen. "mobile social robots could assist older adults throughout their daily activities such as reminding, household tasks, safety, or health monitoring", zegt [(Pouyan Asgharian)](https://www.mdpi.com/2218-6581/11/6/127). Dit laat zien dat robots best veel last kunnen overnemen van het zorgpersoneel.
Aan de andere kant, zoals beschreven in het artikel van [(Frontiers in Robotics and AI, 2021)](https://www.frontiersin.org/articles/10.3389/frobt.2021.605715/full), is de natuurlijke interactie tussen mens en robot complex. Robots moeten niet alleen in staat zijn om de intenties, gevoelens en persoonlijkheden van gebruikers te begrijpen, maar ze moeten ook in staat zijn om op een natuurlijke en medelevende manier te reageren. Dit vereist cognitieve en sociaal-emotionele vaardigheden, evenals geavanceerde redeneer-, perceptie- en leermodules voor robots. Zo zeggen de auteurs dat "In summary, to achieve natural human-robot interaction during cognitive training requires not only multimodal sensing technology and artificial intelligence (e.g., deep learning) but also the development of related fields" [(Frontiers in Robotics and AI, 2021)](https://www.frontiersin.org/articles/10.3389/frobt.2021.605715/full).
## ongebruikte bronnen
* https://digitcult.lim.di.unimi.it/index.php/dc/article/view/54
* https://www.mdpi.com/2076-3417/11/16/7248
* https://www.sciencedirect.com/science/article/pii/S1386505619300498
* https://www.mdpi.com/2075-1702/10/8/622
* https://link.springer.com/article/10.1007/s12652-020-02871-6
* https://www.researchgate.net/profile/Catharina-Wasic-2/publication/345981733_Towards_an_All-Day_Assignment_of_a_Mobile_Service_Robot_for_Elderly_Care_Homes/links/5fb7a5ff92851c933f431a40/Towards-an-All-Day-Assignment-of-a-Mobile-Service-Robot-for-Elderly-Care-Homes.pdf
* https://www.mdpi.com/2218-6581/11/6/127
* https://www.frontiersin.org/articles/10.3389/frobt.2021.605715/full
## bronnen

View File

@@ -1,7 +1,7 @@
# Hoofd en deelvragen met bronnen
## Hoofdvraag
Wat zijn de gevolgen op ouderen door menselijke communicatie vervangen met robots in de ouderenzorg?
Wat zijn de gevolgen op ouderen van menselijke communicatie voor een deel te vervangen met robots in de ouderenzorg?
## Deelvragen
1. Wat zijn de voor en nadelen van robots in de ouderenzorg?

View File

@@ -158,82 +158,56 @@ Done
To do
- Mindmap project
- Issues for sprint 2
- Figma design for the app
Done
-
- Issues for sprint 2
**8 May**
To do
-
- Figma design for the app
- Setup the Pi
Done
-
- Setup the Pi
- Database
- Server
**9 May**
**9-12 May**
To do
-
Done
-
**10 May**
To do
-
Done
-
**11 May**
To do
-
Done
-
**12 May**
To do
-
Done
-
- Hemelvaart/Weekend
**13 May**
To do
-
- Figma design for the app
- Fix database
Done
-
- Fix database
- Figma design for the app
- Implemented design in the app
**14 May**
To do
-
- Ethics research
- Infrastuture, erd and eerd for the database
- Functionality home page app
Done
- Ethics research
- Infrastuture, erd and eerd for the database
-
**15 May**

View File

@@ -91,7 +91,7 @@ In de method `onRobotFocusGained` wordt een `Say` actie gemaakt en uitgevoerd. D
Encapsulation is een princiepe om de interne gegevens van een object te verbergen en alleen toegang te geven via methods.
Voorbeeld: Een bank heeft verschillende methods om geld te storten, geld op te nemen, saldo te controleren, enz. We kunnen niet rechtstreeks toegang krijgen tot de interne gegevens van de bank, zoals de balans, de rekeningnummers, enz. We moeten de methods van de bank gebruiken om deze gegevens te krijgen.
p
Use case:
```java

Some files were not shown because too many files have changed in this diff Show More