feat: initial commit

This commit is contained in:
2020-05-17 16:26:04 +02:00
commit f69cc0b45c
26 changed files with 10131 additions and 0 deletions

223
.gitignore vendored Normal file
View File

@@ -0,0 +1,223 @@
# Created by https://www.gitignore.io/api/node,vuejs,python
# Edit at https://www.gitignore.io/?templates=node,vuejs,python
### Node ###
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# TypeScript v1 declaration files
typings/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
.env.test
# parcel-bundler cache (https://parceljs.org/)
.cache
# next.js build output
.next
# nuxt.js build output
.nuxt
# rollup.js default build output
dist/
# Uncomment the public line if your project uses Gatsby
# https://nextjs.org/blog/next-9-1#public-directory-support
# https://create-react-app.dev/docs/using-the-public-folder/#docsNav
# public
# Storybook build outputs
.out
.storybook-out
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# Temporary folders
tmp/
temp/
### Python ###
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
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.*
nosetests.xml
coverage.xml
*.cover
.hypothesis/
.pytest_cache/
# Translations
*.mo
*.pot
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# pyenv
.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
# celery beat schedule file
celerybeat-schedule
# SageMath parsed files
*.sage.py
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# Mr Developer
.mr.developer.cfg
.project
.pydevproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
### Vuejs ###
# Recommended template: Node.gitignore
npm-debug.log
yarn-error.log
# End of https://www.gitignore.io/api/node,vuejs,python
# custom
.idea/

17
Pipfile Normal file
View File

@@ -0,0 +1,17 @@
[[source]]
name = "pypi"
url = "https://pypi.org/simple"
verify_ssl = true
[dev-packages]
gpiosimulator = "*"
[packages]
flask = ">=1.1.1"
opencv-python = ">=4.2.0.32"
Pillow = ">=7.0.0"
flask-socketio = ">=4.2.1"
eventlet = ">=0.25.1"
[requires]
python_version = "3.8"

260
Pipfile.lock generated Normal file
View File

