Cleanup
This commit is contained in:
parent
c16a7172e7
commit
d4a7d8c0c0
186 changed files with 1 additions and 7056 deletions
312
client/.gitignore
vendored
Normal file
312
client/.gitignore
vendored
Normal file
|
@ -0,0 +1,312 @@
|
|||
# Created by https://www.toptal.com/developers/gitignore/api/macos,python,pycharm
|
||||
# Edit at https://www.toptal.com/developers/gitignore?templates=macos,python,pycharm
|
||||
|
||||
### macOS ###
|
||||
# General
|
||||
.DS_Store
|
||||
.AppleDouble
|
||||
.LSOverride
|
||||
|
||||
# Icon must end with two \r
|
||||
Icon
|
||||
|
||||
|
||||
# Thumbnails
|
||||
._*
|
||||
|
||||
# Files that might appear in the root of a volume
|
||||
.DocumentRevisions-V100
|
||||
.fseventsd
|
||||
.Spotlight-V100
|
||||
.TemporaryItems
|
||||
.Trashes
|
||||
.VolumeIcon.icns
|
||||
.com.apple.timemachine.donotpresent
|
||||
|
||||
# Directories potentially created on remote AFP share
|
||||
.AppleDB
|
||||
.AppleDesktop
|
||||
Network Trash Folder
|
||||
Temporary Items
|
||||
.apdisk
|
||||
|
||||
### macOS Patch ###
|
||||
# iCloud generated files
|
||||
*.icloud
|
||||
|
||||
### PyCharm ###
|
||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
|
||||
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||
|
||||
# User-specific stuff
|
||||
.idea/**/workspace.xml
|
||||
.idea/**/tasks.xml
|
||||
.idea/**/usage.statistics.xml
|
||||
.idea/**/dictionaries
|
||||
.idea/**/shelf
|
||||
|
||||
# AWS User-specific
|
||||
.idea/**/aws.xml
|
||||
|
||||
# Generated files
|
||||
.idea/**/contentModel.xml
|
||||
|
||||
# Sensitive or high-churn files
|
||||
.idea/**/dataSources/
|
||||
.idea/**/dataSources.ids
|
||||
.idea/**/dataSources.local.xml
|
||||
.idea/**/sqlDataSources.xml
|
||||
.idea/**/dynamic.xml
|
||||
.idea/**/uiDesigner.xml
|
||||
.idea/**/dbnavigator.xml
|
||||
|
||||
# Gradle
|
||||
.idea/**/gradle.xml
|
||||
.idea/**/libraries
|
||||
|
||||
# Gradle and Maven with auto-import
|
||||
# When using Gradle or Maven with auto-import, you should exclude module files,
|
||||
# since they will be recreated, and may cause churn. Uncomment if using
|
||||
# auto-import.
|
||||
# .idea/artifacts
|
||||
# .idea/compiler.xml
|
||||
# .idea/jarRepositories.xml
|
||||
# .idea/modules.xml
|
||||
# .idea/*.iml
|
||||
# .idea/modules
|
||||
# *.iml
|
||||
# *.ipr
|
||||
|
||||
# CMake
|
||||
cmake-build-*/
|
||||
|
||||
# Mongo Explorer plugin
|
||||
.idea/**/mongoSettings.xml
|
||||
|
||||
# File-based project format
|
||||
*.iws
|
||||
|
||||
# IntelliJ
|
||||
out/
|
||||
|
||||
# mpeltonen/sbt-idea plugin
|
||||
.idea_modules/
|
||||
|
||||
# JIRA plugin
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
# Cursive Clojure plugin
|
||||
.idea/replstate.xml
|
||||
|
||||
# SonarLint plugin
|
||||
.idea/sonarlint/
|
||||
|
||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||
com_crashlytics_export_strings.xml
|
||||
crashlytics.properties
|
||||
crashlytics-build.properties
|
||||
fabric.properties
|
||||
|
||||
# Editor-based Rest Client
|
||||
.idea/httpRequests
|
||||
|
||||
# Android studio 3.1+ serialized cache file
|
||||
.idea/caches/build_file_checksums.ser
|
||||
|
||||
### PyCharm Patch ###
|
||||
# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
|
||||
|
||||
# *.iml
|
||||
# modules.xml
|
||||
# .idea/misc.xml
|
||||
# *.ipr
|
||||
|
||||
# Sonarlint plugin
|
||||
# https://plugins.jetbrains.com/plugin/7973-sonarlint
|
||||
.idea/**/sonarlint/
|
||||
|
||||
# SonarQube Plugin
|
||||
# https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin
|
||||
.idea/**/sonarIssues.xml
|
||||
|
||||
# Markdown Navigator plugin
|
||||
# https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced
|
||||
.idea/**/markdown-navigator.xml
|
||||
.idea/**/markdown-navigator-enh.xml
|
||||
.idea/**/markdown-navigator/
|
||||
|
||||
# Cache file creation bug
|
||||
# See https://youtrack.jetbrains.com/issue/JBR-2257
|
||||
.idea/$CACHE_FILE$
|
||||
|
||||
# CodeStream plugin
|
||||
# https://plugins.jetbrains.com/plugin/12206-codestream
|
||||
.idea/codestream.xml
|
||||
|
||||
# Azure Toolkit for IntelliJ plugin
|
||||
# https://plugins.jetbrains.com/plugin/8053-azure-toolkit-for-intellij
|
||||
.idea/**/azureSettings.xml
|
||||
|
||||
### Python ###
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
share/python-wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
MANIFEST
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.nox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
*.py,cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
cover/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
db.sqlite3
|
||||
db.sqlite3-journal
|
||||
|
||||
# Flask stuff:
|
||||
instance/
|
||||
.webassets-cache
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
.pybuilder/
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# IPython
|
||||
profile_default/
|
||||
ipython_config.py
|
||||
|
||||
# pyenv
|
||||
# For a library or package, you might want to ignore these files since the code is
|
||||
# intended to run in multiple environments; otherwise, check them in:
|
||||
# .python-version
|
||||
|
||||
# pipenv
|
||||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||
# install all needed dependencies.
|
||||
#Pipfile.lock
|
||||
|
||||
# poetry
|
||||
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
||||
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||
# commonly ignored for libraries.
|
||||
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
||||
#poetry.lock
|
||||
|
||||
# pdm
|
||||
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
||||
#pdm.lock
|
||||
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
||||
# in version control.
|
||||
# https://pdm.fming.dev/#use-with-ide
|
||||
.pdm.toml
|
||||
|
||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
||||
__pypackages__/
|
||||
|
||||
# Celery stuff
|
||||
celerybeat-schedule
|
||||
celerybeat.pid
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# Environments
|
||||
.env
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
.spyproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# mkdocs documentation
|
||||
/site
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
.dmypy.json
|
||||
dmypy.json
|
||||
|
||||
# Pyre type checker
|
||||
.pyre/
|
||||
|
||||
# pytype static type analyzer
|
||||
.pytype/
|
||||
|
||||
# Cython debug symbols
|
||||
cython_debug/
|
||||
|
||||
# PyCharm
|
||||
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
||||
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||
#.idea/
|
||||
|
||||
# End of https://www.toptal.com/developers/gitignore/api/macos,python,pycharm
|
3
client/.idea/.gitignore
generated
vendored
Normal file
3
client/.idea/.gitignore
generated
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
8
client/.idea/client_s2.iml
generated
Normal file
8
client/.idea/client_s2.iml
generated
Normal file
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="PYTHON_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
12
client/.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
12
client/.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
|
@ -0,0 +1,12 @@
|
|||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="PyUnresolvedReferencesInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="ignoredIdentifiers">
|
||||
<list>
|
||||
<option value="list.__getitem__" />
|
||||
</list>
|
||||
</option>
|
||||
</inspection_tool>
|
||||
</profile>
|
||||
</component>
|
6
client/.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
6
client/.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
|
@ -0,0 +1,6 @@
|
|||
<component name="InspectionProjectProfileManager">
|
||||
<settings>
|
||||
<option name="USE_PROJECT_PROFILE" value="false" />
|
||||
<version value="1.0" />
|
||||
</settings>
|
||||
</component>
|
7
client/.idea/misc.xml
generated
Normal file
7
client/.idea/misc.xml
generated
Normal file
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.9" project-jdk-type="Python SDK" />
|
||||
<component name="PyCharmProfessionalAdvertiser">
|
||||
<option name="shown" value="true" />
|
||||
</component>
|
||||
</project>
|
8
client/.idea/modules.xml
generated
Normal file
8
client/.idea/modules.xml
generated
Normal file
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/client_s2.iml" filepath="$PROJECT_DIR$/.idea/client_s2.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
15
client/.idea/saveactions_settings.xml
generated
Normal file
15
client/.idea/saveactions_settings.xml
generated
Normal file
|
@ -0,0 +1,15 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="SaveActionSettings">
|
||||
<option name="actions">
|
||||
<set>
|
||||
<option value="activate" />
|
||||
<option value="activateOnShortcut" />
|
||||
<option value="activateOnBatch" />
|
||||
<option value="organizeImports" />
|
||||
<option value="reformat" />
|
||||
<option value="rearrange" />
|
||||
</set>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
6
client/.idea/vcs.xml
generated
Normal file
6
client/.idea/vcs.xml
generated
Normal file
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
|
||||
</component>
|
||||
</project>
|
1
client/MANIFEST.in
Normal file
1
client/MANIFEST.in
Normal file
|
@ -0,0 +1 @@
|
|||
include readme.md
|
51
client/build_deb.sh
Executable file
51
client/build_deb.sh
Executable file
|
@ -0,0 +1,51 @@
|
|||
#!/usr/bin/bash
|
||||
|
||||
export PYTHONDONTWRITEBYTECODE=1
|
||||
|
||||
# set to 1 for debugging
|
||||
export EXTRACT_PKG="0"
|
||||
|
||||
if [[ -z $VERSION ]]; then
|
||||
echo "Warning, setting VERSION env var to default value 0.0.1-0"
|
||||
export VERSION="0.0.1-0"
|
||||
fi
|
||||
echo "Building Package version: $VERSION"
|
||||
|
||||
# BE CAREFUL TO NOT BUILD IN A PYTHON VENV!
|
||||
|
||||
# be sure to change version if needed!
|
||||
fpm -s python --python-bin python3 --python-pip pip3 --python-package-name-prefix python3 \
|
||||
-m '"Joel Klimont" <joel.klimont@comp-air.at>' \
|
||||
--license 'proprietary' \
|
||||
--description 'Library for robot used in the competition' \
|
||||
--after-install postinstall.sh \
|
||||
--after-upgrade postinstall.sh \
|
||||
--deb-priority "optional" \
|
||||
-d "python3-pip" \
|
||||
-d "nginx" \
|
||||
-d "libnginx-mod-rtmp" \
|
||||
-d "libatlas-base-dev" \
|
||||
-d "python3-numpy" \
|
||||
-d "compsrv" \
|
||||
-v $VERSION -t deb setup.py
|
||||
|
||||
if [ "$EXTRACT_PKG" == "1" ]; then
|
||||
echo "Exracting deb package"
|
||||
mkdir build_extract
|
||||
mv python3-complib_"$VERSION"_all.deb build_extract
|
||||
cd build_extract
|
||||
ar -xv python3-complib_"$VERSION"_all.deb
|
||||
fi
|
||||
|
||||
export DEB=python3-complib_"$VERSION"_all.deb
|
||||
echo "Created: $DEB"
|
||||
|
||||
# --deb-changelog changelog \
|
||||
# --deb-upstream-changelog changelog \
|
||||
# --deb-field "Distribution: stable" \
|
||||
# --deb-dist "stable" \
|
||||
|
||||
# sudo apt purge python3-complib -y
|
||||
# sudo apt install ./python3-*
|
||||
# sudo apt search complib
|
||||
# ar vx ./python3*
|
312
client/compLib/.gitignore
vendored
Normal file
312
client/compLib/.gitignore
vendored
Normal file
|
@ -0,0 +1,312 @@
|
|||
# Created by https://www.toptal.com/developers/gitignore/api/macos,python,pycharm
|
||||
# Edit at https://www.toptal.com/developers/gitignore?templates=macos,python,pycharm
|
||||
|
||||
### macOS ###
|
||||
# General
|
||||
.DS_Store
|
||||
.AppleDouble
|
||||
.LSOverride
|
||||
|
||||
# Icon must end with two \r
|
||||
Icon
|
||||
|
||||
|
||||
# Thumbnails
|
||||
._*
|
||||
|
||||
# Files that might appear in the root of a volume
|
||||
.DocumentRevisions-V100
|
||||
.fseventsd
|
||||
.Spotlight-V100
|
||||
.TemporaryItems
|
||||
.Trashes
|
||||
.VolumeIcon.icns
|
||||
.com.apple.timemachine.donotpresent
|
||||
|
||||
# Directories potentially created on remote AFP share
|
||||
.AppleDB
|
||||
.AppleDesktop
|
||||
Network Trash Folder
|
||||
Temporary Items
|
||||
.apdisk
|
||||
|
||||
### macOS Patch ###
|
||||
# iCloud generated files
|
||||
*.icloud
|
||||
|
||||
### PyCharm ###
|
||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
|
||||
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||
|
||||
# User-specific stuff
|
||||
.idea/**/workspace.xml
|
||||
.idea/**/tasks.xml
|
||||
.idea/**/usage.statistics.xml
|
||||
.idea/**/dictionaries
|
||||
.idea/**/shelf
|
||||
|
||||
# AWS User-specific
|
||||
.idea/**/aws.xml
|
||||
|
||||
# Generated files
|
||||
.idea/**/contentModel.xml
|
||||
|
||||
# Sensitive or high-churn files
|
||||
.idea/**/dataSources/
|
||||
.idea/**/dataSources.ids
|
||||
.idea/**/dataSources.local.xml
|
||||
.idea/**/sqlDataSources.xml
|
||||
.idea/**/dynamic.xml
|
||||
.idea/**/uiDesigner.xml
|
||||
.idea/**/dbnavigator.xml
|
||||
|
||||
# Gradle
|
||||
.idea/**/gradle.xml
|
||||
.idea/**/libraries
|
||||
|
||||
# Gradle and Maven with auto-import
|
||||
# When using Gradle or Maven with auto-import, you should exclude module files,
|
||||
# since they will be recreated, and may cause churn. Uncomment if using
|
||||
# auto-import.
|
||||
# .idea/artifacts
|
||||
# .idea/compiler.xml
|
||||
# .idea/jarRepositories.xml
|
||||
# .idea/modules.xml
|
||||
# .idea/*.iml
|
||||
# .idea/modules
|
||||
# *.iml
|
||||
# *.ipr
|
||||
|
||||
# CMake
|
||||
cmake-build-*/
|
||||
|
||||
# Mongo Explorer plugin
|
||||
.idea/**/mongoSettings.xml
|
||||
|
||||
# File-based project format
|
||||
*.iws
|
||||
|
||||
# IntelliJ
|
||||
out/
|
||||
|
||||
# mpeltonen/sbt-idea plugin
|
||||
.idea_modules/
|
||||
|
||||
# JIRA plugin
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
# Cursive Clojure plugin
|
||||
.idea/replstate.xml
|
||||
|
||||
# SonarLint plugin
|
||||
.idea/sonarlint/
|
||||
|
||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||
com_crashlytics_export_strings.xml
|
||||
crashlytics.properties
|
||||
crashlytics-build.properties
|
||||
fabric.properties
|
||||
|
||||
# Editor-based Rest Client
|
||||
.idea/httpRequests
|
||||
|
||||
# Android studio 3.1+ serialized cache file
|
||||
.idea/caches/build_file_checksums.ser
|
||||
|
||||
### PyCharm Patch ###
|
||||
# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
|
||||
|
||||
# *.iml
|
||||
# modules.xml
|
||||
# .idea/misc.xml
|
||||
# *.ipr
|
||||
|
||||
# Sonarlint plugin
|
||||
# https://plugins.jetbrains.com/plugin/7973-sonarlint
|
||||
.idea/**/sonarlint/
|
||||
|
||||
# SonarQube Plugin
|
||||
# https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin
|
||||
.idea/**/sonarIssues.xml
|
||||
|
||||
# Markdown Navigator plugin
|
||||
# https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced
|
||||
.idea/**/markdown-navigator.xml
|
||||
.idea/**/markdown-navigator-enh.xml
|
||||
.idea/**/markdown-navigator/
|
||||
|
||||
# Cache file creation bug
|
||||
# See https://youtrack.jetbrains.com/issue/JBR-2257
|
||||
.idea/$CACHE_FILE$
|
||||
|
||||
# CodeStream plugin
|
||||
# https://plugins.jetbrains.com/plugin/12206-codestream
|
||||
.idea/codestream.xml
|
||||
|
||||
# Azure Toolkit for IntelliJ plugin
|
||||
# https://plugins.jetbrains.com/plugin/8053-azure-toolkit-for-intellij
|
||||
.idea/**/azureSettings.xml
|
||||
|
||||
### Python ###
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
share/python-wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
MANIFEST
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.nox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
*.py,cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
cover/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
db.sqlite3
|
||||
db.sqlite3-journal
|
||||
|
||||
# Flask stuff:
|
||||
instance/
|
||||
.webassets-cache
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
.pybuilder/
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# IPython
|
||||
profile_default/
|
||||
ipython_config.py
|
||||
|
||||
# pyenv
|
||||
# For a library or package, you might want to ignore these files since the code is
|
||||
# intended to run in multiple environments; otherwise, check them in:
|
||||
# .python-version
|
||||
|
||||
# pipenv
|
||||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||
# install all needed dependencies.
|
||||
#Pipfile.lock
|
||||
|
||||
# poetry
|
||||
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
||||
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||
# commonly ignored for libraries.
|
||||
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
||||
#poetry.lock
|
||||
|
||||
# pdm
|
||||
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
||||
#pdm.lock
|
||||
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
||||
# in version control.
|
||||
# https://pdm.fming.dev/#use-with-ide
|
||||
.pdm.toml
|
||||
|
||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
||||
__pypackages__/
|
||||
|
||||
# Celery stuff
|
||||
celerybeat-schedule
|
||||
celerybeat.pid
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# Environments
|
||||
.env
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
.spyproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# mkdocs documentation
|
||||
/site
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
.dmypy.json
|
||||
dmypy.json
|
||||
|
||||
# Pyre type checker
|
||||
.pyre/
|
||||
|
||||
# pytype static type analyzer
|
||||
.pytype/
|
||||
|
||||
# Cython debug symbols
|
||||
cython_debug/
|
||||
|
||||
# PyCharm
|
||||
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
||||
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||
#.idea/
|
||||
|
||||
# End of https://www.toptal.com/developers/gitignore/api/macos,python,pycharm
|
70
client/compLib/Api.py
Normal file
70
client/compLib/Api.py
Normal file
|
@ -0,0 +1,70 @@
|
|||
import json
|
||||
import logging
|
||||
import os
|
||||
from typing import Dict, Tuple, List
|
||||
|
||||
import requests
|
||||
|
||||
logger = logging.getLogger("seeding-api")
|
||||
|
||||
API_URL = os.getenv("API_URL", "http://localhost:5000/") + "api/"
|
||||
CONF_URL = os.getenv("API_URL", "http://localhost:5000/") + "config/"
|
||||
|
||||
api_override = os.getenv("API_FORCE", "")
|
||||
|
||||
if api_override != "":
|
||||
print(f"API_URL was set to {API_URL} but was overwritten with {api_override}")
|
||||
API_URL = api_override
|
||||
|
||||
API_URL_GET_HEU = API_URL + "getHeuballen"
|
||||
API_URL_GET_LOGISTIC_PLAN = API_URL + "getLogisticPlan"
|
||||
API_URL_GET_MATERIAL_DELIVERIES = API_URL + "getMaterialDeliveries"
|
||||
API_URL_GET_ROBOT_STATE = API_URL + "getRobotState"
|
||||
|
||||
|
||||
class Seeding:
|
||||
"""Class used for communicating with seeding api
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def get_heuballen() -> int:
|
||||
"""Makes the /api/getHeuballen call to the api.
|
||||
|
||||
:return: hueballencode as int.
|
||||
:rtype: int
|
||||
"""
|
||||
res = requests.get(API_URL_GET_HEU)
|
||||
result = json.loads(res.content)
|
||||
logger.debug(f"Seeding.get_heuballen = {result}, status code = {res.status_code}")
|
||||
return result["heuballen"]
|
||||
|
||||
@staticmethod
|
||||
def get_logistic_plan() -> List:
|
||||
"""Makes the /api/getLogisticPlan call to the api.
|
||||
|
||||
:return: Json Object and status code as returned by the api.
|
||||
:rtype: List
|
||||
"""
|
||||
res = requests.get(API_URL_GET_LOGISTIC_PLAN)
|
||||
result = json.loads(res.content)
|
||||
logger.debug(f"Seeding.get_logistic_plan = {result}, status code = {res.status_code}")
|
||||
return result
|
||||
|
||||
@staticmethod
|
||||
def get_material_deliveries() -> List:
|
||||
"""Makes the /api/getMaterialDeliveries call to the api.
|
||||
|
||||
:return: Json Object and status code as returned by the api.
|
||||
:rtype: List
|
||||
"""
|
||||
res = requests.get(API_URL_GET_MATERIAL_DELIVERIES)
|
||||
result = json.loads(res.content)
|
||||
logger.debug(f"Seeding.get_material_deliveries = {result}, status code = {res.status_code}")
|
||||
return result
|
||||
|
||||
@staticmethod
|
||||
def get_robot_state() -> Tuple[Dict, int]:
|
||||
res = requests.get(API_URL_GET_ROBOT_STATE)
|
||||
result = json.loads(res.content)
|
||||
logger.debug(f"Seeding.get_robot_state {result}, status code = {res.status_code}")
|
||||
return result, res.status_code
|
113
client/compLib/CompLib.proto
Normal file
113
client/compLib/CompLib.proto
Normal file
|
@ -0,0 +1,113 @@
|
|||
syntax = "proto3";
|
||||
|
||||
package CompLib;
|
||||
|
||||
message Header {
|
||||
string message_type = 1;
|
||||
}
|
||||
|
||||
message Status {
|
||||
bool successful = 1;
|
||||
string error_message = 2;
|
||||
}
|
||||
|
||||
message GenericRequest {
|
||||
Header header = 1;
|
||||
}
|
||||
|
||||
message GenericResponse {
|
||||
Header header = 1;
|
||||
Status status = 2;
|
||||
}
|
||||
|
||||
message EncoderReadPositionsRequest {
|
||||
Header header = 1;
|
||||
}
|
||||
|
||||
message EncoderReadPositionsResponse {
|
||||
Header header = 1;
|
||||
Status status = 2;
|
||||
repeated int32 positions = 3 [packed = true];
|
||||
}
|
||||
|
||||
message EncoderReadVelocitiesRequest {
|
||||
Header header = 1;
|
||||
}
|
||||
|
||||
message EncoderReadVelocitiesResponse {
|
||||
Header header = 1;
|
||||
Status status = 2;
|
||||
repeated double velocities = 3 [packed = true];
|
||||
}
|
||||
|
||||
message IRSensorsEnableRequest {
|
||||
Header header = 1;
|
||||
}
|
||||
|
||||
message IRSensorsDisableRequest {
|
||||
Header header = 1;
|
||||
}
|
||||
|
||||
message IRSensorsReadAllRequest {
|
||||
Header header = 1;
|
||||
}
|
||||
|
||||
message IRSensorsReadAllResponse {
|
||||
Header header = 1;
|
||||
Status status = 2;
|
||||
repeated uint32 data = 3 [packed = true];
|
||||
}
|
||||
|
||||
message MotorSetPowerRequest {
|
||||
uint32 port = 1;
|
||||
double power = 2;
|
||||
}
|
||||
|
||||
message MotorsSetPowerRequest {
|
||||
Header header = 1;
|
||||
repeated MotorSetPowerRequest requests = 2;
|
||||
}
|
||||
|
||||
message MotorSetSpeedRequest {
|
||||
uint32 port = 1;
|
||||
double speed = 2;
|
||||
}
|
||||
|
||||
message MotorsSetSpeedRequest {
|
||||
Header header = 1;
|
||||
repeated MotorSetSpeedRequest requests = 2;
|
||||
}
|
||||
|
||||
message OdometryReadRequest {
|
||||
Header header = 1;
|
||||
}
|
||||
|
||||
message OdometryReadResponse {
|
||||
Header header = 1;
|
||||
Status status = 2;
|
||||
double x_position = 3;
|
||||
double y_position = 4;
|
||||
double orientation = 5;
|
||||
}
|
||||
|
||||
message DriveDistanceRequest {
|
||||
Header header = 1;
|
||||
double distance_m = 2;
|
||||
double velocity_m_s = 3;
|
||||
}
|
||||
|
||||
message TurnDegreesRequest {
|
||||
Header header = 1;
|
||||
double angle_degrees = 2;
|
||||
double velocity_rad_s = 3;
|
||||
}
|
||||
|
||||
message DriveRequest {
|
||||
Header header = 1;
|
||||
double linear_velocity_m_s = 2;
|
||||
double angular_velocity_rad_s = 3;
|
||||
}
|
||||
|
||||
message HealthUpdateRequest {
|
||||
Header header = 1;
|
||||
}
|
80
client/compLib/CompLibClient.py
Normal file
80
client/compLib/CompLibClient.py
Normal file
|
@ -0,0 +1,80 @@
|
|||
import socket
|
||||
from threading import Lock
|
||||
|
||||
import compLib.CompLib_pb2 as CompLib_pb2
|
||||
|
||||
|
||||
class CompLibClient(object):
|
||||
USE_UNIX_SOCKET = False
|
||||
UNIX_SOCKET_PATH = "/tmp/compLib"
|
||||
USE_TCP_SOCKET = False
|
||||
TCP_SOCKET_HOST = "10.20.5.1"
|
||||
TCP_SOCKET_PORT = 9090
|
||||
SOCKET = None
|
||||
LOCK = Lock()
|
||||
|
||||
@staticmethod
|
||||
def use_unix_socket(socket_path="/tmp/compLib"):
|
||||
CompLibClient.UNIX_SOCKET_PATH = socket_path
|
||||
CompLibClient.USE_UNIX_SOCKET = True
|
||||
CompLibClient.USE_TCP_SOCKET = False
|
||||
|
||||
CompLibClient.SOCKET = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||
CompLibClient.SOCKET.connect(CompLibClient.UNIX_SOCKET_PATH)
|
||||
|
||||
from compLib.HealthCheck import HealthUpdater
|
||||
HealthUpdater.start()
|
||||
|
||||
@staticmethod
|
||||
def use_tcp_socket(socket_host, socket_port=TCP_SOCKET_PORT):
|
||||
CompLibClient.TCP_SOCKET_HOST = socket_host
|
||||
CompLibClient.TCP_SOCKET_PORT = socket_port
|
||||
CompLibClient.USE_UNIX_SOCKET = False
|
||||
CompLibClient.USE_TCP_SOCKET = True
|
||||
|
||||
CompLibClient.SOCKET = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
CompLibClient.SOCKET.connect((CompLibClient.TCP_SOCKET_HOST, CompLibClient.TCP_SOCKET_PORT))
|
||||
|
||||
from compLib.HealthCheck import HealthUpdater
|
||||
HealthUpdater.start()
|
||||
|
||||
@staticmethod
|
||||
def send(data: bytes, size: int) -> bytes:
|
||||
with CompLibClient.LOCK:
|
||||
# if CompLibClient.USE_TCP_SOCKET:
|
||||
# sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
# sock.connect((CompLibClient.TCP_SOCKET_HOST, CompLibClient.TCP_SOCKET_PORT))
|
||||
#
|
||||
# elif CompLibClient.USE_UNIX_SOCKET:
|
||||
# sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||
# sock.connect(CompLibClient.UNIX_SOCKET_PATH)
|
||||
#
|
||||
# else:
|
||||
# return bytes(0)
|
||||
|
||||
CompLibClient.SOCKET.sendall(size.to_bytes(1, byteorder='big'))
|
||||
CompLibClient.SOCKET.sendall(data)
|
||||
|
||||
response_size_bytes = CompLibClient.SOCKET.recv(1)
|
||||
response_size = int.from_bytes(response_size_bytes, byteorder="big")
|
||||
# print(response_size)
|
||||
|
||||
response_bytes = CompLibClient.SOCKET.recv(response_size)
|
||||
# print(response_bytes.hex())
|
||||
# print(len(response_bytes))
|
||||
|
||||
CompLibClient.check_response(response_bytes)
|
||||
|
||||
return response_bytes
|
||||
|
||||
@staticmethod
|
||||
def check_response(response_bytes: bytes) -> bool:
|
||||
# print(f"{response_bytes}")
|
||||
res = CompLib_pb2.GenericResponse()
|
||||
res.ParseFromString(response_bytes)
|
||||
|
||||
if res.status.successful:
|
||||
return True
|
||||
|
||||
# TODO: Log error message if unsuccessful
|
||||
return False
|
1069
client/compLib/CompLib_pb2.py
Normal file
1069
client/compLib/CompLib_pb2.py
Normal file
File diff suppressed because it is too large
Load diff
157
client/compLib/DoubleElimination.py
Normal file
157
client/compLib/DoubleElimination.py
Normal file
|
@ -0,0 +1,157 @@
|
|||
import json
|
||||
import os
|
||||
import time
|
||||
from typing import Tuple, List, Dict
|
||||
|
||||
import requests as requests
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger("seeding-api")
|
||||
|
||||
ch = logging.StreamHandler()
|
||||
ch.setLevel(logging.DEBUG)
|
||||
formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
|
||||
ch.setFormatter(formatter)
|
||||
logger.addHandler(ch)
|
||||
|
||||
RETRY_TIMEOUT = 0.05
|
||||
|
||||
# TODO: rethink how the api url is read
|
||||
API_URL = os.getenv("API_URL", "http://localhost:5000/") + "api/"
|
||||
|
||||
api_override = os.getenv("API_FORCE", "")
|
||||
|
||||
if api_override != "":
|
||||
print(f"API_URL was set to {API_URL} but was overwritten with {api_override}")
|
||||
API_URL = api_override
|
||||
|
||||
API_URL_GET_ROBOT_STATE = API_URL + "getRobotState"
|
||||
|
||||
API_URL_GET_POS = API_URL + "getPos"
|
||||
API_URL_GET_OP = API_URL + "getOp"
|
||||
API_URL_GET_GOAL = API_URL + "getGoal"
|
||||
API_URL_GET_ITEMS = API_URL + "getItems"
|
||||
API_URL_GET_SCORES = API_URL + "getScores"
|
||||
|
||||
|
||||
class Position:
|
||||
"""Datastructure for holding a position
|
||||
"""
|
||||
|
||||
def __init__(self, x, y, degrees):
|
||||
self.x = x
|
||||
self.y = y
|
||||
self.degrees = degrees
|
||||
|
||||
def __repr__(self):
|
||||
return "{x=%s, y=%s, degrees=%s}" % (self.x, self.y, self.degrees)
|
||||
|
||||
def __str__(self):
|
||||
return f"Position(x={round(self.x, 5)}, y={round(self.y, 5)}, degrees={round(self.degrees, 5)})"
|
||||
|
||||
def __eq__(self, o: object) -> bool:
|
||||
if isinstance(o, Position):
|
||||
return self.x == o.x and self.y == o.y and self.degrees == o.degrees
|
||||
return False
|
||||
|
||||
def __ne__(self, o: object) -> bool:
|
||||
return not self.__eq__(o)
|
||||
|
||||
@staticmethod
|
||||
def position_from_json(json_str: Dict):
|
||||
return Position(json_str["x"], json_str["y"], json_str["degrees"])
|
||||
|
||||
|
||||
class DoubleElim:
|
||||
"""Class used for communicating with double elimination api
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def get_pos() -> Tuple[Position, int]:
|
||||
"""Makes the /api/getPos call to the api.
|
||||
:return: A Position object with robot position
|
||||
:rtype: Tuple[Position, int]
|
||||
"""
|
||||
res = requests.get(API_URL_GET_POS)
|
||||
if res.status_code == 408:
|
||||
logger.error(f"DoubleElim.get_position timeout. API={API_URL_GET_POS}")
|
||||
time.sleep(RETRY_TIMEOUT)
|
||||
return DoubleElim.get_pos()
|
||||
elif res.status_code == 503:
|
||||
return Position(0, 0, -1), 503
|
||||
|
||||
response = json.loads(res.content)
|
||||
logger.debug(f"DoubleElim.get_position = {response}, status code = {res.status_code}")
|
||||
return Position(response["x"], response["y"], response["degrees"]), res.status_code
|
||||
|
||||
@staticmethod
|
||||
def get_opponent() -> Tuple[Position, int]:
|
||||
"""Makes the /api/getOp call to the api.
|
||||
:return: A Position object with opponents robot position
|
||||
:rtype: Tuple[Position, int]
|
||||
"""
|
||||
res = requests.get(API_URL_GET_OP)
|
||||
if res.status_code == 408:
|
||||
logger.error(f"DoubleElim.get_opponent timeout. API={API_URL_GET_OP}")
|
||||
time.sleep(RETRY_TIMEOUT)
|
||||
return DoubleElim.get_opponent()
|
||||
elif res.status_code == 503:
|
||||
return Position(0, 0, -1), 503
|
||||
|
||||
response = json.loads(res.content)
|
||||
logger.debug(f"DoubleElim.get_opponent = x:{response}, status code = {res.status_code}")
|
||||
return Position(response["x"], response["y"], response["degrees"]), res.status_code
|
||||
|
||||
@staticmethod
|
||||
def get_goal() -> Tuple[Position, int]:
|
||||
"""Makes the /api/getGoal call to the api.
|
||||
:return: A Position object with x and y coordinates of the goal, rotation is always -1
|
||||
:rtype: Tuple[Position, int]
|
||||
"""
|
||||
res = requests.get(API_URL_GET_GOAL)
|
||||
if res.status_code == 408:
|
||||
logger.error(f"DoubleElim.get_goal timeout. API={API_URL_GET_GOAL}")
|
||||
time.sleep(RETRY_TIMEOUT)
|
||||
return DoubleElim.get_goal()
|
||||
elif res.status_code == 503:
|
||||
return Position(0, 0, -1), 503
|
||||
|
||||
response = json.loads(res.content)
|
||||
logger.debug(f"DoubleElim.get_goal = {response}, status code = {res.status_code}")
|
||||
return Position(response["x"], response["y"], -1), res.status_code
|
||||
|
||||
@staticmethod
|
||||
def get_items() -> Tuple[List[Dict], int]:
|
||||
"""Makes the /api/getItems call to the api.
|
||||
:return: A list will all items currently on the game field. Items are dictionaries that look like: {"id": 0, "x": 0, "y": 0}
|
||||
:rtype: Tuple[List[Dict], int]
|
||||
"""
|
||||
res = requests.get(API_URL_GET_ITEMS)
|
||||
if res.status_code == 408:
|
||||
logger.error(f"DoubleElim.get_items timeout. API={API_URL_GET_ITEMS}")
|
||||
time.sleep(RETRY_TIMEOUT)
|
||||
return DoubleElim.get_items()
|
||||
elif res.status_code == 503:
|
||||
return [], 503
|
||||
|
||||
response = json.loads(res.content)
|
||||
logger.debug(f"DoubleElim.get_items = {response}, status code = {res.status_code}")
|
||||
return response, res.status_code
|
||||
|
||||
@staticmethod
|
||||
def get_scores() -> Tuple[Dict, int]:
|
||||
"""Makes the /api/getScores call to the api.
|
||||
:return: A dictionary with all scores included like: {"self":2,"opponent":0}
|
||||
:rtype: Tuple[Dict, int]
|
||||
"""
|
||||
res = requests.get(API_URL_GET_SCORES)
|
||||
if res.status_code == 408:
|
||||
logger.error(f"DoubleElim.get_scores timeout. API={API_URL_GET_SCORES}")
|
||||
time.sleep(RETRY_TIMEOUT)
|
||||
return DoubleElim.get_scores()
|
||||
elif res.status_code == 503:
|
||||
return {"self": 0, "opponent": 0}, 503
|
||||
|
||||
response = json.loads(res.content)
|
||||
logger.debug(f"DoubleElim.get_scores = {response}, status code = {res.status_code}")
|
||||
return response, res.status_code
|
35
client/compLib/Encoder.py
Normal file
35
client/compLib/Encoder.py
Normal file
|
@ -0,0 +1,35 @@
|
|||
import compLib.CompLib_pb2 as CompLib_pb2
|
||||
from compLib.CompLibClient import CompLibClient
|
||||
|
||||
|
||||
class Encoder(object):
|
||||
"""Class used to read the encoders
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def read_all_positions():
|
||||
"""Read all encoder positions.
|
||||
|
||||
:return: Tuple of all current encoder positions
|
||||
"""
|
||||
request = CompLib_pb2.EncoderReadPositionsRequest()
|
||||
request.header.message_type = request.DESCRIPTOR.full_name
|
||||
|
||||
response = CompLib_pb2.EncoderReadPositionsResponse()
|
||||
response.ParseFromString(CompLibClient.send(request.SerializeToString(), request.ByteSize()))
|
||||
|
||||
return tuple(i for i in response.positions)
|
||||
|
||||
@staticmethod
|
||||
def read_all_velocities():
|
||||
"""Read the velocity of all motors connected.
|
||||
|
||||
:return: Tuple of all current motor velocities
|
||||
"""
|
||||
request = CompLib_pb2.EncoderReadVelocitiesRequest()
|
||||
request.header.message_type = request.DESCRIPTOR.full_name
|
||||
|
||||
response = CompLib_pb2.EncoderReadVelocitiesResponse()
|
||||
response.ParseFromString(CompLibClient.send(request.SerializeToString(), request.ByteSize()))
|
||||
|
||||
return tuple(i for i in response.velocities)
|
23
client/compLib/HealthCheck.py
Normal file
23
client/compLib/HealthCheck.py
Normal file
|
@ -0,0 +1,23 @@
|
|||
import threading
|
||||
import time
|
||||
|
||||
import compLib.CompLib_pb2 as CompLib_pb2
|
||||
from compLib.CompLibClient import CompLibClient
|
||||
|
||||
|
||||
class HealthUpdater(object):
|
||||
started = False
|
||||
|
||||
@staticmethod
|
||||
def start():
|
||||
if not HealthUpdater.started:
|
||||
threading.Thread(target=HealthUpdater.loop, daemon=True).start()
|
||||
HealthUpdater.started = True
|
||||
|
||||
@staticmethod
|
||||
def loop():
|
||||
while True:
|
||||
request = CompLib_pb2.HealthUpdateRequest()
|
||||
request.header.message_type = request.DESCRIPTOR.full_name
|
||||
CompLibClient.send(request.SerializeToString(), request.ByteSize())
|
||||
time.sleep(0.25)
|
40
client/compLib/IRSensor.py
Normal file
40
client/compLib/IRSensor.py
Normal file
|
@ -0,0 +1,40 @@
|
|||
import compLib.CompLib_pb2 as CompLib_pb2
|
||||
|
||||
from compLib.CompLibClient import CompLibClient
|
||||
|
||||
|
||||
class IRSensor(object):
|
||||
"""Access the different IR Sensors of the robot
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def read_all():
|
||||
"""Read all IR sensors at once.
|
||||
|
||||
:return: Array of all current ir sensors
|
||||
"""
|
||||
request = CompLib_pb2.IRSensorsReadAllRequest()
|
||||
request.header.message_type = request.DESCRIPTOR.full_name
|
||||
|
||||
response = CompLib_pb2.IRSensorsReadAllResponse()
|
||||
response.ParseFromString(CompLibClient.send(request.SerializeToString(), request.ByteSize()))
|
||||
|
||||
return [i for i in response.data]
|
||||
|
||||
@staticmethod
|
||||
def enable():
|
||||
"""Turn on all IR emitters
|
||||
"""
|
||||
request = CompLib_pb2.IRSensorsEnableRequest()
|
||||
request.header.message_type = request.DESCRIPTOR.full_name
|
||||
|
||||
CompLibClient.send(request.SerializeToString(), request.ByteSize())
|
||||
|
||||
@staticmethod
|
||||
def disable():
|
||||
"""Turn off all IR emitters
|
||||
"""
|
||||
request = CompLib_pb2.IRSensorsDisableRequest()
|
||||
request.header.message_type = request.DESCRIPTOR.full_name
|
||||
|
||||
CompLibClient.send(request.SerializeToString(), request.ByteSize())
|
117
client/compLib/Motor.py
Normal file
117
client/compLib/Motor.py
Normal file
|
@ -0,0 +1,117 @@
|
|||
import compLib.CompLib_pb2 as CompLib_pb2
|
||||
from compLib.CompLibClient import CompLibClient
|
||||
|
||||
MOTOR_COUNT = 4
|
||||
|
||||
|
||||
class Motor(object):
|
||||
"""Class used to control the motors
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def power(port: int, percent: float):
|
||||
"""Set specified motor to percentage power
|
||||
|
||||
:param port: Port, which the motor is connected to. 0-3
|
||||
:param percent: Percentage of max speed. between -100 and 100
|
||||
:raises: IndexError
|
||||
"""
|
||||
|
||||
if port < 0 or port >= MOTOR_COUNT:
|
||||
raise IndexError("Invalid Motor port specified!")
|
||||
|
||||
if percent < -100 or percent > 100:
|
||||
raise IndexError("Invalid Motor speed specified! Speed is between -100 and 100 percent!")
|
||||
|
||||
request = CompLib_pb2.MotorsSetPowerRequest()
|
||||
request.header.message_type = request.DESCRIPTOR.full_name
|
||||
request.port = port
|
||||
request.power = percent
|
||||
|
||||
CompLibClient.send(request.SerializeToString(), request.ByteSize())
|
||||
|
||||
@staticmethod
|
||||
def multiple_power(*arguments: tuple[int, float]):
|
||||
"""Set specified motors to percentage power
|
||||
|
||||
:param arguments: tuples of port, percentage
|
||||
:raises: IndexError
|
||||
"""
|
||||
request = CompLib_pb2.MotorsSetPowerRequest()
|
||||
request.header.message_type = request.DESCRIPTOR.full_name
|
||||
|
||||
for port, percent in arguments:
|
||||
if port < 0 or port >= MOTOR_COUNT:
|
||||
raise IndexError("Invalid Motor port specified!")
|
||||
|
||||
if percent < -100 or percent > 100:
|
||||
raise IndexError("Invalid Motor speed specified! Speed is between -100 and 100 percent!")
|
||||
|
||||
inner_request = CompLib_pb2.MotorSetPowerRequest()
|
||||
inner_request.port = port
|
||||
inner_request.power = percent
|
||||
|
||||
request.requests.append(inner_request)
|
||||
|
||||
CompLibClient.send(request.SerializeToString(), request.ByteSize())
|
||||
|
||||
@staticmethod
|
||||
def speed(port: int, speed: float):
|
||||
"""Set specified motor to percentage power
|
||||
|
||||
:param port: Port, which the motor is connected to. 0-3
|
||||
:param speed: Speed at which a motor should turn in RPM
|
||||
:raises: IndexError
|
||||
"""
|
||||
|
||||
if port < 0 or port >= MOTOR_COUNT:
|
||||
raise IndexError("Invalid Motor port specified!")
|
||||
|
||||
request = CompLib_pb2.MotorsSetSpeedRequest()
|
||||
request.header.message_type = request.DESCRIPTOR.full_name
|
||||
request.port = port
|
||||
request.speed = speed
|
||||
|
||||
CompLibClient.send(request.SerializeToString(), request.ByteSize())
|
||||
|
||||
@staticmethod
|
||||
def multiple_speed(*arguments: tuple[int, float]):
|
||||
"""Set specified motor to percentage power
|
||||
|
||||
:param arguments: tuples of port, speed in rpm
|
||||
:raises: IndexError
|
||||
"""
|
||||
|
||||
request = CompLib_pb2.MotorsSetSpeedRequest()
|
||||
request.header.message_type = request.DESCRIPTOR.full_name
|
||||
|
||||
for port, speed in arguments:
|
||||
if port < 0 or port >= MOTOR_COUNT:
|
||||
raise IndexError("Invalid Motor port specified!")
|
||||
|
||||
inner_request = CompLib_pb2.MotorSetSpeedRequest()
|
||||
inner_request.port = port
|
||||
inner_request.speed = speed
|
||||
|
||||
request.requests.append(inner_request)
|
||||
|
||||
CompLibClient.send(request.SerializeToString(), request.ByteSize())
|
||||
|
||||
# @staticmethod
|
||||
# def all_off():
|
||||
# """
|
||||
# Turns of all motors
|
||||
# """
|
||||
# Logging.get_logger().debug(f"Motor.all_off")
|
||||
#
|
||||
# for i in range(1, MOTOR_COUNT + 1):
|
||||
# Motor.active_break(i)
|
||||
|
||||
# @staticmethod
|
||||
# def active_break(port: int):
|
||||
# """
|
||||
# Actively break with a specific motor
|
||||
#
|
||||
# :param port: Port, which the motor is connected to. 1-4
|
||||
# """
|
||||
# Motor.pwm(port, 0, MotorMode.BREAK)
|
57
client/compLib/Movement.py
Normal file
57
client/compLib/Movement.py
Normal file
|
@ -0,0 +1,57 @@
|
|||
import compLib.CompLib_pb2 as CompLib_pb2
|
||||
from compLib.CompLibClient import CompLibClient
|
||||
|
||||
|
||||
class Movement(object):
|
||||
"""High level class to control movement of the robot
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def drive_distance(distance: float, speed: float):
|
||||
"""
|
||||
Drive a given distance with a certain speed.
|
||||
Positive distance and speed with result in forward motion. Everything else will move backwards.
|
||||
:param distance: Distance in meters
|
||||
:param speed: Speed in meters per second
|
||||
:return: None
|
||||
"""
|
||||
request = CompLib_pb2.DriveDistanceRequest()
|
||||
request.header.message_type = request.DESCRIPTOR.full_name
|
||||
request.distance_m = distance
|
||||
request.velocity_m_s = speed
|
||||
|
||||
response = CompLib_pb2.GenericResponse()
|
||||
response.ParseFromString(CompLibClient.send(request.SerializeToString(), request.ByteSize()))
|
||||
|
||||
@staticmethod
|
||||
def turn_degrees(degrees: float, speed: float):
|
||||
"""
|
||||
Turn specified degrees with a given speed.
|
||||
Positive degrees and speed with result in counter-clockwise motion. Everything else will be clockwise
|
||||
:param degrees: Degrees between -180 and 180
|
||||
:param speed: Speed in radians per second
|
||||
:return: None
|
||||
"""
|
||||
request = CompLib_pb2.TurnDegreesRequest()
|
||||
request.header.message_type = request.DESCRIPTOR.full_name
|
||||
request.angle_degrees = degrees
|
||||
request.velocity_rad_s = speed
|
||||
|
||||
response = CompLib_pb2.GenericResponse()
|
||||
response.ParseFromString(CompLibClient.send(request.SerializeToString(), request.ByteSize()))
|
||||
|
||||
@staticmethod
|
||||
def drive(linear: float, angular: float):
|
||||
"""
|
||||
Non-blocking way to perform a linear and angular motion at the same time.
|
||||
:param linear: Linear speed in meters per second
|
||||
:param angular: Angular speed in radians per second
|
||||
:return: None
|
||||
"""
|
||||
request = CompLib_pb2.DriveDistanceRequest()
|
||||
request.header.message_type = request.DESCRIPTOR.full_name
|
||||
request.linear_velocity_m_s = linear
|
||||
request.angular_velocity_rad_s = angular
|
||||
|
||||
response = CompLib_pb2.GenericResponse()
|
||||
response.ParseFromString(CompLibClient.send(request.SerializeToString(), request.ByteSize()))
|
89
client/compLib/Seeding.py
Normal file
89
client/compLib/Seeding.py
Normal file
|
@ -0,0 +1,89 @@
|
|||
import numpy as np
|
||||
|
||||
|
||||
# TODO: if set to competition mode, get the seed from the api
|
||||
|
||||
def set_random_seed(seed: int):
|
||||
np.random.seed(seed)
|
||||
|
||||
|
||||
def get_random_number(min: int, max: int):
|
||||
return np.random.randint(256 ** 4, dtype='<u4', size=1)[0] % (max - min + 1) + min
|
||||
|
||||
|
||||
class Gamestate:
|
||||
def __str__(self) -> str:
|
||||
return f"""Seed: {self.seed}
|
||||
Heu Color: {self.heu_color}
|
||||
Material Pairs: {self.material_pairs}
|
||||
Material Zones: {self.materials}
|
||||
Logistic Plan: {self.logistic_plan}
|
||||
Logistic Centers: {self.logistic_center}"""
|
||||
|
||||
def __init__(self, seed: int):
|
||||
self.seed = seed
|
||||
set_random_seed(seed)
|
||||
|
||||
self.heu_color = get_random_number(1, 2)
|
||||
|
||||
self.materials = [0, 0, 0, 0]
|
||||
self.material_pairs = []
|
||||
for i in range(0, 4):
|
||||
num1 = get_random_number(0, 3)
|
||||
self.material_pairs.append([num1, num1])
|
||||
while self.material_pairs[i][1] == num1:
|
||||
self.material_pairs[i][1] = get_random_number(0, 3)
|
||||
|
||||
flat = [item for sublist in self.material_pairs for item in sublist]
|
||||
for i in range(0, 4):
|
||||
self.materials[i] = flat.count(i)
|
||||
|
||||
self.logistic_plan = [0 for i in range(0, 21)]
|
||||
self.logistic_center = [[0, 0, 0, 0] for i in range(0, 4)]
|
||||
visited = [5, 5, 5, 5]
|
||||
|
||||
def __logistic_plan_generator(i: int):
|
||||
drive_to = get_random_number(0, 3)
|
||||
for j in range(0, 4):
|
||||
drive_to = (drive_to + j) % 4
|
||||
if visited[drive_to] <= 0 or drive_to == self.logistic_plan[i - 1]:
|
||||
continue
|
||||
self.logistic_plan[i] = drive_to
|
||||
|
||||
visited[drive_to] -= 1
|
||||
finished = True
|
||||
for k in visited:
|
||||
if k != 0:
|
||||
finished = False
|
||||
|
||||
if finished and drive_to == 2:
|
||||
visited[drive_to] += 1
|
||||
continue
|
||||
|
||||
if finished:
|
||||
return True
|
||||
|
||||
if i < len(self.logistic_plan):
|
||||
if __logistic_plan_generator(i + 1):
|
||||
return True
|
||||
visited[drive_to] += 1
|
||||
return False
|
||||
|
||||
self.logistic_plan[0] = 2
|
||||
visited[2] -= 1
|
||||
_ = __logistic_plan_generator(1)
|
||||
|
||||
self.logistic_plan[-1] = 2
|
||||
for i in range(0, len(self.logistic_plan) - 1):
|
||||
self.logistic_center[self.logistic_plan[i]][self.logistic_plan[i + 1]] += 1
|
||||
|
||||
self.logistic_plan = [x + 10 for x in self.logistic_plan]
|
||||
|
||||
def get_heuballen(self) -> int:
|
||||
return self.heu_color
|
||||
|
||||
def get_logistic_plan(self) -> []:
|
||||
return self.logistic_plan
|
||||
|
||||
def get_material_deliveries(self) -> [[]]:
|
||||
return self.material_pairs
|
0
client/compLib/__init__.py
Normal file
0
client/compLib/__init__.py
Normal file
24
client/dev01.py
Normal file
24
client/dev01.py
Normal file
|
@ -0,0 +1,24 @@
|
|||
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()
|
34
client/dev03.py
Normal file
34
client/dev03.py
Normal file
|
@ -0,0 +1,34 @@
|
|||
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()
|
3
client/docs/.gitignore
vendored
Normal file
3
client/docs/.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
build
|
||||
logs.db
|
||||
!lib
|
20
client/docs/Makefile
Normal file
20
client/docs/Makefile
Normal file
|
@ -0,0 +1,20 @@
|
|||
# Minimal makefile for Sphinx documentation
|
||||
#
|
||||
|
||||
# You can set these variables from the command line, and also
|
||||
# from the environment for the first two.
|
||||
SPHINXOPTS ?=
|
||||
SPHINXBUILD ?= sphinx-build
|
||||
SOURCEDIR = source
|
||||
BUILDDIR = build
|
||||
|
||||
# Put it first so that "make" without argument is like "make help".
|
||||
help:
|
||||
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
|
||||
.PHONY: help Makefile
|
||||
|
||||
# Catch-all target: route all unknown targets to Sphinx using the new
|
||||
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
||||
%: Makefile
|
||||
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
35
client/docs/make.bat
Normal file
35
client/docs/make.bat
Normal file
|
@ -0,0 +1,35 @@
|
|||
@ECHO OFF
|
||||
|
||||
pushd %~dp0
|
||||
|
||||
REM Command file for Sphinx documentation
|
||||
|
||||
if "%SPHINXBUILD%" == "" (
|
||||
set SPHINXBUILD=sphinx-build
|
||||
)
|
||||
set SOURCEDIR=source
|
||||
set BUILDDIR=build
|
||||
|
||||
if "%1" == "" goto help
|
||||
|
||||
%SPHINXBUILD% >NUL 2>NUL
|
||||
if errorlevel 9009 (
|
||||
echo.
|
||||
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
|
||||
echo.installed, then set the SPHINXBUILD environment variable to point
|
||||
echo.to the full path of the 'sphinx-build' executable. Alternatively you
|
||||
echo.may add the Sphinx directory to PATH.
|
||||
echo.
|
||||
echo.If you don't have Sphinx installed, grab it from
|
||||
echo.http://sphinx-doc.org/
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
|
||||
goto end
|
||||
|
||||
:help
|
||||
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
|
||||
|
||||
:end
|
||||
popd
|
0
client/docs/source/_static/.gitkeep
Normal file
0
client/docs/source/_static/.gitkeep
Normal file
63
client/docs/source/conf.py
Normal file
63
client/docs/source/conf.py
Normal file
|
@ -0,0 +1,63 @@
|
|||
# Configuration file for the Sphinx documentation builder.
|
||||
#
|
||||
# This file only contains a selection of the most common options. For a full
|
||||
# list see the documentation:
|
||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html
|
||||
|
||||
# -- Path setup --------------------------------------------------------------
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
#
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.insert(0, os.path.abspath('../..'))
|
||||
sys.setrecursionlimit(1500)
|
||||
os.environ["EXTENSIVE_LOGGING"] = "False"
|
||||
|
||||
# -- Project information -----------------------------------------------------
|
||||
|
||||
project = 'CompLib'
|
||||
copyright = '2022, Verein zur Förderung von Wissenschaft und Technik an Schulen (F-WuTS)'
|
||||
author = 'robo4you'
|
||||
|
||||
# The full version, including alpha/beta/rc tags
|
||||
release = '0.2.3'
|
||||
|
||||
# -- General configuration ---------------------------------------------------
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||
# ones.
|
||||
extensions = [
|
||||
'sphinx.ext.autodoc',
|
||||
'sphinx_rtd_theme'
|
||||
]
|
||||
|
||||
autodoc_mock_imports = ["smbus", "compLib.PCA9685", "RPi",
|
||||
"pigpio", "flask", "apt", "influxdb_client"]
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
# This pattern also affects html_static_path and html_extra_path.
|
||||
exclude_patterns = []
|
||||
|
||||
# -- Options for HTML output -------------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
#
|
||||
html_theme = 'sphinx_rtd_theme'
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ['_static']
|
||||
|
||||
|
||||
language = "de"
|
189
client/docs/source/images/compair-logo-white.svg
Normal file
189
client/docs/source/images/compair-logo-white.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 188 KiB |
18
client/docs/source/index.rst
Normal file
18
client/docs/source/index.rst
Normal file
|
@ -0,0 +1,18 @@
|
|||
.. image:: images/compair-logo-white.svg
|
||||
|
||||
Dokumentation des Roboters
|
||||
##########################
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:caption: Contents:
|
||||
|
||||
Contents
|
||||
*********
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 5
|
||||
:glob:
|
||||
|
||||
other/usage
|
||||
lib/index.rst
|
47
client/docs/source/lib/classes/Motor.rst
Normal file
47
client/docs/source/lib/classes/Motor.rst
Normal file
|
@ -0,0 +1,47 @@
|
|||
.. _lib_motor:
|
||||
|
||||
Motoren
|
||||
********
|
||||
|
||||
Dokumentation der Klasse
|
||||
========================
|
||||
|
||||
.. autoclass:: compLib.Motor.Motor
|
||||
:members:
|
||||
|
||||
Genauere Informationen
|
||||
======================
|
||||
|
||||
Power vs Speed
|
||||
--------------
|
||||
Zur ansteuerung der Motoren kann entweder ``Motor.power(...)`` oder ``Motor.speed(...)`` verwendet werden.
|
||||
Der Unterschied der 2 Funktionen liegt dabei in der Einheit des 2. Parameters. Bei ``Motor.power()`` wird dabei ein Wert zwischen -100% und 100% der maximalen Geschwindigkeit angegeben.
|
||||
Im Gegensatz dazu erlaubt einem ``Motor.speed()`` eine Geschwindigkeit in Umdrehungen pro Minute.
|
||||
|
||||
Normal vs Multiple
|
||||
------------------
|
||||
Der Aufruf der funktionen kann entweder über ``Motor.power(port, percent)`` oder ``Motor.power((port, percent), (port, percent), ..)`` erfolgen.
|
||||
Der zweite Aufruf ermöglicht dem Entwickler dabei beide Motoren in einem Aufruf anzusteuern und bringt einen kleinen Vorteil in der Leistungsfähigkeit der Software.
|
||||
|
||||
|
||||
Beispiele
|
||||
=========
|
||||
|
||||
Vorwärts fahren
|
||||
-------------
|
||||
|
||||
Mit folgenden Programm drehen sich beide Motoren mit 50% ihrer maximalen Geschwindigkeit.
|
||||
Dabei ist zu beachten, dass ein Motor in die entgegengesetzte Richtung zum aneren Motor gedreht werden muss, da diese spiegelverkehrt montiert sind.
|
||||
|
||||
Zusätzlich ist ein ``time.sleep(5)`` notwendig, welches das Programm für 5 Sekunden pausiert. Diese Pause wird benötigt, da der Roboter automatisch alle Motoren beim Ende des Progammes deaktiviert.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from compLib.Motor import Motor
|
||||
import time
|
||||
|
||||
Motor.power(0, -50)
|
||||
Motor.power(3, 50)
|
||||
|
||||
time.sleep(5)
|
||||
|
BIN
client/docs/source/lib/classes/images/chessboard.jpg
Normal file
BIN
client/docs/source/lib/classes/images/chessboard.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 33 KiB |
BIN
client/docs/source/lib/classes/images/chessboard_detected.jpg
Normal file
BIN
client/docs/source/lib/classes/images/chessboard_detected.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 69 KiB |
BIN
client/docs/source/lib/classes/images/opencv_http_stream.png
Normal file
BIN
client/docs/source/lib/classes/images/opencv_http_stream.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 391 KiB |
BIN
client/docs/source/lib/classes/images/opencv_processed.png
Normal file
BIN
client/docs/source/lib/classes/images/opencv_processed.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 356 KiB |
8
client/docs/source/lib/index.rst
Normal file
8
client/docs/source/lib/index.rst
Normal file
|
@ -0,0 +1,8 @@
|
|||
compLib
|
||||
#######
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 5
|
||||
:glob:
|
||||
|
||||
classes/*
|
32
client/docs/source/other/usage.rst
Normal file
32
client/docs/source/other/usage.rst
Normal file
|
@ -0,0 +1,32 @@
|
|||
.. _other_usage:
|
||||
|
||||
Beispiele
|
||||
#########
|
||||
|
||||
Vorwärts und rückwärts fahren
|
||||
*****************************
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import time
|
||||
from compLib.Motor import *
|
||||
|
||||
def forward():
|
||||
Motor.power(1, -30);
|
||||
Motor.power(2, 30);
|
||||
|
||||
|
||||
def backward():
|
||||
Motor.power(1, 30);
|
||||
Motor.power(2, -30);
|
||||
|
||||
def main():
|
||||
print("hallo ich bin ein roboter beep buup")
|
||||
|
||||
forward()
|
||||
time.sleep(1)
|
||||
backward()
|
||||
time.sleep(1)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
109
client/lf.py
Normal file
109
client/lf.py
Normal file
|
@ -0,0 +1,109 @@
|
|||
import time
|
||||
|
||||
from compLib.CompLibClient import CompLibClient
|
||||
from compLib.IRSensor import IRSensor
|
||||
from compLib.Motor import Motor
|
||||
|
||||
DRIVE_SPEED = 5.0
|
||||
COLOR_BREAK = 1500.0
|
||||
KP = 2.0
|
||||
KD = 0.0
|
||||
|
||||
|
||||
def drive(left_speed, right_speed):
|
||||
print(left_speed, right_speed)
|
||||
|
||||
right_speed *= -1.0
|
||||
|
||||
Motor.speed(0, right_speed)
|
||||
Motor.speed(3, left_speed)
|
||||
|
||||
|
||||
def follow(sleep_time=0.1):
|
||||
last_error = 0
|
||||
sensors_black = 0
|
||||
while sensors_black <= 3:
|
||||
sensor_values = IRSensor.read_all()
|
||||
|
||||
sensors_black = 0
|
||||
for sensor in sensor_values:
|
||||
if sensor > COLOR_BREAK:
|
||||
sensors_black += 1
|
||||
|
||||
error = last_error
|
||||
if sensor_values[2] > COLOR_BREAK:
|
||||
error = 0
|
||||
elif sensor_values[0] > COLOR_BREAK:
|
||||
error = -1.5
|
||||
elif sensor_values[4] > COLOR_BREAK:
|
||||
error = 1.5
|
||||
elif sensor_values[1] > COLOR_BREAK:
|
||||
error = -1
|
||||
elif sensor_values[3] > COLOR_BREAK:
|
||||
error = 1
|
||||
elif error == 1.5:
|
||||
error = 3.5
|
||||
elif error == -1.5:
|
||||
error = -3.5
|
||||
|
||||
last_error = error
|
||||
|
||||
adjustment = KP * error + KD * (error - last_error)
|
||||
left_speed = DRIVE_SPEED + adjustment
|
||||
right_speed = DRIVE_SPEED - adjustment
|
||||
|
||||
print(sensor_values)
|
||||
print(f"{left_speed} {right_speed} {adjustment} {error}")
|
||||
drive(left_speed, right_speed)
|
||||
|
||||
drive(0, 0)
|
||||
time.sleep(sleep_time)
|
||||
|
||||
|
||||
def follow_simple():
|
||||
left_speed = DRIVE_SPEED
|
||||
right_speed = DRIVE_SPEED
|
||||
sensor_values = IRSensor.read_all()
|
||||
while True:
|
||||
sensor_values = IRSensor.read_all()
|
||||
# for i in range(len(sensor_values)):
|
||||
# sensor_values[i] = (sensor_values[i] + new_sensor_values[i]) / 2.0
|
||||
|
||||
print(sensor_values)
|
||||
|
||||
if sensor_values[0] > COLOR_BREAK and sensor_values[4] > COLOR_BREAK:
|
||||
break
|
||||
|
||||
if sensor_values[0] > COLOR_BREAK:
|
||||
left_speed = -DRIVE_SPEED / 2
|
||||
right_speed = DRIVE_SPEED
|
||||
elif sensor_values[4] > COLOR_BREAK:
|
||||
left_speed = DRIVE_SPEED
|
||||
right_speed = -DRIVE_SPEED / 2
|
||||
elif sensor_values[2] > COLOR_BREAK:
|
||||
left_speed = DRIVE_SPEED
|
||||
right_speed = DRIVE_SPEED
|
||||
|
||||
drive(left_speed, right_speed)
|
||||
|
||||
|
||||
def main():
|
||||
CompLibClient.use_unix_socket()
|
||||
|
||||
IRSensor.enable()
|
||||
time.sleep(0.1)
|
||||
|
||||
# while True:
|
||||
# print(IRSensor.read_all())
|
||||
|
||||
# follow_simple()
|
||||
# drive(5, 5)
|
||||
# time.sleep(5)
|
||||
# follow()
|
||||
# follow()
|
||||
# follow()
|
||||
# follow()
|
||||
# follow(0.2)
|
||||
|
||||
|
||||
main()
|
174
client/main.py
Normal file
174
client/main.py
Normal file
|
@ -0,0 +1,174 @@
|
|||
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()
|
36
client/postinstall.sh
Normal file
36
client/postinstall.sh
Normal file
|
@ -0,0 +1,36 @@
|
|||
grep -qxF "apt update" /etc/rc.local
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "adding apt update to rc.local"
|
||||
sed -i "2s/^/apt update\n/" /etc/rc.local
|
||||
fi
|
||||
|
||||
pip3 install requests flask
|
||||
|
||||
#echo "Setting up opencv4"
|
||||
#pkg-config --modversion opencv4
|
||||
|
||||
echo "Setting up nginx rtmp server"
|
||||
sudo /etc/init.d/nginx start
|
||||
|
||||
{
|
||||
echo 'load_module "modules/ngx_rtmp_module.so";'
|
||||
echo 'worker_processes auto;'
|
||||
echo 'rtmp_auto_push on;'
|
||||
echo 'events {}'
|
||||
echo 'rtmp {'
|
||||
echo ' server {'
|
||||
echo ' listen 1935;'
|
||||
echo ' listen [::]:1935 ipv6only=on;'
|
||||
echo ' application live {'
|
||||
echo ' live on;'
|
||||
echo ' record off;'
|
||||
echo ' }'
|
||||
echo ' }'
|
||||
echo '}'
|
||||
} >| /etc/nginx/nginx.conf
|
||||
|
||||
base64 -d << UPD
|
||||
CiBfX19fX18gICAgIF9fX19fXyAgICAgX18gICAgX18gICAgIF9fX19fXyAgIF9fICAgICAgICAgX18gICAgIF9fX19fXyAgICAgICAgICAgICAgICAgIAovXCAgX19fXCAgIC9cICBfXyBcICAgL1wgIi0uLyAgXCAgIC9cICA9PSBcIC9cIFwgICAgICAgL1wgXCAgIC9cICA9PSBcICAgICAgICAgICAgICAgICAKXCBcIFxfX19fICBcIFwgXC9cIFwgIFwgXCBcLS4vXCBcICBcIFwgIF8tLyBcIFwgXF9fX18gIFwgXCBcICBcIFwgIF9fPCAgICAgICAgICAgICAgICAgCiBcIFxfX19fX1wgIFwgXF9fX19fXCAgXCBcX1wgXCBcX1wgIFwgXF9cICAgIFwgXF9fX19fXCAgXCBcX1wgIFwgXF9fX19fXCAgICAgICAgICAgICAgIAogIFwvX19fX18vICAgXC9fX19fXy8gICBcL18vICBcL18vICAgXC9fLyAgICAgXC9fX19fXy8gICBcL18vICAgXC9fX19fXy8gICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiBfXyAgX18gICAgIF9fX19fXyAgICAgIF9fX19fXyAgIF9fX19fXyAgICAgICAgX19fX18gICAgIF9fX19fXyAgICAgX19fX19fICAgX19fX19fICAgIAovXCBcL1wgXCAgIC9cICA9PSBcICAgIC9cX18gIF9cIC9cICBfXyBcICAgICAgL1wgIF9fLS4gIC9cICBfXyBcICAgL1xfXyAgX1wgL1wgIF9fX1wgICAKXCBcIFxfXCBcICBcIFwgIF8tLyAgICBcL18vXCBcLyBcIFwgXC9cIFwgICAgIFwgXCBcL1wgXCBcIFwgIF9fIFwgIFwvXy9cIFwvIFwgXCAgX19cICAgCiBcIFxfX19fX1wgIFwgXF9cICAgICAgICAgXCBcX1wgIFwgXF9fX19fXCAgICAgXCBcX19fXy0gIFwgXF9cIFxfXCAgICBcIFxfXCAgXCBcX19fX19cIAogIFwvX19fX18vICAgXC9fLyAgICAgICAgICBcL18vICAgXC9fX19fXy8gICAgICBcL19fX18vICAgXC9fL1wvXy8gICAgIFwvXy8gICBcL19fX19fLyA=
|
||||
UPD
|
||||
echo ""
|
||||
echo ""
|
24
client/setup.py
Normal file
24
client/setup.py
Normal file
|
@ -0,0 +1,24 @@
|
|||
#!/usr/bin/python3
|
||||
import setuptools
|
||||
import os
|
||||
|
||||
print("Using version: {str(os.environ['VERSION'])}")
|
||||
|
||||
setuptools.setup(
|
||||
name="complib",
|
||||
version=str(os.environ["VERSION"]),
|
||||
author="F-WuTs",
|
||||
author_email="joel.klimont@comp-air.at",
|
||||
description="",
|
||||
summary="Robot client library for the compAIR competition",
|
||||
platforms=["any"],
|
||||
url="https://github.com/F-WuTS/compLIB",
|
||||
packages=setuptools.find_packages(),
|
||||
include_package_data=True,
|
||||
classifiers=[
|
||||
"Programming Language :: Python :: 3.9",
|
||||
"License :: Other/Proprietary License",
|
||||
"Operating System :: Unix"
|
||||
],
|
||||
license="proprietary"
|
||||
)
|
23
client/sphinx_to_github.sh
Executable file
23
client/sphinx_to_github.sh
Executable file
|
@ -0,0 +1,23 @@
|
|||
export BUILDING_DOCS=true
|
||||
cd docs || exit
|
||||
rm -rf build
|
||||
rm -rf gh-pages
|
||||
|
||||
make html
|
||||
|
||||
git clone git@github.com:F-WuTS/compLIB.git gh-pages
|
||||
|
||||
cd gh-pages || exit
|
||||
git checkout gh-pages
|
||||
|
||||
cp -r ../build/html/* .
|
||||
|
||||
git add .
|
||||
git commit -a -m "Update documentation"
|
||||
git push origin gh-pages
|
||||
|
||||
cd ..
|
||||
rm -rf gh-pages
|
||||
|
||||
cd ..
|
||||
export BUILDING_DOCS=false
|
97
client/test.py
Normal file
97
client/test.py
Normal file
|
@ -0,0 +1,97 @@
|
|||
import json
|
||||
import unittest
|
||||
import requests
|
||||
|
||||
import compLib.Seeding as Seeding
|
||||
import compLib.Api as SeedingApi
|
||||
import compLib.DoubleElimination as De
|
||||
|
||||
|
||||
class SeedingTest(unittest.TestCase):
|
||||
def test_basic_seed(self):
|
||||
gamestate = Seeding.Gamestate(0)
|
||||
self.assertEqual(gamestate.seed, 0)
|
||||
self.assertEqual(gamestate.heu_color, 1)
|
||||
self.assertEqual(gamestate.get_heuballen(), 1)
|
||||
self.assertEqual(gamestate.get_logistic_plan(),
|
||||
[12, 13, 10, 13, 12, 10, 11, 10, 12, 11, 12, 13, 10, 12, 10, 11, 13, 11, 13, 11, 12])
|
||||
self.assertEqual(gamestate.get_material_deliveries(), [[3, 1], [0, 3], [3, 1], [3, 1]])
|
||||
|
||||
|
||||
def util_get_info():
|
||||
res = requests.get(SeedingApi.CONF_URL + "getInfo")
|
||||
return json.loads(res.text)
|
||||
|
||||
|
||||
def util_set_seeding():
|
||||
res = requests.get(SeedingApi.CONF_URL + "setToSeeding")
|
||||
return res.status_code == 200
|
||||
|
||||
|
||||
def util_set_de():
|
||||
res = requests.get(SeedingApi.CONF_URL + "setToDoubleElim")
|
||||
return res.status_code == 200
|
||||
|
||||
|
||||
def util_start_match():
|
||||
res = requests.get(SeedingApi.CONF_URL + "startMatch")
|
||||
return res.status_code == 200
|
||||
|
||||
|
||||
def util_reset_state():
|
||||
res = requests.get(SeedingApi.CONF_URL + "resetState")
|
||||
return res.status_code == 200
|
||||
|
||||
|
||||
def util_set_seed(seed):
|
||||
res = requests.get(SeedingApi.CONF_URL + "resetState", params={"seed": seed})
|
||||
return res.status_code == 200
|
||||
|
||||
|
||||
class SeedingApiTest(unittest.TestCase):
|
||||
def test_api_seeding_extensive(self):
|
||||
self.assertTrue(util_set_seeding())
|
||||
self.assertTrue(util_get_info()["is_seeding"])
|
||||
for seed in range(0, 256):
|
||||
print(f"Testing seed: {seed}")
|
||||
gamestate = Seeding.Gamestate(seed)
|
||||
self.assertTrue(util_set_seed(seed))
|
||||
seeding_api = SeedingApi.Seeding()
|
||||
self.assertEqual(seeding_api.get_heuballen(), gamestate.get_heuballen())
|
||||
self.assertEqual(seeding_api.get_logistic_plan(), gamestate.get_logistic_plan())
|
||||
self.assertEqual(seeding_api.get_material_deliveries(), gamestate.get_material_deliveries())
|
||||
|
||||
|
||||
class DeApiTest(unittest.TestCase):
|
||||
def test_api_de(self):
|
||||
self.assertTrue(util_set_de())
|
||||
self.assertTrue(util_reset_state())
|
||||
self.assertFalse(util_get_info()["is_seeding"])
|
||||
|
||||
de = De.DoubleElim()
|
||||
self.assertEqual(de.get_pos(), (De.Position(0, 0, -1), 503))
|
||||
self.assertEqual(de.get_opponent(), (De.Position(0, 0, -1), 503))
|
||||
self.assertEqual(de.get_goal(), (De.Position(0, 0, -1), 503))
|
||||
self.assertEqual(de.get_items(), ([], 503))
|
||||
self.assertEqual(de.get_scores(), ({"self": 0, "opponent": 0}, 503))
|
||||
|
||||
self.assertTrue(util_start_match())
|
||||
self.assertLessEqual(util_get_info()["timeleft"], 120)
|
||||
|
||||
self.assertEqual(de.get_pos()[1], 200)
|
||||
self.assertEqual(de.get_opponent()[1], 200)
|
||||
self.assertEqual(de.get_goal()[1], 200)
|
||||
self.assertEqual(de.get_items()[1], 200)
|
||||
self.assertEqual(de.get_scores()[1], 200)
|
||||
|
||||
self.assertTrue(0 <= de.get_pos()[0].x <= 250)
|
||||
self.assertTrue(0 <= de.get_pos()[0].y <= 250)
|
||||
self.assertTrue(0 <= de.get_pos()[0].degrees <= 360)
|
||||
self.assertEqual(de.get_items(), ([], 200))
|
||||
|
||||
self.assertTrue(util_reset_state())
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
Reference in a new issue