Merge commit '8c2322adaed3d4374a7524bdb9ae8fb27f74fe7f'
11个文件已删除
101 文件已重命名
52个文件已添加
4个文件已修改
| | |
| | | # Byte-compiled / optimized / DLL files |
| | | __pycache__/ |
| | | *.py[cod] |
| | | *$py.class |
| | | # cache |
| | | **/__pycache__/ |
| | | |
| | | # 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 |
| | | |
| | | # PEP 582; used by e.g. github.com/David-OConnor/pyflow |
| | | __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/ |
| | | /*.udp |
| | | |
| | | .vs |
| | | # proto |
| | | src/protos/aerial_pb2.py |
| | | |
| | | # env |
| | | env/aerial_deploy |
| | | env/*.gz |
| | | |
| | | # demodata |
| | | src/microwave/demo/saveUdPData/ |
| | | |
| | | # data & image & microwave |
| | | Data |
| | | Images |
| | | Microwaves |
| | | Manual_Microwave* |
| | | |
| | | # log |
| | | *.log |
| | | |
| | |
| | | "version": "0.2.0", |
| | | "configurations": [ |
| | | { |
| | | "name": "udp server test", |
| | | "name": "Client_local", |
| | | "type": "python", |
| | | "request": "launch", |
| | | "program": "src/udp_test/udp.py", |
| | | "program": "${workspaceFolder}/src/Client.py", |
| | | "args": [ |
| | | "localhost", |
| | | "chai", |
| | | "password123", |
| | | "aerial_rpc", |
| | | "pod1", |
| | | "http://localhost/api", |
| | | "localhost" |
| | | ], |
| | | "console": "integratedTerminal" |
| | | }, |
| | | { |
| | | "name": "Python: 当前文件", |
| | | "name": "Client_production", |
| | | "type": "python", |
| | | "request": "launch", |
| | | "program": "${file}", |
| | | "program": "${workspaceFolder}/src/Client.py", |
| | | "args": [ |
| | | "172.17.17.206", |
| | | "chai", |
| | | "password123", |
| | | "aerial_rpc", |
| | | "pod1", |
| | | "http://172.17.17.206/api", |
| | | "192.168.2.65" |
| | | ], |
| | | "console": "integratedTerminal" |
| | | }, |
| | | { |
| | | "name": "Python: Flask-Server", |
| | | "name": "Server_local", |
| | | "type": "python", |
| | | "request": "launch", |
| | | "program": "${workspaceFolder}/src/Server/Server.py", |
| | | "console": "integratedTerminal", |
| | | "cwd": "${workspaceFolder}/src/Server" |
| | | "program": "${workspaceFolder}/src/Server.py", |
| | | "args": [ |
| | | "localhost", |
| | | "chai", |
| | | "password123", |
| | | "aerial_rpc", |
| | | "5000", |
| | | "./Images" |
| | | ], |
| | | "console": "integratedTerminal" |
| | | }, |
| | | { |
| | | "name": "Python: parser", |
| | | "name": "Server_production", |
| | | "type": "python", |
| | | "request": "launch", |
| | | "program": "${workspaceFolder}/src/Client/ParserTest.py", |
| | | "console": "integratedTerminal", |
| | | "cwd": "${workspaceFolder}/src/Client" |
| | | "program": "${workspaceFolder}/src/Server.py", |
| | | "args": [ |
| | | "172.17.17.206", |
| | | "chai", |
| | | "password123", |
| | | "aerial_rpc", |
| | | "5000", |
| | | "./Images" |
| | | ], |
| | | "console": "integratedTerminal" |
| | | }, |
| | | { |
| | | "name": "udp2bin", |
| | | "type": "python", |
| | | "request": "launch", |
| | | "program": "${workspaceFolder}/src/utils/udp2bin.py", |
| | | "args": [ |
| | | "./Manual_Microwave/pod1-2022-02-21-15-34-45/" |
| | | ], |
| | | "console": "integratedTerminal" |
| | | }, |
| | | { |
| | | "name": "bin2ply", |
| | | "type": "python", |
| | | "request": "launch", |
| | | "program": "${workspaceFolder}/src/utils/bin2ply.py", |
| | | "args": [ |
| | | "./Manual_Microwave/pod1-2022-02-21-15-34-45/" |
| | | ], |
| | | "console": "integratedTerminal" |
| | | } |
| | | ] |
| | | } |
| | |
| | | "--proto_path=${workspaceRoot}/proto", |
| | | "--python_out=${workspaceRoot}/src/protos" |
| | | ] |
| | | } |
| | | }, |
| | | "python":{ |
| | | }, |
| | | "jupyter.kernels.filter": [ |
| | | { |
| | | "type": "jupyterKernelspec", |
| | | "path": "${workspaceFolder}/env/aerial_deploy/python.exe" |
| | | } |
| | | ] |
| | | } |
| | |
| | | |
| | | ## 创建环境 |
| | | |
| | | ``` |
| | | conda create -n aerial python=3.9 |
| | | conda install --name aerial flask pika protobuf requests |
| | | conda activate aerial |
| | | pip install pika opencv-contrib-python |
| | | Just click ```JustDoubleClickMe.bat``` file to auto setiing the env, which is located in the ```env``` folder. |
| | | |
| | | ## 运行采集端 |
| | | |
| | | ``` |
| | | |
| | | ## 运行采集端 |
| | | |
| | | ``` |
| | | cd src/Client |
| | | python Client.py |
| | | ``` |
| | | Double click to run ```startClient.bat``` |
| | | |
| | | ## 运行服务端 |
| | | |
| | | ``` |
| | | cd src/Server |
| | | python Server.py |
| | | ``` |
| | | Double click to run ```startServer.bat``` |
| New file |
| | |
| | | @echo off |
| | | |
| | | @REM change to the filepath |
| | | cd %~dp0 |
| | | echo change to path: %cd% |
| | | |
| | | set aerialpython=%cd%/env/aerial_deploy/python.exe |
| | | set envsetting=%cd%/env/SettingEnv.bat |
| | | |
| | | @REM Setting the env |
| | | if not exist %aerialpython% ( |
| | | call %envsetting% |
| | | ) |
| | | |
| | | set BINfolder=./Manual_Microwave_test/pod1-2022-02-21-15-34-45/ |
| | | |
| | | @REM ---------------Usage: bin2ply.py [BINfolder] |
| | | %aerialpython% ./src/utils/bin2ply.py %BINfolder% |
| | | pause |
| New file |
| | |
| | | @echo off |
| | | |
| | | @REM change to the filepath |
| | | cd %~dp0 |
| | | echo change to path: %cd% |
| | | |
| | | set aerialpython=%cd%/env/aerial_deploy/python.exe |
| | | set envsetting=%cd%/env/SettingEnv.bat |
| | | |
| | | @REM Setting the env |
| | | if not exist %aerialpython% ( |
| | | call %envsetting% |
| | | ) |
| | | |
| | | set PLYfile=./Manual_Microwave_test/pod1-2022-02-21-15-34-45/2522.ply |
| | | @REM -------------- Usage: plot_ply.py [PLYfile]" |
| | | %aerialpython% ./src/utils/plot_ply.py %PLYfile% |
| | | pause |
| New file |
| | |
| | | @echo off |
| | | |
| | | @REM change to the filepath |
| | | cd %~dp0 |
| | | echo change to path: %cd% |
| | | |
| | | set aerialpython=%cd%/env/aerial_deploy/python.exe |
| | | set envsetting=%cd%/env/SettingEnv.bat |
| | | |
| | | @REM Setting the env |
| | | if not exist %aerialpython% ( |
| | | call %envsetting% |
| | | ) |
| | | |
| | | set MQhost=localhost |
| | | set MQuser=chai |
| | | set MQpassword=password123 |
| | | set QUEUEname=aerial_rpc |
| | | set DEVICEname=pod1 |
| | | set SERVERhost=http://localhost/api |
| | | set MICROWAVEhost=localhost |
| | | set LOGfile=ClientTEST.log |
| | | |
| | | @REM Launch the Client |
| | | echo the log file will be saved in the [%LOGfile%] file |
| | | echo Client.py is running ... |
| | | @REM -------- Usage: Client.py [MQhost] [MQuser] [MQpassword] [QUEUEname] [DEVICEname] [SERVERhost] [MICROWAVEhost] |
| | | %aerialpython% ./src/Client.py %MQhost% %MQuser% %MQpassword% %QUEUEname% %DEVICEname% %SERVERhost% %MICROWAVEhost% >> %LOGfile% |
| | | echo Client.py has been terminited. |
| | | pause |
| New file |
| | |
| | | @echo off |
| | | |
| | | @REM change to the filepath |
| | | cd %~dp0 |
| | | echo change to path: %cd% |
| | | |
| | | set aerialpython=%cd%/env/aerial_deploy/python.exe |
| | | set envsetting=%cd%/env/SettingEnv.bat |
| | | |
| | | @REM Setting the env |
| | | if not exist %aerialpython% ( |
| | | call %envsetting% |
| | | ) |
| | | |
| | | set MQhost=localhost |
| | | set MQuser=chai |
| | | set MQpassword=password123 |
| | | set QUEUEname=aerial_rpc |
| | | set WEBport=5000 |
| | | set SAVEfolder=./ImagesTEST |
| | | set LOGfile=ServerTEST.log |
| | | |
| | | @REM Launch the Server |
| | | @REM -------- Usage: Server.py [MQhost] [MQuser] [MQpassword] [QUEUEname] [WEBport] [SAVEfolder]") |
| | | echo the log file will be saved in the [%LOGfile%] file |
| | | echo Server.py is running ... |
| | | @REM -------- Usage: Server.py [MQhost] [MQuser] [MQpassword] [QUEUEname] [WEBport] [SAVEfolder]") |
| | | %aerialpython% ./src/Server.py %MQhost% %MQuser% %MQpassword% %QUEUEname% %WEBport% %SAVEfolder% >> %LOGfile% |
| | | echo Server.py has been terminited. |
| | | pause |
| | | |
| New file |
| | |
| | | @echo off |
| | | |
| | | @REM change to the filepath |
| | | cd %~dp0 |
| | | echo change to path: %cd% |
| | | |
| | | set aerialpython=%cd%/env/aerial_deploy/python.exe |
| | | set envsetting=%cd%/env/SettingEnv.bat |
| | | |
| | | @REM Setting the env |
| | | if not exist %aerialpython% ( |
| | | call %envsetting% |
| | | ) |
| | | |
| | | set UDPfolder=./Manual_Microwave_test/pod1-2022-02-21-15-34-45/ |
| | | |
| | | @REM ---------------Usage: udp2bin.py [UDPfolder] |
| | | %aerialpython% ./src/utils/udp2bin.py %UDPfolder% |
| | | pause |
| New file |
| | |
| | | @echo off |
| | | |
| | | @REM change to the filepath |
| | | cd %~dp0 |
| | | echo change to path: %cd% |
| | | |
| | | set aerialpython=%cd%/env/aerial_deploy/python.exe |
| | | set envsetting=%cd%/env/SettingEnv.bat |
| | | |
| | | @REM Setting the env |
| | | if not exist %aerialpython% ( |
| | | call %envsetting% |
| | | ) |
| | | |
| | | set UDPfolder=./Manual_Microwave_test/pod1-2022-02-21-15-34-45/ |
| | | |
| | | @REM ---------------Usage: udp2bin.py [UDPfolder] |
| | | %aerialpython% ./src/utils/udp2bin.py %UDPfolder% |
| | | @REM ---------------Usage: bin2ply.py [BINfolder] |
| | | %aerialpython% ./src/utils/bin2ply.py %UDPfolder% |
| | | pause |
| New file |
| | |
| | | @echo off |
| | | |
| | | @REM change to the filepath |
| | | cd %~dp0 |
| | | echo change to path: %cd% |
| | | |
| | | set aerialpython=%cd%/env/aerial_deploy/python.exe |
| | | set envsetting=%cd%/env/SettingEnv.bat |
| | | |
| | | @REM Setting the env |
| | | if not exist %aerialpython% ( |
| | | call %envsetting% |
| | | ) |
| | | |
| | | set MICROWAVEhost=172.17.17.206 |
| | | SET PACKETthreshold=100 |
| | | SET DEVICEname=pod1 |
| | | SET SAVEfolder=./Manual_Microwave_test |
| | | @REM ---------------Usage: udp_get.py [MICROWAVEhost] [PACKETthreshold] [DEVICEname] [SAVEfolder] |
| | | %aerialpython% ./src/utils/udp_get.py %MICROWAVEhost% %PACKETthreshold% %DEVICEname% %SAVEfolder% |
| | | pause |
| New file |
| | |
| | | @echo off |
| | | |
| | | @REM change to the filepath |
| | | cd %~dp0 |
| | | echo change to path: %cd% |
| | | |
| | | set aerialpython=%cd%/env/aerial_deploy/python.exe |
| | | set envsetting=%cd%/env/SettingEnv.bat |
| | | |
| | | @REM Setting the env |
| | | if not exist %aerialpython% ( |
| | | call %envsetting% |
| | | ) |
| | | @REM please the folder path of the bin files. |
| | | @REM set BINfolder=./Manual_Microwave/pod1-2012-12-12-12-12-12/ |
| | | |
| | | @REM ---------------Usage: bin2ply.py [BINfolder] |
| | | %aerialpython% ./src/utils/bin2ply.py %BINfolder% |
| | | pause |
| New file |
| | |
| | | @echo off |
| | | |
| | | @REM change to the filepath |
| | | cd %~dp0 |
| | | echo change to path: %cd% |
| | | |
| | | echo Exporting env ... |
| | | conda pack -o aerial.tar.gz |
| | | |
| | | echo Done! |
| New file |
| | |
| | | @echo off |
| | | |
| | | cd %~dp0 |
| | | echo ========== Setting Env ============== |
| | | call SettingEnv.bat |
| | | echo setting done! |
| | | echo ========== Testing Env ============== |
| | | echo test it with hello word... |
| | | set aerialpython=%cd%/aerial_deploy/python.exe |
| | | %aerialpython% -c "import cv2, pika, flask, pika; print('hello world!')" |
| | | echo =========== ALL DONE ================ |
| | | |
| | | echo Press any key to exit this windiow. |
| | | pause |
| New file |
| | |
| | | @echo off |
| | | |
| | | @REM change to the filepath |
| | | cd %~dp0 |
| | | echo change to path: %cd% |
| | | if exist aerial_deploy ( |
| | | echo the folder aerial_deploy is exited, removing it ... |
| | | rmdir /S /Q aerial_deploy |
| | | echo remove done! |
| | | ) |
| | | |
| | | mkdir aerial_deploy |
| | | echo setting the env ... |
| | | tar -xzf ./aerial.tar.gz -C %cd%/aerial_deploy |
| | | echo ALL DONE! |
| | | |
| | | |
| | | |
| | | |
| New file |
| | |
| | | @echo off |
| | | |
| | | @REM change to the filepath |
| | | cd %~dp0 |
| | | echo change to path: %cd% |
| | | |
| | | set aerialpython=%cd%/env/aerial_deploy/python.exe |
| | | set envsetting=%cd%/env/SettingEnv.bat |
| | | |
| | | @REM Setting the env |
| | | if not exist %aerialpython% ( |
| | | call %envsetting% |
| | | ) |
| | | @REM please the folder path of the bin files. |
| | | @REM set PLYfile=./Manual_Microwave/pod1-2022-02-21-15-34-45/2522.ply |
| | | |
| | | @REM -------------- Usage: plot_ply.py [PLYfile]" |
| | | %aerialpython% ./src/utils/plot_ply.py %PLYfile% |
| | | pause |
| New file |
| | |
| | | import signal |
| | | import os, sys |
| | | |
| | | batfile_dir = os.path.join(__file__, "..", "protos/compile.bat" ) |
| | | batfile_path = os.path.abspath(batfile_dir) |
| | | os.system(batfile_path) |
| | | |
| | | from engine.AcquisitionMain import AcquisitionMain |
| | | from engine.AcquisitionMain import Config |
| | | |
| | | def quit(signum, frame): |
| | | print('You choose to stop me.') |
| | | sys.exit() |
| | | |
| | | if __name__ == '__main__': |
| | | def help(): |
| | | print("Usage: Client.py [MQhost] [MQuser] [MQpassword] [QUEUEname] [DEVICEname] [SERVERhost] [MICROWAVEhost]") |
| | | print("EXAMPLE: Client.py 172.17.17.206 chai password123 aerial_rpc pod1 http://172.17.17.206/api 192.168.2.65") |
| | | exit(1) |
| | | |
| | | if len(sys.argv) != 8: |
| | | help() |
| | | try: |
| | | MQhost = str(sys.argv[1]) |
| | | MQuser = str(sys.argv[2]) |
| | | MQpassword = str(sys.argv[3]) |
| | | QUEUEname = str(sys.argv[4]) |
| | | DEVICEname = str(sys.argv[5]) |
| | | SERVERhost = str(sys.argv[6]) |
| | | MICROWAVEhost = str(sys.argv[7]) |
| | | |
| | | except Exception as e: |
| | | print(e) |
| | | help() |
| | | |
| | | print("Start AcquisitionMain") |
| | | signal.signal(signal.SIGINT, quit) |
| | | signal.signal(signal.SIGTERM, quit) |
| | | # client = AcquisitionMain('192.168.3.54', 'chai', |
| | | # 'password123', 'aerial_rpc', 'pod1', 'http://192.168.3.54:5000/api', 10) |
| | | config_dir = os.path.join(__file__, "..", "config.json" ) |
| | | config_path = os.path.abspath(config_dir) |
| | | config = Config(config_path) |
| | | client = AcquisitionMain(MQhost, |
| | | MQuser, |
| | | MQpassword, |
| | | QUEUEname, |
| | | DEVICEname, |
| | | SERVERhost, |
| | | MICROWAVEhost, # udp server host, 192.168.2.65 for production |
| | | config) |
| | | client.start() |
| New file |
| | |
| | | from .components import * |
| | | from .constants import * |
| | | from .parsers import * |
| | | from .servers import * |
| New file |
| | |
| | | from ctypes import Structure, c_ubyte, c_uint16, c_uint32, c_int16 |
| | | from bitarray import bitarray, util |
| | | import math |
| | | |
| | | """ |
| | | UDP packets 0 --> ... --> UDP packets n |
| | | Handshake --> HeaderBlock --> DetectionBlock --> TrackerBlock --> FooterBlock |
| | | |
| | | """ |
| | | |
| | | |
| | | class Handshake(Structure): |
| | | """ |
| | | Handshake structure, 24 bytes |
| | | """ |
| | | _pack_ = 1 |
| | | _fields_ = [ |
| | | ('Magic', c_ubyte*8), |
| | | ('FrameDataLength', c_uint32), |
| | | ('Reserved', c_ubyte * 12) |
| | | ] |
| | | |
| | | |
| | | class HeaderBlock(Structure): |
| | | """ |
| | | Header structure, 48 bytes |
| | | """ |
| | | _pack_ = 1 |
| | | _fields_ = [ |
| | | ('Magic', c_ubyte * 8), # [2 1 4 3 6 5 8 7] |
| | | ('FrameNumber', c_uint32), # frame number |
| | | ('VersionNumber', c_uint32), # Version number, uint32_t format: MMddhhmm |
| | | ('NumberOfDetection', c_uint16), # Number of Detection in the frame |
| | | ('NumberOfTrack', c_uint16), # Number of Detection in the frame |
| | | ('HostSpeed', c_uint16), # divide by 100 to get ego speed in m/s (e.g. 6453 = 64.53 m/s, e.g. -2456 = -24.56 m/s) |
| | | ('HostAngle', c_uint16), # divide by 100 to get host angle in degree. Clockwise rotation corresponds to positive rotation.(e.g. 1400 = 14 deg) |
| | | ('Reserved', c_ubyte * 8), |
| | | ('RangeAccuracyIdx', c_uint16), # divide by 10000 to get value in m |
| | | ('DopplerAccuracyIdx', c_uint16), # divide by 10000 to get value in m/s |
| | | ('AzimuthAccuracyIdx', c_uint16), # divide by 10000 to get value in degree |
| | | ('ElevationAccuracyIdx', c_uint16), # divide by 10000 to get value in degree |
| | | ('DspWorkload', c_ubyte), |
| | | ('ARMWorkload', c_ubyte), |
| | | ('Reserved2', c_ubyte * 6), |
| | | ] |
| | | def __new__(cls, buf): |
| | | # new instance from buf |
| | | return cls.from_buffer_copy(buf) |
| | | |
| | | def __init__(self, data): |
| | | # claculate parameters |
| | | self.RangeAccuracy = self.RangeAccuracyIdx / 10000.0 |
| | | self.DopplerAccuracy = self.DopplerAccuracyIdx / 10000.0 |
| | | self.AzimuthAccuracy = self.AzimuthAccuracyIdx / 10000.0 |
| | | self.ElevationAccuracy = self.ElevationAccuracyIdx / 10000.0 |
| | | |
| | | |
| | | |
| | | class FooterBlock(Structure): |
| | | """ |
| | | Footer structure, 32 bytes |
| | | """ |
| | | _pack_ = 1 |
| | | _fields_ = [ |
| | | ('Reserved1', c_ubyte * 8), |
| | | ('RangeAccuracyIdx', c_uint16), # divide by 10000 to get value in m |
| | | ('DopplerAccuracyIdx', c_uint16), # divide by 10000 to get value in m |
| | | ('AzimuthAccuracyIdx', c_uint16), # divide by 10000 to get value in degree |
| | | ('ElevationAccuracyIdx', c_uint16), # divide by 10000 to get value in degree |
| | | ('Reserved2', c_ubyte * 16), |
| | | ] |
| | | def __new__(cls, buf): |
| | | # new instance from buf |
| | | return cls.from_buffer_copy(buf) |
| | | |
| | | def __init__(self, data): |
| | | # claculate parameters |
| | | self.RangeAccuracy = self.RangeAccuracyIdx / 10000.0 |
| | | self.DopplerAccuracy = self.DopplerAccuracyIdx / 10000.0 |
| | | self.AzimuthAccuracy = self.AzimuthAccuracyIdx / 10000.0 |
| | | self.ElevationAccuracy = self.ElevationAccuracyIdx / 10000.0 |
| | | |
| | | |
| | | class DetectionBlock: |
| | | """ |
| | | Detection structure |
| | | using bitarray parse structure because of ctypes can't parse compact bitfields |
| | | """ |
| | | |
| | | def __init__(self, header: HeaderBlock, footer: FooterBlock, data): |
| | | buf = bytearray(data) |
| | | buf.reverse() |
| | | bits = bitarray() |
| | | bits.frombytes(bytes(buf)) |
| | | # print(bits) |
| | | # parse data structure |
| | | self.Flag = bits[1] |
| | | self.RangeIndex = util.ba2int(bits[54:64]) |
| | | self.DropplerIndex = util.ba2int(bits[45:54]) |
| | | if bits[44]: |
| | | self.DropplerIndex -= 512 |
| | | self.AzimuthIndex = util.ba2int(bits[35:44]) |
| | | if bits[34]: |
| | | self.AzimuthIndex -= 512 |
| | | self.BetaIndex = util.ba2int(bits[25:34]) |
| | | if bits[24]: |
| | | self.BetaIndex -= 512 |
| | | self.PowerValue = util.ba2int(bits[8:24]) |
| | | |
| | | if not self.Flag: |
| | | # using header's parameters |
| | | RangeAccuracy = header.RangeAccuracy |
| | | DopplerAccuracy = header.DopplerAccuracy |
| | | AzimuthAccuracy = header.AzimuthAccuracy |
| | | ElevationAccuracy = header.ElevationAccuracy |
| | | else: |
| | | # using footer's parameters |
| | | RangeAccuracy = footer.RangeAccuracy |
| | | DopplerAccuracy = footer.DopplerAccuracy |
| | | AzimuthAccuracy = footer.AzimuthAccuracy |
| | | ElevationAccuracy = footer.ElevationAccuracy |
| | | |
| | | # claculation |
| | | self.Power = self.PowerValue / 100.0 |
| | | self.Range = self.RangeIndex * RangeAccuracy |
| | | self.Doppler = self.DropplerIndex * DopplerAccuracy |
| | | self.Beta = self.BetaIndex * ElevationAccuracy |
| | | self.Azimuth = self.AzimuthIndex * AzimuthAccuracy |
| | | # degrees to radians |
| | | alpha = math.radians(self.Azimuth) |
| | | beta = math.radians(self.Beta) |
| | | # XYZ: The XYZ coordinates can be retrieved using the following equation: |
| | | # X = Range * Sin(Alpha) * Cos(Beta) |
| | | # Y = Range * Sin(Beta) |
| | | # Z = Range * Cos(Alpha) * Cos(Beta) |
| | | # or |
| | | # Z = sqrt(Range^2 - X^2 - Y^2) |
| | | self.X = self.Range * math.sin(alpha) * math.cos(beta) |
| | | self.Y = self.Range * math.sin(beta) |
| | | self.Z = math.sqrt(self.Range * self.Range - |
| | | self.X * self.X - self.Y * self.Y) |
| | | |
| | | class TrackerBlock(Structure): |
| | | """ |
| | | Tracker structure |
| | | """ |
| | | _pack_ = 1 |
| | | _fields_ = [ |
| | | ('TrackID', c_uint32), # 0 to 4294967296 Track ID |
| | | ('XPos', c_int16), # -32768 to 32767, divide by 100 to get x in m (e.g. 6453 = 64.53 m, e.g.: -2456 = -24.56 m) |
| | | ('YPos', c_int16), # -32768 to 32767, divide by 100 to get y in m (e.g. 6453 = 64.53 m, e.g. -2456 = -24.56 m) |
| | | ('ZPos', c_uint16), # 0 to 65535, divide by 100 to get z in m (e.g. 12654 = 126.54 m) |
| | | ('XDot', c_int16), # -32768 to 32767, divide by 100 to get speed in the x direction in m/s (e.g. 6453 = 64.53 m/s, e.g. -2456 = -24.56 m/s) |
| | | ('YDot', c_int16), # -32768 to 32767, divide by 100 to get speed in the y direction in m/s (e.g. 6453 = 64.53 m/s, e.g. -2456 = -24.56 m/s) |
| | | ('ZDot', c_int16), # -32768 to 32767, divide by 100 to get speed in the z direction in m/s (e.g. 6453 = 64.53 m/s, e.g. -2456 = -24.56 m/s) |
| | | ('Res1', c_uint16), |
| | | ('Res2', c_uint16), |
| | | ('Res3', c_uint16), |
| | | ('Flag', c_uint16), # 0 to 65535. 16 1-bit flags, the flag definitions are internal to Oculii. |
| | | # Bit 3 – Bit 15 : Reserved |
| | | # Bit 0, Bit 1, Bit 2 : Track Quality. Currently only values 1 and 2 are used. Filter to use only value ‘2’. |
| | | ('Class', c_uint16), # 0 to 5. Reserved for future. |
| | | # 0: Unknown Class |
| | | # 1: Pedestrian |
| | | # 2: Motorcycle/Bike |
| | | # 3: Vehicle and SUV |
| | | # 4: Bus and Truck |
| | | # 5: Background |
| | | ('Conf', c_uint16), |
| | | ('Res4', c_uint16), |
| | | ('Res5', c_uint16), |
| | | ] |
| New file |
| | |
| | | HAND_SHAKE_MAGIC = b"\x01\x09\x08\x09\x01\x00\x02\x02" |
| | | HEADER_MAGIC = b"\x02\x01\x04\x03\x06\x05\x08\x07" |
| New file |
| | |
| | | @echo off |
| | | |
| | | @REM change to the filepath |
| | | cd %~dp0 |
| | | echo change to path: %cd% |
| | | |
| | | set aerialpython=%cd%/../../../env/aerial_deploy/python.exe |
| | | set envsetting=%cd%/env/SettingEnv.bat |
| | | |
| | | @REM Setting the env |
| | | if not exist %aerialpython% ( |
| | | call %envsetting% |
| | | ) |
| | | |
| | | echo All data will be save in '%cd%/saveUDPData/' folder |
| | | |
| | | %aerialpython% udp_test_get.py microwave |
| | | |
| | | echo =========== ALL DONE ================ |
| | | |
| | | echo Press any key to exit this windiow. |
| | | pause |
| New file |
| | |
| | | @echo off |
| | | |
| | | @REM change to the filepath |
| | | cd %~dp0 |
| | | echo change to path: %cd% |
| | | |
| | | set aerialpython=%cd%/../../../env/aerial_deploy/python.exe |
| | | set envsetting=%cd%/env/SettingEnv.bat |
| | | |
| | | @REM Setting the env |
| | | if not exist %aerialpython% ( |
| | | call %envsetting% |
| | | ) |
| | | |
| | | echo All data will be saved in '%cd%/saveUDPData/' folder |
| | | |
| | | %aerialpython% udp_test_get.py test |
| | | |
| | | echo =========== ALL GET DONE ================ |
| | | |
| | | echo Press any key to exit this windiow. |
| | | pause |
| New file |
| | |
| | | @echo off |
| | | |
| | | @REM change to the filepath |
| | | cd %~dp0 |
| | | echo change to path: %cd% |
| | | |
| | | set aerialpython=%cd%/../../../env/aerial_deploy/python.exe |
| | | set envsetting=%cd%/env/SettingEnv.bat |
| | | |
| | | @REM Setting the env |
| | | if not exist %aerialpython% ( |
| | | call %envsetting% |
| | | ) |
| | | |
| | | start AutoGetUDPtest.bat |
| | | start AutoSendUDPtest.bat |
| New file |
| | |
| | | @echo off |
| | | |
| | | @REM change to the filepath |
| | | cd %~dp0 |
| | | echo change to path: %cd% |
| | | |
| | | set aerialpython=%cd%/../../../env/aerial_deploy/python.exe |
| | | set envsetting=%cd%/env/SettingEnv.bat |
| | | |
| | | @REM Setting the env |
| | | if not exist %aerialpython% ( |
| | | call %envsetting% |
| | | ) |
| | | |
| | | echo All data saved in '%cd%/demoUDPData/' folder will be sent to 127.0.0.1:9911 |
| | | |
| | | %aerialpython% udp_test_send.py |
| | | |
| | | echo =========== ALL SEND DONE ================ |
| | | |
| | | echo Press any key to exit this windiow. |
| | | pause |
| New file |
| | |
| | | import os |
| | | import sys |
| | | |
| | | # add python path of microwave to sys.path |
| | | microwave_path = os.path.join(__file__, *(['..'] * 3)) |
| | | microwave_path = os.path.abspath(microwave_path) |
| | | sys.path.insert(0, microwave_path) |
| | | |
| | | from microwave.parsers import MicroWaveParser |
| | | |
| | | if __name__ == '__main__': |
| | | if len(sys.argv) != 2: |
| | | print('Usage: python MicroWave2Ply.py [filename.bin]') |
| | | exit(1) |
| | | |
| | | filename = sys.argv[1] |
| | | (fn, ext) = os.path.splitext(filename) |
| | | with open(filename, "rb") as udp_file: |
| | | buf = udp_file.read() |
| | | point_cloud = MicroWaveParser.ParserFrame(buf) |
| | | with open(fn + ".ply", "w") as f: |
| | | f.write("ply\n") |
| | | f.write("format ascii 1.0\n") |
| | | f.write("comment MicroWave2Ply generated\n") |
| | | f.write("element vertex %d\n" % len(point_cloud)) |
| | | f.write("property float x\n") |
| | | f.write("property float y\n") |
| | | f.write("property float z\n") |
| | | f.write("element face 0\n") |
| | | f.write("property list uchar int vertex_indices\n") |
| | | f.write("end_header\n") |
| | | for p in point_cloud: |
| | | x, y, z = p |
| | | f.write("{:.5f} {:.5f} {:.5f}\n".format(x, y, z)) |
| | | print("Done!") |
| New file |
| | |
| | | import os |
| | | from sys import argv |
| | | import sys |
| | | |
| | | # add python path of microwave to sys.path |
| | | microwave_path = os.path.join(__file__, *(['..'] * 3)) |
| | | microwave_path = os.path.abspath(microwave_path) |
| | | sys.path.insert(0, microwave_path) |
| | | |
| | | from microwave.servers import MicroWaveReceiver |
| | | |
| | | |
| | | if __name__ == '__main__': |
| | | if len(sys.argv) != 2: |
| | | print('Usage: python MicroWaveReceiverTest.py [folder]') |
| | | exit(1) |
| | | folder = sys.argv[1] |
| | | files = ["packet{}.udp".format(i) for i in range(100)] |
| | | receiver = MicroWaveReceiver() |
| | | for file in files: |
| | | filename = os.path.join(folder, file) |
| | | with open(filename, "rb") as f: |
| | | data = f.read() |
| | | receiver.AddBuf(data) |
| | | if receiver.DataFrameReady: |
| | | frame_number = receiver.Header.FrameNumber |
| | | bin_name = os.path.join(folder, "{}.bin".format(frame_number)) |
| | | print("Frame {} ready".format(frame_number)) |
| | | with open(bin_name, "wb") as bin_file: |
| | | bin_file.write(receiver.DataFrame) |
| | | bin_file.close() |
| New file |
| | |
| | | import sys |
| | | import time |
| | | import os |
| | | from socketserver import BaseRequestHandler, UDPServer |
| | | |
| | | # add python path of microwave to sys.path |
| | | microwave_path = os.path.join(__file__, *(['..'] * 3)) |
| | | microwave_path = os.path.abspath(microwave_path) |
| | | sys.path.insert(0, microwave_path) |
| | | |
| | | from microwave.servers import MicroWaveReceiver |
| | | |
| | | |
| | | class MicroWaveRequestHandlertest(BaseRequestHandler): |
| | | def handle(self): |
| | | # Get message and client socket |
| | | buf, _ = self.request |
| | | receiver = self.server.Receiver |
| | | receiver.AddBuf(buf) |
| | | if receiver.DataFrameReady: |
| | | # data frame ready |
| | | frame_number = receiver.Header.FrameNumber |
| | | bin_name = os.path.join(self.server.OutputFolder, "{}.bin".format(frame_number)) |
| | | print("Frame {} ready".format(frame_number)) |
| | | with open(bin_name, "wb") as bin_file: |
| | | bin_file.write(receiver.DataFrame) |
| | | |
| | | |
| | | class MicroWaveUDPServertest(UDPServer): |
| | | def __init__(self, server_address, output_folder): |
| | | super().__init__(server_address, MicroWaveRequestHandlertest) |
| | | # create receiver instance |
| | | self.Receiver = MicroWaveReceiver() |
| | | self.OutputFolder = output_folder |
| | | |
| | | if __name__ == '__main__': |
| | | if len(sys.argv) == 2: |
| | | output_folder = sys.argv[1] |
| | | else: |
| | | output_folder = '.' |
| | | |
| | | # host = '192.168.2.65' |
| | | host = '' |
| | | port = 9911 |
| | | server = MicroWaveUDPServertest((host, port), output_folder) |
| | | server.packed_count = 0 |
| | | print(time.asctime(),'Server started on port', port) |
| | | print('....') |
| | | print('ctrl-c to quit server.') |
| | | try: |
| | | server.serve_forever() |
| | | except KeyboardInterrupt: |
| | | server.server_close() |
| | | print(time.asctime(),"Server Stopped") |
| | | except: |
| | | server.server_close() |
| | | print(time.asctime(),"Server Stopped") |
| New file |
| | |
| | | { |
| | | "cells": [ |
| | | { |
| | | "cell_type": "code", |
| | | "execution_count": 3, |
| | | "metadata": {}, |
| | | "outputs": [ |
| | | { |
| | | "name": "stdout", |
| | | "output_type": "stream", |
| | | "text": [ |
| | | "[Open3D WARNING] [ViewControl] SetViewPoint() failed because window height and width are not set.\n" |
| | | ] |
| | | } |
| | | ], |
| | | "source": [ |
| | | "import open3d as o3d\n", |
| | | "# visualization of point clouds.\n", |
| | | "# pcd = o3d.io.read_point_cloud('dense2_without_color.ply')\n", |
| | | "# show = [pcd]\n", |
| | | "pcd2522 = o3d.io.read_point_cloud('demoData/2522.ply')\n", |
| | | "pcd2523 = o3d.io.read_point_cloud('demoData2523.ply')\n", |
| | | "pcd2524 = o3d.io.read_point_cloud('demoData2524.ply')\n", |
| | | "pcd2525 = o3d.io.read_point_cloud('demoData2525.ply')\n", |
| | | "pcd2526 = o3d.io.read_point_cloud('demoData2526.ply')\n", |
| | | "pcd2527 = o3d.io.read_point_cloud('demoData2527.ply')\n", |
| | | "show = [pcd2522,pcd2523,pcd2524,pcd2525,pcd2526,pcd2527]\n", |
| | | "o3d.visualization.draw_geometries(show)\n" |
| | | ] |
| | | }, |
| | | { |
| | | "cell_type": "code", |
| | | "execution_count": null, |
| | | "metadata": {}, |
| | | "outputs": [], |
| | | "source": [] |
| | | } |
| | | ], |
| | | "metadata": { |
| | | "interpreter": { |
| | | "hash": "35e65690039548a4ed71bb11d5d15cea8607c9411f67738c48033f1deba4df50" |
| | | }, |
| | | "kernelspec": { |
| | | "display_name": "Python 3.9.10 ('huaneng_server')", |
| | | "language": "python", |
| | | "name": "python3" |
| | | }, |
| | | "language_info": { |
| | | "codemirror_mode": { |
| | | "name": "ipython", |
| | | "version": 3 |
| | | }, |
| | | "file_extension": ".py", |
| | | "mimetype": "text/x-python", |
| | | "name": "python", |
| | | "nbconvert_exporter": "python", |
| | | "pygments_lexer": "ipython3", |
| | | "version": "3.9.10" |
| | | }, |
| | | "orig_nbformat": 4 |
| | | }, |
| | | "nbformat": 4, |
| | | "nbformat_minor": 2 |
| | | } |
| New file |
| | |
| | | from socketserver import BaseRequestHandler, UDPServer |
| | | import time |
| | | import os, sys |
| | | |
| | | |
| | | cudir,_ = os.path.split(__file__) |
| | | file_folder = os.path.join(cudir,"saveUDPData") |
| | | |
| | | if not os.path.exists(file_folder): |
| | | os.makedirs(file_folder) |
| | | print(f"make a new folder: {file_folder}") |
| | | |
| | | packed_count = 0 |
| | | |
| | | class PointCloudUDPRequestHandler(BaseRequestHandler): |
| | | |
| | | def handle(self): |
| | | |
| | | global packed_count |
| | | |
| | | print(time.asctime(),' Got connection from {}, {}'.format(self.client_address, packed_count)) |
| | | # Get message and client socket |
| | | msg, sock = self.request |
| | | f = open('{}/packet{}.udp'.format(file_folder,packed_count), 'wb') |
| | | f.write(msg) |
| | | f.close() |
| | | packed_count += 1 |
| | | if packed_count >= 1000000: |
| | | UDPServer.server_close(server) |
| | | |
| | | |
| | | if __name__ == '__main__': |
| | | |
| | | def help(): |
| | | print("Usage: udp_test_get.py [host]. host can be 'test' or 'microwave' ") |
| | | exit(1) |
| | | |
| | | if len(sys.argv) == 2: |
| | | if sys.argv[1] == 'test': |
| | | host = '' |
| | | elif sys.argv[1] == 'microwave': |
| | | host = '192.168.2.65' |
| | | else: |
| | | help() |
| | | else: |
| | | help() |
| | | |
| | | global server |
| | | # host = '' |
| | | # host = '192.168.2.65' # use this host to get the udp data from microwave device |
| | | port = 9911 |
| | | server =UDPServer((host, port), PointCloudUDPRequestHandler) |
| | | print(time.asctime(),'Server started on port', port) |
| | | print('....') |
| | | print('ctrl-c to quit server.') |
| | | try: |
| | | server.serve_forever() |
| | | except KeyboardInterrupt: |
| | | server.server_close() |
| | | print(time.asctime(),"Server Stopped") |
| | | except: |
| | | server.server_close() |
| | | print(time.asctime(),"Server Stopped") |
| New file |
| | |
| | | import time |
| | | import socket |
| | | import os, sys |
| | | |
| | | cudir,_ = os.path.split(__file__) |
| | | file_folder = os.path.join(cudir,"demoData") |
| | | |
| | | packed_count = 0 |
| | | if __name__ == '__main__': |
| | | |
| | | files = ["packet{}.udp".format(i) for i in range(0, 100)] |
| | | for file in files: |
| | | with open(os.path.join(file_folder,file), "rb") as f: |
| | | message = f.read() |
| | | client_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) |
| | | client_socket.settimeout(1.0) |
| | | addr = ("127.0.0.1", 9911) |
| | | client_socket.sendto(message, addr) |
| | | print (time.asctime(), f' Sending {file} to {addr} ...') |
| | | time.sleep(0.1) |
| | | print('Done!') |
| New file |
| | |
| | | from .components import * |
| | | from .constants import * |
| | | from ctypes import sizeof, string_at |
| | | |
| | | |
| | | |
| | | class MicroWaveParser: |
| | | @classmethod |
| | | def ParserFrame(cls, buffer: bytes) -> list: |
| | | """ |
| | | 解析完整的一帧数据,数据包括数据头,数据体,数据尾,返回点云数组 |
| | | """ |
| | | header = HeaderBlock(buffer[:sizeof(HeaderBlock)]) |
| | | if HEADER_MAGIC == string_at(header.Magic, 8): |
| | | footer = FooterBlock(buffer[-sizeof(FooterBlock):]) |
| | | point_cloud = [] |
| | | for i in range(header.NumberOfDetection): |
| | | detection = DetectionBlock(header, footer, buffer[i * 8 + sizeof(HeaderBlock): (i + 1) * 8 + sizeof(HeaderBlock)]) |
| | | point = (detection.X, detection.Y, detection.Z) |
| | | point_cloud.append(point) |
| | | return point_cloud |
| | | else: |
| | | return [] |
| New file |
| | |
| | | import os, sys |
| | | from ctypes import sizeof, string_at |
| | | from socketserver import BaseRequestHandler, UDPServer |
| | | from .components import * |
| | | from .constants import * |
| | | |
| | | # add python path of src to sys.path |
| | | src_path = os.path.join(__file__, *(['..'] * 2)) |
| | | src_path = os.path.abspath(src_path) |
| | | sys.path.insert(0, src_path) |
| | | |
| | | from protos import aerial_pb2 as pb |
| | | |
| | | |
| | | |
| | | UDP_STATE_IDLE = 0 |
| | | UDP_STATE_HAND_SHAKE = 1 |
| | | UDP_STATE_DATA = 2 |
| | | UDP_STATE_FOOTER = 3 |
| | | |
| | | class MicroWaveReceiver: |
| | | """ |
| | | micro wave data receiver |
| | | use AddBuf method add udp packet to receiver |
| | | when DataFrameReady == True, you can get data frame |
| | | """ |
| | | def __init__(self): |
| | | self.state = UDP_STATE_IDLE |
| | | self.PointCount = 0 |
| | | self.TrackCount = 0 |
| | | self.DataFrameReady = False |
| | | self.DataFrame = None |
| | | self.Header = None |
| | | self.Footer = None |
| | | |
| | | def _receive_data(self, data) -> None: |
| | | """ |
| | | receive data packet from udp |
| | | """ |
| | | self.data_buf.extend(data) |
| | | self.ReceivedDataLength += len(data) |
| | | if self.ReceivedDataLength == self.DataLength: |
| | | # if received data length equal expected data length |
| | | # then we can get footer block |
| | | self.state = UDP_STATE_FOOTER |
| | | return |
| | | |
| | | def _receive_footer(self, data) -> None: |
| | | # receive footer block |
| | | self.footer_buf.extend(data) |
| | | self.ReceivedFooterLength += len(data) |
| | | if self.ReceivedFooterLength == sizeof(FooterBlock): |
| | | self.Footer = FooterBlock.from_buffer_copy(self.footer_buf) |
| | | # after received footer block, the data frame is ready |
| | | self.DataFrameReady = True |
| | | # reset state to idle, ready for next data frame |
| | | self.state = UDP_STATE_IDLE |
| | | return |
| | | |
| | | def AddBuf(self, buf: bytes) -> None: |
| | | # add a udp packet to receiver |
| | | buf_size = len(buf) |
| | | if self.state == UDP_STATE_IDLE: |
| | | if buf_size == sizeof(Handshake): |
| | | handshake = Handshake.from_buffer_copy(buf) |
| | | if HAND_SHAKE_MAGIC == string_at(handshake.Magic, 8): |
| | | self.DataFrameReady = False |
| | | self.state = UDP_STATE_HAND_SHAKE |
| | | self.DataFrame = None |
| | | self.Header = None |
| | | self.Footer = None |
| | | elif self.state == UDP_STATE_HAND_SHAKE: |
| | | # after received handshake packet, we can get header block |
| | | self.Header = HeaderBlock.from_buffer_copy(buf[:sizeof(HeaderBlock)]) |
| | | if HEADER_MAGIC == string_at(self.Header.Magic, 8): |
| | | self.DataFrame = bytearray(buf) |
| | | N = self.Header.NumberOfDetection |
| | | Nt = self.Header.NumberOfTrack |
| | | self.PointCount = 0 |
| | | self.TrackCount = 0 |
| | | self.DataLength = N * 8 + Nt * sizeof(TrackerBlock) |
| | | self.RemainLength = self.DataLength + sizeof(FooterBlock) |
| | | self.data_buf = bytearray() |
| | | self.footer_buf = bytearray() |
| | | self.Points = [] |
| | | self.ReceivedDataLength = 0 |
| | | self.ReceivedFooterLength = 0 |
| | | # the next packet should be data block |
| | | self.state = UDP_STATE_DATA |
| | | |
| | | header_size = sizeof(HeaderBlock) |
| | | # 处理第一个数据包中的数据 |
| | | data_size = min(buf_size - header_size, self.DataLength) |
| | | self._receive_data(buf[header_size: header_size + data_size]) |
| | | |
| | | # 判断第一个数据包中是否包含Footer Block |
| | | if (header_size + data_size) < buf_size: |
| | | self._receive_footer(buf[header_size + data_size]) |
| | | elif self.state == UDP_STATE_DATA: |
| | | # receive data block |
| | | self.DataFrame.extend(buf) |
| | | remain_data_size = self.DataLength - self.ReceivedDataLength |
| | | data_size = min(buf_size, remain_data_size) |
| | | self._receive_data(buf[: data_size]) |
| | | if data_size < buf_size: |
| | | self._receive_footer(buf[data_size: ]) |
| | | elif self.state == UDP_STATE_FOOTER: |
| | | # receive footer block |
| | | self.DataFrame.extend(buf) |
| | | self._receive_footer(buf) |
| | | |
| | | |
| | | |
| | | class MicroWaveRequestHandler(BaseRequestHandler): |
| | | """ |
| | | micro wave udp request handler |
| | | """ |
| | | def handle(self): |
| | | # Get message and client socket |
| | | buf, _ = self.request |
| | | receiver = self.server.Receiver |
| | | # add buffer to receiver |
| | | receiver.AddBuf(buf) |
| | | if receiver.DataFrameReady: |
| | | # dataframe ready, add to udp_queue |
| | | msg = pb.RequestCommand() |
| | | msg.sys_command = pb.SysCommand.MICRO_WAVE_COMMAND |
| | | msg.sub_command = pb.SubCommand.MICRO_WAVE_SUB_COMMAND |
| | | data1 = pb.MicroWaveMessage() |
| | | data1.length = len(receiver.DataFrame) |
| | | data1.data = bytes(receiver.DataFrame) |
| | | data1_str = data1.SerializeToString() |
| | | msg.data1.length = len(data1_str) |
| | | msg.data1.data = data1_str |
| | | self.server.msg_queue.put(msg) |
| | | |
| | | |
| | | class MicroWaveUDPServer(UDPServer): |
| | | """ |
| | | micro wave udp server |
| | | """ |
| | | def __init__(self, server_address, msg_queue): |
| | | super().__init__(server_address, MicroWaveRequestHandler) |
| | | # create receiver instance |
| | | self.Receiver = MicroWaveReceiver() |
| | | self.msg_queue = msg_queue |
| New file |
| | |
| | | from posixpath import abspath |
| | | import sys # NOQA: E402 |
| | | import os |
| | | from flask import Flask, request |
| | | |
| | | batfile_dir = os.path.join(__file__, "..", "protos/compile.bat" ) |
| | | batfile_path = os.path.abspath(batfile_dir) |
| | | os.system(batfile_path) |
| | | |
| | | from engine.DeviceManager import DeviceManager |
| | | from engine.MessageQueueThread import MessageQueueThread |
| | | from protos import aerial_pb2 as pb |
| | | |
| | | |
| | | |
| | | class MyServer(Flask): |
| | | def __init__(self, host, user, password, queue, port): |
| | | Flask.__init__(self, __name__) |
| | | self.host = host |
| | | self.user = user |
| | | self.password = password |
| | | self.queue = queue |
| | | self.port = port |
| | | |
| | | self.route('/api', methods=['POST'])(self.api) |
| | | self.route('/', methods=['GET'])(self.hello) |
| | | self._def_routes() |
| | | self._device_manager = DeviceManager(host, user, password) |
| | | |
| | | def _def_routes(self): |
| | | self.routes = { |
| | | pb.SysCommand.SYS_COMMAND: self._on_sys_command, |
| | | } |
| | | |
| | | def _on_sys_command(self, req: pb.RequestCommand, resp: pb.ResponseCommand): |
| | | if pb.SubCommand.POWER_ON_SUB_COMMAND == req.sub_command: |
| | | print('power on message received') |
| | | self._device_manager.get_device(req.device_id,save_folder) |
| | | elif pb.SubCommand.POWER_OFF_SUB_COMMAND == req.sub_command: |
| | | device = self._device_manager.get_device(req.device_id,save_folder) |
| | | device['power_on'] = False |
| | | print('power off message received') |
| | | return |
| | | |
| | | def _default(self, req: pb.RequestCommand, resp: pb.ResponseCommand): |
| | | print('onknown command') |
| | | |
| | | def api(self): |
| | | req = pb.RequestCommand() |
| | | req.ParseFromString(request.data) |
| | | dispatcher = self.routes.get(req.sys_command, self._default) |
| | | resp = pb.ResponseCommand() |
| | | dispatcher(req, resp) |
| | | resp.checksum = 12345 |
| | | response = Flask.response_class( |
| | | resp.SerializeToString(), |
| | | mimetype='application/x-protobuf' |
| | | ) |
| | | return response, 200 |
| | | |
| | | def hello(self): |
| | | return 'Hello, This is acquisition demo API!' |
| | | |
| | | def run_rabbitmq(self, host: str, user: str, password: str, queue: str) -> None: |
| | | self._message_queue_thread = MessageQueueThread( |
| | | host, user, password, queue, self._device_manager) |
| | | self._message_queue_thread.start() |
| | | |
| | | def run_all(self): |
| | | self.run_rabbitmq(self.host, self.user, self.password, self.queue) |
| | | self.run(debug=False, host="0.0.0.0", port=self.port) |
| | | |
| | | def send_controll_message(self, device_id, msg): |
| | | device = self._device_manager.get_device(device_id) |
| | | if device is None: |
| | | channel = device.controll_channel |
| | | channel.basic_publish( |
| | | exchange='', |
| | | routing_key='', |
| | | body=msg.SerializeToString()) |
| | | |
| | | def send_dust_cleaner_cmd(self, device_id, sub_cmd, period): |
| | | msg = pb.ControllMessage() |
| | | msg.sys_command = pb.ControlSysCommand.DUST_CLEANER_COMMAND |
| | | msg.sub_command = sub_cmd |
| | | data_msg = pb.DustCleanerMessage() |
| | | data_msg.period = period |
| | | data1_str = data_msg.SerializeToString() |
| | | msg.data1.length = len(data1_str) |
| | | msg.data1.data = data1_str |
| | | |
| | | |
| | | if __name__ == "__main__": |
| | | def help(): |
| | | print("Usage: Server.py [MQhost] [MQuser] [MQpassword] [QUEUEname] [WEBport] [SAVEfolder]") |
| | | print("EXAMPLE: Server.py localhost chai password123 aerial_rpc 5000 ./Images") |
| | | exit(1) |
| | | |
| | | if len(sys.argv) != 7: |
| | | help() |
| | | try: |
| | | MQhost = str(sys.argv[1]) |
| | | MQuser = str(sys.argv[2]) |
| | | MQpassword = str(sys.argv[3]) |
| | | QUEUEname = str(sys.argv[4]) |
| | | WEBport = int(sys.argv[5]) |
| | | SAVEfolder = str(sys.argv[6]) |
| | | global save_folder |
| | | save_folder = SAVEfolder |
| | | |
| | | except Exception as e: |
| | | print(e) |
| | | help() |
| | | server = MyServer(host="localhost", user='chai', password='password123', queue='aerial_rpc', port=5000) |
| | | server.run_all() |
| New file |
| | |
| | | { |
| | | "Device_name": "实时堆体识别", |
| | | "Device_ID": "e8d28684-c908-457e-ade9-381451d26b0c", |
| | | "Device_Network_para": { |
| | | "Network_SSID": "thisisaWiFI", |
| | | "Network_Password": "thisisaWiFIpassword", |
| | | "Network_mode": "5g", |
| | | "Network_MAC": "AA-BB-CC-DD-EE-FF", |
| | | "Network_IP": "192.168.99.99" |
| | | }, |
| | | "Captue_Image_para": { |
| | | "brightness": 50, |
| | | "contrast": 50, |
| | | "hue": 50, |
| | | "saturation": 50, |
| | | "clarity": 50, |
| | | "white_balance": 50, |
| | | "frame_rate": 20, |
| | | "capture_interval": 10, |
| | | "dodec_type": "h264", |
| | | "resolution": "4k", |
| | | "IFrame_interval": 10, |
| | | "overlap": 0.8, |
| | | "level_angle": 2, |
| | | "left_angle": -3, |
| | | "right_angle": 1, |
| | | "device_mid_x": 100, |
| | | "device_mid_y": 50, |
| | | "device_mid_z": 8000, |
| | | "camera_1_x": -100, |
| | | "camera_1_y": -100, |
| | | "camera_1_z": -100, |
| | | "camera_2_x": -100, |
| | | "camera_2_y": -100, |
| | | "camera_2_z": -100, |
| | | "camera_3_x": -100, |
| | | "camera_3_y": -100, |
| | | "camera_3_z": -100, |
| | | "camera_4_x": -100, |
| | | "camera_4_y": -100, |
| | | "camera_4_z": -100, |
| | | "left_pupil_distance": 400, |
| | | "right_pupil_distance": 800 |
| | | }, |
| | | "Millimeter_Wave_para": { |
| | | "level_angle": 2, |
| | | "left_angle": -3, |
| | | "right_angle": 1, |
| | | "MW_x": 100, |
| | | "MW_y": 50, |
| | | "MW_z": 8000, |
| | | "MW_IP": "192.168.168.9", |
| | | "MW_Port": 50055, |
| | | "protocol": "tcp", |
| | | "dest_IP": "192.168.168.100", |
| | | "dest_port": 50056, |
| | | "dest_protocol": "xieyi?TCP" |
| | | }, |
| | | "Clean_Brush_para": { |
| | | "clean_lens_start_angle": 10, |
| | | "clean_lens_end_angle": 90, |
| | | "clean_lens_num": 2, |
| | | "clean_lens_period": 1200, |
| | | "clean_self_start_angle": 10, |
| | | "clean_self_end_angle": 55, |
| | | "clean_self_num": 2, |
| | | "clean_self_period": 2400 |
| | | }, |
| | | "High_Light_para": { |
| | | "open_hour": 18, |
| | | "open_minute": 30, |
| | | "close_hour": 6, |
| | | "close_minute": 30, |
| | | "brightness": 30, |
| | | "color": "white" |
| | | }, |
| | | "AI_Algorithm_para": { |
| | | "threshold": 99.6, |
| | | "para_1": 100, |
| | | "para_2": 1 |
| | | } |
| | | } |
| New file |
| | |
| | | import sys # NOQA: E402 |
| | | import os |
| | | import cv2 |
| | | import logging |
| | | import json |
| | | import pika |
| | | import queue |
| | | import requests |
| | | import time |
| | | |
| | | from .CaptureThread import CaptureThread |
| | | from .ControllThread import ControllThread |
| | | from .MicroWaveUDPThread import MicroWaveUDPThread |
| | | |
| | | # add python path of src to sys.path |
| | | src_path = os.path.join(__file__, *(['..'] * 2)) |
| | | src_path = os.path.abspath(src_path) |
| | | sys.path.insert(0, src_path) |
| | | |
| | | from protos import aerial_pb2 as pb |
| | | |
| | | |
| | | IMAGE_WIDTH = 3840 |
| | | IMAGE_HEIGHT = 2880 |
| | | CAMERA_COUNT = 4 |
| | | |
| | | class Config: |
| | | """ |
| | | config class |
| | | """ |
| | | def __init__(self, config_file: str): |
| | | self.interval: float = 10 |
| | | self.resolution = '4k' |
| | | |
| | | self.clean_lens_start_angle = 10 |
| | | self.clean_lens_end_angle = 90 |
| | | self.clean_lens_num = 2 |
| | | self.clean_lens_period = 1200 |
| | | self.clean_self_start_angle = 10 |
| | | self.clean_self_end_angle = 55 |
| | | self.clean_self_num = 2 |
| | | self.clean_self_period = 240 |
| | | |
| | | # load config file |
| | | with open(config_file, 'r') as f: |
| | | self.config = json.load(f) |
| | | self.device_id = self.config['Device_ID'] |
| | | self.interval = self.config['Captue_Image_para']['capture_interval'] |
| | | self.resolution = self.config['Captue_Image_para']['resolution'] |
| | | |
| | | Clean_Brush_para = self.config['Clean_Brush_para'] |
| | | self.clean_lens_start_angle = Clean_Brush_para['clean_lens_start_angle'] |
| | | self.clean_lens_end_angle = Clean_Brush_para['clean_lens_end_angle'] |
| | | self.clean_lens_num = Clean_Brush_para['clean_lens_num'] |
| | | self.clean_lens_period = Clean_Brush_para['clean_lens_period'] |
| | | self.clean_self_start_angle = Clean_Brush_para['clean_self_start_angle'] |
| | | self.clean_self_end_angle = Clean_Brush_para['clean_self_end_angle'] |
| | | self.clean_self_num = Clean_Brush_para['clean_self_num'] |
| | | self.clean_self_period = Clean_Brush_para['clean_self_period'] |
| | | f.close() |
| | | return |
| | | |
| | | class AcquisitionMain: |
| | | """ |
| | | acquisition main class |
| | | """ |
| | | def __init__(self, |
| | | rabbitmq_host: str, |
| | | rabbitmq_user: str, |
| | | rabbitmq_password: str, |
| | | rabbitmq_queue: str, |
| | | device_id: str, |
| | | api_url: str, |
| | | udp_server_host: str, |
| | | config: Config) -> None: |
| | | """ |
| | | init AcquisitionMain class |
| | | Args: |
| | | rabbitmq_host: rabbitmq server host |
| | | rabbitmq_user: rabbitmq user |
| | | rabbitmq_password: rabbitmq password |
| | | rabbitmq_queue: rabbitmq upload queue |
| | | device_id: device id |
| | | api_url: server api url |
| | | udp_server_host: udp server host for micro wave, localhost for testing or 192.168.2.65 for production |
| | | config: config object |
| | | """ |
| | | self.rabbitmq_host: str = rabbitmq_host |
| | | self.udp_server_host: str = udp_server_host |
| | | self.rabbitmq_user: str = rabbitmq_user |
| | | self.rabbitmq_password: str = rabbitmq_password |
| | | self.rabbitmq_queue: str = rabbitmq_queue |
| | | self.device_id: str = device_id |
| | | self.message_send: int = 0 |
| | | self.api_url: str = api_url |
| | | self.config = config |
| | | self.image_quality: float = 95 |
| | | self.cameras: list = [] |
| | | self.msg_queue = queue.Queue() |
| | | # thread members |
| | | self._controll_thread = None |
| | | self._capture_thread = None |
| | | self._udp_thread = None |
| | | |
| | | def _start_udp_thread(self): |
| | | """start udp thread""" |
| | | if self._udp_thread is None: |
| | | self._udp_thread = MicroWaveUDPThread((self.udp_server_host, 9911), self.msg_queue) |
| | | self._udp_thread.setDaemon(True) |
| | | self._udp_thread.start() |
| | | |
| | | def _stop_udp_thread(self): |
| | | """stop udp thread""" |
| | | if not self._udp_thread is None: |
| | | self._udp_thread.stop() |
| | | self._udp_thread = None |
| | | |
| | | def _start_capture_thread(self): |
| | | """start camera capture thread""" |
| | | if self._capture_thread is None: |
| | | self._open_cameras() |
| | | if len(self.cameras) == 0: |
| | | print("No camera available") |
| | | return |
| | | self._capture_thread = CaptureThread( |
| | | self.cameras, self.msg_queue, self.config.interval, self.image_quality) |
| | | self._capture_thread.setDaemon(True) |
| | | self._capture_thread.start() |
| | | |
| | | def _stop_capture_thread(self): |
| | | """stop camera capture thread""" |
| | | if not self._capture_thread is None: |
| | | self._capture_thread.stop() |
| | | self._capture_thread = None |
| | | |
| | | def _start_controll_thread(self): |
| | | """start controll thread""" |
| | | if self._controll_thread is None: |
| | | self._controll_thread = ControllThread( |
| | | self.rabbitmq_host, self.rabbitmq_user, self.rabbitmq_password, self.device_id + "_callback", |
| | | self.config) |
| | | self._controll_thread.setDaemon(True) |
| | | self._controll_thread.start() |
| | | |
| | | def _stop_controll_thread(self): |
| | | """stop controll thread""" |
| | | if not self._controll_thread is None: |
| | | self._controll_thread.stop() |
| | | self._controll_thread = None |
| | | |
| | | def _connect_message_queue(self) -> None: |
| | | """connect message queue of rabbitmq""" |
| | | credentials = pika.PlainCredentials(self.rabbitmq_user, self.rabbitmq_password) |
| | | parameters = pika.ConnectionParameters( |
| | | credentials=credentials, host=self.rabbitmq_host) |
| | | # 连接队列服务器 |
| | | self._connection = pika.BlockingConnection(parameters) |
| | | self.channel = self._connection.channel() |
| | | self.channel.queue_declare(queue='', exclusive=True) |
| | | |
| | | def _close_message_queue(self) -> None: |
| | | """close message queue of rabbitmq""" |
| | | self._connection.close() |
| | | |
| | | def _set_logging(self): |
| | | """set logging""" |
| | | logging.basicConfig(level=logging.INFO, |
| | | format='%(asctime)s %(levelname)s %(message)s', |
| | | datefmt='%Y-%m-%d %H:%M:%S') |
| | | self.logger = logging.getLogger(__name__) |
| | | |
| | | def _send_data(self, req: pb.RequestCommand) -> None: |
| | | """send data to rabbitmq""" |
| | | req.device_id = self.device_id |
| | | body = req.SerializeToString() |
| | | self.channel.basic_publish( |
| | | exchange='', |
| | | routing_key=self.rabbitmq_queue, |
| | | body=body) |
| | | self.message_send += 1 |
| | | return |
| | | |
| | | def _call(self, req: pb.RequestCommand, timeout: int = 10) -> pb.ResponseCommand: |
| | | """call server api""" |
| | | req.device_id = self.device_id |
| | | self.response = None |
| | | body = req.SerializeToString() |
| | | response = requests.post( |
| | | self.api_url, |
| | | data=body, |
| | | headers={'Content-Type': 'application/x-protobuf'}, |
| | | timeout=timeout) |
| | | resp = pb.ResponseCommand() |
| | | resp.ParseFromString(response.content) |
| | | return resp |
| | | |
| | | def _send_power_on_message(self) -> pb.ResponseCommand: |
| | | """send power on message""" |
| | | print("send power on message") |
| | | req = pb.RequestCommand() |
| | | req.sys_command = pb.SysCommand.SYS_COMMAND |
| | | req.sub_command = pb.SubCommand.POWER_ON_SUB_COMMAND |
| | | return self._call(req) |
| | | |
| | | def _send_power_off_message(self) -> pb.ResponseCommand: |
| | | """send power off message""" |
| | | print("send power off message") |
| | | req = pb.RequestCommand() |
| | | req.sys_command = pb.SysCommand.SYS_COMMAND |
| | | req.sub_command = pb.SubCommand.POWER_OFF_SUB_COMMAND |
| | | return self._call(req) |
| | | |
| | | def _open_cameras(self): |
| | | """ |
| | | Test the ports and returns a tuple with the available ports and the ones that are working. |
| | | """ |
| | | self.cameras = [] |
| | | self.working_ports = [] |
| | | for dev_port in range(CAMERA_COUNT): |
| | | camera = cv2.VideoCapture(dev_port, cv2.CAP_DSHOW) |
| | | camera.set(cv2.CAP_PROP_FRAME_WIDTH, IMAGE_WIDTH) |
| | | camera.set(cv2.CAP_PROP_FRAME_HEIGHT, IMAGE_HEIGHT) |
| | | camera.set(cv2.CAP_PROP_FPS, 1) |
| | | if camera.isOpened(): |
| | | is_reading, img = camera.read() |
| | | w = camera.get(3) |
| | | h = camera.get(4) |
| | | if is_reading: |
| | | print("Port %s is working and reads images (%s x %s)" % |
| | | (dev_port, h, w)) |
| | | self.working_ports.append(dev_port) |
| | | self.cameras.append(camera) |
| | | |
| | | def _main_loop(self): |
| | | # main loop of the acquisition main program |
| | | self._connect_message_queue() |
| | | while True: |
| | | try: |
| | | if not self.msg_queue.empty(): |
| | | msg = self.msg_queue.get() |
| | | self._send_data(msg) |
| | | print("send message") |
| | | time.sleep(0.1) |
| | | except Exception as e: |
| | | break |
| | | self._close_message_queue() |
| | | self._stop_udp_thread() |
| | | self._stop_capture_thread() |
| | | self._stop_controll_thread() |
| | | print("Stopped") |
| | | |
| | | def start(self) -> None: |
| | | """start all threads""" |
| | | self._start_controll_thread() |
| | | self._start_capture_thread() |
| | | self._start_udp_thread() |
| | | self._main_loop() |
| New file |
| | |
| | | import sys |
| | | import cv2 # NOQA: E402 |
| | | import os |
| | | import numpy as np |
| | | import threading |
| | | import time |
| | | |
| | | |
| | | # add python path of src to sys.path |
| | | src_path = os.path.join(__file__, *(['..'] * 2)) |
| | | src_path = os.path.abspath(src_path) |
| | | sys.path.insert(0, src_path) |
| | | |
| | | from protos import aerial_pb2 as pb |
| | | |
| | | |
| | | class CaptureThread(threading.Thread): |
| | | """ |
| | | camera capture thread |
| | | """ |
| | | def __init__(self, cameras, msg_queue, interval, image_quality = 95): |
| | | """init the thread""" |
| | | threading.Thread.__init__(self) |
| | | self.cameras = cameras |
| | | self.msg_queue = msg_queue |
| | | self.interval = interval |
| | | self.image_quality = image_quality |
| | | self.is_stop = False |
| | | |
| | | def stop(self): |
| | | """stop the thread""" |
| | | self.is_stop = True |
| | | |
| | | def run(self): |
| | | print("CaptureThread started") |
| | | self.next_time = time.time() + self.interval |
| | | while not self.is_stop: |
| | | this_time = time.time() |
| | | if this_time > self.next_time: |
| | | data1 = pb.ImagesMessage() |
| | | for i in range(len(self.cameras)): |
| | | _, frame = self.cameras[i].read() |
| | | encode_param = [int(cv2.IMWRITE_JPEG_QUALITY), self.image_quality] |
| | | _, encimg = cv2.imencode('.jpg', frame, encode_param) |
| | | if frame is not None: |
| | | np_array = np.asarray(encimg) # frame 转换为numpy数组 |
| | | byte_array = np_array.tobytes() # numpy数组转换为byte数组 |
| | | if i == 0: |
| | | data1.image1 = byte_array |
| | | elif i == 1: |
| | | data1.image2 = byte_array |
| | | elif i == 2: |
| | | data1.image3 = byte_array |
| | | elif i == 3: |
| | | data1.image4 = byte_array |
| | | data1_str = data1.SerializeToString() |
| | | |
| | | # create protobuf message |
| | | req = pb.RequestCommand() |
| | | req.sys_command = pb.SysCommand.FIVE_G_COMMAND |
| | | req.sub_command = pb.SubCommand.FIVE_G_SEND_IMAGE_SUB_COMMAND |
| | | req.data1.length = len(data1_str) |
| | | req.data1.data = data1_str |
| | | # add message to queue |
| | | self.msg_queue.put(req) |
| | | self.next_time += self.interval |
| | | time.sleep(0.1) |
| | | for camera in self.cameras: |
| | | camera.release() |
| | | print("CaptureThread stopped") |
| New file |
| | |
| | | |
| | | import os, sys |
| | | import queue |
| | | import time |
| | | import pika |
| | | import threading |
| | | from .DustCleanerThread import DustCleanerThread |
| | | |
| | | # add python path of src to sys.path |
| | | src_path = os.path.join(__file__, *(['..'] * 2)) |
| | | src_path = os.path.abspath(src_path) |
| | | sys.path.insert(0, src_path) |
| | | |
| | | from protos import aerial_pb2 as pb |
| | | |
| | | class ControllThread(threading.Thread): |
| | | """ |
| | | controll thread |
| | | accept controll message from rabbitmq |
| | | """ |
| | | def __init__(self, host: str, user: str, password: str, callback_queue: str, config): |
| | | threading.Thread.__init__(self) |
| | | # setup dust cleaner command queue and thread |
| | | self.config = config |
| | | self._dust_cleaner_cmd_queue = queue.Queue() |
| | | self._dust_cleaner_thread = DustCleanerThread(self._dust_cleaner_cmd_queue, self.config) |
| | | self._dust_cleaner_thread.setDaemon(True) |
| | | self._dust_cleaner_thread.start() |
| | | |
| | | self._init_callback(host, user, password, callback_queue) |
| | | |
| | | def _def_routes(self): |
| | | """define controll message routes""" |
| | | self.routes = { |
| | | pb.ControlSysCommand.DUST_CLEANER_COMMAND: self._on_dust_cleaner_command, |
| | | } |
| | | |
| | | def _on_dust_cleaner_command(self, msg: pb.ControllMessage): |
| | | # add message to dust cleaner command queue |
| | | self._dust_cleaner_cmd_queue.put(msg) |
| | | return |
| | | |
| | | def _default(self, req: pb.ControllMessage): |
| | | print('default controll handler') |
| | | return |
| | | |
| | | def _init_callback(self, host: str, user: str, password: str, queue: str): |
| | | """init rabbitmq channel""" |
| | | credentials = pika.PlainCredentials(user, password) |
| | | parameters = pika.ConnectionParameters( |
| | | credentials=credentials, host=host) |
| | | connection = pika.BlockingConnection(parameters) |
| | | self._channel = connection.channel() |
| | | self._channel.queue_declare(queue=queue, durable=False) |
| | | self._channel.basic_qos(prefetch_count=1) |
| | | self._channel.basic_consume( |
| | | on_message_callback=self._on_callback_request, queue=queue) |
| | | |
| | | def _on_callback_request(self, ch, method, properties, body): |
| | | print('callback received') |
| | | msg = pb.ControllMessage() |
| | | msg.ParseFromString(body) |
| | | dispatcher = self.routes.get(msg.sys_command, self._default) |
| | | dispatcher(msg) |
| | | |
| | | ch.basic_ack(delivery_tag=method.delivery_tag) |
| | | return |
| | | |
| | | def stop(self): |
| | | """stop controll thread""" |
| | | self._channel.stop_consuming() |
| | | self._dust_cleaner_thread.stop() |
| | | |
| | | def run(self): |
| | | print("ControllThread started") |
| | | self._channel.start_consuming() |
| | | |
| | | |
| | | if __name__ == "__main__": |
| | | print("Begin CallbackThread Test") |
| | | cb_thread = ControllThread("localhost", "chai", "password123", "pod1") |
| | | cb_thread.start() |
| | | |
| | | time.sleep(3) |
| | | |
| | | cb_thread.stop() |
| New file |
| | |
| | | import datetime |
| | | import os |
| | | import pika |
| | | |
| | | class DeviceManager: |
| | | def __init__(self, host, user, password): |
| | | self.host = host |
| | | self.user = user |
| | | self.password = password |
| | | self._devices = {} |
| | | |
| | | def _create_controll_channel(self, device_id: str): |
| | | credentials = pika.PlainCredentials(self.user, self.password) |
| | | parameters = pika.ConnectionParameters( |
| | | credentials=credentials, host=self.host) |
| | | # 连接队列服务器 |
| | | connection = pika.BlockingConnection(parameters) |
| | | channel = connection.channel() |
| | | channel.queue_declare(queue=device_id + "_callback") |
| | | return channel |
| | | |
| | | def get_device(self, device_id: str, save_folder: str): |
| | | device = self._devices.get(device_id, None) |
| | | if device is None: |
| | | start = datetime.datetime.now() |
| | | if not os.path.exists(save_folder): |
| | | os.mkdir(save_folder) |
| | | path = os,path.join(save_folder,f"{device_id}-{start.strftime('%Y-%m-%d-%H-%M-%S')}") |
| | | if not os.path.exists(path): |
| | | os.mkdir(path) |
| | | device = dict( |
| | | power_on=True, |
| | | srart=start, |
| | | path=path, |
| | | images=0, |
| | | micro_wave=0, |
| | | controll_channel=self._create_controll_channel(device_id) |
| | | ) |
| | | self._devices[device_id] = device |
| | | return device |
| New file |
| | |
| | | # -*- coding: utf-8 -*- |
| | | __author__ = 'wangzhibo 2022.01.20' |
| | | |
| | | import serial |
| | | import serial.tools.list_ports |
| | | |
| | | |
| | | class DustCleaner(): |
| | | # 初始化 |
| | | def __init__(self, com, bps, timeout): |
| | | self.port = com |
| | | self.bps = bps |
| | | self.timeout = timeout |
| | | self.com_port = None |
| | | self.Open() |
| | | |
| | | # 打印设备基本信息 |
| | | def Print_Name(self): |
| | | print(self.com_port.name) # 设备名字 |
| | | print(self.com_port.port) # 读或者写端口 |
| | | print(self.com_port.baudrate) # 波特率 |
| | | print(self.com_port.bytesize) # 字节大小 |
| | | print(self.com_port.parity) # 校验位 |
| | | print(self.com_port.stopbits) # 停止位 |
| | | print(self.com_port.timeout) # 读超时设置 |
| | | print(self.com_port.writeTimeout) # 写超时 |
| | | print(self.com_port.xonxoff) # 软件流控 |
| | | print(self.com_port.rtscts) # 软件流控 |
| | | print(self.com_port.dsrdtr) # 硬件流控 |
| | | print(self.com_port.interCharTimeout) # 字符间隔超时 |
| | | |
| | | # 打开串口 |
| | | def Open(self) -> bool: |
| | | try: |
| | | # 打开串口,并得到串口对象 |
| | | self.com_port = serial.Serial(self.port, self.bps, timeout=self.timeout) |
| | | # 判断是否打开成功 |
| | | if (self.com_port.is_open): |
| | | return True |
| | | else: |
| | | return False |
| | | except Exception as _: |
| | | return False |
| | | |
| | | # 关闭串口 |
| | | def Close(self) -> None: |
| | | self.com_port.close() |
| | | print(self.com_port.is_open) # 检验串口是否打开 |
| | | |
| | | # 打印可用串口列表 |
| | | @classmethod |
| | | def Print_Used_Com(): |
| | | port_list = list(serial.tools.list_ports.comports()) |
| | | print(port_list) |
| | | |
| | | # 发数据 |
| | | def Send(self, data): |
| | | if (not self.com_port is None) and self.com_port.is_open(): |
| | | self.com_port.write(data) |
| | | self.Recive() |
| | | |
| | | def SendNoChecksum(self, data): |
| | | checksum = 0 |
| | | array = bytearray(data) |
| | | for i in array[:-1]: |
| | | checksum += i |
| | | checksum = checksum % 256 |
| | | array[-1] = checksum |
| | | self.Send(bytes(array)) |
| | | |
| | | def Send_onetime_clean_self(self): # 发送函数 |
| | | self.Send(bytes([0x5A, 0x04, 0x70, 0xCE])) # 用write函数向串口发送数据 |
| | | |
| | | def Send_onetime_clean_camera(self): # 发送函数 |
| | | self.Send(bytes([0x5A, 0x04, 0x71, 0xCF])) # 用write函数向串口发送数据 |
| | | |
| | | def Send_close_period_clean_self(self): |
| | | self.Send(bytes([0x5A, 0x06, 0x74, 0x00, 0x00, 0xD4])) # close self period clean |
| | | |
| | | def Send_close_period_clean_camera(self): |
| | | self.Send(bytes([0x5A, 0x06, 0x75, 0x00, 0x00, 0xD5])) # close self period clean |
| | | |
| | | def Send_period_clean_self(self, period: int): |
| | | minute_H = period // 256 |
| | | minute_L = period % 256 |
| | | self.SendNoChecksum(bytes([0x5A, 0x06, 0x74, minute_H, minute_L, 0x00])) |
| | | |
| | | def Send_period_clean_camera(self, period: int): |
| | | minute_H = period // 256 |
| | | minute_L = period % 256 |
| | | self.SendNoChecksum(bytes([0x5A, 0x06, 0x75, minute_H, minute_L, 0x00])) |
| | | |
| | | def Send_self_clean_params(self, start_angle: int, end_angle: int, num: int): |
| | | self.SendNoChecksum(bytes([0x5A, 0x07, 0x72, start_angle, end_angle, num, 0x00])) |
| | | |
| | | def Send_camera_clean_params(self, start_angle: int, end_angle: int, num: int): |
| | | self.SendNoChecksum(bytes([0x5A, 0x07, 0x73, start_angle, end_angle, num, 0x00])) |
| | | |
| | | def Recive(self): |
| | | return self.main_engine.read_all() |
| | | |
| | | |
| | | if __name__ == '__main__': |
| | | # DustCleaner.Print_Used_Com() |
| | | cleaner = DustCleaner("com11", 115200, 1) |
| | | if cleaner.Open(): |
| | | cleaner.Send_close_period_clean_camera() |
| | | cleaner.Recive() |
| New file |
| | |
| | | import sys # NOQA: E402 |
| | | import os |
| | | import threading |
| | | import time |
| | | |
| | | from .DustCleaner import DustCleaner |
| | | |
| | | # add python path of src to sys.path |
| | | src_path = os.path.join(__file__, *(['..'] * 2)) |
| | | src_path = os.path.abspath(src_path) |
| | | sys.path.insert(0, src_path) |
| | | |
| | | from protos import aerial_pb2 as pb |
| | | |
| | | |
| | | |
| | | class DustCleanerThread (threading.Thread): |
| | | """ |
| | | dust cleaner threads |
| | | """ |
| | | def __init__(self, cmd_queue, config): |
| | | threading.Thread.__init__(self) |
| | | self.config = config |
| | | self.cmd_queue = cmd_queue |
| | | self.stop = False |
| | | self.cleaner = DustCleaner("com11", 115200, 1) |
| | | self._init_dust_cleaner() |
| | | |
| | | def _init_dust_cleaner(self): |
| | | """init dust cleaner""" |
| | | # send dust cleaner self clean command |
| | | self.cleaner.Send_self_clean_params( |
| | | self.config.clean_self_start_angle, |
| | | self.config.clean_self_end_angle, |
| | | self.config.clean_self_num) |
| | | # send dust cleaner period clean self command |
| | | self.cleaner.Send_period_clean_self(self.config.clean_self_period) |
| | | # send dust cleaner camera clean command |
| | | self.cleaner.Send_camera_clean_params( |
| | | self.config.clean_lens_start_angle, |
| | | self.config.clean_lens_end_angle, |
| | | self.config.clean_lens_num) |
| | | # send dust cleaner period clean camera command |
| | | self.cleaner.Send_period_clean_camera(self.config.clean_lens_period) |
| | | |
| | | def run(self): |
| | | print("DustCleanerThread started") |
| | | while not self.stop: |
| | | # check if there is a command in the queue |
| | | if not self.cmd_queue.empty(): |
| | | cmd = self.cmd_queue.get() |
| | | dust_cleaner_msg = pb.DustCleanerMessage() |
| | | dust_cleaner_msg.ParseFromString(cmd.data1.data) |
| | | if cmd.sub_command == pb.ControlSubCommand.DUST_CLEANER_ONETIME_CLEAN_SELF: |
| | | self.cleaner.Send_onetime_clean_self() |
| | | elif cmd.sub_command == pb.ControlSubCommand.DUST_CLEANER_ONETIME_CLEAN_CAMERA: |
| | | self.cleaner.Send_onetime_clean_camera() |
| | | elif cmd.sub_command == pb.ControlSubCommand.DUST_CLEANER_CLOSE_PERIOD_CLEAN_SELF: |
| | | self.cleaner.Send_close_period_clean_self() |
| | | elif cmd.sub_command == pb.ControlSubCommand.DUST_CLEANER_CLOSE_PERIOD_CLEAN_CAMERA: |
| | | self.cleaner.Send_close_period_clean_camera() |
| | | elif cmd.sub_command == pb.ControlSubCommand.DUST_CLEANER_PERIOD_CLEAN_SELF: |
| | | self.cleaner.Send_close_period_clean_self(dust_cleaner_msg.period) |
| | | elif cmd.sub_command == pb.ControlSubCommand.DUST_CLEANER_PERIOD_CLEAN_CAMERA: |
| | | self.cleaner.Send_period_clean_camera(dust_cleaner_msg.period) |
| | | time.sleep(0.1) |
| | | print("DustCleanerThread stopped") |
| New file |
| | |
| | | import sys # NOQA: E402 |
| | | import os |
| | | import pika |
| | | import threading |
| | | from ctypes import sizeof |
| | | from .DeviceManager import DeviceManager |
| | | |
| | | # add python path of src to sys.path |
| | | src_path = os.path.join(__file__, *(['..'] * 2)) |
| | | src_path = os.path.abspath(src_path) |
| | | sys.path.insert(0, src_path) |
| | | |
| | | from microwave.components import HeaderBlock |
| | | from protos import aerial_pb2 as pb |
| | | |
| | | class MessageQueueThread(threading.Thread): |
| | | def __init__(self, |
| | | host: str, |
| | | user: str, |
| | | password: str, |
| | | queue: str, |
| | | device_manager: DeviceManager): |
| | | threading.Thread.__init__(self) |
| | | self._device_manager = device_manager |
| | | self._def_routes() |
| | | self.message_received: int = 0 |
| | | |
| | | credentials = pika.PlainCredentials(user, password) |
| | | parameters = pika.ConnectionParameters( |
| | | credentials=credentials, host=host) |
| | | connection = pika.BlockingConnection(parameters) |
| | | self._channel = connection.channel() |
| | | self._channel.queue_declare(queue=queue, durable=True) |
| | | self._channel.basic_qos(prefetch_count=1) |
| | | self._channel.basic_consume( |
| | | on_message_callback=self._on_request, queue=queue) |
| | | |
| | | def _def_routes(self): |
| | | self._routes = { |
| | | pb.SysCommand.FIVE_G_COMMAND: self._on_five_g_command, |
| | | pb.SysCommand.MICRO_WAVE_COMMAND: self._on_micro_wave_command, |
| | | } |
| | | |
| | | def _default(self, req: pb.RequestCommand, resp: pb.ResponseCommand): |
| | | print('onknown command') |
| | | |
| | | def _write_image(self, device: dict, idx: int, image: bytes): |
| | | if (image is None) | (len(image) == 0): |
| | | return |
| | | filename = f'{device["path"]}/{idx}-{device["images"]}.jpg' |
| | | with open(filename, 'wb') as f: |
| | | f.write(image) |
| | | f.close() |
| | | |
| | | def _on_five_g_command(self, req: pb.RequestCommand, resp: pb.ResponseCommand): |
| | | # print('five g command') |
| | | if pb.SubCommand.FIVE_G_SEND_IMAGE_SUB_COMMAND == req.sub_command: |
| | | print( |
| | | f'send image sub command received, length={req.data1.length}') |
| | | if req.data1.length > 0: |
| | | device = self._device_manager.get_device(req.device_id) |
| | | img_msg = pb.ImagesMessage() |
| | | img_msg.ParseFromString(req.data1.data) |
| | | # print(img_msg.image1) |
| | | count = device["images"] |
| | | self._write_image(device, 1, img_msg.image1) |
| | | self._write_image(device, 2, img_msg.image2) |
| | | self._write_image(device, 3, img_msg.image3) |
| | | self._write_image(device, 4, img_msg.image4) |
| | | self._write_image(device, 5, img_msg.image5) |
| | | device['images'] += 1 |
| | | |
| | | def _on_micro_wave_command(self, req: pb.RequestCommand, resp: pb.ResponseCommand): |
| | | print('micro wave command') |
| | | if pb.SubCommand.MICRO_WAVE_SUB_COMMAND == req.sub_command: |
| | | print('micro wave sub command received') |
| | | device = self._device_manager.get_device(req.device_id) |
| | | micro_wave_msg = pb.MicroWaveMessage() |
| | | micro_wave_msg.ParseFromString(req.data1.data) |
| | | if (micro_wave_msg.length == len(micro_wave_msg.data)): |
| | | header = HeaderBlock.from_buffer_copy(micro_wave_msg[:sizeof(HeaderBlock)]) |
| | | filename = f'{device["path"]}/{device["micro_wave"]}-{header.FrameNumber}.micro_wave' |
| | | with open(filename, 'wb') as f: |
| | | f.write(micro_wave_msg.data) |
| | | f.close() |
| | | device['micro_wave'] += 1 |
| | | |
| | | def _on_request(self, ch, method, properties, body): |
| | | req = pb.RequestCommand() |
| | | req.ParseFromString(body) |
| | | dispatcher = self._routes.get(req.sys_command, self._default) |
| | | resp = pb.ResponseCommand() |
| | | dispatcher(req, resp) |
| | | resp.checksum = 12345 |
| | | resp.state = pb.ResponseState.SUCCESS |
| | | if properties.reply_to != None: |
| | | ch.basic_publish(exchange='', |
| | | routing_key=properties.reply_to, # 收消息的队列 |
| | | properties=pika.BasicProperties( |
| | | correlation_id=properties.correlation_id), # 返回消息的队列 |
| | | body=resp.SerializeToString()) # 返回结果数据 |
| | | ch.basic_ack(delivery_tag=method.delivery_tag) # 确保消息被 客户端接收 |
| | | self.message_received += 1 |
| | | return |
| | | |
| | | def run(self): |
| | | print(' [*] RabbitMQ Server started. Waiting for messages.') |
| | | self._channel.start_consuming() |
| New file |
| | |
| | | import os, sys |
| | | import threading |
| | | |
| | | # add python path of src to sys.path |
| | | src_path = os.path.join(__file__, *(['..'] * 2)) |
| | | src_path = os.path.abspath(src_path) |
| | | sys.path.insert(0, src_path) |
| | | |
| | | from microwave.servers import MicroWaveUDPServer |
| | | |
| | | |
| | | class MicroWaveUDPThread (threading.Thread): |
| | | def __init__(self, server_address, msg_queue): |
| | | threading.Thread.__init__(self) |
| | | self.udp_server = MicroWaveUDPServer(server_address, msg_queue) |
| | | |
| | | def run(self): |
| | | print("MicroWaveUDPThread started") |
| | | self.udp_server.serve_forever() |
| | | |
| | | def stop(self): |
| | | self.udp_server.server_close() |
| New file |
| | |
| | | from .AcquisitionMain import * |
| | | from .CaptureThread import * |
| | | from .ControllThread import * |
| | | from .DeviceManager import * |
| | | from .DustCleaner import * |
| | | from .DustCleanerThread import * |
| | | from .MessageQueueThread import * |
| | | from .MicroWaveUDPThread import * |
| File was renamed from proto/aerial.proto |
| | |
| | | bytes data = 6; // 数据 |
| | | int32 checksum = 7; // 校验码 |
| | | } |
| | | |
| | | |
| | | // 服务端向采集端发送的主指令 |
| | | enum ControlSysCommand { |
| | | DUST_CLEANER_COMMAND = 0; |
| | | } |
| | | |
| | | // 服务端向采集端发送的子命令 |
| | | enum ControlSubCommand { |
| | | // dust cleaner sub commands |
| | | DUST_CLEANER_ONETIME_CLEAN_SELF = 0; |
| | | DUST_CLEANER_ONETIME_CLEAN_CAMERA = 1; |
| | | DUST_CLEANER_CLOSE_PERIOD_CLEAN_SELF = 2; |
| | | DUST_CLEANER_CLOSE_PERIOD_CLEAN_CAMERA = 3; |
| | | DUST_CLEANER_PERIOD_CLEAN_SELF = 4; |
| | | DUST_CLEANER_PERIOD_CLEAN_CAMERA = 5; |
| | | } |
| | | |
| | | // dust cleaner command message |
| | | message DustCleanerMessage { |
| | | uint32 period = 1; |
| | | } |
| | | |
| | | // 控制上位机消息 |
| | | message ControllMessage { |
| | | int32 sync_word = 1; // 同步字 |
| | | ControlSysCommand sys_command = 3; // 主命令 |
| | | ControlSubCommand sub_command = 4; // 子命令 |
| | | DataField data = 5; // 数据 |
| | | int32 checksum = 7; // 校验码 |
| | | } |
| New file |
| | |
| | | @echo off |
| | | |
| | | @REM change to the filepath |
| | | cd %~dp0 |
| | | echo change to path: %cd% |
| | | |
| | | set protoc=%cd%/../../env/aerial_deploy/Library/bin/protoc.exe |
| | | |
| | | %protoc% aerial.proto --python_out=%cd% |
| | | |
| | | echo compile done! |
| New file |
| | |
| | | name: aerial |
| | | channels: |
| | | - conda-forge |
| | | - defaults |
| | | dependencies: |
| | | - bitarray=2.3.6=py39hb82d6ee_0 |
| | | - bzip2=1.0.8=h8ffe710_4 |
| | | - ca-certificates=2021.10.8=h5b45459_0 |
| | | - click=8.0.3=py39hcbf5309_1 |
| | | - colorama=0.4.4=pyh9f0ad1d_0 |
| | | - flask=2.0.2=pyhd8ed1ab_0 |
| | | - freetype=2.10.4=h546665d_1 |
| | | - fribidi=1.0.10=h8d14728_0 |
| | | - itsdangerous=2.0.1=pyhd8ed1ab_0 |
| | | - jbig=2.1=h8d14728_2003 |
| | | - jinja2=3.0.3=pyhd8ed1ab_0 |
| | | - jpeg=9e=h8ffe710_0 |
| | | - lcms2=2.12=h2a16943_0 |
| | | - lerc=3.0=h0e60522_0 |
| | | - libdeflate=1.8=h8ffe710_0 |
| | | - libffi=3.4.2=h8ffe710_5 |
| | | - libimagequant=2.17.0=hcfcfb64_1 |
| | | - libpng=1.6.37=h1d00b33_2 |
| | | - libprotobuf=3.19.4=h7755175_0 |
| | | - libtiff=4.3.0=hd413186_2 |
| | | - libwebp=1.2.2=h57928b3_0 |
| | | - libwebp-base=1.2.2=h8ffe710_1 |
| | | - libxcb=1.13=hcd874cb_1004 |
| | | - libzlib=1.2.11=h8ffe710_1013 |
| | | - llvm-openmp=12.0.1=h2d74725_1 |
| | | - lz4-c=1.9.3=h8ffe710_1 |
| | | - m2w64-gcc-libgfortran=5.3.0=6 |
| | | - m2w64-gcc-libs=5.3.0=7 |
| | | - m2w64-gcc-libs-core=5.3.0=7 |
| | | - m2w64-gmp=6.1.0=2 |
| | | - m2w64-libwinpthread-git=5.0.0.4634.697f757=2 |
| | | - markupsafe=2.0.1=py39hb82d6ee_1 |
| | | - msys2-conda-epoch=20160418=1 |
| | | - openjpeg=2.4.0=hb211442_1 |
| | | - openssl=3.0.0=h8ffe710_2 |
| | | - pika=1.2.0=pyh44b312d_0 |
| | | - pillow=9.0.1=py39ha53f419_0 |
| | | - pip=22.0.3=pyhd8ed1ab_0 |
| | | - protobuf=3.19.4=py39h415ef7b_0 |
| | | - pthread-stubs=0.4=hcd874cb_1001 |
| | | - python=3.9.10=hcf16a7b_2_cpython |
| | | - python_abi=3.9=2_cp39 |
| | | - setuptools=60.8.1=py39hcbf5309_0 |
| | | - six=1.16.0=pyh6c4a22f_0 |
| | | - sqlite=3.37.0=h8ffe710_0 |
| | | - tk=8.6.11=h8ffe710_1 |
| | | - tzdata=2021e=he74cb21_0 |
| | | - ucrt=10.0.20348.0=h57928b3_0 |
| | | - vc=14.2=hb210afc_6 |
| | | - vs2015_runtime=14.29.30037=h902a5da_6 |
| | | - werkzeug=2.0.3=pyhd8ed1ab_1 |
| | | - wheel=0.37.1=pyhd8ed1ab_0 |
| | | - xorg-libxau=1.0.9=hcd874cb_0 |
| | | - xorg-libxdmcp=1.1.3=hcd874cb_0 |
| | | - xz=5.2.5=h62dcd97_1 |
| | | - zlib=1.2.11=h8ffe710_1013 |
| | | - zstd=1.5.2=h6255e5f_0 |
| | | - pip: |
| | | - anyio==3.5.0 |
| | | - argon2-cffi==21.3.0 |
| | | - argon2-cffi-bindings==21.2.0 |
| | | - asttokens==2.0.5 |
| | | - attrs==21.4.0 |
| | | - babel==2.9.1 |
| | | - backcall==0.2.0 |
| | | - black==22.1.0 |
| | | - bleach==4.1.0 |
| | | - certifi==2021.10.8 |
| | | - cffi==1.15.0 |
| | | - charset-normalizer==2.0.12 |
| | | - debugpy==1.5.1 |
| | | - decorator==5.1.1 |
| | | - defusedxml==0.7.1 |
| | | - deprecation==2.1.0 |
| | | - entrypoints==0.4 |
| | | - executing==0.8.2 |
| | | - future==0.18.2 |
| | | - idna==3.3 |
| | | - ipykernel==6.9.0 |
| | | - ipython==8.0.1 |
| | | - ipython-genutils==0.2.0 |
| | | - ipywidgets==7.6.5 |
| | | - iso8601==1.0.2 |
| | | - jedi==0.18.1 |
| | | - json5==0.9.6 |
| | | - jsonschema==4.4.0 |
| | | - jupyter-client==7.1.2 |
| | | - jupyter-core==4.9.1 |
| | | - jupyter-packaging==0.11.1 |
| | | - jupyter-server==1.13.5 |
| | | - jupyterlab==3.2.9 |
| | | - jupyterlab-pygments==0.1.2 |
| | | - jupyterlab-server==2.10.3 |
| | | - jupyterlab-widgets==1.0.2 |
| | | - matplotlib-inline==0.1.3 |
| | | - mistune==0.8.4 |
| | | - mypy-extensions==0.4.3 |
| | | - nbclassic==0.3.5 |
| | | - nbclient==0.5.10 |
| | | - nbconvert==6.4.2 |
| | | - nbformat==5.1.3 |
| | | - nest-asyncio==1.5.4 |
| | | - notebook==6.4.8 |
| | | - numpy==1.22.2 |
| | | - open3d==0.14.1 |
| | | - opencv-contrib-python==4.5.5.62 |
| | | - packaging==21.3 |
| | | - pandocfilters==1.5.0 |
| | | - parso==0.8.3 |
| | | - pathspec==0.9.0 |
| | | - pickleshare==0.7.5 |
| | | - platformdirs==2.5.0 |
| | | - prometheus-client==0.13.1 |
| | | - prompt-toolkit==3.0.28 |
| | | - pure-eval==0.2.2 |
| | | - pycparser==2.21 |
| | | - pygments==2.11.2 |
| | | - pyparsing==3.0.7 |
| | | - pyrsistent==0.18.1 |
| | | - pyserial==3.5 |
| | | - python-dateutil==2.8.2 |
| | | - pytz==2021.3 |
| | | - pywin32==303 |
| | | - pywinpty==1.1.6 |
| | | - pyyaml==6.0 |
| | | - pyzmq==22.3.0 |
| | | - requests==2.27.1 |
| | | - send2trash==1.8.0 |
| | | - serial==0.0.97 |
| | | - sniffio==1.2.0 |
| | | - stack-data==0.1.4 |
| | | - terminado==0.13.1 |
| | | - testpath==0.5.0 |
| | | - tomli==2.0.1 |
| | | - tomlkit==0.9.2 |
| | | - tornado==6.1 |
| | | - traitlets==5.1.1 |
| | | - typing-extensions==4.1.1 |
| | | - urllib3==1.26.8 |
| | | - wcwidth==0.2.5 |
| | | - webencodings==0.5.1 |
| | | - websocket-client==1.2.3 |
| | | - widgetsnbextension==3.5.2 |
| | | prefix: C:\Users\wuxinjun\miniconda3\envs\aerial |
| New file |
| | |
| | | from .tools import * |
| New file |
| | |
| | | import os |
| | | import sys |
| | | import time |
| | | |
| | | # add python path of src to sys.path |
| | | src_path = os.path.join(__file__, *(['..'] * 2)) |
| | | src_path = os.path.abspath(src_path) |
| | | sys.path.insert(0, src_path) |
| | | |
| | | from microwave.parsers import MicroWaveParser |
| | | from tools import file_fliter |
| | | |
| | | if __name__ == "__main__": |
| | | def help(): |
| | | print("Usage: bin2ply.py [BINfolder]") |
| | | print("EXAMPLE: BIN2ply.py ./manual_ply/pod1-2012-12-12-12-12-12/") |
| | | exit(1) |
| | | |
| | | if len(sys.argv) != 2: |
| | | help() |
| | | try: |
| | | BINfolder = str(sys.argv[1]) |
| | | # example pod1-2022-02-21-13-25-03_packet125.udp --> 125 |
| | | sort_lambda = lambda x:int(x.split('.')[0]) |
| | | bin_files = file_fliter(BINfolder,'bin', sort_lambda) |
| | | |
| | | except Exception as e: |
| | | print(e) |
| | | help() |
| | | |
| | | for file in bin_files: |
| | | |
| | | filename = file |
| | | (fn, ext) = os.path.splitext(filename) |
| | | with open(os.path.join(BINfolder,file), "rb") as bin_file: |
| | | buf = bin_file.read() |
| | | point_cloud = MicroWaveParser.ParserFrame(buf) |
| | | with open(os.path.join(BINfolder,fn +".ply"), "w") as f: |
| | | f.write("ply\n") |
| | | f.write("format ascii 1.0\n") |
| | | f.write("comment MicroWave2Ply generated\n") |
| | | f.write("element vertex %d\n" % len(point_cloud)) |
| | | f.write("property float x\n") |
| | | f.write("property float y\n") |
| | | f.write("property float z\n") |
| | | f.write("element face 0\n") |
| | | f.write("property list uchar int vertex_indices\n") |
| | | f.write("end_header\n") |
| | | n_p = 0 |
| | | for p in point_cloud: |
| | | x, y, z = p |
| | | f.write("{:.5f} {:.5f} {:.5f}\n".format(x, y, z)) |
| | | n_p += 1 |
| | | print(time.asctime(),f"Frame {fn}.ply have been saved with {n_p} points!") |
| New file |
| | |
| | | import open3d as o3d |
| | | import sys |
| | | |
| | | if __name__ == "__main__": |
| | | def help(): |
| | | print("Usage: plot_ply.py [PLYfile]") |
| | | print("EXAMPLE: plot_ply ./Manual_Microwave/pod1-2022-02-21-15-34-45/2522.ply") |
| | | exit(1) |
| | | |
| | | if len(sys.argv) != 2: |
| | | help() |
| | | try: |
| | | PLYfile = str(sys.argv[1]) |
| | | |
| | | pcd = o3d.io.read_point_cloud(PLYfile) |
| | | |
| | | except Exception as e: |
| | | print(e) |
| | | help() |
| | | |
| | | show = [pcd] |
| | | |
| | | o3d.visualization.draw_geometries(show) |
| New file |
| | |
| | | import os, sys |
| | | |
| | | def file_fliter(folder:str, file_ext:str, sort_format): |
| | | |
| | | files_List = os.listdir(folder) |
| | | target_files = [] |
| | | |
| | | # flitered by file extention name |
| | | for file in files_List: |
| | | if file.split('.')[-1] == file_ext: |
| | | target_files.append(file) |
| | | # sort the list by the sort_format |
| | | target_files.sort(key=sort_format) |
| | | |
| | | return target_files |
| | | |
| | | |
| New file |
| | |
| | | import os |
| | | from sys import argv |
| | | import sys |
| | | import time |
| | | |
| | | # add python path of src to sys.path |
| | | src_path = os.path.join(__file__, *(['..'] * 2)) |
| | | src_path = os.path.abspath(src_path) |
| | | sys.path.insert(0, src_path) |
| | | |
| | | from microwave.servers import MicroWaveReceiver |
| | | from tools import file_fliter |
| | | |
| | | |
| | | if __name__ == '__main__': |
| | | |
| | | def help(): |
| | | print("Usage: udp2bin.py [UDPfolder]") |
| | | print("EXAMPLE: udp2bin.py ./manual_ply/pod1-2012-12-12-12-12-12/") |
| | | exit(1) |
| | | |
| | | if len(sys.argv) != 2: |
| | | help() |
| | | try: |
| | | UDPfolder = str(sys.argv[1]) |
| | | # example pod1-2022-02-21-13-25-03_packet125.udp --> 125 |
| | | sort_lambda = lambda x:int(x.split('packet')[1][:-4]) |
| | | udp_files = file_fliter(UDPfolder,'udp', sort_lambda) |
| | | |
| | | except Exception as e: |
| | | print(e) |
| | | help() |
| | | |
| | | receiver = MicroWaveReceiver() |
| | | for file in udp_files: |
| | | filename = os.path.join(UDPfolder, file) |
| | | with open(filename, "rb") as f: |
| | | data = f.read() |
| | | receiver.AddBuf(data) |
| | | if receiver.DataFrameReady: |
| | | frame_number = receiver.Header.FrameNumber |
| | | bin_name = os.path.join(UDPfolder, "{}.bin".format(frame_number)) |
| | | print(time.asctime(),"Frame {} ready".format(frame_number)) |
| | | with open(bin_name, "wb") as bin_file: |
| | | bin_file.write(receiver.DataFrame) |
| | | bin_file.close() |
| New file |
| | |
| | | import datetime |
| | | from pickle import GLOBAL |
| | | from socketserver import BaseRequestHandler, UDPServer |
| | | import time |
| | | import os, sys |
| | | |
| | | |
| | | # cudir,_ = os.path.split(__file__) |
| | | # file_folder = os.path.join(cudir,"saveUDPData") |
| | | |
| | | # if not os.path.exists(file_folder): |
| | | # os.makedirs(file_folder) |
| | | # print(f"make a new folder: {file_folder}") |
| | | |
| | | packed_count = 0 |
| | | |
| | | class PointCloudUDPRequestHandler(BaseRequestHandler): |
| | | |
| | | def handle(self): |
| | | |
| | | global packed_count |
| | | global path |
| | | |
| | | if packed_count == 0: |
| | | start = datetime.datetime.now() |
| | | if not os.path.exists(save_folder): |
| | | os.mkdir(save_folder) |
| | | path = os.path.join(save_folder,f"{device_id}-{start.strftime('%Y-%m-%d-%H-%M-%S')}") |
| | | if not os.path.exists(path): |
| | | os.mkdir(path) |
| | | path = os.path.abspath(path) |
| | | |
| | | print(time.asctime(),' Got connection from {}, {}'.format(self.client_address, packed_count)) |
| | | # Get message and client socket |
| | | msg, sock = self.request |
| | | time_tag = datetime.datetime.now().strftime('%Y-%m-%d-%H-%M-%S') |
| | | f = open('{}/{}_packet{}.udp'.format(path,time_tag,packed_count), 'wb') |
| | | f.write(msg) |
| | | f.close() |
| | | packed_count += 1 |
| | | |
| | | if packed_count >= packet_threshold: |
| | | UDPServer.server_close(server) |
| | | |
| | | |
| | | if __name__ == '__main__': |
| | | |
| | | def help(): |
| | | print("Usage: udp_get.py [MICROWAVEhost] [PACKETthreshold] [DEVICEname] [SAVEfolder]") |
| | | print("EXAMPLE: udp_get.py 192.168.2.65 1000 pod1 ./manual_ply") |
| | | exit(1) |
| | | |
| | | if len(sys.argv) != 5: |
| | | help() |
| | | try: |
| | | MICROWAVEhost = str(sys.argv[1]) |
| | | PACKETthreshold = int(sys.argv[2]) |
| | | DEVICEname = str(sys.argv[3]) |
| | | SAVEfolder = str(sys.argv[4]) |
| | | |
| | | global packet_threshold |
| | | packet_threshold = PACKETthreshold |
| | | global device_id |
| | | device_id = DEVICEname |
| | | global save_folder |
| | | save_folder = SAVEfolder |
| | | |
| | | except Exception as e: |
| | | print(e) |
| | | help() |
| | | |
| | | global server |
| | | |
| | | # host = '' |
| | | # host = '192.168.2.65' # use this host to get the udp data from microwave device |
| | | port = 9911 |
| | | server =UDPServer((MICROWAVEhost, port), PointCloudUDPRequestHandler) |
| | | print(time.asctime(),'Server started on port', port) |
| | | print('....') |
| | | print('ctrl-c to quit server.') |
| | | try: |
| | | server.serve_forever() |
| | | except KeyboardInterrupt: |
| | | server.server_close() |
| | | print(time.asctime(),"Server Stopped") |
| | | except: |
| | | server.server_close() |
| | | print(time.asctime(),"Server Stopped") |
| New file |
| | |
| | | @echo off |
| | | |
| | | @REM change to the filepath |
| | | cd %~dp0 |
| | | echo change to path: %cd% |
| | | |
| | | set aerialpython=%cd%/env/aerial_deploy/python.exe |
| | | set envsetting=%cd%/env/SettingEnv.bat |
| | | |
| | | @REM Setting the env |
| | | if not exist %aerialpython% ( |
| | | call %envsetting% |
| | | ) |
| | | |
| | | set MQhost=172.17.17.206 |
| | | set MQuser=chai |
| | | set MQpassword=password123 |
| | | set QUEUEname=aerial_rpc |
| | | set DEVICEname=pod1 |
| | | set SERVERhost=http://172.17.17.206/api |
| | | set MICROWAVEhost=192.168.2.65 |
| | | set LOGfile=Client.log |
| | | |
| | | @REM Launch the Client |
| | | echo the log file will be saved in the [%LOGfile%] file |
| | | echo Client.py is running ... |
| | | @REM -------- Usage: Client.py [MQhost] [MQuser] [MQpassword] [QUEUEname] [DEVICEname] [SERVERhost] [MICROWAVEhost] |
| | | %aerialpython% ./src/Client.py %MQhost% %MQuser% %MQpassword% %QUEUEname% %DEVICEname% %SERVERhost% %MICROWAVEhost% >> %LOGfile% |
| | | echo Client.py has been terminited. |
| | | pause |
| New file |
| | |
| | | @echo off |
| | | |
| | | @REM change to the filepath |
| | | cd %~dp0 |
| | | echo change to path: %cd% |
| | | |
| | | set aerialpython=%cd%/env/aerial_deploy/python.exe |
| | | set envsetting=%cd%/env/SettingEnv.bat |
| | | |
| | | @REM Setting the env |
| | | if not exist %aerialpython% ( |
| | | call %envsetting% |
| | | ) |
| | | |
| | | set MQhost=172.17.17.206 |
| | | set MQuser=chai |
| | | set MQpassword=password123 |
| | | set QUEUEname=aerial_rpc |
| | | set WEBport=5000 |
| | | set SAVEfolder=./Images |
| | | set LOGfile=Server.log |
| | | |
| | | @REM Launch the Server |
| | | echo the log file will be saved in the [%LOGfile%] file |
| | | echo Server.py is running ... |
| | | @REM -------- Usage: Server.py [MQhost] [MQuser] [MQpassword] [QUEUEname] [WEBport] [SAVEfolder]") |
| | | %aerialpython% ./src/Server.py %MQhost% %MQuser% %MQpassword% %QUEUEname% %WEBport% %SAVEfolder% >> >> %LOGfile% |
| | | echo Server.py has been terminited. |
| | | pause |
| | | |
| New file |
| | |
| | | @echo off |
| | | |
| | | @REM change to the filepath |
| | | cd %~dp0 |
| | | echo change to path: %cd% |
| | | |
| | | set aerialpython=%cd%/env/aerial_deploy/python.exe |
| | | set envsetting=%cd%/env/SettingEnv.bat |
| | | |
| | | @REM Setting the env |
| | | if not exist %aerialpython% ( |
| | | call %envsetting% |
| | | ) |
| | | |
| | | @REM please the folder path of the udp files. |
| | | @REM set UDPfolder=./Manual_Microwave/pod1-2012-12-12-12-12-12/ |
| | | |
| | | @REM ---------------Usage: udp2bin.py [UDPfolder] |
| | | %aerialpython% ./src/utils/udp2bin.py %UDPfolder% |
| | | pause |
| New file |
| | |
| | | @echo off |
| | | |
| | | @REM change to the filepath |
| | | cd %~dp0 |
| | | echo change to path: %cd% |
| | | |
| | | set aerialpython=%cd%/env/aerial_deploy/python.exe |
| | | set envsetting=%cd%/env/SettingEnv.bat |
| | | |
| | | @REM Setting the env |
| | | if not exist %aerialpython% ( |
| | | call %envsetting% |
| | | ) |
| | | |
| | | @REM please the folder path of the udp files. |
| | | @REM set UDPfolder=./Manual_Microwave/pod1-2012-12-12-12-12-12/ |
| | | |
| | | @REM ---------------Usage: udp2bin.py [UDPfolder] |
| | | %aerialpython% ./src/utils/udp2bin.py %UDPfolder% |
| | | @REM ---------------Usage: bin2ply.py [BINfolder] |
| | | %aerialpython% ./src/utils/bin2ply.py %UDPfolder% |
| | | pause |
| New file |
| | |
| | | @echo off |
| | | |
| | | @REM change to the filepath |
| | | cd %~dp0 |
| | | echo change to path: %cd% |
| | | |
| | | set aerialpython=%cd%/env/aerial_deploy/python.exe |
| | | set envsetting=%cd%/env/SettingEnv.bat |
| | | |
| | | @REM Setting the env |
| | | if not exist %aerialpython% ( |
| | | call %envsetting% |
| | | ) |
| | | |
| | | set MICROWAVEhost=192.168.2.65 |
| | | SET PACKETthreshold=1000 |
| | | SET DEVICEname=pod1 |
| | | SET SAVEfolder=./Manual_Microwave |
| | | @REM ---------------Usage: udp_get.py [MICROWAVEhost] [PACKETthreshold] [DEVICEname] [SAVEfolder] |
| | | %aerialpython% ./src/utils/udp_get.py %MICROWAVEhost% %PACKETthreshold% %DEVICEname% %SAVEfolder% |
| | | pause |