@@ -0,0 +1,260 @@
{
"_meta": {
"hash": {
"sha256": "7af0d68da6f8b291e308dcbb0f43308554f6003211349e71b15462f322e14e5e"
},
"pipfile-spec": 6,
"requires": {
"python_version": "3.8"
},
"sources": [
{
"name": "pypi",
"url": "https://pypi.org/simple",
"verify_ssl": true
}
]
},
"default": {
"click": {
"hashes": [
"sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a",
"sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"
],
"version": "==7.1.2"
},
"dnspython": {
"hashes": [
"sha256:36c5e8e38d4369a08b6780b7f27d790a292b2b08eea01607865bf0936c558e01",
"sha256:f69c21288a962f4da86e56c4905b49d11aba7938d3d740e80d9e366ee4f1632d"
],
"version": "==1.16.0"
},
"eventlet": {
"hashes": [
"sha256:4c8ab42c51bff55204fef43cff32616558bedbc7538d876bb6a96ce820c7f9ed",
"sha256:955f2cf538829bfcb7b3aa885ace40e8ae5965dcd5b876c384d0c5869702db1d"
],
"index": "pypi",
"version": "==0.25.2"
},
"flask": {
"hashes": [
"sha256:4efa1ae2d7c9865af48986de8aeb8504bf32c7f3d6fdc9353d34b21f4b127060",
"sha256:8a4fdd8936eba2512e9c85df320a37e694c93945b33ef33c89946a340a238557"
],
"index": "pypi",
"version": "==1.1.2"
},
"flask-socketio": {
"hashes": [
"sha256:5969e1d4ead37ec9164f82779ec86239f0f394a08b20477d2056903010920f36",
"sha256:7f9b54ac9cd92e28a657c58f51943d97e76b988840c8795784e7b2bafb13103f"
],
"index": "pypi",
"version": "==4.3.0"
},
"gpiosimulator": {
"hashes": [
"sha256:08a221d03c9c5bd137d573b24aa0ebb9871760b12b8a1090392cbded3d06fee8"
],
"index": "pypi",
"version": "==0.1"
},
"greenlet": {
"hashes": [
"sha256:000546ad01e6389e98626c1367be58efa613fa82a1be98b0c6fc24b563acc6d0",
"sha256:0d48200bc50cbf498716712129eef819b1729339e34c3ae71656964dac907c28",
"sha256:23d12eacffa9d0f290c0fe0c4e81ba6d5f3a5b7ac3c30a5eaf0126bf4deda5c8",
"sha256:37c9ba82bd82eb6a23c2e5acc03055c0e45697253b2393c9a50cef76a3985304",
"sha256:51155342eb4d6058a0ffcd98a798fe6ba21195517da97e15fca3db12ab201e6e",
"sha256:51503524dd6f152ab4ad1fbd168fc6c30b5795e8c70be4410a64940b3abb55c0",
"sha256:7457d685158522df483196b16ec648b28f8e847861adb01a55d41134e7734122",
"sha256:8041e2de00e745c0e05a502d6e6db310db7faa7c979b3a5877123548a4c0b214",
"sha256:81fcd96a275209ef117e9ec91f75c731fa18dcfd9ffaa1c0adbdaa3616a86043",
"sha256:853da4f9563d982e4121fed8c92eea1a4594a2299037b3034c3c898cb8e933d6",
"sha256:8b4572c334593d449113f9dc8d19b93b7b271bdbe90ba7509eb178923327b625",
"sha256:9416443e219356e3c31f1f918a91badf2e37acf297e2fa13d24d1cc2380f8fbc",
"sha256:9854f612e1b59ec66804931df5add3b2d5ef0067748ea29dc60f0efdcda9a638",
"sha256:99a26afdb82ea83a265137a398f570402aa1f2b5dfb4ac3300c026931817b163",
"sha256:a19bf883b3384957e4a4a13e6bd1ae3d85ae87f4beb5957e35b0be287f12f4e4",
"sha256:a9f145660588187ff835c55a7d2ddf6abfc570c2651c276d3d4be8a2766db490",
"sha256:ac57fcdcfb0b73bb3203b58a14501abb7e5ff9ea5e2edfa06bb03035f0cff248",
"sha256:bcb530089ff24f6458a81ac3fa699e8c00194208a724b644ecc68422e1111939",
"sha256:beeabe25c3b704f7d56b573f7d2ff88fc99f0138e43480cecdfcaa3b87fe4f87",
"sha256:d634a7ea1fc3380ff96f9e44d8d22f38418c1c381d5fac680b272d7d90883720",
"sha256:d97b0661e1aead761f0ded3b769044bb00ed5d33e1ec865e891a8b128bf7c656",
"sha256:e538b8dae561080b542b0f5af64d47ef859f22517f7eca617bb314e0e03fd7ef"
],
"version": "==0.4.15"
},
"itsdangerous": {
"hashes": [
"sha256:321b033d07f2a4136d3ec762eac9f16a10ccd60f53c0c91af90217ace7ba1f19",
"sha256:b12271b2047cb23eeb98c8b5622e2e5c5e9abd9784a153e9d8ef9cb4dd09d749"
],
"version": "==1.1.0"
},
"jinja2": {
"hashes": [
"sha256:89aab215427ef59c34ad58735269eb58b1a5808103067f7bb9d5836c651b3bb0",
"sha256:f0a4641d3cf955324a89c04f3d94663aa4d638abe8f733ecd3582848e1c37035"
],
"version": "==2.11.2"
},
"markupsafe": {
"hashes": [
"sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473",
"sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161",
"sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235",
"sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5",
"sha256:13d3144e1e340870b25e7b10b98d779608c02016d5184cfb9927a9f10c689f42",
"sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff",
"sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b",
"sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1",
"sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e",
"sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183",
"sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66",
"sha256:596510de112c685489095da617b5bcbbac7dd6384aeebeda4df6025d0256a81b",
"sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1",
"sha256:6788b695d50a51edb699cb55e35487e430fa21f1ed838122d722e0ff0ac5ba15",
"sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1",
"sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e",
"sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b",
"sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905",
"sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735",
"sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d",
"sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e",
"sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d",
"sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c",
"sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21",
"sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2",
"sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5",
"sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b",
"sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6",
"sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f",
"sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f",
"sha256:cdb132fc825c38e1aeec2c8aa9338310d29d337bebbd7baa06889d09a60a1fa2",
"sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7",
"sha256:e8313f01ba26fbbe36c7be1966a7b7424942f670f38e666995b88d012765b9be"
],
"version": "==1.1.1"
},
"monotonic": {
"hashes": [
"sha256:23953d55076df038541e648a53676fb24980f7a1be290cdda21300b3bc21dfb0",
"sha256:552a91f381532e33cbd07c6a2655a21908088962bb8fa7239ecbcc6ad1140cc7"
],
"version": "==1.5"
},
"numpy": {
"hashes": [
"sha256:00d7b54c025601e28f468953d065b9b121ddca7fff30bed7be082d3656dd798d",
"sha256:02ec9582808c4e48be4e93cd629c855e644882faf704bc2bd6bbf58c08a2a897",
"sha256:0e6f72f7bb08f2f350ed4408bb7acdc0daba637e73bce9f5ea2b207039f3af88",
"sha256:1be2e96314a66f5f1ce7764274327fd4fb9da58584eaff00b5a5221edefee7d6",
"sha256:2466fbcf23711ebc5daa61d28ced319a6159b260a18839993d871096d66b93f7",
"sha256:2b573fcf6f9863ce746e4ad00ac18a948978bb3781cffa4305134d31801f3e26",
"sha256:3f0dae97e1126f529ebb66f3c63514a0f72a177b90d56e4bce8a0b5def34627a",
"sha256:50fb72bcbc2cf11e066579cb53c4ca8ac0227abb512b6cbc1faa02d1595a2a5d",
"sha256:57aea170fb23b1fd54fa537359d90d383d9bf5937ee54ae8045a723caa5e0961",
"sha256:709c2999b6bd36cdaf85cf888d8512da7433529f14a3689d6e37ab5242e7add5",
"sha256:7d59f21e43bbfd9a10953a7e26b35b6849d888fc5a331fa84a2d9c37bd9fe2a2",
"sha256:904b513ab8fbcbdb062bed1ce2f794ab20208a1b01ce9bd90776c6c7e7257032",
"sha256:96dd36f5cdde152fd6977d1bbc0f0561bccffecfde63cd397c8e6033eb66baba",
"sha256:9933b81fecbe935e6a7dc89cbd2b99fea1bf362f2790daf9422a7bb1dc3c3085",
"sha256:bbcc85aaf4cd84ba057decaead058f43191cc0e30d6bc5d44fe336dc3d3f4509",
"sha256:dccd380d8e025c867ddcb2f84b439722cf1f23f3a319381eac45fd077dee7170",
"sha256:e22cd0f72fc931d6abc69dc7764484ee20c6a60b0d0fee9ce0426029b1c1bdae",
"sha256:ed722aefb0ebffd10b32e67f48e8ac4c5c4cf5d3a785024fdf0e9eb17529cd9d",
"sha256:efb7ac5572c9a57159cf92c508aad9f856f1cb8e8302d7fdb99061dbe52d712c",
"sha256:efdba339fffb0e80fcc19524e4fdbda2e2b5772ea46720c44eaac28096d60720",
"sha256:f22273dd6a403ed870207b853a856ff6327d5cbce7a835dfa0645b3fc00273ec"
],
"version": "==1.18.4"
},
"opencv-python": {
"hashes": [
"sha256:068928b9907b3d3acd53b129062557d6b0b8b324bfade77f028dbe4dfe482bf2",
"sha256:0e7c91718351449877c2d4141abd64eee1f9c8701bcfaf4e8627bd023e303368",
"sha256:1ab92d807427641ec45d28d5907426aa06b4ffd19c5b794729c74d91cd95090e",
"sha256:31d634dea1b47c231b88d384f90605c598214d0c596443c9bb808e11761829f5",
"sha256:5fdfc0bed37315f27d30ae5ae9bad47ec0a0a28c323739d39c8177b7e0929238",
"sha256:6fa8fac14dd5af4819d475f74af12d65fbbfa391d3110c3a972934a5e6507c24",
"sha256:78cc89ebc808886eb190626ee71ab65e47f374121975f86e4d5f7c0e3ce6bed9",
"sha256:7c7ba11720d01cb572b4b6945d115cb103462c0a28996b44d4e540d06e6a90fd",
"sha256:a37ee82f1b8ed4b4645619c504311e71ce845b78f40055e78d71add5fab7da82",
"sha256:aa3ca1f54054e1c6439fdf1edafa2a2b940a9eaac04a7b422a1cba9b2d7b9690",
"sha256:b9de3dd956574662712da8e285f0f54327959a4e95b96a2847d3c3f5ee7b96e2",
"sha256:c0087b428cef9a32d977390656d91b02245e0e91f909870492df7e39202645dd",
"sha256:d87e506ab205799727f0efa34b3888949bf029a3ada5eb000ff632606370ca6e",
"sha256:d8a55585631f9c9eca4b1a996e9732ae023169cf2f46f69e4518d67d96198226",
"sha256:dcb8da8c5ebaa6360c8555547a4c7beb6cd983dd95ba895bb78b86cc8cf3de2b",
"sha256:e2206bb8c17c0f212f1f356d82d72dd090ff4651994034416da9bf0c29732825",
"sha256:e3c57d6579e5bf85f564d6d48d8ee89868b92879a9232b9975d072c346625e92",
"sha256:ef89cbf332b9a735d8a82e9ff79cc743eeeb775ad1cd7100bc2aa2429b496f07",
"sha256:f45c1c3cdda1857bedd4dfe0bbd49c9419af0cc57f33490341edeae97d18f037",
"sha256:fb3c855347310788e4286b867997be354c55535597966ed5dac876d9166013a4"
],
"index": "pypi",
"version": "==4.2.0.34"
},
"pillow": {
"hashes": [
"sha256:04766c4930c174b46fd72d450674612ab44cca977ebbcc2dde722c6933290107",
"sha256:0e2a3bceb0fd4e0cb17192ae506d5f082b309ffe5fc370a5667959c9b2f85fa3",
"sha256:0f01e63c34f0e1e2580cc0b24e86a5ccbbfa8830909a52ee17624c4193224cd9",
"sha256:12e4bad6bddd8546a2f9771485c7e3d2b546b458ae8ff79621214119ac244523",
"sha256:1f694e28c169655c50bb89a3fa07f3b854d71eb47f50783621de813979ba87f3",
"sha256:3d25dd8d688f7318dca6d8cd4f962a360ee40346c15893ae3b95c061cdbc4079",
"sha256:4b02b9c27fad2054932e89f39703646d0c543f21d3cc5b8e05434215121c28cd",
"sha256:9744350687459234867cbebfe9df8f35ef9e1538f3e729adbd8fde0761adb705",
"sha256:a0b49960110bc6ff5fead46013bcb8825d101026d466f3a4de3476defe0fb0dd",
"sha256:ae2b270f9a0b8822b98655cb3a59cdb1bd54a34807c6c56b76dd2e786c3b7db3",
"sha256:b37bb3bd35edf53125b0ff257822afa6962649995cbdfde2791ddb62b239f891",
"sha256:b532bcc2f008e96fd9241177ec580829dee817b090532f43e54074ecffdcd97f",
"sha256:b67a6c47ed963c709ed24566daa3f95a18f07d3831334da570c71da53d97d088",
"sha256:b943e71c2065ade6fef223358e56c167fc6ce31c50bc7a02dd5c17ee4338e8ac",
"sha256:ccc9ad2460eb5bee5642eaf75a0438d7f8887d484490d5117b98edd7f33118b7",
"sha256:d23e2aa9b969cf9c26edfb4b56307792b8b374202810bd949effd1c6e11ebd6d",
"sha256:eaa83729eab9c60884f362ada982d3a06beaa6cc8b084cf9f76cae7739481dfa",
"sha256:ee94fce8d003ac9fd206496f2707efe9eadcb278d94c271f129ab36aa7181344",
"sha256:f455efb7a98557412dc6f8e463c1faf1f1911ec2432059fa3e582b6000fc90e2",
"sha256:f46e0e024346e1474083c729d50de909974237c72daca05393ee32389dabe457",
"sha256:f54be399340aa602066adb63a86a6a5d4f395adfdd9da2b9a0162ea808c7b276",
"sha256:f784aad988f12c80aacfa5b381ec21fd3f38f851720f652b9f33facc5101cf4d"
],
"index": "pypi",
"version": "==7.1.2"
},
"python-engineio": {
"hashes": [
"sha256:222926adb4bc6e03a8fc8e0ef2a3309f030c1c3f8e0fcc94c9ba214574565f02",
"sha256:2481732d93646998f7372ef0ecf003af7817b82720b881db173c3d50b4887916"
],
"version": "==3.12.1"
},
"python-socketio": {
"hashes": [
"sha256:149b98c33f8c3d09273fb4ebeb83781e4dc9411b56b27d9f058bec1bd1ed74b7",
"sha256:81280cbbb7018d8ecdd006bf6025979733d347c0f2612282c1e21f6ed7d3b55b"
],
"version": "==4.5.1"
},
"six": {
"hashes": [
"sha256:236bdbdce46e6e6a3d61a337c0f8b763ca1e8717c03b369e87a7ec7ce1319c0a",
"sha256:8f3cd2e254d8f793e7f3d6d9df77b92252b52637291d0f0da013c76ea2724b6c"
],
"version": "==1.14.0"
},
"werkzeug": {
"hashes": [
"sha256:2de2a5db0baeae7b2d2664949077c2ac63fbd16d98da0ff71837f7d1dea3fd43",
"sha256:6c80b1e5ad3665290ea39320b91e1be1e0d5f60652b964a3070216de83d2e47c"
],
"version": "==1.0.1"
}
},
"develop": {}
}

