feat: initial commit
This commit is contained in:
223
.gitignore
vendored
Normal file
223
.gitignore
vendored
Normal 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
17
Pipfile
Normal 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
260
Pipfile.lock
generated
Normal 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
37
app.py
Normal 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')
|
||||
2
client/.browserslistrc
Normal file
2
client/.browserslistrc
Normal file
@@ -0,0 +1,2 @@
|
||||
> 1%
|
||||
last 2 versions
|
||||
7
client/.editorconfig
Normal file
7
client/.editorconfig
Normal 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
17
client/.eslintrc.js
Normal 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
21
client/.gitignore
vendored
Normal 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
24
client/README.md
Normal 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
5
client/babel.config.js
Normal file
@@ -0,0 +1,5 @@
|
||||
module.exports = {
|
||||
presets: [
|
||||
'@vue/cli-plugin-babel/preset',
|
||||
],
|
||||
};
|
||||
30
client/package.json
Normal file
30
client/package.json
Normal 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
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
17
client/public/index.html
Normal 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
65
client/src/App.vue
Normal 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
BIN
client/src/assets/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.7 KiB |
58
client/src/components/HelloWorld.vue
Normal file
58
client/src/components/HelloWorld.vue
Normal 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>
|
||||
18
client/src/components/ImageStream.vue
Normal file
18
client/src/components/ImageStream.vue
Normal 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>
|
||||
59
client/src/components/Nipple.vue
Normal file
59
client/src/components/Nipple.vue
Normal 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
17
client/src/main.js
Normal 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
9081
client/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
0
control/__init__.py
Normal file
0
control/__init__.py
Normal file
34
control/camera.py
Normal file
34
control/camera.py
Normal 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
110
control/walle.py
Normal 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
7
install.sh
Normal 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
22
simplecv.py
Normal 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
|
||||
Reference in New Issue
Block a user