From f2724e79f7b79e5a125d52191cedf3590390f605 Mon Sep 17 00:00:00 2001 From: Joel Klimont Date: Thu, 10 Nov 2022 23:14:09 +0100 Subject: [PATCH 01/22] added example code from guide to test --- client/test.py | 55 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/client/test.py b/client/test.py index 0f54f54..4da0034 100644 --- a/client/test.py +++ b/client/test.py @@ -61,6 +61,60 @@ class SeedingApiTest(unittest.TestCase): self.assertEqual(seeding_api.get_logistic_plan(), gamestate.get_logistic_plan()) self.assertEqual(seeding_api.get_material_deliveries(), gamestate.get_material_deliveries()) + def test_gamestate(self): + seed = 42 + gamestate = Seeding.Gamestate(seed) + print(gamestate) + + print(gamestate.get_heuballen()) + heu_color = gamestate.get_heuballen() + if heu_color == 1: + print("Heuballen liegen auf den gelben Linien") + # TODO: code um die über die gelben Linien zu fahren + elif heu_color == 2: + print("Heuballen liegen auf den blauen Linien") + # TODO: code um die über die blauen Linien zu fahren + + materials = gamestate.get_material_deliveries() + print(materials) + + for material_pair in materials: + print(f"Der Roboter sollte jetzt die beiden Materialien {material_pair} holen") + + for material in material_pair: + if material == 0: + print(f"Der Roboter sollte jetzt Holz aufnehmen, Zone: {material}") + # TODO: code um in die Material Zone mit dem Holz zu fahren + elif material == 1: + print(f"Der Roboter sollte jetzt Stahl aufnehmen, Zone: {material}") + # TODO: code um in die Material Zone mit dem Holz zu fahren + elif material == 2: + print(f"Der Roboter sollte jetzt Beton aufnehmen, Zone: {material}") + # TODO: code um in die Material Zone mit dem Holz zu fahren + elif material == 3: + print(f"Der Roboter sollte jetzt Ziegelsteine aufnehmen, Zone: {material}") + # TODO: code um in die Material Zone mit dem Holz zu fahren + + print("Der Roboter sollte jetzt die beiden Materialien zur Baustelle fahren") + # TODO: code um zur Baustelle zu fahren + + logistic_plan = gamestate.get_logistic_plan() + print(logistic_plan) + + for zone in logistic_plan: + if zone == 10: + print(f"Roboter sollte jetzt zur grünen Zone fahren: {zone}") + # TODO: code um in die grüne Zone zu fahren + elif zone == 11: + print(f"Roboter sollte jetzt zur roten Zone fahren: {zone}") + # TODO: code um in die rote Zone zu fahren + elif zone == 12: + print(f"Roboter sollte jetzt zur blauen Zone fahren: {zone}") + # TODO: code um in die blaue Zone zu fahren + elif zone == 13: + print(f"Roboter sollte jetzt zur gelben Zone fahren: {zone}") + # TODO: code um in die gelbe Zone zu fahren + class DeApiTest(unittest.TestCase): def test_api_de(self): @@ -92,6 +146,5 @@ class DeApiTest(unittest.TestCase): self.assertTrue(util_reset_state()) - if __name__ == '__main__': unittest.main() From 765336231b1f89264d9db6a6fa7b565497a50efc Mon Sep 17 00:00:00 2001 From: Joel Klimont Date: Fri, 11 Nov 2022 17:22:01 +0100 Subject: [PATCH 02/22] added updating instructions to documentation --- .../source/gettingStarted/images/09_update.png | Bin 0 -> 152112 bytes client/docs/source/gettingStarted/index.rst | 1 + client/docs/source/gettingStarted/update.rst | 13 +++++++++++++ 3 files changed, 14 insertions(+) create mode 100644 client/docs/source/gettingStarted/images/09_update.png create mode 100644 client/docs/source/gettingStarted/update.rst diff --git a/client/docs/source/gettingStarted/images/09_update.png b/client/docs/source/gettingStarted/images/09_update.png new file mode 100644 index 0000000000000000000000000000000000000000..bd73d23ce4583db77b8a34340094d4ec390dd9d0 GIT binary patch literal 152112 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 Date: Fri, 11 Nov 2022 17:47:40 +0100 Subject: [PATCH 03/22] added env variable to overwrite seeding seed when in competition mode --- README.md | 1 + client/compLib/Seeding.py | 13 ++++++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 4014440..79b1f1f 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,7 @@ pip install sphinx-rtd-theme + `DEBUG`, default="0", If set to != "0" (default), debug prints will be enabled + `API_URL`, default="http://localhost:5000/" + `API_FORCE`, default="", if set to !="" (default), it will replace the API_URL env variable ++ `FORCE_SEED`, default="-1", if set to !="-1" (default), the seeding seed supplied by the user will be ignored and this seed will be used instead # Stream Video diff --git a/client/compLib/Seeding.py b/client/compLib/Seeding.py index 6ac3c2f..2eae33e 100644 --- a/client/compLib/Seeding.py +++ b/client/compLib/Seeding.py @@ -1,8 +1,10 @@ import logging +import os import numpy as np # TODO: if set to competition mode, get the seed from the api +FORCE_SEED = int(os.getenv("FORCE_SEED", "-1")) logger = logging.getLogger("complib-logger") @@ -32,9 +34,14 @@ Logistic Centers: {self.logistic_center}""" :param seed: Seed welcher zum Erstellen des Gamestates benutzt werden soll. """ - logger.debug(f"Creating gamestate with seed: {seed}") - self.seed = seed - self.__set_random_seed(seed) + if FORCE_SEED == -1: + self.seed = seed + else: + print(f"Wettkampfmodus, zufälliger Seed wird verwendet: Seed={FORCE_SEED}") + self.seed = FORCE_SEED + + logger.debug(f"Creating gamestate with seed: {self.seed}") + self.__set_random_seed(self.seed) self.heu_color = self.__get_random_number(1, 2) From 9e589fd681d04641f30b71a1b098d83ecf9f3899 Mon Sep 17 00:00:00 2001 From: Konstantin Lampalzer Date: Sun, 13 Nov 2022 02:52:30 +0100 Subject: [PATCH 04/22] Change motor speed to cm/s --- client/compLib/Motor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/compLib/Motor.py b/client/compLib/Motor.py index 9d13aa2..3529ba1 100644 --- a/client/compLib/Motor.py +++ b/client/compLib/Motor.py @@ -62,7 +62,7 @@ class Motor(object): """Geschwindigkeit des Motors einstellen :param port: Port, an welchen der Motor angesteckt ist. 0-3 - :param speed: Drehzahl, mit der sich ein Motor dreht, in Radianten pro Sekunde (rad/s) + :param speed: Drehzahl, mit der sich ein Motor dreht, in Centimeter pro Sekunde (cm/s) :raises: IndexError """ From ee4f6a516d767618b8b2f0a44340bd555ae9e7c3 Mon Sep 17 00:00:00 2001 From: Konstantin Lampalzer Date: Fri, 18 Nov 2022 15:47:47 +0100 Subject: [PATCH 05/22] Update faq --- client/docs/source/faq.rst | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/client/docs/source/faq.rst b/client/docs/source/faq.rst index 8573755..2e2f4b3 100644 --- a/client/docs/source/faq.rst +++ b/client/docs/source/faq.rst @@ -12,4 +12,21 @@ See :ref:`gettingstarted_codeserver` Was ist der Benutzername und das Passwort für den Raspberry Pi? --------------------------------------------------------------- -``compair`` ``compair`` \ No newline at end of file +``compair`` ``compair`` + +Wie aktualisiere ich meine Software? +------------------------------------ + +.. code-block:: bash + + sudo apt update + sudo apt upgrade + sudo update-firmware + +Wie kann ich die SD-Karte neu beschreiben? +------------------------------------------ +`SD-Karten Image `_ + +Software zum Schreiben der SD-Karte `balenaEtcher `_ + + From f03df1b3b3f93688ec24cdda93890c10dc597031 Mon Sep 17 00:00:00 2001 From: Joel Klimont Date: Fri, 18 Nov 2022 17:19:40 +0100 Subject: [PATCH 06/22] updated opencv documentation (camera module) added enabling of legacy support for the camera module to the postinstall script --- client/compLib/Camera.py | 4 +--- client/docs/source/lib/classes/Opencv.rst | 13 +++++++++++++ client/docs/source/lib/index.rst | 1 + client/postinstall.sh | 2 ++ 4 files changed, 17 insertions(+), 3 deletions(-) create mode 100644 client/docs/source/lib/classes/Opencv.rst diff --git a/client/compLib/Camera.py b/client/compLib/Camera.py index 125fe8b..3a7d764 100644 --- a/client/compLib/Camera.py +++ b/client/compLib/Camera.py @@ -1,7 +1,5 @@ import sys -from typing import Tuple, Any - -import numpy as np +from typing import Any # build image is somehow different from raspberry image? opencv-python is installed to a directory which is not in the pythonpath by default.... sys.path.append("/usr/lib/python3.9/site-packages") diff --git a/client/docs/source/lib/classes/Opencv.rst b/client/docs/source/lib/classes/Opencv.rst new file mode 100644 index 0000000..bd299c1 --- /dev/null +++ b/client/docs/source/lib/classes/Opencv.rst @@ -0,0 +1,13 @@ +.. _lib_camera: + +Camera und OpenCV +******************* + +Dokumentation des Camera Moduls +================================ + +.. autoclass:: compLib.Camera.Marker + :members: + +.. autoclass:: compLib.Camera.Camera + :members: diff --git a/client/docs/source/lib/index.rst b/client/docs/source/lib/index.rst index 4ca5dec..d781e5e 100644 --- a/client/docs/source/lib/index.rst +++ b/client/docs/source/lib/index.rst @@ -9,3 +9,4 @@ compLib classes/IRSensor classes/Seeding classes/DoubleElimination + classes/Opencv diff --git a/client/postinstall.sh b/client/postinstall.sh index 2612645..a6a94da 100644 --- a/client/postinstall.sh +++ b/client/postinstall.sh @@ -9,6 +9,8 @@ pip3 install requests flask echo "Setting up nginx rtmp server" sudo /etc/init.d/nginx start +sudo raspi-config nonint do_legacy 0 + { echo 'load_module "modules/ngx_rtmp_module.so";' echo 'worker_processes auto;' From 13eefdceb17d423ca34b16a684da4ea10bdc734e Mon Sep 17 00:00:00 2001 From: Joel Klimont Date: Sat, 19 Nov 2022 01:42:11 +0100 Subject: [PATCH 07/22] fixed a bug where the postinstall script would fail, if "raspi-config" is not installed on the system --- client/postinstall.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/postinstall.sh b/client/postinstall.sh index a6a94da..cf9ce4b 100644 --- a/client/postinstall.sh +++ b/client/postinstall.sh @@ -9,7 +9,7 @@ pip3 install requests flask echo "Setting up nginx rtmp server" sudo /etc/init.d/nginx start -sudo raspi-config nonint do_legacy 0 +sudo raspi-config nonint do_legacy 0 || echo "(WARNING) raspi-config not found, cannot enable legacy camera support" { echo 'load_module "modules/ngx_rtmp_module.so";' From 19d98f1f04007a5b5177c1db518ecc68438b584a Mon Sep 17 00:00:00 2001 From: Joel Klimont Date: Thu, 24 Nov 2022 15:32:15 +0100 Subject: [PATCH 08/22] nginx server is now stopped, as it is not needed anymore --- client/postinstall.sh | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/client/postinstall.sh b/client/postinstall.sh index cf9ce4b..e82bcd3 100644 --- a/client/postinstall.sh +++ b/client/postinstall.sh @@ -6,8 +6,8 @@ fi pip3 install requests flask -echo "Setting up nginx rtmp server" -sudo /etc/init.d/nginx start +#echo "Setting up nginx rtmp server" +#sudo /etc/init.d/nginx start sudo raspi-config nonint do_legacy 0 || echo "(WARNING) raspi-config not found, cannot enable legacy camera support" @@ -28,6 +28,9 @@ sudo raspi-config nonint do_legacy 0 || echo "(WARNING) raspi-config not found, echo '}' } >| /etc/nginx/nginx.conf +echo "Stopping nginx rtmp server as its not required anymore" +sudo /etc/init.d/nginx stop + base64 -d << UPD CiBfX19fX18gICAgIF9fX19fXyAgICAgX18gICAgX18gICAgIF9fX19fXyAgIF9fICAgICAgICAgX18gICAgIF9fX19fXyAgICAgICAgICAgICAgICAgIAovXCAgX19fXCAgIC9cICBfXyBcICAgL1wgIi0uLyAgXCAgIC9cICA9PSBcIC9cIFwgICAgICAgL1wgXCAgIC9cICA9PSBcICAgICAgICAgICAgICAgICAKXCBcIFxfX19fICBcIFwgXC9cIFwgIFwgXCBcLS4vXCBcICBcIFwgIF8tLyBcIFwgXF9fX18gIFwgXCBcICBcIFwgIF9fPCAgICAgICAgICAgICAgICAgCiBcIFxfX19fX1wgIFwgXF9fX19fXCAgXCBcX1wgXCBcX1wgIFwgXF9cICAgIFwgXF9fX19fXCAgXCBcX1wgIFwgXF9fX19fXCAgICAgICAgICAgICAgIAogIFwvX19fX18vICAgXC9fX19fXy8gICBcL18vICBcL18vICAgXC9fLyAgICAgXC9fX19fXy8gICBcL18vICAgXC9fX19fXy8gICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiBfXyAgX18gICAgIF9fX19fXyAgICAgIF9fX19fXyAgIF9fX19fXyAgICAgICAgX19fX18gICAgIF9fX19fXyAgICAgX19fX19fICAgX19fX19fICAgIAovXCBcL1wgXCAgIC9cICA9PSBcICAgIC9cX18gIF9cIC9cICBfXyBcICAgICAgL1wgIF9fLS4gIC9cICBfXyBcICAgL1xfXyAgX1wgL1wgIF9fX1wgICAKXCBcIFxfXCBcICBcIFwgIF8tLyAgICBcL18vXCBcLyBcIFwgXC9cIFwgICAgIFwgXCBcL1wgXCBcIFwgIF9fIFwgIFwvXy9cIFwvIFwgXCAgX19cICAgCiBcIFxfX19fX1wgIFwgXF9cICAgICAgICAgXCBcX1wgIFwgXF9fX19fXCAgICAgXCBcX19fXy0gIFwgXF9cIFxfXCAgICBcIFxfXCAgXCBcX19fX19cIAogIFwvX19fX18vICAgXC9fLyAgICAgICAgICBcL18vICAgXC9fX19fXy8gICAgICBcL19fX18vICAgXC9fL1wvXy8gICAgIFwvXy8gICBcL19fX19fLyA= UPD From 4c24717278c39b62dc42a4c88bfcca4f98618444 Mon Sep 17 00:00:00 2001 From: Konstantin Lampalzer Date: Sat, 17 Dec 2022 23:40:07 +0100 Subject: [PATCH 09/22] Skip posinstall on x86_64 --- client/postinstall.sh | 7 +++++++ 1 file changed, 7 insertions(+) mode change 100644 => 100755 client/postinstall.sh diff --git a/client/postinstall.sh b/client/postinstall.sh old mode 100644 new mode 100755 index e82bcd3..f2a5b39 --- a/client/postinstall.sh +++ b/client/postinstall.sh @@ -1,3 +1,10 @@ +#!/usr/bin/env bash + +if [[ $(uname -m) == "x86_64" ]]; then + echo "Not running on RPi - Skipping postinstall" + exit 0 +fi + grep -qxF "apt update" /etc/rc.local if [ $? -ne 0 ]; then echo "adding apt update to rc.local" From c02cfcd71c44c53fc164bbf70af70c64c0470bd7 Mon Sep 17 00:00:00 2001 From: Konstantin Lampalzer Date: Sat, 17 Dec 2022 23:59:06 +0100 Subject: [PATCH 10/22] Move client foler --- client/.gitignore => .gitignore | 0 {client/.idea => .idea}/.gitignore | 0 {client/.idea => .idea}/client_s2.iml | 0 .../inspectionProfiles/Project_Default.xml | 0 .../inspectionProfiles/profiles_settings.xml | 0 {client/.idea => .idea}/misc.xml | 0 {client/.idea => .idea}/modules.xml | 0 .../.idea => .idea}/saveactions_settings.xml | 0 {client/.idea => .idea}/vcs.xml | 0 client/MANIFEST.in => MANIFEST.in | 0 build.sh | 1 - client/build_deb.sh => build_deb.sh | 0 client/dev01.py | 24 --- client/dev03.py | 34 ---- client/lf.py | 96 ---------- client/main.py | 174 ------------------ {client/compLib => compLib}/.gitignore | 0 {client/compLib => compLib}/Api.py | 0 {client/compLib => compLib}/Camera.py | 0 {client/compLib => compLib}/CompLib.proto | 0 {client/compLib => compLib}/CompLibClient.py | 0 {client/compLib => compLib}/CompLib_pb2.py | 0 .../compLib => compLib}/DoubleElimination.py | 0 {client/compLib => compLib}/Encoder.py | 0 {client/compLib => compLib}/HealthCheck.py | 0 {client/compLib => compLib}/IRSensor.py | 0 {client/compLib => compLib}/Motor.py | 0 {client/compLib => compLib}/Movement.py | 0 {client/compLib => compLib}/Seeding.py | 0 {client/compLib => compLib}/__init__.py | 0 {client/docs => docs}/.gitignore | 0 {client/docs => docs}/Makefile | 0 {client/docs => docs}/make.bat | 0 {client/docs => docs}/source/_static/.gitkeep | 0 {client/docs => docs}/source/conf.py | 0 {client/docs => docs}/source/faq.rst | 0 .../source/gettingStarted/codeServer.rst | 0 .../source/gettingStarted/firstProgram.rst | 0 .../source/gettingStarted/images/01_boot.png | Bin .../source/gettingStarted/images/02_psk.png | Bin .../images/03_codeServerFile.png | Bin .../images/04_codeServerRun.png | Bin .../images/05_codeServerTerminal.png | Bin .../images/06_codeServerFolder.png | Bin .../gettingStarted/images/07_irSensor.webp | Bin .../gettingStarted/images/08_notepad.png | Bin .../gettingStarted/images/09_update.png | Bin .../source/gettingStarted/index.rst | 0 .../source/gettingStarted/secondProgram.rst | 0 .../source/gettingStarted/thridProgram.rst | 0 .../source/gettingStarted/update.rst | 0 .../source/gettingStarted/wifi.rst | 0 .../source/images/compair-logo-white.svg | 0 {client/docs => docs}/source/index.rst | 0 .../source/lib/classes/DoubleElimination.rst | 0 .../source/lib/classes/Encoder.rst | 0 .../source/lib/classes/IRSensor.rst | 0 .../source/lib/classes/Motor.rst | 0 .../source/lib/classes/Opencv.rst | 0 .../source/lib/classes/Seeding.rst | 0 .../source/lib/classes/images/chessboard.jpg | Bin .../classes/images/chessboard_detected.jpg | Bin .../lib/classes/images/opencv_http_stream.png | Bin .../lib/classes/images/opencv_processed.png | Bin {client/docs => docs}/source/lib/index.rst | 0 .../docs => docs}/source/other/hardware.rst | 0 .../source/other/images/Mainboard.png | Bin .../source/other/images/Sensorarray.png | Bin {client/docs => docs}/source/other/usage.rst | 0 .../source/software/installation.rst | 0 ...rLinearityTest.py => motorLinearityTest.py | 0 client/postinstall.sh => postinstall.sh | 0 client/setup.py => setup.py | 0 ...sphinx_to_github.sh => sphinx_to_github.sh | 0 client/test.py => test.py | 0 75 files changed, 329 deletions(-) rename client/.gitignore => .gitignore (100%) rename {client/.idea => .idea}/.gitignore (100%) rename {client/.idea => .idea}/client_s2.iml (100%) rename {client/.idea => .idea}/inspectionProfiles/Project_Default.xml (100%) rename {client/.idea => .idea}/inspectionProfiles/profiles_settings.xml (100%) rename {client/.idea => .idea}/misc.xml (100%) rename {client/.idea => .idea}/modules.xml (100%) rename {client/.idea => .idea}/saveactions_settings.xml (100%) rename {client/.idea => .idea}/vcs.xml (100%) rename client/MANIFEST.in => MANIFEST.in (100%) rename client/build_deb.sh => build_deb.sh (100%) delete mode 100644 client/dev01.py delete mode 100644 client/dev03.py delete mode 100644 client/lf.py delete mode 100644 client/main.py rename {client/compLib => compLib}/.gitignore (100%) rename {client/compLib => compLib}/Api.py (100%) rename {client/compLib => compLib}/Camera.py (100%) rename {client/compLib => compLib}/CompLib.proto (100%) rename {client/compLib => compLib}/CompLibClient.py (100%) rename {client/compLib => compLib}/CompLib_pb2.py (100%) rename {client/compLib => compLib}/DoubleElimination.py (100%) rename {client/compLib => compLib}/Encoder.py (100%) rename {client/compLib => compLib}/HealthCheck.py (100%) rename {client/compLib => compLib}/IRSensor.py (100%) rename {client/compLib => compLib}/Motor.py (100%) rename {client/compLib => compLib}/Movement.py (100%) rename {client/compLib => compLib}/Seeding.py (100%) rename {client/compLib => compLib}/__init__.py (100%) rename {client/docs => docs}/.gitignore (100%) rename {client/docs => docs}/Makefile (100%) rename {client/docs => docs}/make.bat (100%) rename {client/docs => docs}/source/_static/.gitkeep (100%) rename {client/docs => docs}/source/conf.py (100%) rename {client/docs => docs}/source/faq.rst (100%) rename {client/docs => docs}/source/gettingStarted/codeServer.rst (100%) rename {client/docs => docs}/source/gettingStarted/firstProgram.rst (100%) rename {client/docs => docs}/source/gettingStarted/images/01_boot.png (100%) rename {client/docs => docs}/source/gettingStarted/images/02_psk.png (100%) rename {client/docs => docs}/source/gettingStarted/images/03_codeServerFile.png (100%) rename {client/docs => docs}/source/gettingStarted/images/04_codeServerRun.png (100%) rename {client/docs => docs}/source/gettingStarted/images/05_codeServerTerminal.png (100%) rename {client/docs => docs}/source/gettingStarted/images/06_codeServerFolder.png (100%) rename {client/docs => docs}/source/gettingStarted/images/07_irSensor.webp (100%) rename {client/docs => docs}/source/gettingStarted/images/08_notepad.png (100%) rename {client/docs => docs}/source/gettingStarted/images/09_update.png (100%) rename {client/docs => docs}/source/gettingStarted/index.rst (100%) rename {client/docs => docs}/source/gettingStarted/secondProgram.rst (100%) rename {client/docs => docs}/source/gettingStarted/thridProgram.rst (100%) rename {client/docs => docs}/source/gettingStarted/update.rst (100%) rename {client/docs => docs}/source/gettingStarted/wifi.rst (100%) rename {client/docs => docs}/source/images/compair-logo-white.svg (100%) rename {client/docs => docs}/source/index.rst (100%) rename {client/docs => docs}/source/lib/classes/DoubleElimination.rst (100%) rename {client/docs => docs}/source/lib/classes/Encoder.rst (100%) rename {client/docs => docs}/source/lib/classes/IRSensor.rst (100%) rename {client/docs => docs}/source/lib/classes/Motor.rst (100%) rename {client/docs => docs}/source/lib/classes/Opencv.rst (100%) rename {client/docs => docs}/source/lib/classes/Seeding.rst (100%) rename {client/docs => docs}/source/lib/classes/images/chessboard.jpg (100%) rename {client/docs => docs}/source/lib/classes/images/chessboard_detected.jpg (100%) rename {client/docs => docs}/source/lib/classes/images/opencv_http_stream.png (100%) rename {client/docs => docs}/source/lib/classes/images/opencv_processed.png (100%) rename {client/docs => docs}/source/lib/index.rst (100%) rename {client/docs => docs}/source/other/hardware.rst (100%) rename {client/docs => docs}/source/other/images/Mainboard.png (100%) rename {client/docs => docs}/source/other/images/Sensorarray.png (100%) rename {client/docs => docs}/source/other/usage.rst (100%) rename {client/docs => docs}/source/software/installation.rst (100%) rename client/motorLinearityTest.py => motorLinearityTest.py (100%) rename client/postinstall.sh => postinstall.sh (100%) rename client/setup.py => setup.py (100%) rename client/sphinx_to_github.sh => sphinx_to_github.sh (100%) rename client/test.py => test.py (100%) diff --git a/client/.gitignore b/.gitignore similarity index 100% rename from client/.gitignore rename to .gitignore diff --git a/client/.idea/.gitignore b/.idea/.gitignore similarity index 100% rename from client/.idea/.gitignore rename to .idea/.gitignore diff --git a/client/.idea/client_s2.iml b/.idea/client_s2.iml similarity index 100% rename from client/.idea/client_s2.iml rename to .idea/client_s2.iml diff --git a/client/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml similarity index 100% rename from client/.idea/inspectionProfiles/Project_Default.xml rename to .idea/inspectionProfiles/Project_Default.xml diff --git a/client/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml similarity index 100% rename from client/.idea/inspectionProfiles/profiles_settings.xml rename to .idea/inspectionProfiles/profiles_settings.xml diff --git a/client/.idea/misc.xml b/.idea/misc.xml similarity index 100% rename from client/.idea/misc.xml rename to .idea/misc.xml diff --git a/client/.idea/modules.xml b/.idea/modules.xml similarity index 100% rename from client/.idea/modules.xml rename to .idea/modules.xml diff --git a/client/.idea/saveactions_settings.xml b/.idea/saveactions_settings.xml similarity index 100% rename from client/.idea/saveactions_settings.xml rename to .idea/saveactions_settings.xml diff --git a/client/.idea/vcs.xml b/.idea/vcs.xml similarity index 100% rename from client/.idea/vcs.xml rename to .idea/vcs.xml diff --git a/client/MANIFEST.in b/MANIFEST.in similarity index 100% rename from client/MANIFEST.in rename to MANIFEST.in diff --git a/build.sh b/build.sh index 657ddf0..f9f3020 100644 --- a/build.sh +++ b/build.sh @@ -4,7 +4,6 @@ mkdir output DEB="empty" -cd client source build_deb.sh echo "Ran build deb, created: $DEB" mv $DEB ../output diff --git a/client/build_deb.sh b/build_deb.sh similarity index 100% rename from client/build_deb.sh rename to build_deb.sh diff --git a/client/dev01.py b/client/dev01.py deleted file mode 100644 index 6ebfb8c..0000000 --- a/client/dev01.py +++ /dev/null @@ -1,24 +0,0 @@ -import time - -from compLib.CompLibClient import CompLibClient - - -def main(): - from compLib.Motor import Motor - - # Motor.speed(0, -50) - # Motor.speed(3, 50) - - Motor.power(0, 50) - Motor.power(3, -50) - - time.sleep(2) - - Motor.power(0, 0) - Motor.power(3, -0) - - -if __name__ == '__main__': - CompLibClient.use_tcp_socket("dev01.local") - # follow() - main() diff --git a/client/dev03.py b/client/dev03.py deleted file mode 100644 index d4ed808..0000000 --- a/client/dev03.py +++ /dev/null @@ -1,34 +0,0 @@ -import time - -from compLib.CompLibClient import CompLibClient -from compLib.IRSensor import IRSensor - - -def main(): - # Motor.speed(0, -50) - # Motor.speed(3, 50) - - # Motor.power(0, 50) - # Motor.power(3, -50) - # - # time.sleep(2) - # - # Motor.power(0, 0) - # Motor.power(3, -0) - - start_time = time.time() - for i in range(0, 1000): - IRSensor.read_all() - # Motor.multiple_power((0, 1), (3, 1)) - # Motor.speed(0, 1) - # Motor.speed(3, 1) - - print(1000.0 / (time.time() - start_time)) - - -if __name__ == '__main__': - # CompLibClient.use_tcp_socket("dev03.local") - CompLibClient.use_unix_socket() - # follow() - # cProfile.run("main()") - main() diff --git a/client/lf.py b/client/lf.py deleted file mode 100644 index 7476dc9..0000000 --- a/client/lf.py +++ /dev/null @@ -1,96 +0,0 @@ -from compLib.Motor import Motor -from compLib.IRSensor import IRSensor -from compLib.CompLibClient import CompLibClient - -import time -import math - -DRIVE_SPEED = 20.0 -COLOR_BREAK = 850 -KP = 7.5 -KD = 0.0 - -SAMPLE_TIME_S = 0.001 -CUTOFF_FREQ_HZ = 50.0 - -RC = 1.0 / (2.0 * math.pi * CUTOFF_FREQ_HZ) - -FIRST_COEFF = SAMPLE_TIME_S / (SAMPLE_TIME_S + RC) -SECOND_COEFF = RC / (SAMPLE_TIME_S + RC) - -out_old = 0.0 -start_time = time.time() - - -def drive(leftSpeed, rightSpeed): - rightSpeed *= -0.906 - - Motor.multiple_power((0, min(max(-100, rightSpeed), 100)), (3, min(max(-100, leftSpeed), 100))) - -def follow(sleepTime = 0.3): - global out_old - lastError = 0 - sensorsBlack = 0 - while sensorsBlack < 3: - sensor_data = IRSensor.read_all() - - sensorsBlack = 0 - for i in range(0, 5): - if sensor_data[i] > COLOR_BREAK: - sensorsBlack += 1 - - - middle_sensor = sensor_data[2] - filtered_sensor = FIRST_COEFF * middle_sensor + SECOND_COEFF * out_old - out_old = filtered_sensor - - sample_time = str(time.time() - start_time).replace(".", ",") - print(f"{sample_time} {middle_sensor} {int(filtered_sensor)}") - - error = lastError - if sensor_data[2] > COLOR_BREAK: - error = 0 - elif sensor_data[0] > COLOR_BREAK: - error = -1.5 - elif sensor_data[4] > COLOR_BREAK: - error = 1.5 - elif sensor_data[1] > COLOR_BREAK: - error = -1 - elif sensor_data[3] > COLOR_BREAK: - error = 1 - elif error == 1.5: - error = 3 - elif error == -1.5: - error = -3 - - lastError = error - - adjustment = KP * error + KD * (error - lastError) - leftSpeed = DRIVE_SPEED + adjustment - rightSpeed = DRIVE_SPEED - adjustment - - # print(f"{leftSpeed} {rightSpeed} {adjustment} {error}") - drive(leftSpeed, rightSpeed) - - time.sleep(SAMPLE_TIME_S) - - drive(0, 0) - time.sleep(sleepTime) - -def main(): - CompLibClient.use_unix_socket() - - IRSensor.enable() - time.sleep(0.5) - - # while True: - # print(IRSensor.read_all()) - # time.sleep(0.01) - - follow() - follow() - follow() - follow() - follow(0.2) - -main() \ No newline at end of file diff --git a/client/main.py b/client/main.py deleted file mode 100644 index 7e75006..0000000 --- a/client/main.py +++ /dev/null @@ -1,174 +0,0 @@ -import time - -from compLib.CompLibClient import CompLibClient - - -# def send(data, size): -# with socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) as sock: -# sock.connect(SOCKET_PATH) -# sock.sendall(size.to_bytes(1, byteorder='big')) -# sock.sendall(data) -# -# response_size_bytes = sock.recv(1) -# response_size = int.from_bytes(response_size_bytes, byteorder="big") -# # print(f"Response size: {response_size}") -# -# response_bytes = sock.recv(response_size) -# generic_response = CompLib_pb2.GenericResponse() -# -# generic_response.ParseFromString(response_bytes) -# # print(f"Response: {generic_response}") -# -# # reponseBytes = - - -def main(): - # encoder_read_positions_request = CompLib_pb2.EncoderReadPositionsRequest() - # # readSensorsRequest.header = CompLib_pb2.Header() - # encoder_read_positions_request.header.message_type = encoder_read_positions_request.DESCRIPTOR.full_name - # - # start_time = time.time() - # for i in range(100000): - # send(encoder_read_positions_request.SerializeToString(), encoder_read_positions_request.ByteSize()) - # print("--- %s seconds ---" % (time.time() - start_time)) - - from compLib.IRSensor import IRSensor - IRSensor.enable() - - startTime = time.time() - while time.time() - startTime < 10: - print(IRSensor.read_all()) - time.sleep(0.01) - - # from compLib.Encoder import Encoder - # print(Encoder.read_all_positions()) - # print(Encoder.read_all_velocities()) - - # from compLib.Motor import Motor - - # Motor.speed(0, -50) - # Motor.speed(3, 50) - - # Motor.power(0, -50) - # Motor.power(3, 50) - - # time.sleep(5) - - -# -# import time -# time.sleep(2) -# -# Motor.speed(0, 0) -# Motor.speed(3, -0) - -# Motor.power(0, 0) -# Motor.power(3, 0) - -# import math -# from compLib.Movement import Movement -# Movement.turn_degrees(90, math.pi * 2) -# Movement.turn_degrees(-90, math.pi * 2) -# -# Movement.turn_degrees(90, math.pi * 2) -# Movement.turn_degrees(90, -math.pi * 2) -# -# Movement.turn_degrees(90, math.pi * 2) -# Movement.turn_degrees(-90, -math.pi * 2) - -# from compLib.Movement import Movement -# Movement.drive_distance(0.1, 0.5) -# Movement.drive_distance(-0.1, 0.5) -# -# Movement.drive_distance(0.1, 0.5) -# Movement.drive_distance(0.1, -0.5) -# -# Movement.drive_distance(0.1, 0.5) -# Movement.drive_distance(-0.1, -0.5) - -# from compLib.Movement import Movement -# import math -# import time -# Movement.drive_distance(0.5, 0.5) -# time.sleep(1) -# Movement.turn_degrees(90, math.pi * 2) -# time.sleep(1) -# -# Movement.drive_distance(0.5, 0.5) -# time.sleep(1) -# Movement.turn_degrees(90, math.pi * 2) -# time.sleep(1) -# -# Movement.drive_distance(0.5, 0.5) -# time.sleep(1) -# Movement.turn_degrees(90, math.pi * 2) -# time.sleep(1) -# -# Movement.drive_distance(0.5, 0.5) -# time.sleep(1) -# Movement.turn_degrees(90, math.pi * 2) -# time.sleep(1) - -# import time -# -# from compLib.IRSensor import IRSensor -# from compLib.Motor import Motor -# -# IRSensor.enable() -# -# DRIVE_SPEED = 2.0 -# COLOR_BREAK = 900 -# KP = 0.25 -# KD = 0.0 -# -# -# def drive(leftSpeed, rightSpeed): -# Motor.speed(0, -rightSpeed) -# Motor.power(3, leftSpeed) -# -# -# def follow(sleepTime=0.1): -# lastError = 0 -# sensorsBlack = 0 -# -# while sensorsBlack < 3: -# data = IRSensor.read_all() -# -# sensorsBlack = 0 -# for i in range(len(data)): -# if data[i] > COLOR_BREAK: -# sensorsBlack += 1 -# -# error = lastError -# if data[2] > COLOR_BREAK: -# error = 0 -# elif data[0] > COLOR_BREAK: -# error = -1.5 -# elif data[4] > COLOR_BREAK: -# error = 1.5 -# elif data[1] > COLOR_BREAK: -# error = -1 -# elif data[3] > COLOR_BREAK: -# error = 1 -# elif error == 1.5: -# error = 3 -# elif error == -1.5: -# error = -3 -# -# lastError = error -# -# adjustment = KP * error + KD * (error - lastError) -# leftSpeed = DRIVE_SPEED + adjustment -# rightSpeed = DRIVE_SPEED - adjustment -# -# print(f"{leftSpeed} {rightSpeed} {adjustment} {error}") -# drive(leftSpeed, rightSpeed) -# -# drive(0, 0) -# time.sleep(sleepTime) - - -if __name__ == '__main__': - CompLibClient.use_tcp_socket("dev03.local") - # follow() - main() diff --git a/client/compLib/.gitignore b/compLib/.gitignore similarity index 100% rename from client/compLib/.gitignore rename to compLib/.gitignore diff --git a/client/compLib/Api.py b/compLib/Api.py similarity index 100% rename from client/compLib/Api.py rename to compLib/Api.py diff --git a/client/compLib/Camera.py b/compLib/Camera.py similarity index 100% rename from client/compLib/Camera.py rename to compLib/Camera.py diff --git a/client/compLib/CompLib.proto b/compLib/CompLib.proto similarity index 100% rename from client/compLib/CompLib.proto rename to compLib/CompLib.proto diff --git a/client/compLib/CompLibClient.py b/compLib/CompLibClient.py similarity index 100% rename from client/compLib/CompLibClient.py rename to compLib/CompLibClient.py diff --git a/client/compLib/CompLib_pb2.py b/compLib/CompLib_pb2.py similarity index 100% rename from client/compLib/CompLib_pb2.py rename to compLib/CompLib_pb2.py diff --git a/client/compLib/DoubleElimination.py b/compLib/DoubleElimination.py similarity index 100% rename from client/compLib/DoubleElimination.py rename to compLib/DoubleElimination.py diff --git a/client/compLib/Encoder.py b/compLib/Encoder.py similarity index 100% rename from client/compLib/Encoder.py rename to compLib/Encoder.py diff --git a/client/compLib/HealthCheck.py b/compLib/HealthCheck.py similarity index 100% rename from client/compLib/HealthCheck.py rename to compLib/HealthCheck.py diff --git a/client/compLib/IRSensor.py b/compLib/IRSensor.py similarity index 100% rename from client/compLib/IRSensor.py rename to compLib/IRSensor.py diff --git a/client/compLib/Motor.py b/compLib/Motor.py similarity index 100% rename from client/compLib/Motor.py rename to compLib/Motor.py diff --git a/client/compLib/Movement.py b/compLib/Movement.py similarity index 100% rename from client/compLib/Movement.py rename to compLib/Movement.py diff --git a/client/compLib/Seeding.py b/compLib/Seeding.py similarity index 100% rename from client/compLib/Seeding.py rename to compLib/Seeding.py diff --git a/client/compLib/__init__.py b/compLib/__init__.py similarity index 100% rename from client/compLib/__init__.py rename to compLib/__init__.py diff --git a/client/docs/.gitignore b/docs/.gitignore similarity index 100% rename from client/docs/.gitignore rename to docs/.gitignore diff --git a/client/docs/Makefile b/docs/Makefile similarity index 100% rename from client/docs/Makefile rename to docs/Makefile diff --git a/client/docs/make.bat b/docs/make.bat similarity index 100% rename from client/docs/make.bat rename to docs/make.bat diff --git a/client/docs/source/_static/.gitkeep b/docs/source/_static/.gitkeep similarity index 100% rename from client/docs/source/_static/.gitkeep rename to docs/source/_static/.gitkeep diff --git a/client/docs/source/conf.py b/docs/source/conf.py similarity index 100% rename from client/docs/source/conf.py rename to docs/source/conf.py diff --git a/client/docs/source/faq.rst b/docs/source/faq.rst similarity index 100% rename from client/docs/source/faq.rst rename to docs/source/faq.rst diff --git a/client/docs/source/gettingStarted/codeServer.rst b/docs/source/gettingStarted/codeServer.rst similarity index 100% rename from client/docs/source/gettingStarted/codeServer.rst rename to docs/source/gettingStarted/codeServer.rst diff --git a/client/docs/source/gettingStarted/firstProgram.rst b/docs/source/gettingStarted/firstProgram.rst similarity index 100% rename from client/docs/source/gettingStarted/firstProgram.rst rename to docs/source/gettingStarted/firstProgram.rst diff --git a/client/docs/source/gettingStarted/images/01_boot.png b/docs/source/gettingStarted/images/01_boot.png similarity index 100% rename from client/docs/source/gettingStarted/images/01_boot.png rename to docs/source/gettingStarted/images/01_boot.png diff --git a/client/docs/source/gettingStarted/images/02_psk.png b/docs/source/gettingStarted/images/02_psk.png similarity index 100% rename from client/docs/source/gettingStarted/images/02_psk.png rename to docs/source/gettingStarted/images/02_psk.png diff --git a/client/docs/source/gettingStarted/images/03_codeServerFile.png b/docs/source/gettingStarted/images/03_codeServerFile.png similarity index 100% rename from client/docs/source/gettingStarted/images/03_codeServerFile.png rename to docs/source/gettingStarted/images/03_codeServerFile.png diff --git a/client/docs/source/gettingStarted/images/04_codeServerRun.png b/docs/source/gettingStarted/images/04_codeServerRun.png similarity index 100% rename from client/docs/source/gettingStarted/images/04_codeServerRun.png rename to docs/source/gettingStarted/images/04_codeServerRun.png diff --git a/client/docs/source/gettingStarted/images/05_codeServerTerminal.png b/docs/source/gettingStarted/images/05_codeServerTerminal.png similarity index 100% rename from client/docs/source/gettingStarted/images/05_codeServerTerminal.png rename to docs/source/gettingStarted/images/05_codeServerTerminal.png diff --git a/client/docs/source/gettingStarted/images/06_codeServerFolder.png b/docs/source/gettingStarted/images/06_codeServerFolder.png similarity index 100% rename from client/docs/source/gettingStarted/images/06_codeServerFolder.png rename to docs/source/gettingStarted/images/06_codeServerFolder.png diff --git a/client/docs/source/gettingStarted/images/07_irSensor.webp b/docs/source/gettingStarted/images/07_irSensor.webp similarity index 100% rename from client/docs/source/gettingStarted/images/07_irSensor.webp rename to docs/source/gettingStarted/images/07_irSensor.webp diff --git a/client/docs/source/gettingStarted/images/08_notepad.png b/docs/source/gettingStarted/images/08_notepad.png similarity index 100% rename from client/docs/source/gettingStarted/images/08_notepad.png rename to docs/source/gettingStarted/images/08_notepad.png diff --git a/client/docs/source/gettingStarted/images/09_update.png b/docs/source/gettingStarted/images/09_update.png similarity index 100% rename from client/docs/source/gettingStarted/images/09_update.png rename to docs/source/gettingStarted/images/09_update.png diff --git a/client/docs/source/gettingStarted/index.rst b/docs/source/gettingStarted/index.rst similarity index 100% rename from client/docs/source/gettingStarted/index.rst rename to docs/source/gettingStarted/index.rst diff --git a/client/docs/source/gettingStarted/secondProgram.rst b/docs/source/gettingStarted/secondProgram.rst similarity index 100% rename from client/docs/source/gettingStarted/secondProgram.rst rename to docs/source/gettingStarted/secondProgram.rst diff --git a/client/docs/source/gettingStarted/thridProgram.rst b/docs/source/gettingStarted/thridProgram.rst similarity index 100% rename from client/docs/source/gettingStarted/thridProgram.rst rename to docs/source/gettingStarted/thridProgram.rst diff --git a/client/docs/source/gettingStarted/update.rst b/docs/source/gettingStarted/update.rst similarity index 100% rename from client/docs/source/gettingStarted/update.rst rename to docs/source/gettingStarted/update.rst diff --git a/client/docs/source/gettingStarted/wifi.rst b/docs/source/gettingStarted/wifi.rst similarity index 100% rename from client/docs/source/gettingStarted/wifi.rst rename to docs/source/gettingStarted/wifi.rst diff --git a/client/docs/source/images/compair-logo-white.svg b/docs/source/images/compair-logo-white.svg similarity index 100% rename from client/docs/source/images/compair-logo-white.svg rename to docs/source/images/compair-logo-white.svg diff --git a/client/docs/source/index.rst b/docs/source/index.rst similarity index 100% rename from client/docs/source/index.rst rename to docs/source/index.rst diff --git a/client/docs/source/lib/classes/DoubleElimination.rst b/docs/source/lib/classes/DoubleElimination.rst similarity index 100% rename from client/docs/source/lib/classes/DoubleElimination.rst rename to docs/source/lib/classes/DoubleElimination.rst diff --git a/client/docs/source/lib/classes/Encoder.rst b/docs/source/lib/classes/Encoder.rst similarity index 100% rename from client/docs/source/lib/classes/Encoder.rst rename to docs/source/lib/classes/Encoder.rst diff --git a/client/docs/source/lib/classes/IRSensor.rst b/docs/source/lib/classes/IRSensor.rst similarity index 100% rename from client/docs/source/lib/classes/IRSensor.rst rename to docs/source/lib/classes/IRSensor.rst diff --git a/client/docs/source/lib/classes/Motor.rst b/docs/source/lib/classes/Motor.rst similarity index 100% rename from client/docs/source/lib/classes/Motor.rst rename to docs/source/lib/classes/Motor.rst diff --git a/client/docs/source/lib/classes/Opencv.rst b/docs/source/lib/classes/Opencv.rst similarity index 100% rename from client/docs/source/lib/classes/Opencv.rst rename to docs/source/lib/classes/Opencv.rst diff --git a/client/docs/source/lib/classes/Seeding.rst b/docs/source/lib/classes/Seeding.rst similarity index 100% rename from client/docs/source/lib/classes/Seeding.rst rename to docs/source/lib/classes/Seeding.rst diff --git a/client/docs/source/lib/classes/images/chessboard.jpg b/docs/source/lib/classes/images/chessboard.jpg similarity index 100% rename from client/docs/source/lib/classes/images/chessboard.jpg rename to docs/source/lib/classes/images/chessboard.jpg diff --git a/client/docs/source/lib/classes/images/chessboard_detected.jpg b/docs/source/lib/classes/images/chessboard_detected.jpg similarity index 100% rename from client/docs/source/lib/classes/images/chessboard_detected.jpg rename to docs/source/lib/classes/images/chessboard_detected.jpg diff --git a/client/docs/source/lib/classes/images/opencv_http_stream.png b/docs/source/lib/classes/images/opencv_http_stream.png similarity index 100% rename from client/docs/source/lib/classes/images/opencv_http_stream.png rename to docs/source/lib/classes/images/opencv_http_stream.png diff --git a/client/docs/source/lib/classes/images/opencv_processed.png b/docs/source/lib/classes/images/opencv_processed.png similarity index 100% rename from client/docs/source/lib/classes/images/opencv_processed.png rename to docs/source/lib/classes/images/opencv_processed.png diff --git a/client/docs/source/lib/index.rst b/docs/source/lib/index.rst similarity index 100% rename from client/docs/source/lib/index.rst rename to docs/source/lib/index.rst diff --git a/client/docs/source/other/hardware.rst b/docs/source/other/hardware.rst similarity index 100% rename from client/docs/source/other/hardware.rst rename to docs/source/other/hardware.rst diff --git a/client/docs/source/other/images/Mainboard.png b/docs/source/other/images/Mainboard.png similarity index 100% rename from client/docs/source/other/images/Mainboard.png rename to docs/source/other/images/Mainboard.png diff --git a/client/docs/source/other/images/Sensorarray.png b/docs/source/other/images/Sensorarray.png similarity index 100% rename from client/docs/source/other/images/Sensorarray.png rename to docs/source/other/images/Sensorarray.png diff --git a/client/docs/source/other/usage.rst b/docs/source/other/usage.rst similarity index 100% rename from client/docs/source/other/usage.rst rename to docs/source/other/usage.rst diff --git a/client/docs/source/software/installation.rst b/docs/source/software/installation.rst similarity index 100% rename from client/docs/source/software/installation.rst rename to docs/source/software/installation.rst diff --git a/client/motorLinearityTest.py b/motorLinearityTest.py similarity index 100% rename from client/motorLinearityTest.py rename to motorLinearityTest.py diff --git a/client/postinstall.sh b/postinstall.sh similarity index 100% rename from client/postinstall.sh rename to postinstall.sh diff --git a/client/setup.py b/setup.py similarity index 100% rename from client/setup.py rename to setup.py diff --git a/client/sphinx_to_github.sh b/sphinx_to_github.sh similarity index 100% rename from client/sphinx_to_github.sh rename to sphinx_to_github.sh diff --git a/client/test.py b/test.py similarity index 100% rename from client/test.py rename to test.py From dcef53712fc151154cc783834ede174b95352660 Mon Sep 17 00:00:00 2001 From: Konstantin Lampalzer Date: Sun, 18 Dec 2022 00:03:26 +0100 Subject: [PATCH 11/22] fix keyerror setup py --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index fb84e02..8fffc86 100644 --- a/setup.py +++ b/setup.py @@ -6,7 +6,7 @@ print("Using version: {str(os.environ['VERSION'])}") setuptools.setup( name="complib", - version=str(os.environ["VERSION"]), + version=str(os.environ.get('VERSION', "")), author="F-WuTs", author_email="joel.klimont@comp-air.at", description="", From b95b9bf5187da8c07ef1e95b97899ac74a969be2 Mon Sep 17 00:00:00 2001 From: itssme Date: Sun, 18 Dec 2022 14:00:11 +0100 Subject: [PATCH 12/22] (MINOR) updated readme --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 79b1f1f..381e0fb 100644 --- a/README.md +++ b/README.md @@ -42,3 +42,5 @@ ffmpeg -f v4l2 -framerate 30 -video_size 640x480 -i /dev/video0 -b:v 2M -f flv # Bullseye now only supports libcamera https://www.raspberrypi.com/news/bullseye-camera-system/ + +(This can still be mitigated by enabling "old camera support" in der raspi-config settings. (This is eine automatically in der postinstallscript) From 671292a6cf9a0874e8fa749b880bda4aadc56942 Mon Sep 17 00:00:00 2001 From: Joel Klimont Date: Sun, 18 Dec 2022 15:08:20 +0100 Subject: [PATCH 13/22] fixed moving built package to the correct output directory --- README.md | 2 +- build.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 381e0fb..0c64463 100644 --- a/README.md +++ b/README.md @@ -43,4 +43,4 @@ ffmpeg -f v4l2 -framerate 30 -video_size 640x480 -i /dev/video0 -b:v 2M -f flv https://www.raspberrypi.com/news/bullseye-camera-system/ -(This can still be mitigated by enabling "old camera support" in der raspi-config settings. (This is eine automatically in der postinstallscript) +(This can still be mitigated by enabling "old camera support" in the raspi-config settings. (This is done automatically in the postinstallscript) diff --git a/build.sh b/build.sh index f9f3020..670cd27 100644 --- a/build.sh +++ b/build.sh @@ -6,4 +6,4 @@ DEB="empty" source build_deb.sh echo "Ran build deb, created: $DEB" -mv $DEB ../output +mv $DEB ./output From f09d20ade2ff1db11ea23ca425a9858d48674489 Mon Sep 17 00:00:00 2001 From: Joel Klimont Date: Sat, 14 Jan 2023 15:11:57 +0100 Subject: [PATCH 14/22] removed .idea folder from repo --- .idea/.gitignore | 3 --- .idea/client_s2.iml | 8 -------- .idea/inspectionProfiles/Project_Default.xml | 12 ------------ .idea/inspectionProfiles/profiles_settings.xml | 6 ------ .idea/misc.xml | 7 ------- .idea/modules.xml | 8 -------- .idea/saveactions_settings.xml | 15 --------------- .idea/vcs.xml | 6 ------ 8 files changed, 65 deletions(-) delete mode 100644 .idea/.gitignore delete mode 100644 .idea/client_s2.iml delete mode 100644 .idea/inspectionProfiles/Project_Default.xml delete mode 100644 .idea/inspectionProfiles/profiles_settings.xml delete mode 100644 .idea/misc.xml delete mode 100644 .idea/modules.xml delete mode 100644 .idea/saveactions_settings.xml delete mode 100644 .idea/vcs.xml diff --git a/.idea/.gitignore b/.idea/.gitignore deleted file mode 100644 index 26d3352..0000000 --- a/.idea/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml diff --git a/.idea/client_s2.iml b/.idea/client_s2.iml deleted file mode 100644 index d0876a7..0000000 --- a/.idea/client_s2.iml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml deleted file mode 100644 index 9277599..0000000 --- a/.idea/inspectionProfiles/Project_Default.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml deleted file mode 100644 index 105ce2d..0000000 --- a/.idea/inspectionProfiles/profiles_settings.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100644 index f6104af..0000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index 8417644..0000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/saveactions_settings.xml b/.idea/saveactions_settings.xml deleted file mode 100644 index b7b3f34..0000000 --- a/.idea/saveactions_settings.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 6c0b863..0000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file From cf415d38e812b859608fea11cfd7ee0a1bd711c1 Mon Sep 17 00:00:00 2001 From: Joel Klimont Date: Fri, 10 Feb 2023 13:44:28 +0100 Subject: [PATCH 15/22] fixed documentation --- compLib/Camera.py | 24 +++++-- docs/source/lib/classes/Opencv.rst | 66 ++++++++++++++++++ docs/source/lib/classes/images/6x6_1000-0.png | Bin 0 -> 5880 bytes 3 files changed, 83 insertions(+), 7 deletions(-) create mode 100644 docs/source/lib/classes/images/6x6_1000-0.png diff --git a/compLib/Camera.py b/compLib/Camera.py index 3a7d764..0937ec1 100644 --- a/compLib/Camera.py +++ b/compLib/Camera.py @@ -1,5 +1,5 @@ import sys -from typing import Any +from typing import Any, Tuple, List # build image is somehow different from raspberry image? opencv-python is installed to a directory which is not in the pythonpath by default.... sys.path.append("/usr/lib/python3.9/site-packages") @@ -58,6 +58,7 @@ class Camera: def __video_feed(): """ Define route for serving jpeg stream. + :return: Return the response generated along with the specific media. """ return Response(self.__camera._newest_frame_generator(), @@ -67,13 +68,15 @@ class Camera: def __index(): """ Define route for serving a static http site to view the stream. - :return: Static html page + + :return: Static html page where the video stream of Opencv can be viewed. """ return HTML def __start_flask(self): """ Function for running flask server in a thread. + :return: """ logging.getLogger("complib-logger").info("starting flask server") @@ -121,27 +124,31 @@ class Camera: self.__logger.info("Initialized vision") - def get_frame(self): + def get_frame(self) -> Any: """ - Die Funktion das neuste Bild, welches die Kamera aufgenommen hat zurück. + Die Funktion gibt das neuste Bild, welches die Kamera aufgenommen, hat zurück. + :return: Ein "opencv image frame" """ img16 = self.__camera_stream.read() return img16 - def detect_markers(self, image): + def detect_markers(self, image) -> Any: """ Funktion um die ArUco Marker in einem Bild zu erkennen. + :param image: Bild, welches die Kamera aufgenommen hat. :return: Gibt drei Variablen zurueck. Erstens eine Liste an Postionen der "Ecken" der erkannten Markern. Zweitens eine Liste an IDs der erkannten Markern und dritten noch Debug Informationen (diese können ignoriert werden). """ return cv2.aruco.detectMarkers(image, self.aruco_dict, parameters=self.aruco_params) - def detect_markers_midpoint(self, image) -> tuple[list[Marker], Any]: + def detect_markers_midpoint(self, image) -> Tuple[List[Marker], Any]: """ Funktion um die ArUco Marker in einem Bild zu erkennen, einzuzeichnen und den Mittelpunkt der Marker auszurechnen. + :param image: Bild, welches die Kamera aufgenommen hat. :return: Gibt zwei Variablen zurueck. Erstens eine Liste an "Markern" und zweitens das Bild mit den eigezeichneten Marken. + :rtype: Tuple[List[Marker], Any] """ (corners, ids, rejected) = self.detect_markers(image) self.draw_markers(image, corners, ids) @@ -154,9 +161,10 @@ class Camera: return res, image - def draw_markers(self, image, corners, ids): + def draw_markers(self, image, corners, ids) -> Any: """ Zeichnet die erkannten Markern mit ihren IDs in das Bild. + :param image: Original Bild, in dem die Marker erkannt wurden. :param corners: List der Positionen der Ecken der erkannten Marker. :param ids: IDs der erkannten Markern. @@ -167,6 +175,7 @@ class Camera: def publish_frame(self, image): """ Sendet das Bild, welches der Funktion übergeben wird, an den Webserver, damit es der Nutzer in seinem Browser ansehen kann. + :param image: Opencv Bild, welches dem Nutzer angezeigt werden soll. :return: None """ @@ -177,6 +186,7 @@ class Camera: def _newest_frame_generator(self): """ Private generator which is called directly from flask server. + :return: Yields image/jpeg encoded frames published from publish_frame function. """ while True: diff --git a/docs/source/lib/classes/Opencv.rst b/docs/source/lib/classes/Opencv.rst index bd299c1..9d788db 100644 --- a/docs/source/lib/classes/Opencv.rst +++ b/docs/source/lib/classes/Opencv.rst @@ -11,3 +11,69 @@ Dokumentation des Camera Moduls .. autoclass:: compLib.Camera.Camera :members: + +Beispiele +========= + +Bild Anzeigen +--------------- + +Das folgende Programm fragt Bilder von der Kamera ab und schickt sie an den Webserver, der im Hintergrund läuft. Der Benutzer kann dann auf die Webseite: http://raspi_ip:9898 gehen und die Ausgabe der Kamera sehen. + +.. code-block:: python + + from compLib.Camera import * + + camera = Camera() + while True: + image = camera.get_frame() + camera.publish_frame(image) + +ArUco Marker Erkennen +------------------------ + +In diesem Programm werden die ArUco Marker, die sich am Spielfeld befinden, erkannt. Diese "QR-Code" ähnlichen Marker finden sich in den Logistikzonen und können dazu verwendet werden zu erkennen, wo der Roboter hinfahren sollt etc. + +.. code-block:: python + + from compLib.Camera import * + + camera = Camera() + while True: + image = camera.get_frame() + + markers, image = camera.detect_markers_midpoint(image) + print(markers) + print("-----------------") + + camera.publish_frame(image) + +Hier ist z.B. der ArUco Marker mit der ID 0. Führe das Programm aus und lass den Roboter auf den Bildschirm schauen. Das Programm sollte die 2D Position ausgeben, welcher der ArUco Marker (genauer sein Mittelpunkt) im Camera Bild hat. + +|ArucoExample| + +.. |ArucoExample| image:: images/6x6_1000-0.png + +Um die Positionen zu verarbeiten, muss dann nur noch das "markers" array durchgegangen werden. Das könnte z.B. so gemacht werden: + +.. code-block:: python + + from compLib.Camera import * + + camera = Camera() + while True: + image = camera.get_frame() + + markers, image = camera.detect_markers_midpoint(image) + print(markers) + print("-----------------") + + for marker in markers: + print(f"Marker mit der id: {marker.id}") + print(f"Ist auf der X Position: {marker.x}") + print(f"und auf der Y Position: {marker.y}") + print("-----------------") + + camera.publish_frame(image) + +Wichtig ist noch zu beachten, dass die X und Y Positionen ihren Ursprung in der linken oberen Ecke des Bildes haben. D.h. die Position (0,0) ist im oberen linken Bildrand. diff --git a/docs/source/lib/classes/images/6x6_1000-0.png b/docs/source/lib/classes/images/6x6_1000-0.png new file mode 100644 index 0000000000000000000000000000000000000000..747e1e152b9c3249baab59c86fcff38544fb8b53 GIT binary patch literal 5880 zcmeAS@N?(olHy`uVBq!ia0y~yV15C@9Be=l-^Ev+FfcH-W;#0ucse^P6cpvBW#*(Z zFlbDyooMTE*g@uKy!{d-Q9WnP5;|!sjdqR}- zQZ{Kjy%2TeSs<NcK25tGS$!5xIwDaKd5K{rA&)#Ctyq*b z<^A~`YYOf?S~E>+O`-q4Lj``(agVIdI;w1FaP1IKSlq-rB|*_`wOd!G$lK$#fByEx zt4#M<$7@h@W-*WGq{r<4oA2M9^|Q0kTvLYqR$R{SWDbtEOkY>!*2~{6`^&;%!yF!U zIes1E<@rm(XGeYEcyWtOZ{6%!d)Q;%G1U6+O7Z9uS@81w^TzMSzn1A-DCRC%vum&E zx58fxOIEIa!dpH=O_NOe;g4*0H&AT%h7(~8!x;TbZ+ESN1f0LY+98=99G;_spag~|K%!-Z-(0@NaazTYsp9#MdCVV*^g!k0XgGo^4yvW0 z(RzoRiulH>84T~PgHvZyIUhq!5BF&81I(PbD;h{LBe6OrzsMcQRoJ#uXRh!RY`q7|lAv)35-V;3-Eb Date: Fri, 10 Feb 2023 14:02:07 +0100 Subject: [PATCH 16/22] fixed syntax error in postinstallscript --- postinstall.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/postinstall.sh b/postinstall.sh index f2a5b39..4f6f94e 100755 --- a/postinstall.sh +++ b/postinstall.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -if [[ $(uname -m) == "x86_64" ]]; then +if [ $(uname -m) == "x86_64" ]; then echo "Not running on RPi - Skipping postinstall" exit 0 fi From fa4cc1a0ad7a7ecb6d2a06599c5e7a41c7ca17c0 Mon Sep 17 00:00:00 2001 From: Joel Klimont Date: Fri, 10 Feb 2023 14:29:13 +0100 Subject: [PATCH 17/22] fixed syntax error in postinstallscript --- postinstall.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/postinstall.sh b/postinstall.sh index 4f6f94e..b37be50 100755 --- a/postinstall.sh +++ b/postinstall.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -if [ $(uname -m) == "x86_64" ]; then +if [ "$(uname -m)" = "x86_64" ]; then echo "Not running on RPi - Skipping postinstall" exit 0 fi From de112d98e423d3d4d45a040dbbae73724e78dbf5 Mon Sep 17 00:00:00 2001 From: Matthias Guzmits Date: Tue, 18 Jul 2023 00:44:34 +0200 Subject: [PATCH 18/22] Added basic drive functions --- compLib/CMakeLists.txt | 55 ++++++++++ compLib/include/comp_lib_node.h | 14 +++ compLib/include/motor.h | 54 ++++++++++ compLib/include/sequence_lock.h | 11 ++ compLib/package.xml | 22 ++++ compLib/src/comp_lib_node.cpp | 10 ++ compLib/src/main.cpp | 66 ++++++++++++ compLib/src/motor.cpp | 171 ++++++++++++++++++++++++++++++++ 8 files changed, 403 insertions(+) create mode 100644 compLib/CMakeLists.txt create mode 100644 compLib/include/comp_lib_node.h create mode 100644 compLib/include/motor.h create mode 100644 compLib/include/sequence_lock.h create mode 100644 compLib/package.xml create mode 100644 compLib/src/comp_lib_node.cpp create mode 100644 compLib/src/main.cpp create mode 100644 compLib/src/motor.cpp diff --git a/compLib/CMakeLists.txt b/compLib/CMakeLists.txt new file mode 100644 index 0000000..113ea36 --- /dev/null +++ b/compLib/CMakeLists.txt @@ -0,0 +1,55 @@ +cmake_minimum_required(VERSION 3.26) +project(comp_lib) + +if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") + add_compile_options(-Wall -Wextra -Wpedantic) +endif() + +# find dependencies +find_package(ament_cmake REQUIRED) +find_package(rclcpp REQUIRED) +find_package(rclcpp_action REQUIRED) +find_package(std_msgs REQUIRED) +find_package(irobot_create_msgs REQUIRED) +find_package(geometry_msgs REQUIRED) + +# add_executable(talker src/publisher_member_function.cpp) +# ament_target_dependencies(talker rclcpp std_msgs irobot_create_msgs) + +# add_executable(listener src/subscriber_member_function.cpp) +# ament_target_dependencies(listener rclcpp std_msgs irobot_create_msgs) + +# add_executable(drive src/drive_action.cpp) +# ament_target_dependencies(drive rclcpp rclcpp_action std_msgs irobot_create_msgs) + +# add_executable(set_vel src/set_speed.cpp) +# ament_target_dependencies(set_vel rclcpp rclcpp_action std_msgs irobot_create_msgs geometry_msgs) + +add_executable(compLib_node src/main.cpp src/motor.cpp) +ament_target_dependencies(compLib_node rclcpp rclcpp_action std_msgs irobot_create_msgs geometry_msgs) + +target_include_directories(compLib_node PRIVATE include) + +install(TARGETS + #talker + #listener + #drive + #set_vel + compLib_node + DESTINATION lib/${PROJECT_NAME}) +# uncomment the following section in order to fill in +# further dependencies manually. +# find_package( REQUIRED) + +if(BUILD_TESTING) + find_package(ament_lint_auto REQUIRED) + # the following line skips the linter which checks for copyrights + # uncomment the line when a copyright and license is not present in all source files + #set(ament_cmake_copyright_FOUND TRUE) + # the following line skips cpplint (only works in a git repo) + # uncomment the line when this package is not in a git repo + #set(ament_cmake_cpplint_FOUND TRUE) + ament_lint_auto_find_test_dependencies() +endif() + +ament_package() diff --git a/compLib/include/comp_lib_node.h b/compLib/include/comp_lib_node.h new file mode 100644 index 0000000..271c19a --- /dev/null +++ b/compLib/include/comp_lib_node.h @@ -0,0 +1,14 @@ +#ifndef ROS_NODE_H +#define ROS_NODE_H + +#include "rclcpp/rclcpp.hpp" + +class CompLibNode : public rclcpp::Node +{ +public: + CompLibNode(); + + +}; + +#endif \ No newline at end of file diff --git a/compLib/include/motor.h b/compLib/include/motor.h new file mode 100644 index 0000000..24e6ce4 --- /dev/null +++ b/compLib/include/motor.h @@ -0,0 +1,54 @@ +#ifndef MOTOR_H +#define MOTOR_H + +#include +#include + +#include + +#include "rclcpp/rclcpp.hpp" +#include "rclcpp_action/rclcpp_action.hpp" + +#include "irobot_create_msgs/action/drive_distance.hpp" +#include "irobot_create_msgs/action/rotate_angle.hpp" + +class DriveDistNode : public rclcpp::Node +{ +public: + DriveDistNode(); + void drive_dist(float meters, float velocity); + void kill(); +private: + void result_callback(const rclcpp_action::ClientGoalHandle::WrappedResult & result); + rclcpp_action::Client::SharedPtr drive_dist_action_; + bool processing; +}; + +class SetSpeedNode : public rclcpp::Node +{ +public: + SetSpeedNode(); + void drive(float speed); + void stop(); + void kill(); +private: + void set_speed(float speed); + void drive_loop(float speed); + rclcpp::Publisher::SharedPtr speed_publisher_; + bool run = true; + std::thread t; +}; + +class RotateAngleNode : public rclcpp::Node +{ +public: + RotateAngleNode(); + void rotate_angle(float angle, float velocity); + void kill(); +private: + void result_callback(const rclcpp_action::ClientGoalHandle::WrappedResult & result); + rclcpp_action::Client::SharedPtr rotate_angle_action_; + bool processing; +}; + +#endif \ No newline at end of file diff --git a/compLib/include/sequence_lock.h b/compLib/include/sequence_lock.h new file mode 100644 index 0000000..a74dd14 --- /dev/null +++ b/compLib/include/sequence_lock.h @@ -0,0 +1,11 @@ +#ifndef SEQUENCE_LOCK_H +#define SEQUENCE_LOCK_H + +#include + +namespace SequenceLock +{ + std::mutex m; +} + +#endif \ No newline at end of file diff --git a/compLib/package.xml b/compLib/package.xml new file mode 100644 index 0000000..b05fe71 --- /dev/null +++ b/compLib/package.xml @@ -0,0 +1,22 @@ + + + + comp_lib + 0.0.0 + TODO: Package description + matthias + TODO: License declaration + + ament_cmake + rclcpp + rclcpp_action + std_msgs + irobot_create_msgs + + ament_lint_auto + ament_lint_common + + + ament_cmake + + diff --git a/compLib/src/comp_lib_node.cpp b/compLib/src/comp_lib_node.cpp new file mode 100644 index 0000000..6052379 --- /dev/null +++ b/compLib/src/comp_lib_node.cpp @@ -0,0 +1,10 @@ +#include "ros_node.h" + +#include "rclcpp/rclcpp.hpp" +#include "rclcpp_action/rclcpp_action.hpp" + +CompLibNode::CompLibNode() +: Node("CompLibNode") +{ + +} \ No newline at end of file diff --git a/compLib/src/main.cpp b/compLib/src/main.cpp new file mode 100644 index 0000000..87ba18b --- /dev/null +++ b/compLib/src/main.cpp @@ -0,0 +1,66 @@ +#include +#include +#include +#include + +#include "motor.h" + +std::mutex action_mutex; + +// #lazyness +void run_node(std::shared_ptr node) +{ + rclcpp::spin(node); +} + +void run_node1(std::shared_ptr node) +{ + rclcpp::spin(node); +} + +void run_node2(std::shared_ptr node) +{ + rclcpp::spin(node); +} + +int main(int argc, char * argv[]) +{ + rclcpp::init(argc, argv); + + auto ddn = std::make_shared(); + auto ssn = std::make_shared(); + auto ran = std::make_shared(); + + std::thread t; + std::thread t1; + std::thread t2; + + t = std::thread(run_node, ddn); + t1 = std::thread(run_node1, ssn); + t2 = std::thread(run_node2, ran); + + ssn->drive(0.2); + + std::this_thread::sleep_for (std::chrono::milliseconds(2000)); + + ssn->stop(); + + // std::this_thread::sleep_for (std::chrono::milliseconds(1000)); + + ran->rotate_angle(-45, 0.5); + // std::this_thread::sleep_for (std::chrono::milliseconds(5000)); + + ddn->drive_dist(0.2, 0.3); + + // std::this_thread::sleep_for (std::chrono::milliseconds(5000)); + + ddn->kill(); + ssn->kill(); + ddn->kill(); + + t.join(); + t1.join(); + t2.join(); + + return 0; +} \ No newline at end of file diff --git a/compLib/src/motor.cpp b/compLib/src/motor.cpp new file mode 100644 index 0000000..8adef43 --- /dev/null +++ b/compLib/src/motor.cpp @@ -0,0 +1,171 @@ +#include +#include +#include +#include +#include + +#include + +#include "rclcpp/rclcpp.hpp" +#include "rclcpp_action/rclcpp_action.hpp" + +#include "irobot_create_msgs/action/drive_distance.hpp" +#include "irobot_create_msgs/action/rotate_angle.hpp" + +#include "motor.h" +#include "sequence_lock.h" + +double pi = 2 * acos(0.0); + +DriveDistNode::DriveDistNode() +: Node("drive_dist_node") +{ + drive_dist_action_ = rclcpp_action::create_client( + this, + "/drive_distance" + ); +} + +void DriveDistNode::drive_dist(float meters, float velocity) +{ + std::cout << "drive dist" << std::endl; + processing = true; + auto data = irobot_create_msgs::action::DriveDistance::Goal(); + auto send_goal_options = rclcpp_action::Client::SendGoalOptions(); + send_goal_options.result_callback = + std::bind(&DriveDistNode::result_callback, this, std::placeholders::_1); + + data.distance = meters; + data.max_translation_speed = velocity; + drive_dist_action_->async_send_goal(data, send_goal_options); + + while (processing) {} +} + +void DriveDistNode::result_callback(const rclcpp_action::ClientGoalHandle::WrappedResult & result) +{ + processing = false; + std::cout << "finished dist" << std::endl; + switch (result.code) { + case rclcpp_action::ResultCode::SUCCEEDED: + return; + case rclcpp_action::ResultCode::ABORTED: + RCLCPP_ERROR(this->get_logger(), "Goal was aborted"); + return; + case rclcpp_action::ResultCode::CANCELED: + RCLCPP_ERROR(this->get_logger(), "Goal was canceled"); + return; + default: + RCLCPP_ERROR(this->get_logger(), "Unknown result code"); + return; + } +} + +void DriveDistNode::kill() +{ + std::cout << "DriveDistNode killed" << std::endl; + rclcpp::shutdown(); +} + +SetSpeedNode::SetSpeedNode() +: Node("set_speed_node") +{ + speed_publisher_ = this->create_publisher( + "/cmd_vel", + rclcpp::SensorDataQoS() + ); +} + +void SetSpeedNode::drive_loop(float speed) +{ + std::cout << "Loop" << std::endl; + while (run) + { + set_speed(speed); + // sleep set as described at http://wiki.ros.org/Robots/TIAGo/Tutorials/motions/cmd_vel + std::this_thread::sleep_for (std::chrono::milliseconds(333)); + } +} + +void SetSpeedNode::set_speed(float speed) +{ + auto data = geometry_msgs::msg::Twist(); + + data.linear.x = speed; + data.linear.y = 0; + data.linear.z = 0; + data.angular.x = 0; + data.angular.x = 0; + data.angular.x = 0; + speed_publisher_->publish(data); +} + +void SetSpeedNode::drive(float speed) +{ + std::cout << "Drive" << std::endl; + run = true; + t = std::thread(&SetSpeedNode::drive_loop, this, speed); +} + +void SetSpeedNode::stop() +{ + std::cout << "stop" << std::endl; + run = false; +} + +void SetSpeedNode::kill() +{ + std::cout << "SetSpeedNode killed" << std::endl; + rclcpp::shutdown(); +} + +RotateAngleNode::RotateAngleNode() +: Node("rotate_angle_node") +{ + rotate_angle_action_ = rclcpp_action::create_client( + this, + "rotate_angle" + ); +} + +void RotateAngleNode::rotate_angle(float angle, float velocity) +{ + processing = true; + angle *= pi / 180; + auto data = irobot_create_msgs::action::RotateAngle::Goal(); + auto send_goal_options = rclcpp_action::Client::SendGoalOptions(); + send_goal_options.result_callback = + std::bind(&RotateAngleNode::result_callback, this, std::placeholders::_1); + + + data.angle = angle; + data.max_rotation_speed = velocity; + rotate_angle_action_->async_send_goal(data, send_goal_options); + + while (processing) {} +} + +void RotateAngleNode::result_callback(const rclcpp_action::ClientGoalHandle::WrappedResult & result) +{ + processing = false; + std::cout << "finished rotation" << std::endl; + switch (result.code) { + case rclcpp_action::ResultCode::SUCCEEDED: + return; + case rclcpp_action::ResultCode::ABORTED: + RCLCPP_ERROR(this->get_logger(), "Goal was aborted"); + return; + case rclcpp_action::ResultCode::CANCELED: + RCLCPP_ERROR(this->get_logger(), "Goal was canceled"); + return; + default: + RCLCPP_ERROR(this->get_logger(), "Unknown result code"); + return; + } +} + +void RotateAngleNode::kill() +{ + std::cout << "RotateAngleNode killed" << std::endl; + rclcpp::shutdown(); +} \ No newline at end of file From 9c40daae888ae4fee92dededd3049c22366379be Mon Sep 17 00:00:00 2001 From: itssme Date: Tue, 18 Jul 2023 09:17:25 +0200 Subject: [PATCH 19/22] (MAJOR) Bump to new major version --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 0c64463..78d7204 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # compLIB +Rewrite for ROS is the live packaged version since 18.07.2023. + # Dependencies ## Building documentation From 27962d16a79f508bd8890175c18a2c7046d40ce6 Mon Sep 17 00:00:00 2001 From: itssme Date: Tue, 18 Jul 2023 09:18:33 +0200 Subject: [PATCH 20/22] (MAJOR) Bump to new major version after deleting invalid tag --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 78d7204..33f9085 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,8 @@ Rewrite for ROS is the live packaged version since 18.07.2023. # Dependencies +TODO: document + ## Building documentation ``` pip install sphinx-rtd-theme From ed04957d94e0067e2e5e58d2b4ec3c9752ce7421 Mon Sep 17 00:00:00 2001 From: Matthias Guzmits Date: Wed, 19 Jul 2023 18:36:07 +0200 Subject: [PATCH 21/22] Add drive arc functionality --- compLib/include/motor.h | 13 ++++++++ compLib/src/main.cpp | 14 +++++++- compLib/src/motor.cpp | 72 +++++++++++++++++++++++++++++++++++------ 3 files changed, 89 insertions(+), 10 deletions(-) diff --git a/compLib/include/motor.h b/compLib/include/motor.h index 24e6ce4..a2096c0 100644 --- a/compLib/include/motor.h +++ b/compLib/include/motor.h @@ -10,6 +10,7 @@ #include "rclcpp_action/rclcpp_action.hpp" #include "irobot_create_msgs/action/drive_distance.hpp" +#include "irobot_create_msgs/action/drive_arc.hpp" #include "irobot_create_msgs/action/rotate_angle.hpp" class DriveDistNode : public rclcpp::Node @@ -51,4 +52,16 @@ private: bool processing; }; +class DriveArcNode : public rclcpp::Node +{ +public: + DriveArcNode(); + void drive_arc(float angle, float radius, float velocity, int direction=1); + void kill(); +private: + void result_callback(const rclcpp_action::ClientGoalHandle::WrappedResult & result); + rclcpp_action::Client::SharedPtr drive_arc_action_; + bool processing; +}; + #endif \ No newline at end of file diff --git a/compLib/src/main.cpp b/compLib/src/main.cpp index 87ba18b..c10699b 100644 --- a/compLib/src/main.cpp +++ b/compLib/src/main.cpp @@ -23,6 +23,11 @@ void run_node2(std::shared_ptr node) rclcpp::spin(node); } +void run_node3(std::shared_ptr node) +{ + rclcpp::spin(node); +} + int main(int argc, char * argv[]) { rclcpp::init(argc, argv); @@ -30,16 +35,19 @@ int main(int argc, char * argv[]) auto ddn = std::make_shared(); auto ssn = std::make_shared(); auto ran = std::make_shared(); + auto dan = std::make_shared(); std::thread t; std::thread t1; std::thread t2; + std::thread t3; t = std::thread(run_node, ddn); t1 = std::thread(run_node1, ssn); t2 = std::thread(run_node2, ran); + t3 = std::thread(run_node3, dan); - ssn->drive(0.2); + ssn->drive(0.3); std::this_thread::sleep_for (std::chrono::milliseconds(2000)); @@ -54,13 +62,17 @@ int main(int argc, char * argv[]) // std::this_thread::sleep_for (std::chrono::milliseconds(5000)); + dan->drive_arc(90, 0.5, 0.5); + ddn->kill(); ssn->kill(); ddn->kill(); + dan->kill(); t.join(); t1.join(); t2.join(); + t3.join(); return 0; } \ No newline at end of file diff --git a/compLib/src/motor.cpp b/compLib/src/motor.cpp index 8adef43..a0e4528 100644 --- a/compLib/src/motor.cpp +++ b/compLib/src/motor.cpp @@ -10,6 +10,7 @@ #include "rclcpp_action/rclcpp_action.hpp" #include "irobot_create_msgs/action/drive_distance.hpp" +#include "irobot_create_msgs/action/drive_arc.hpp" #include "irobot_create_msgs/action/rotate_angle.hpp" #include "motor.h" @@ -28,7 +29,7 @@ DriveDistNode::DriveDistNode() void DriveDistNode::drive_dist(float meters, float velocity) { - std::cout << "drive dist" << std::endl; + RCLCPP_INFO(this->get_logger(), "drive dist"); processing = true; auto data = irobot_create_msgs::action::DriveDistance::Goal(); auto send_goal_options = rclcpp_action::Client::SendGoalOptions(); @@ -45,9 +46,9 @@ void DriveDistNode::drive_dist(float meters, float velocity) void DriveDistNode::result_callback(const rclcpp_action::ClientGoalHandle::WrappedResult & result) { processing = false; - std::cout << "finished dist" << std::endl; switch (result.code) { case rclcpp_action::ResultCode::SUCCEEDED: + RCLCPP_INFO(this->get_logger(), "finished dist"); return; case rclcpp_action::ResultCode::ABORTED: RCLCPP_ERROR(this->get_logger(), "Goal was aborted"); @@ -63,7 +64,7 @@ void DriveDistNode::result_callback(const rclcpp_action::ClientGoalHandleget_logger(), "DriveDistNode killed"); rclcpp::shutdown(); } @@ -78,7 +79,6 @@ SetSpeedNode::SetSpeedNode() void SetSpeedNode::drive_loop(float speed) { - std::cout << "Loop" << std::endl; while (run) { set_speed(speed); @@ -102,20 +102,20 @@ void SetSpeedNode::set_speed(float speed) void SetSpeedNode::drive(float speed) { - std::cout << "Drive" << std::endl; + RCLCPP_INFO(this->get_logger(), "Start drive"); run = true; t = std::thread(&SetSpeedNode::drive_loop, this, speed); } void SetSpeedNode::stop() { - std::cout << "stop" << std::endl; run = false; + RCLCPP_INFO(this->get_logger(), "Stop drive"); } void SetSpeedNode::kill() { - std::cout << "SetSpeedNode killed" << std::endl; + RCLCPP_INFO(this->get_logger(), "SetSpeedNode killed"); rclcpp::shutdown(); } @@ -148,9 +148,9 @@ void RotateAngleNode::rotate_angle(float angle, float velocity) void RotateAngleNode::result_callback(const rclcpp_action::ClientGoalHandle::WrappedResult & result) { processing = false; - std::cout << "finished rotation" << std::endl; switch (result.code) { case rclcpp_action::ResultCode::SUCCEEDED: + RCLCPP_INFO(this->get_logger(), "finished rotation"); return; case rclcpp_action::ResultCode::ABORTED: RCLCPP_ERROR(this->get_logger(), "Goal was aborted"); @@ -166,6 +166,60 @@ void RotateAngleNode::result_callback(const rclcpp_action::ClientGoalHandleget_logger(), "RotateAngleNode killed"); + rclcpp::shutdown(); +} + +DriveArcNode::DriveArcNode() +: Node("drive_arc_node") +{ + drive_arc_action_ = rclcpp_action::create_client( + this, + "/drive_arc" + ); +} + + +void DriveArcNode::drive_arc(float angle, float radius, float velocity, int direction) +{ + processing = true; + angle *= pi / 180; + auto data = irobot_create_msgs::action::DriveArc::Goal(); + auto send_goal_options = rclcpp_action::Client::SendGoalOptions(); + send_goal_options.result_callback = + std::bind(&DriveArcNode::result_callback, this, std::placeholders::_1); + + + data.angle = angle; + data.radius = radius; + data.translate_direction = direction; + data.max_translation_speed = velocity; + drive_arc_action_->async_send_goal(data, send_goal_options); + + while (processing) {} +} + +void DriveArcNode::result_callback(const rclcpp_action::ClientGoalHandle::WrappedResult & result) +{ + processing = false; + switch (result.code) { + case rclcpp_action::ResultCode::SUCCEEDED: + RCLCPP_INFO(this->get_logger(), "finished arc"); + return; + case rclcpp_action::ResultCode::ABORTED: + RCLCPP_ERROR(this->get_logger(), "Goal was aborted"); + return; + case rclcpp_action::ResultCode::CANCELED: + RCLCPP_ERROR(this->get_logger(), "Goal was canceled"); + return; + default: + RCLCPP_ERROR(this->get_logger(), "Unknown result code"); + return; + } +} + +void DriveArcNode::kill() +{ + RCLCPP_INFO(this->get_logger(), "DriveArcNode killed"); rclcpp::shutdown(); } \ No newline at end of file From c593059fb15624e2e58a9effc606f4a9f4eb5d79 Mon Sep 17 00:00:00 2001 From: Matthias Guzmits Date: Wed, 19 Jul 2023 19:17:59 +0200 Subject: [PATCH 22/22] Add button functionality --- compLib/CMakeLists.txt | 2 +- compLib/include/controls.h | 24 +++++++++++++++++ compLib/src/controls.cpp | 53 ++++++++++++++++++++++++++++++++++++++ compLib/src/main.cpp | 15 +++++++++++ 4 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 compLib/include/controls.h create mode 100644 compLib/src/controls.cpp diff --git a/compLib/CMakeLists.txt b/compLib/CMakeLists.txt index 113ea36..d539099 100644 --- a/compLib/CMakeLists.txt +++ b/compLib/CMakeLists.txt @@ -25,7 +25,7 @@ find_package(geometry_msgs REQUIRED) # add_executable(set_vel src/set_speed.cpp) # ament_target_dependencies(set_vel rclcpp rclcpp_action std_msgs irobot_create_msgs geometry_msgs) -add_executable(compLib_node src/main.cpp src/motor.cpp) +add_executable(compLib_node src/main.cpp src/motor.cpp src/controls.cpp) ament_target_dependencies(compLib_node rclcpp rclcpp_action std_msgs irobot_create_msgs geometry_msgs) target_include_directories(compLib_node PRIVATE include) diff --git a/compLib/include/controls.h b/compLib/include/controls.h new file mode 100644 index 0000000..24a3780 --- /dev/null +++ b/compLib/include/controls.h @@ -0,0 +1,24 @@ +#ifndef CONTROLS_H +#define CONTROLS_H + +#include "rclcpp/rclcpp.hpp" +#include "rclcpp_action/rclcpp_action.hpp" + +#include "irobot_create_msgs/msg/interface_buttons.hpp" +#include "irobot_create_msgs/msg/lightring_leds.hpp" + +class ButtonPressNode : public rclcpp::Node +{ +public: + ButtonPressNode(); + void bt1_wait(); + void bt2_wait(); + void kill(); +private: + void result_callback(const irobot_create_msgs::msg::InterfaceButtons::SharedPtr result); + rclcpp::Subscription::SharedPtr interface_buttons_subscriber_; + bool button1{false}; + bool button2{false}; +}; + +#endif \ No newline at end of file diff --git a/compLib/src/controls.cpp b/compLib/src/controls.cpp new file mode 100644 index 0000000..a4a84a5 --- /dev/null +++ b/compLib/src/controls.cpp @@ -0,0 +1,53 @@ +#include "rclcpp/rclcpp.hpp" +#include "rclcpp_action/rclcpp_action.hpp" + +#include "irobot_create_msgs/msg/interface_buttons.hpp" + +#include "controls.h" + +ButtonPressNode::ButtonPressNode() +: Node("button_press_node") +{ + interface_buttons_subscriber_ = this->create_subscription( + "/interface_buttons", + rclcpp::SensorDataQoS(), + std::bind(&ButtonPressNode::result_callback, this, std::placeholders::_1) + ); +} + +void ButtonPressNode::bt1_wait() +{ + RCLCPP_INFO(this->get_logger(), "Wait for button 1..."); + button1 = false; + while (!button1) {} + button1 = false; +} + +void ButtonPressNode::bt2_wait() +{ + RCLCPP_INFO(this->get_logger(), "Wait for button 2..."); + button2 = false; + while (!button2) {} + button2 = false; +} + +void ButtonPressNode::result_callback(const irobot_create_msgs::msg::InterfaceButtons::SharedPtr result) +{ + if (result->button_1.is_pressed) { + button1 = true; + } + + if (result->button_2.is_pressed) { + button2 = true; + } + + if (result->button_power.is_pressed) { + + } +} + +void ButtonPressNode::kill() +{ + RCLCPP_INFO(this->get_logger(), "ButtonPressNode killed"); + rclcpp::shutdown(); +} \ No newline at end of file diff --git a/compLib/src/main.cpp b/compLib/src/main.cpp index c10699b..5c6296f 100644 --- a/compLib/src/main.cpp +++ b/compLib/src/main.cpp @@ -4,6 +4,7 @@ #include #include "motor.h" +#include "controls.h" std::mutex action_mutex; @@ -28,6 +29,11 @@ void run_node3(std::shared_ptr node) rclcpp::spin(node); } +void run_node4(std::shared_ptr node) +{ + rclcpp::spin(node); +} + int main(int argc, char * argv[]) { rclcpp::init(argc, argv); @@ -36,16 +42,23 @@ int main(int argc, char * argv[]) auto ssn = std::make_shared(); auto ran = std::make_shared(); auto dan = std::make_shared(); + auto bpn = std::make_shared(); std::thread t; std::thread t1; std::thread t2; std::thread t3; + std::thread t4; t = std::thread(run_node, ddn); t1 = std::thread(run_node1, ssn); t2 = std::thread(run_node2, ran); t3 = std::thread(run_node3, dan); + t4 = std::thread(run_node4, bpn); + + bpn->bt1_wait(); + bpn->bt2_wait(); + bpn->bt1_wait(); ssn->drive(0.3); @@ -68,11 +81,13 @@ int main(int argc, char * argv[]) ssn->kill(); ddn->kill(); dan->kill(); + bpn->kill(); t.join(); t1.join(); t2.join(); t3.join(); + t4.join(); return 0; } \ No newline at end of file