37
app.py Normal file
View File

@@ -0,0 +1,37 @@
from control.camera import Camera
from control.walle import WallE
from flask import Flask, jsonify, send_file, Response
from flask_socketio import SocketIO
# DEBUG = True
boundary = 'lkajflkasdjlkfaj'
app = Flask(__name__, static_url_path='', static_folder='client/dist')
app.config.from_object(__name__)
sio = SocketIO(app)
walle = WallE()
@app.route('/')
def index():
return send_file('client/dist/index.html')
@app.route('/imagestream.mjpg')
def image_stream():
# cam = Camera()
# return Response(cam.mjpeg_stream(boundary.encode()),
# mimetype='multipart/x-mixed-replace; boundary=lkajflkasdjlkfaj')
return ""
@sio.on("move")
def message(directions):
walle.set_movement(directions['angle'], directions['distance'])
print(f"Moving in direction {directions['angle']:f} with velocity {directions['distance']}")
if __name__ == '__main__':
sio.run(app, host='0.0.0.0')

BIN
app.zip Normal file

Binary file not shown.

2
client/.browserslistrc Normal file
View File

@@ -0,0 +1,2 @@
> 1%
last 2 versions

7
client/.editorconfig Normal file
View File

@@ -0,0 +1,7 @@
[*.{js,jsx,ts,tsx,vue}]
indent_style = space
indent_size = 2
end_of_line = lf
trim_trailing_whitespace = true
insert_final_newline = true
max_line_length = 100

17
client/.eslintrc.js Normal file
View File

@@ -0,0 +1,17 @@
module.exports = {
root: true,
env: {
node: true,
},
extends: [
'plugin:vue/essential',
'@vue/airbnb',
],
parserOptions: {
parser: 'babel-eslint',
},
rules: {
'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
},
};

21
client/.gitignore vendored Normal file
View File

@@ -0,0 +1,21 @@
.DS_Store
node_modules
/dist
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

24
client/README.md Normal file
View File

@@ -0,0 +1,24 @@
# client
## Project setup
```
yarn install
```
### Compiles and hot-reloads for development
```
yarn serve
```
### Compiles and minifies for production
```
yarn build
```
### Lints and fixes files
```
yarn lint
```
### Customize configuration
See [Configuration Reference](https://cli.vuejs.org/config/).

5
client/babel.config.js Normal file
View File

@@ -0,0 +1,5 @@
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset',
],
};

30
client/package.json Normal file
View File

@@ -0,0 +1,30 @@
{
"name": "client",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"buildw": "vue-cli-service build --watch",
"lint": "vue-cli-service lint"
},
"dependencies": {
"core-js": "^3.6.4",
"nipplejs": "^0.8.5",
"vue": "^2.6.11",
"vue-socket.io": "^3.0.7"
},
"devDependencies": {
"@vue/cli-plugin-babel": "~4.2.0",
"@vue/cli-plugin-eslint": "~4.2.0",
"@vue/cli-service": "~4.2.0",
"@vue/eslint-config-airbnb": "^5.0.2",
"babel-eslint": "^10.0.3",
"eslint": "^6.7.2",
"eslint-plugin-import": "^2.20.1",
"eslint-plugin-vue": "^6.1.2",
"node-sass": "^4.12.0",
"sass-loader": "^8.0.2",
"vue-template-compiler": "^2.6.11"
}
}

BIN
client/public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

17
client/public/index.html Normal file
View File

@@ -0,0 +1,17 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>

65
client/src/App.vue Normal file
View File

@@ -0,0 +1,65 @@
<template>
<div id="app">
<div class="toggle-button" @click="toggleFullScreen">
toggleFullScreen
</div>
<image-stream :path="streamSource"/>
<Nipple :position="'left'" @move="moveCamera"/>
<Nipple :position="'right'" @move="moveWalle"/>
</div>
</template>
<script>
import ImageStream from './components/ImageStream.vue';
import Nipple from './components/Nipple.vue';
export default {
name: 'App',
mounted() {
},
data() {
return {
streamSource: '/imagestream.mjpg',
};
},
methods: {
toggleFullScreen() {
if (document.fullscreenElement) {
document.exitFullscreen();
} else {
window.document.body.requestFullscreen();
}
},
moveCamera({ distance, angle }) {
console.log({ action: 'camera', distance, angle });
},
moveWalle({ distance, angle }) {
this.$socket.emit('move', {
angle, distance,
});
// console.log({ action: 'walle', distance, angle });
},
},
components: {
ImageStream,
Nipple,
},
};
</script>
<style lang="scss">
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
}
.toggle-button {
position: fixed;
top: 0;
left: 0;
background: #42b983;
color: white;
}
</style>

BIN
client/src/assets/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

View File

@@ -0,0 +1,58 @@
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<p>
For a guide and recipes on how to configure / customize this project,<br>
check out the
<a href="https://cli.vuejs.org" target="_blank" rel="noopener">vue-cli documentation</a>.
</p>
<h3>Installed CLI Plugins</h3>
<ul>
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-babel" target="_blank" rel="noopener">babel</a></li>
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-eslint" target="_blank" rel="noopener">eslint</a></li>
</ul>
<h3>Essential Links</h3>
<ul>
<li><a href="https://vuejs.org" target="_blank" rel="noopener">Core Docs</a></li>
<li><a href="https://forum.vuejs.org" target="_blank" rel="noopener">Forum</a></li>
<li><a href="https://chat.vuejs.org" target="_blank" rel="noopener">Community Chat</a></li>
<li><a href="https://twitter.com/vuejs" target="_blank" rel="noopener">Twitter</a></li>
<li><a href="https://news.vuejs.org" target="_blank" rel="noopener">News</a></li>
</ul>
<h3>Ecosystem</h3>
<ul>
<li><a href="https://router.vuejs.org" target="_blank" rel="noopener">vue-router</a></li>
<li><a href="https://vuex.vuejs.org" target="_blank" rel="noopener">vuex</a></li>
<li><a href="https://github.com/vuejs/vue-devtools#vue-devtools" target="_blank" rel="noopener">vue-devtools</a></li>
<li><a href="https://vue-loader.vuejs.org" target="_blank" rel="noopener">vue-loader</a></li>
<li><a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">awesome-vue</a></li>
</ul>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
props: {
msg: String,
},
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="scss">
h3 {
margin: 40px 0 0;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
</style>

View File

@@ -0,0 +1,18 @@
<template>
<img class="video-stream" :src="path" alt="">
</template>
<script>
export default {
name: 'ImageStream',
props: {
path: String,
},
};
</script>
<style scoped lang="scss">
.video-stream {
width: 100%;
}
</style>

View File

@@ -0,0 +1,59 @@
<template>
<div class="nipple-area" ref="nippleArea" :class="['nipple-position-' + position]">
</div>
</template>
<script>
import nipplejs from 'nipplejs';
export default {
name: 'Nipple',
props: {
position: String,
},
data() {
return {
nipple: null,
};
},
mounted() {
this.nipple = nipplejs.create({
zone: this.$refs.nippleArea,
mode: 'static',
position: {
left: '50%',
top: '50%',
},
color: 'red',
});
this.nipple.on('move', (evt, data) => {
this.$emit('move', {
distance: data.distance,
angle: data.angle.degree,
});
});
this.nipple.on('end', () => {
this.$emit('move', {
distance: 0,
angle: 0,
});
});
},
};
</script>
<style scoped lang="sass">
.nipple-area
width: 200px
height: 200px
background: rebeccapurple
position: fixed
bottom: 0
.nipple-position
&-left
left: 0
&-right
right: 0
</style>

17
client/src/main.js Normal file
View File

@@ -0,0 +1,17 @@
import Vue from 'vue';
import VueSocketIO from 'vue-socket.io';
import App from './App.vue';
Vue.use(new VueSocketIO({
debug: true,
connection: 'http://192.168.0.100:5000',
options: {
transport: 'websocket',
},
}));
Vue.config.productionTip = false;
new Vue({
render: (h) => h(App),
}).$mount('#app');

9081
client/yarn.lock Normal file

File diff suppressed because it is too large Load Diff

0
control/__init__.py Normal file
View File

34
control/camera.py Normal file
View File

@@ -0,0 +1,34 @@
from io import BytesIO
import cv2
from PIL import Image
class Camera:
capture: cv2.VideoCapture
def __init__(self):
self.capture = cv2.VideoCapture(0)
def generate_images(self):
try:
while True:
return_code, image = self.capture.read()
if not return_code:
continue
image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
jpg = Image.fromarray(image_rgb)
byte_stream = BytesIO()
jpg.save(byte_stream, 'JPEG')
yield bytes(byte_stream.getbuffer())
finally:
self.capture.release()
def mjpeg_stream(self, boundary: bytes):
for frame in self.generate_images():
if not frame:
break
yield b''.join([
b'--', boundary, b'\r\n',
b'Content-Type: image/jpeg\r\n\r\n',
frame,
b'\r\n'])

110
control/walle.py Normal file
View File

@@ -0,0 +1,110 @@
import math
from typing import Optional
import atexit
if True: # NOTE: false on pi
from RPiSim.GPIO import GPIO
else:
from RPi import GPIO
PIN_MOTOR_A_ENABLE = 6
PIN_MOTOR_A_REVERSE = 12
PIN_MOTOR_B_ENABLE = 0
PIN_MOTOR_B_REVERSE = 5
PWM_FREQUENCY = 10_000 # 10 KHz
if not hasattr(GPIO, 'PWM'):
class PWM:
def __init__(self, pin, freq):
self.pin = pin
self.freq = freq
self.dc: Optional[float] = None
self.name = None
def start(self, dc: float):
self.dc = dc
def ChangeDutyCycle(self, dc):
self.dc = dc
print(f'[{self.pin}@{self.freq}Hz]{" " + self.name if self.name else ""} => {self.dc}')
def stop(self):
print("stop pwm")
GPIO.PWM = PWM
class Motor:
def __init__(self, pin_enable, pin_reverse):
self.pin_enable = pin_enable
self.pin_reverse = pin_reverse
GPIO.setup(pin_enable, GPIO.OUT)
GPIO.setup(pin_reverse, GPIO.OUT)
GPIO.output(pin_reverse, GPIO.LOW)
self.pwm_enable = GPIO.PWM(pin_enable, PWM_FREQUENCY)
self.pwm_enable.start(0.0)
self.is_reverse = False
def set(self, val):
"""
Set the speed of the motor
Args:
val: Value between 1.0 and -1.0
"""
self._set_reverse(val)
absval = abs(val)
if absval > 1:
print(f"clipping {val} to 1")
absval = 1
self.pwm_enable.ChangeDutyCycle(absval)
def _set_reverse(self, val):
if val >= 0 and self.is_reverse:
GPIO.output(self.pin_reverse, GPIO.LOW)
self.is_reverse = False
elif val < 0 and not self.is_reverse:
GPIO.output(self.pin_reverse, GPIO.HIGH)
self.is_reverse = True
def stop(self):
self.pwm_enable.stop()
GPIO.output(self.pin_reverse, GPIO.LOW)
class WallE:
def __init__(self):
GPIO.setmode(GPIO.BCM)
self.motor_a = Motor(PIN_MOTOR_A_ENABLE, PIN_MOTOR_A_REVERSE)
self.motor_b = Motor(PIN_MOTOR_B_ENABLE, PIN_MOTOR_B_REVERSE)
atexit.register(self.cleanup)
def cleanup(self):
print("cleaning up")
self.motor_a.stop()
self.motor_b.stop()
GPIO.cleanup()
def set_movement(self, angle: float, distance: float):
angle_rad = math.radians(angle)
x = math.cos(angle_rad)
y = math.sin(angle_rad)
velocity_l = distance * (abs(x - 1.0) / 2.0)
velocity_r = distance * ((x + 1.0) / 2.0)
if y > 0:
self.motor_a.set(velocity_l)
self.motor_b.set(velocity_r)
else:
self.motor_a.set(-velocity_l)
self.motor_b.set(-velocity_r)
def set_eye_velocity(self, up_down: float, left_right: float):
pass

7
install.sh Normal file
View File

@@ -0,0 +1,7 @@
#!/bin/bash
sudo apt update
sudo apt upgrade
sudo apt install python3-rpi.gpio python3-opencv python3-flask python3-socketio python3-eventlet python3-pil python3-pip
pip3 install --user python-socketio

22
simplecv.py Normal file
View File

@@ -0,0 +1,22 @@
import numpy as np
import cv2
cap = cv2.VideoCapture(0)
while(True):
# Capture frame-by-frame
ret, frame = cap.read()
# Our operations on the frame come here
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# Display the resulting frame
cv2.imshow('frame', gray)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# When everything done, release the capture
cap.release()
cv2.destroyAllWindows()
if __name__ == '__main__':
pass