diff --git a/.gitignore b/.gitignore index 5d381cc..f94999d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,162 +1,7 @@ -# ---> Python -# Byte-compiled / optimized / DLL files -__pycache__/ -*.py[cod] -*$py.class - -# C extensions -*.so - -# Distribution / packaging -.Python -build/ -develop-eggs/ -dist/ -downloads/ -eggs/ -.eggs/ -lib/ -lib64/ -parts/ -sdist/ -var/ -wheels/ -share/python-wheels/ -*.egg-info/ -.installed.cfg -*.egg -MANIFEST - -# PyInstaller -# Usually these files are written by a python script from a template -# before PyInstaller builds the exe, so as to inject date/other infos into it. -*.manifest -*.spec - -# Installer logs -pip-log.txt -pip-delete-this-directory.txt - -# Unit test / coverage reports -htmlcov/ -.tox/ -.nox/ -.coverage -.coverage.* -.cache -nosetests.xml -coverage.xml -*.cover -*.py,cover -.hypothesis/ -.pytest_cache/ -cover/ - -# Translations -*.mo -*.pot - -# Django stuff: -*.log -local_settings.py -db.sqlite3 -db.sqlite3-journal - -# Flask stuff: -instance/ -.webassets-cache - -# Scrapy stuff: -.scrapy - -# Sphinx documentation -docs/_build/ - -# PyBuilder -.pybuilder/ -target/ - -# Jupyter Notebook -.ipynb_checkpoints - -# IPython -profile_default/ -ipython_config.py - -# pyenv -# For a library or package, you might want to ignore these files since the code is -# intended to run in multiple environments; otherwise, check them in: -# .python-version - -# pipenv -# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. -# However, in case of collaboration, if having platform-specific dependencies or dependencies -# having no cross-platform support, pipenv may install dependencies that don't work, or not -# install all needed dependencies. -#Pipfile.lock - -# poetry -# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. -# This is especially recommended for binary packages to ensure reproducibility, and is more -# commonly ignored for libraries. -# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control -#poetry.lock - -# pdm -# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. -#pdm.lock -# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it -# in version control. -# https://pdm.fming.dev/#use-with-ide -.pdm.toml - -# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm -__pypackages__/ - -# Celery stuff -celerybeat-schedule -celerybeat.pid - -# SageMath parsed files -*.sage.py - -# Environments -.env -.venv -env/ +.idea/ +__pycache__ venv/ -ENV/ -env.bak/ -venv.bak/ - -# Spyder project settings -.spyderproject -.spyproject - -# Rope project settings -.ropeproject - -# mkdocs documentation -/site - -# mypy -.mypy_cache/ -.dmypy.json -dmypy.json - -# Pyre type checker -.pyre/ - -# pytype static type analyzer -.pytype/ - -# Cython debug symbols -cython_debug/ - -# PyCharm -# JetBrains specific template is maintained in a separate JetBrains.gitignore that can -# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore -# and can be added to the global gitignore or merged into this file. For a more nuclear -# option (not recommended) you can uncomment the following to ignore the entire idea folder. -#.idea/ - +code/__pycache__ +code/testbench.py +assets/logs/ +assets/configs/io_device_XBC_* \ No newline at end of file diff --git a/README.md b/README.md index c3a6226..a1ad3e8 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,37 @@ -# APIs +## 一、功能 + +## 三、相关文件以及路径 + +``` +======================================================================== +/home/luoshi/bin/controller/user_settings/ +/home/luoshi/bin/controller/interactive_data/XMC12-R1300-W7G3B1C/ +registers.xml +registers.json +fieldbus_device.json +io_device_XBC_XMATE_ROKAE_RSC_1 +io_device_XBC_XMATE_ROKAE_MINI_1 +io_device_XBC_5_ROKAE_RSC_1 +io_device_XBC_5_ROKAE_MINI_1 +======================================================================== +/home/luoshi/bin/controller/interactive_data/XMC12-R1300-W7G3B1C/ +sys_io_1.cfg +======================================================================== +``` + + + +## 四、寄存器功能码规划 + +- 40000~40499:只读寄存器 +- 40500~40999:只写寄存器 +- 41000~41100:自定义只读寄存器 + + +## 五、待办 + +- [ ] socket 断开后触发软急停,并恢复,目的是让所有运动的指令,停止运行防止意外发生 +- [ ] 外部通信实现 + +## 九、目前存在问题 -根据rokae confluence上的接口规范,实现的自用API接口工具 \ No newline at end of file diff --git a/assets/configs/fieldbus_device.json b/assets/configs/fieldbus_device.json new file mode 100644 index 0000000..e7de260 --- /dev/null +++ b/assets/configs/fieldbus_device.json @@ -0,0 +1,75 @@ +{ + "device_list": [ + { + "enable": true, + "endian": 1, + "extend_attr": { + "RTU": { + "serial_name": "" + }, + "TCP": { + "ip": "0.0.0.0", + "port": 502 + }, + "coils": { + "max_num": 16, + "start_addr": 0 + }, + "discrete_input": { + "max_num": 16, + "start_addr": 0 + }, + "hold_register": { + "max_num": 2000, + "start_addr": 40000 + }, + "input_register": { + "max_num": 2000, + "start_addr": 4000 + }, + "protol_type": "TCP", + "slaver_id": 1 + }, + "mode": "slaver", + "name": "autotest", + "type": "MODBUS" + } + ], + "support_types": [ + { + "device_type": "MODBUS", + "support_mode": { + "master": 10, + "slaver": 10 + } + }, + { + "device_type": "CCLINK", + "support_mode": { + "master": 0, + "slaver": 1 + } + }, + { + "device_type": "ETHERCAT", + "support_mode": { + "master": 0, + "slaver": 10 + } + }, + { + "device_type": "PROFINET", + "support_mode": { + "master": 0, + "slaver": 1 + } + }, + { + "device_type": "EtherNetIP", + "support_mode": { + "master": 0, + "slaver": 1 + } + } + ] +} diff --git a/assets/configs/registers.json b/assets/configs/registers.json new file mode 100644 index 0000000..18e1508 --- /dev/null +++ b/assets/configs/registers.json @@ -0,0 +1,472 @@ +{ + "MODBUS": [ + { + "property": { + "device_name": "autotest", + "endian": 1 + }, + "regs": { + "rd": [ + { + "addr": 40000, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "ctrl_clear_alarm", + "len": 1, + "name": "r_clear_alarm", + "retain": false, + "type": "bool" + }, + { + "addr": 40001, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "ctrl_estop_reset", + "len": 1, + "name": "r_estop_reset", + "retain": false, + "type": "bool" + }, + { + "addr": 40002, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "ctrl_estop_reset_clear_alarm", + "len": 1, + "name": "r_onekey_reset", + "retain": false, + "type": "bool" + }, + { + "addr": 40003, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "ctrl_motor_off", + "len": 1, + "name": "r_motor_off", + "retain": false, + "type": "bool" + }, + { + "addr": 40004, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "ctrl_motor_on", + "len": 1, + "name": "r_motor_on", + "retain": false, + "type": "bool" + }, + { + "addr": 40005, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "ctrl_motoron_pptomain_start", + "len": 1, + "name": "r_onekey_start", + "retain": false, + "type": "bool" + }, + { + "addr": 40006, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "ctrl_motoron_start", + "len": 1, + "name": "r_motoron_start", + "retain": false, + "type": "bool" + }, + { + "addr": 40007, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "ctrl_pause_motoroff", + "len": 1, + "name": "r_pause_motoroff", + "retain": false, + "type": "bool" + }, + { + "addr": 40008, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "ctrl_pptomain", + "len": 1, + "name": "r_pp2main", + "retain": false, + "type": "bool" + }, + { + "addr": 40009, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "ctrl_program_start", + "len": 1, + "name": "r_prog_start", + "retain": false, + "type": "bool" + }, + { + "addr": 40010, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "ctrl_program_stop", + "len": 1, + "name": "r_prog_stop", + "retain": false, + "type": "bool" + }, + { + "addr": 40011, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "ctrl_reduced_mode", + "len": 1, + "name": "r_reduced_mode", + "retain": false, + "type": "bool" + }, + { + "addr": 40012, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "ctrl_soft_estop", + "len": 1, + "name": "r_soft_estop", + "retain": false, + "type": "bool" + }, + { + "addr": 40013, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "ctrl_switch_auto_motoron", + "len": 1, + "name": "r_auto_motoron", + "retain": false, + "type": "bool" + }, + { + "addr": 40014, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "ctrl_switch_operation_auto", + "len": 1, + "name": "r_switch_auto", + "retain": false, + "type": "bool" + }, + { + "addr": 40015, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "ctrl_switch_operation_manu", + "len": 1, + "name": "r_switch_manual", + "retain": false, + "type": "bool" + }, + { + "addr": 40016, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "enable_safe_region01", + "len": 1, + "name": "r_safe_region01", + "retain": false, + "type": "bool" + }, + { + "addr": 40017, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "enable_safe_region02", + "len": 1, + "name": "r_safe_region02", + "retain": false, + "type": "bool" + }, + { + "addr": 40018, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "enable_safe_region03", + "len": 1, + "name": "r_safe_region03", + "retain": false, + "type": "bool" + } + ], + "rdwr": [ + { + "addr": 40500, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "sta_alarm", + "len": 1, + "name": "w_alarm_state", + "retain": false, + "type": "bool" + }, + { + "addr": 40501, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "sta_collision", + "len": 1, + "name": "w_clsn_alarm_stat", + "retain": false, + "type": "bool" + }, + { + "addr": 40502, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "sta_collision_open", + "len": 1, + "name": "w_clsn_open_stat", + "retain": false, + "type": "bool" + }, + { + "addr": 40503, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "sta_controller_is_running", + "len": 1, + "name": "w_controller_running", + "retain": false, + "type": "bool" + }, + { + "addr": 40504, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "sta_encoder_low_battery", + "len": 1, + "name": "w_encoder_low", + "retain": false, + "type": "bool" + }, + { + "addr": 40505, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "sta_estop", + "len": 1, + "name": "w_estop_stat", + "retain": false, + "type": "bool" + }, + { + "addr": 40506, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "sta_motor", + "len": 1, + "name": "w_motor_stat", + "retain": false, + "type": "bool" + }, + { + "addr": 40507, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "sta_operation_mode", + "len": 1, + "name": "w_operation_mode", + "retain": false, + "type": "bool" + }, + { + "addr": 40508, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "sta_program", + "len": 1, + "name": "w_prog_stat", + "retain": false, + "type": "bool" + }, + { + "addr": 40509, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "sta_program_not_run", + "len": 1, + "name": "w_prog_not_run", + "retain": false, + "type": "bool" + }, + { + "addr": 40510, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "sta_program_reset", + "len": 1, + "name": "w_prog_reset", + "retain": false, + "type": "bool" + }, + { + "addr": 40511, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "sta_reduced_mode", + "len": 1, + "name": "w_reduced_mode_stat", + "retain": false, + "type": "bool" + }, + { + "addr": 40512, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "sta_robot_is_busy", + "len": 1, + "name": "w_robot_is_busy", + "retain": false, + "type": "bool" + }, + { + "addr": 40513, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "sta_robot_moving", + "len": 1, + "name": "w_robot_moving", + "retain": false, + "type": "bool" + }, + { + "addr": 40514, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "sta_safe_door", + "len": 1, + "name": "w_safe_door", + "retain": false, + "type": "bool" + }, + { + "addr": 40515, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "sta_safe_region01", + "len": 1, + "name": "w_safe_region01", + "retain": false, + "type": "bool" + }, + { + "addr": 40516, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "sta_safe_region02", + "len": 1, + "name": "w_safe_region02", + "retain": false, + "type": "bool" + }, + { + "addr": 40517, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "sta_safe_region03", + "len": 1, + "name": "w_safe_region03", + "retain": false, + "type": "bool" + }, + { + "addr": 40518, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "sta_soft_estop", + "len": 1, + "name": "w_soft_estop_stat", + "retain": false, + "type": "bool" + } + ] + } + } + ] +} diff --git a/assets/configs/registers.xml b/assets/configs/registers.xml new file mode 100644 index 0000000..106cfc6 --- /dev/null +++ b/assets/configs/registers.xml @@ -0,0 +1,725 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/configs/系统IO功能对照表.xlsx b/assets/configs/系统IO功能对照表.xlsx new file mode 100644 index 0000000..2002b67 Binary files /dev/null and b/assets/configs/系统IO功能对照表.xlsx differ diff --git a/assets/json/collision.get_params.json b/assets/json/collision.get_params.json new file mode 100644 index 0000000..62b0a45 --- /dev/null +++ b/assets/json/collision.get_params.json @@ -0,0 +1,5 @@ +{ + "id": "xxxxxxxxxxx", + "module": "safety", + "command": "collision.get_params" +} \ No newline at end of file diff --git a/assets/json/collision.set_params.json b/assets/json/collision.set_params.json new file mode 100644 index 0000000..3f8b101 --- /dev/null +++ b/assets/json/collision.set_params.json @@ -0,0 +1,13 @@ +{ + "id": "xxxxxxxxxxx", + "module": "safety", + "command": "collision.set_params", + "data": { + "enable": false, + "mode": 0, + "coeff": [0,0,0,0,0,0,0], + "coeff_level": 0, + "action": 1, + "percent": 1 + } +} \ No newline at end of file diff --git a/assets/json/collision.set_state.json b/assets/json/collision.set_state.json new file mode 100644 index 0000000..04bfbb5 --- /dev/null +++ b/assets/json/collision.set_state.json @@ -0,0 +1,7 @@ +{ + "module": "safety", + "command": "collision.set_state", + "data": { + "collision_state": false + } +} \ No newline at end of file diff --git a/assets/json/controller.get_params.json b/assets/json/controller.get_params.json new file mode 100644 index 0000000..92dac53 --- /dev/null +++ b/assets/json/controller.get_params.json @@ -0,0 +1,5 @@ +{ + "id":"xxxxxxxxxxx", + "module":"system", + "command":"controller.get_params" +} \ No newline at end of file diff --git a/assets/json/controller.heart.json b/assets/json/controller.heart.json new file mode 100644 index 0000000..27300d6 --- /dev/null +++ b/assets/json/controller.heart.json @@ -0,0 +1,5 @@ +{ + "id": "xxxxxxxxxxx", + "module": "system", + "command": "controller.heart" +} \ No newline at end of file diff --git a/assets/json/controller.reboot.json b/assets/json/controller.reboot.json new file mode 100644 index 0000000..a0ef6da --- /dev/null +++ b/assets/json/controller.reboot.json @@ -0,0 +1,8 @@ +{ + "id": "xxxxxxxxxxx", + "module": "system", + "command": "controller.reboot", + "data": { + "arg": 6 + } +} \ No newline at end of file diff --git a/assets/json/controller.set_params.json b/assets/json/controller.set_params.json new file mode 100644 index 0000000..3759298 --- /dev/null +++ b/assets/json/controller.set_params.json @@ -0,0 +1,8 @@ +{ + "id": "xxxxxxxxxxx", + "module": "system", + "command": "controller.set_params", + "data": { + "time": "2020-02-28 15:28:30" + } +} \ No newline at end of file diff --git a/assets/json/device.get_params.json b/assets/json/device.get_params.json new file mode 100644 index 0000000..62cd79d --- /dev/null +++ b/assets/json/device.get_params.json @@ -0,0 +1,5 @@ +{ + "id": "xxxxxxxxxxx", + "module": "system", + "command": "device.get_params" +} \ No newline at end of file diff --git a/assets/json/diagnosis.get_params.json b/assets/json/diagnosis.get_params.json new file mode 100644 index 0000000..7e57457 --- /dev/null +++ b/assets/json/diagnosis.get_params.json @@ -0,0 +1,8 @@ +{ + "id": "xxxxxxxxxxx", + "module": "robot", + "command": "diagnosis.get_params", + "data": { + "version": "1.4.1" + } +} \ No newline at end of file diff --git a/assets/json/diagnosis.open.json b/assets/json/diagnosis.open.json new file mode 100644 index 0000000..7fe21c2 --- /dev/null +++ b/assets/json/diagnosis.open.json @@ -0,0 +1,12 @@ +{ + "id": "xxxxxxxxxxx", + "module": "robot", + "command": "diagnosis.open", + "data": { + "open": false, + "display_open": false, + "overrun": false, + "turn_area": false, + "delay_motion": false + } +} \ No newline at end of file diff --git a/assets/json/diagnosis.save.json b/assets/json/diagnosis.save.json new file mode 100644 index 0000000..6564248 --- /dev/null +++ b/assets/json/diagnosis.save.json @@ -0,0 +1,8 @@ +{ + "id": "xxxxxxxxxxx", + "module": "robot", + "command": "diagnosis.save", + "data": { + "save": true + } +} \ No newline at end of file diff --git a/assets/json/diagnosis.set_params.json b/assets/json/diagnosis.set_params.json new file mode 100644 index 0000000..0bb13cc --- /dev/null +++ b/assets/json/diagnosis.set_params.json @@ -0,0 +1,10 @@ +{ + "id": "xxxxxxxxxxx", + "module": "robot", + "command": "diagnosis.set_params", + "data": { + "display_pdo_params": [], + "frequency": 50, + "version": "1.4.1" + } +} \ No newline at end of file diff --git a/assets/json/drag.get_params.json b/assets/json/drag.get_params.json new file mode 100644 index 0000000..9c56d28 --- /dev/null +++ b/assets/json/drag.get_params.json @@ -0,0 +1,5 @@ +{ + "id": "xxxxxxxxxxx", + "module": "dynamic", + "command": "drag.get_params" +} \ No newline at end of file diff --git a/assets/json/drag.set_params.json b/assets/json/drag.set_params.json new file mode 100644 index 0000000..52b0b6f --- /dev/null +++ b/assets/json/drag.set_params.json @@ -0,0 +1,10 @@ +{ + "id": "xxxxxxxxxxx", + "module": "dynamic", + "command": "drag.set_params", + "data": { + "enable": true, + "space": 0, + "type": 0 + } +} \ No newline at end of file diff --git a/assets/json/fieldbus_device.get_params.json b/assets/json/fieldbus_device.get_params.json new file mode 100644 index 0000000..6eca806 --- /dev/null +++ b/assets/json/fieldbus_device.get_params.json @@ -0,0 +1,5 @@ +{ + "id": "xxxxxxxxxxx", + "module": "fieldbus", + "command": "fieldbus_device.get_params" +} \ No newline at end of file diff --git a/assets/json/fieldbus_device.load_cfg.json b/assets/json/fieldbus_device.load_cfg.json new file mode 100644 index 0000000..79e1731 --- /dev/null +++ b/assets/json/fieldbus_device.load_cfg.json @@ -0,0 +1,8 @@ +{ + "id": "xxxxxxxxxxx", + "module": "fieldbus", + "command": "fieldbus_device.load_cfg", + "data": { + "file_name": "fieldbus_device.json" + } +} \ No newline at end of file diff --git a/assets/json/fieldbus_device.set_params.json b/assets/json/fieldbus_device.set_params.json new file mode 100644 index 0000000..d6828f6 --- /dev/null +++ b/assets/json/fieldbus_device.set_params.json @@ -0,0 +1,9 @@ +{ + "id": "xxxxxxxxxxx", + "module": "fieldbus", + "command": "fieldbus_device.set_params", + "data": { + "device_name": "modbus_1", + "enable": true + } +} \ No newline at end of file diff --git a/assets/json/io_device.load_cfg.json b/assets/json/io_device.load_cfg.json new file mode 100644 index 0000000..790f75c --- /dev/null +++ b/assets/json/io_device.load_cfg.json @@ -0,0 +1,5 @@ +{ + "id": "xxxxxxxxxxx", + "module": "io", + "command": "io_device.load_cfg" +} \ No newline at end of file diff --git a/assets/json/jog.get_params.json b/assets/json/jog.get_params.json new file mode 100644 index 0000000..db98a71 --- /dev/null +++ b/assets/json/jog.get_params.json @@ -0,0 +1,5 @@ +{ + "id": "xxxxxxxxxxx", + "module": "motion", + "command": "jog.get_params" +} \ No newline at end of file diff --git a/assets/json/jog.set_params.json b/assets/json/jog.set_params.json new file mode 100644 index 0000000..6c89d14 --- /dev/null +++ b/assets/json/jog.set_params.json @@ -0,0 +1,10 @@ +{ + "id": "xxxxxxxxxxx", + "module": "motion", + "command": "jog.set_params", + "data": { + "step": 1000, + "override": 0.2, + "space": 5 + } +} \ No newline at end of file diff --git a/assets/json/jog.start.json b/assets/json/jog.start.json new file mode 100644 index 0000000..afe54cc --- /dev/null +++ b/assets/json/jog.start.json @@ -0,0 +1,10 @@ +{ + "id": "xxxxxxxxxxx", + "module": "motion", + "command": "jog.start", + "data": { + "index": 0, + "direction": true, + "is_ext": false + } +} \ No newline at end of file diff --git a/assets/json/log_code.data.code_list.json b/assets/json/log_code.data.code_list.json new file mode 100644 index 0000000..c6f1ee2 --- /dev/null +++ b/assets/json/log_code.data.code_list.json @@ -0,0 +1,8 @@ +{ + "id": "log_code.data.code_list", + "s": { + "log_code.data": { + "code_list": [] + } + } +} \ No newline at end of file diff --git a/assets/json/log_code.data.json b/assets/json/log_code.data.json new file mode 100644 index 0000000..021b678 --- /dev/null +++ b/assets/json/log_code.data.json @@ -0,0 +1,5 @@ +{ + "g": { + "log_code.data": "null" + } +} \ No newline at end of file diff --git a/assets/json/modbus.get_params.json b/assets/json/modbus.get_params.json new file mode 100644 index 0000000..8bdde30 --- /dev/null +++ b/assets/json/modbus.get_params.json @@ -0,0 +1,5 @@ +{ + "id": "xxxxxxxxxxx", + "module": "fieldbus", + "command": "modbus.get_params" +} \ No newline at end of file diff --git a/assets/json/modbus.load_cfg.json b/assets/json/modbus.load_cfg.json new file mode 100644 index 0000000..95d5e69 --- /dev/null +++ b/assets/json/modbus.load_cfg.json @@ -0,0 +1,8 @@ +{ + "id": "xxxxxxxxxxx", + "module": "fieldbus", + "command": "modbus.load_cfg", + "data": { + "file" : "registers.json" + } +} \ No newline at end of file diff --git a/assets/json/move.get_joint_pos.json b/assets/json/move.get_joint_pos.json new file mode 100644 index 0000000..9754405 --- /dev/null +++ b/assets/json/move.get_joint_pos.json @@ -0,0 +1,5 @@ +{ + "id": "xxxxxxxxxxx", + "module": "motion", + "command": "move.get_joint_pos" +} \ No newline at end of file diff --git a/assets/json/move.get_monitor_cfg.json b/assets/json/move.get_monitor_cfg.json new file mode 100644 index 0000000..75fb033 --- /dev/null +++ b/assets/json/move.get_monitor_cfg.json @@ -0,0 +1,5 @@ +{ + "id": "xxxxxxxxxxx", + "module": "motion", + "command": "move.get_monitor_cfg" +} \ No newline at end of file diff --git a/assets/json/move.get_params.json b/assets/json/move.get_params.json new file mode 100644 index 0000000..bfe06e2 --- /dev/null +++ b/assets/json/move.get_params.json @@ -0,0 +1,5 @@ +{ + "id": "xxxxxxxxxxx", + "module": "motion", + "command": "move.get_params" +} \ No newline at end of file diff --git a/assets/json/move.get_pos.json b/assets/json/move.get_pos.json new file mode 100644 index 0000000..9124631 --- /dev/null +++ b/assets/json/move.get_pos.json @@ -0,0 +1,5 @@ +{ + "id": "xxxxxxxxxxx", + "module": "motion", + "command": "move.get_pos" +} \ No newline at end of file diff --git a/assets/json/move.get_quickstop_distance.json b/assets/json/move.get_quickstop_distance.json new file mode 100644 index 0000000..ac5f0b2 --- /dev/null +++ b/assets/json/move.get_quickstop_distance.json @@ -0,0 +1,5 @@ +{ + "id": "xxxxxxxxxxx", + "module": "motion", + "command": "move.get_quickstop_distance" +} \ No newline at end of file diff --git a/assets/json/move.get_quickturn_pos.json b/assets/json/move.get_quickturn_pos.json new file mode 100644 index 0000000..74ecae0 --- /dev/null +++ b/assets/json/move.get_quickturn_pos.json @@ -0,0 +1,5 @@ +{ + "id" : "xxxxxxxxx", + "module": "motion", + "command": "move.get_quickturn_pos" +} \ No newline at end of file diff --git a/assets/json/move.quick_turn.json b/assets/json/move.quick_turn.json new file mode 100644 index 0000000..3a72afc --- /dev/null +++ b/assets/json/move.quick_turn.json @@ -0,0 +1,8 @@ +{ + "id": "xxxxxxxxxxx", + "module": "motion", + "command": "move.quick_turn", + "data": { + "name":"home" + } +} \ No newline at end of file diff --git a/assets/json/move.set_monitor_cfg.json b/assets/json/move.set_monitor_cfg.json new file mode 100644 index 0000000..68c3f35 --- /dev/null +++ b/assets/json/move.set_monitor_cfg.json @@ -0,0 +1,8 @@ +{ + "id": "xxxxxxxxxxx", + "module": "motion", + "command": "move.set_monitor_cfg", + "data": { + "ref_coordinate": 1 + } +} \ No newline at end of file diff --git a/assets/json/move.set_params.json b/assets/json/move.set_params.json new file mode 100644 index 0000000..8788a6c --- /dev/null +++ b/assets/json/move.set_params.json @@ -0,0 +1,17 @@ +{ + "id": "xxxxxxxxxxx", + "module": "motion", + "command": "move.set_params", + "data": { + "MOTION": { + "JOINT_MAX_SPEED": [1.0,0.0,0.0,0.0,0.0,0.0], + "JOINT_MAX_ACC": [1.0,0.0,0.0,0.0,0.0,0.0], + "JOINT_MAX_JERK": [1.0,0.0,0.0], + "TCP_MAX_SPEED": 500, + "DEFAULT_ACC_PARAMS": [0.3,1.0], + "VEL_SMOOTH_FACTOR": 3.33, + "ACC_RAMPTIME_JOG": 0.01 + } + } + +} \ No newline at end of file diff --git a/assets/json/move.set_quickstop_distance.json b/assets/json/move.set_quickstop_distance.json new file mode 100644 index 0000000..000d5f5 --- /dev/null +++ b/assets/json/move.set_quickstop_distance.json @@ -0,0 +1,8 @@ +{ + "id": "xxxxxxxxxxx", + "module": "motion", + "command": "move.set_quickstop_distance", + "data":{ + "distance": 2 + } +} \ No newline at end of file diff --git a/assets/json/move.set_quickturn_pos.json b/assets/json/move.set_quickturn_pos.json new file mode 100644 index 0000000..164e442 --- /dev/null +++ b/assets/json/move.set_quickturn_pos.json @@ -0,0 +1,15 @@ +{ + "id" : "xxxxxxxxx", + "module": "motion", + "command": "move.set_quickturn_pos", + "data": { + "enable_home": false, + "enable_drag": false, + "enable_transport": false, + "joint_home": [0.0,0.0,0.0,0.0,0.0,0.0,0.0], + "joint_drag": [0.0,0.0,0.0,0.0,0.0,0.0,0.0], + "joint_transport": [0.0,0.0,0.0,0.0,0.0,0.0,0.0], + "end_posture": 0, + "home_error_range":[0.0,0.0,0.0,0.0,0.0,0.0,0.0] + } +} \ No newline at end of file diff --git a/assets/json/move.stop.json b/assets/json/move.stop.json new file mode 100644 index 0000000..17648f0 --- /dev/null +++ b/assets/json/move.stop.json @@ -0,0 +1,8 @@ +{ + "id": "xxxxxxxxxxx", + "module": "motion", + "command": "move.stop", + "data":{ + "stoptype": 0 + } +} \ No newline at end of file diff --git a/assets/json/overview.get_autoload.json b/assets/json/overview.get_autoload.json new file mode 100644 index 0000000..49e3b79 --- /dev/null +++ b/assets/json/overview.get_autoload.json @@ -0,0 +1,5 @@ +{ + "id": "xxxxxxxxxxx", + "module": "project", + "command": "overview.get_autoload" +} \ No newline at end of file diff --git a/assets/json/overview.get_cur_prj.json b/assets/json/overview.get_cur_prj.json new file mode 100644 index 0000000..8e50c5a --- /dev/null +++ b/assets/json/overview.get_cur_prj.json @@ -0,0 +1,5 @@ +{ + "id": "xxxxxxxxxxx", + "module": "project", + "command": "overview.get_cur_prj" +} \ No newline at end of file diff --git a/assets/json/overview.reload.json b/assets/json/overview.reload.json new file mode 100644 index 0000000..a2485a2 --- /dev/null +++ b/assets/json/overview.reload.json @@ -0,0 +1,9 @@ +{ + "id": "xxxxxxxxxxx", + "module": "project", + "command": "overview.reload", + "data": { + "prj_path": "", + "tasks": [] + } +} \ No newline at end of file diff --git a/assets/json/overview.set_autoload.json b/assets/json/overview.set_autoload.json new file mode 100644 index 0000000..791d4fb --- /dev/null +++ b/assets/json/overview.set_autoload.json @@ -0,0 +1,8 @@ +{ + "id": "xxxxxxxxxxx", + "module": "project", + "command": "overview.set_autoload", + "data": { + "autoload_prj_path": "" + } +} \ No newline at end of file diff --git a/assets/json/register.set_value.json b/assets/json/register.set_value.json new file mode 100644 index 0000000..6b64af3 --- /dev/null +++ b/assets/json/register.set_value.json @@ -0,0 +1,11 @@ +{ + "id": "xxxxxxxxxxx", + "module": "fieldbus", + "command": "register.set_value", + "data": { + "name": "", + "type": "bool", + "bias": 0, + "value": 0 + } +} \ No newline at end of file diff --git a/assets/json/rl_task.pp_to_main.json b/assets/json/rl_task.pp_to_main.json new file mode 100644 index 0000000..3e2247f --- /dev/null +++ b/assets/json/rl_task.pp_to_main.json @@ -0,0 +1,8 @@ +{ + "id": "xxxxxxxxxxx", + "module": "project", + "command": "rl_task.pp_to_main", + "data": { + "tasks": [] + } +} \ No newline at end of file diff --git a/assets/json/rl_task.run.json b/assets/json/rl_task.run.json new file mode 100644 index 0000000..52e89a1 --- /dev/null +++ b/assets/json/rl_task.run.json @@ -0,0 +1,8 @@ +{ + "id": "xxxxxxxxxxx", + "module": "project", + "command": "rl_task.run", + "data": { + "tasks": [] + } +} \ No newline at end of file diff --git a/assets/json/rl_task.set_run_params.json b/assets/json/rl_task.set_run_params.json new file mode 100644 index 0000000..8490383 --- /dev/null +++ b/assets/json/rl_task.set_run_params.json @@ -0,0 +1,9 @@ +{ + "id": "xxxxxxxxxxx", + "module": "project", + "command": "rl_task.set_run_params", + "data": { + "loop_mode": true, + "override": 1.0 + } +} \ No newline at end of file diff --git a/assets/json/rl_task.stop.json b/assets/json/rl_task.stop.json new file mode 100644 index 0000000..03b0f6b --- /dev/null +++ b/assets/json/rl_task.stop.json @@ -0,0 +1,8 @@ +{ + "id": "xxxxxxxxxxx", + "module": "project", + "command": "rl_task.stop", + "data": { + "tasks": [] + } +} \ No newline at end of file diff --git a/assets/json/safety.safety_area.overall_enable.json b/assets/json/safety.safety_area.overall_enable.json new file mode 100644 index 0000000..517e64b --- /dev/null +++ b/assets/json/safety.safety_area.overall_enable.json @@ -0,0 +1,7 @@ +{ + "c": { + "safety.safety_area.overall_enable": { + "enable": true + } + } +} \ No newline at end of file diff --git a/assets/json/safety.safety_area.safety_area_enable.json b/assets/json/safety.safety_area.safety_area_enable.json new file mode 100644 index 0000000..505fe50 --- /dev/null +++ b/assets/json/safety.safety_area.safety_area_enable.json @@ -0,0 +1,8 @@ +{ + "c": { + "safety.safety_area.safety_area_enable": { + "id": 0, + "enable": true + } + } +} \ No newline at end of file diff --git a/assets/json/safety.safety_area.signal_enable.json b/assets/json/safety.safety_area.signal_enable.json new file mode 100644 index 0000000..8a1fbac --- /dev/null +++ b/assets/json/safety.safety_area.signal_enable.json @@ -0,0 +1,7 @@ +{ + "c": { + "safety.safety_area.signal_enable": { + "signal": true + } + } +} \ No newline at end of file diff --git a/assets/json/safety_area_data.json b/assets/json/safety_area_data.json new file mode 100644 index 0000000..e9b982a --- /dev/null +++ b/assets/json/safety_area_data.json @@ -0,0 +1,5 @@ +{ + "g": { + "safety_area_data": null + } +} \ No newline at end of file diff --git a/assets/json/servo.clear_alarm.json b/assets/json/servo.clear_alarm.json new file mode 100644 index 0000000..bc3b7f8 --- /dev/null +++ b/assets/json/servo.clear_alarm.json @@ -0,0 +1,5 @@ +{ + "id": "xxxxxxxxxxx", + "module": "robot", + "command": "servo.clear_alarm" +} \ No newline at end of file diff --git a/assets/json/socket.get_params.json b/assets/json/socket.get_params.json new file mode 100644 index 0000000..2971e6a --- /dev/null +++ b/assets/json/socket.get_params.json @@ -0,0 +1,5 @@ +{ + "id": "xxxxxxxxxxx", + "module": "network", + "command": "socket.get_params" +} \ No newline at end of file diff --git a/assets/json/socket.set_params.json b/assets/json/socket.set_params.json new file mode 100644 index 0000000..9635cae --- /dev/null +++ b/assets/json/socket.set_params.json @@ -0,0 +1,17 @@ +{ + "id": "xxxxxxxxxxx", + "module": "network", + "command": "socket.set_params", + "data": { + "enable": true, + "ip": "", + "name": "c1", + "port": "8080", + "suffix": "\r", + "type": 1, + "reconnect_flag": false, + "auto_connect": true, + "disconnection_triggering_behavior": 0, + "disconnection_detection_time": 10 + } +} \ No newline at end of file diff --git a/assets/json/soft_limit.get_params.json b/assets/json/soft_limit.get_params.json new file mode 100644 index 0000000..6f1f222 --- /dev/null +++ b/assets/json/soft_limit.get_params.json @@ -0,0 +1,5 @@ +{ + "id": "xxxxxxxxxxx", + "module": "safety", + "command": "soft_limit.get_params" +} \ No newline at end of file diff --git a/assets/json/soft_limit.set_params.json b/assets/json/soft_limit.set_params.json new file mode 100644 index 0000000..de23404 --- /dev/null +++ b/assets/json/soft_limit.set_params.json @@ -0,0 +1,13 @@ +{ + "id": "xxxxxxxxxxx", + "module": "safety", + "command": "soft_limit.set_params", + "data": + { + "enable": true + "upper": [0,0,0,0,0,0,0], + "lower": [0,0,0,0,0,0,0], + "reduced_upper": [0,0,0,0,0,0,0], + "reduced_lower": [0,0,0,0,0,0,0] + } +} \ No newline at end of file diff --git a/assets/json/state.get_state.json b/assets/json/state.get_state.json new file mode 100644 index 0000000..1a2b981 --- /dev/null +++ b/assets/json/state.get_state.json @@ -0,0 +1,5 @@ +{ + "id": "xxxxxxxxxxx", + "module": "system", + "command": "state.get_state" +} \ No newline at end of file diff --git a/assets/json/state.get_tp_mode.json b/assets/json/state.get_tp_mode.json new file mode 100644 index 0000000..5b59ed0 --- /dev/null +++ b/assets/json/state.get_tp_mode.json @@ -0,0 +1,5 @@ +{ + "id": "xxxxxxxxxxx", + "module": "system", + "command": "state.get_tp_mode" +} \ No newline at end of file diff --git a/assets/json/state.set_tp_mode.json b/assets/json/state.set_tp_mode.json new file mode 100644 index 0000000..608dd02 --- /dev/null +++ b/assets/json/state.set_tp_mode.json @@ -0,0 +1,8 @@ +{ + "id": "xxxxxxxxxxx", + "module": "system", + "command": "state.set_tp_mode", + "data": { + "tp_mode": "with" + } +} \ No newline at end of file diff --git a/assets/json/state.switch_auto.json b/assets/json/state.switch_auto.json new file mode 100644 index 0000000..0c0a872 --- /dev/null +++ b/assets/json/state.switch_auto.json @@ -0,0 +1,5 @@ +{ + "id": "xxxxxxxxxxx", + "module": "system", + "command": "state.switch_auto" +} \ No newline at end of file diff --git a/assets/json/state.switch_manual.json b/assets/json/state.switch_manual.json new file mode 100644 index 0000000..0451d04 --- /dev/null +++ b/assets/json/state.switch_manual.json @@ -0,0 +1,5 @@ +{ + "id": "xxxxxxxxxxx", + "module": "system", + "command": "state.switch_manual" +} \ No newline at end of file diff --git a/assets/json/state.switch_motor_off.json b/assets/json/state.switch_motor_off.json new file mode 100644 index 0000000..0618931 --- /dev/null +++ b/assets/json/state.switch_motor_off.json @@ -0,0 +1,5 @@ +{ + "id": "xxxxxxxxxxx", + "module": "system", + "command": "state.switch_motor_off" +} \ No newline at end of file diff --git a/assets/json/state.switch_motor_on.json b/assets/json/state.switch_motor_on.json new file mode 100644 index 0000000..0bbcc72 --- /dev/null +++ b/assets/json/state.switch_motor_on.json @@ -0,0 +1,5 @@ +{ + "id": "xxxxxxxxxxx", + "module": "system", + "command": "state.switch_motor_on" +} \ No newline at end of file diff --git a/assets/json/system_io.query_configuration.json b/assets/json/system_io.query_configuration.json new file mode 100644 index 0000000..27d16bd --- /dev/null +++ b/assets/json/system_io.query_configuration.json @@ -0,0 +1,5 @@ +{ + "id": "xxxxxxxxxxx", + "module": "io", + "command": "system_io.query_configuration" +} \ No newline at end of file diff --git a/assets/json/system_io.query_event_cfg.json b/assets/json/system_io.query_event_cfg.json new file mode 100644 index 0000000..5af3217 --- /dev/null +++ b/assets/json/system_io.query_event_cfg.json @@ -0,0 +1,5 @@ +{ + "id": "xxxxxxxxxxx", + "module": "io", + "command": "system_io.query_event_cfg" +} \ No newline at end of file diff --git a/assets/json/system_io.update_configuration.json b/assets/json/system_io.update_configuration.json new file mode 100644 index 0000000..aaeb41f --- /dev/null +++ b/assets/json/system_io.update_configuration.json @@ -0,0 +1,9 @@ +{ + "id": "xxxxxxxxxxx", + "module": "io", + "command": "system_io.update_configuration", + "data": { + "input_system_io": {}, + "output_system_io": {} + } +} \ No newline at end of file diff --git a/code/clibs.py b/code/clibs.py new file mode 100644 index 0000000..8b2d188 --- /dev/null +++ b/code/clibs.py @@ -0,0 +1,46 @@ +from sys import stdout +from os import mkdir, remove, listdir +from os.path import exists +from socket import setdefaulttimeout +from loguru import logger + + +ip_addr = "192.168.2.160" +# ip_addr = "192.168.168.128" +# ip_addr = "192.168.40.130" +ssh_port = 22 +socket_port = 5050 +username = "luoshi" +password = "luoshi2019" # for real robot +# password = "forpqart" # for robot vm +xService_port = 6666 +external_port = 8080 +modbus_port = 502 +interval = 0.5 # interval after actions being triggered, such as modbus/socket/external communication operations +heartbeat_interval = 2 +RADIAN = 57.3 # 180 / 3.1415926 +MAX_FRAME_SIZE = 1024 +TIMEOUT = 3 +setdefaulttimeout(TIMEOUT) +PREFIX = "../assets" +log_path = f"{PREFIX}/logs/" +log_data_debug = f"{PREFIX}/logs/debug.log" + +if not exists(log_path): + mkdir(log_path) +else: + for _ in listdir(log_path): + remove("".join([log_path, _])) +logger.remove() +logger.add(stdout, level="INFO") +logger.add( + sink=log_data_debug, + level="DEBUG", + format="{time: YYYY-MM-DD HH:mm:ss} | {level} | {message}", + rotation="10 KB", + encoding="utf-8", + enqueue=True, + diagnose=True, + colorize=True, + # filter=lambda x: "DEBUG" in str(x["level"]).upper() +) diff --git a/code/common.py b/code/common.py new file mode 100644 index 0000000..5e0837e --- /dev/null +++ b/code/common.py @@ -0,0 +1,100 @@ +import time +import openapi +import json + + +def initialization(): + hr = openapi.HmiRequest() + pd = openapi.PreDos() + # 推送配置文件 + robot_params = hr.get_robot_params() + robot_type = robot_params["robot_type"] + security_type = robot_params["security_type"] + controller_type = robot_params["controller_type"] + io_device_file = "_".join(["io_device", controller_type, security_type, "1"]) + + user_settings = "/home/luoshi/bin/controller/user_settings" + interactive_data = f"/home/luoshi/bin/controller/interactive_data/{robot_type}" + + config_files = [ + "..\\assets\\configs\\fieldbus_device.json", + "..\\assets\\configs\\registers.json", + "..\\assets\\configs\\registers.xml" + ] + for config_file in config_files: + filename = config_file.split("\\")[-1] + pd.push_file_to_server(config_file, f"{user_settings}/{filename}") + pd.push_file_to_server(config_file, f"{interactive_data}/{filename}") + + io_device_autotest = {'ai_num': 0, 'ao_num': 0, 'di_num': 16, 'do_num': 16, 'extend_attr': {'mode': 'slaver', 'name': 'autotest', 'type': 'MODBUS'}, 'id': 5, 'name': 'autotest', 'type': 6} + io_device_file_local = f"..\\assets\\configs\\{io_device_file}" + io_device_file_local_tmp = f"..\\assets\\configs\\{io_device_file}_tmp" + io_device_file_remote = f"{user_settings}/{io_device_file}" + pd.pull_file_from_server(io_device_file_remote, io_device_file_local) + with open(io_device_file_local, mode="r", encoding="utf-8") as f: + data = json.load(f) + for _ in data["device_list"]: + if _["extend_attr"].get("name", None) == "autotest": + break + else: + data["device_list"].append(io_device_autotest) + with open(io_device_file_local_tmp, mode="w", encoding="utf-8") as f_tmp: + json.dump(data, f_tmp, indent=4) + pd.push_file_to_server(io_device_file_local_tmp, f"{user_settings}/{io_device_file}") + pd.push_file_to_server(io_device_file_local_tmp, f"{interactive_data}/{io_device_file}") + + hr.reload_io() + hr.reload_registers() + hr.reload_fieldbus() + hr.set_fieldbus_device_params("autotest", True) + + md = openapi.ModbusRequest() + # 触发急停并恢复 + md.r_soft_estop(0) + md.r_soft_estop(1) + + # 断开示教器连接 + hr.switch_tp_mode("without") + + # 清空 system IO 配置 + hr.update_system_io_configuration([], [], [], [], []) + + # 关闭缩减模式 + md.r_reduced_mode(0) + + # 关闭安全区域 + hr.set_safety_area_overall(False) + hr.set_safety_area_signal(False) + for i in range(10): + hr.set_safety_area_enable(i, False) + + # 打开外部通信 + hr.set_socket_params(True, "", "name", "8080", "\r", 1, True, True, 0, 10) + + # 关闭拖动 + hr.set_drag_params(False, 1, 2) + + # 关闭碰撞检测 + hr.set_collision_params(False, 0, 1, 100) + + # 清除所有错误码 + hr.set_filtered_error_code("clear", []) + + # 回拖动位姿 + hr.switch_operation_mode("manual") + hr.switch_motor_state("on") + hr.set_quickturn_pos(enable_drag=True) + hr.move2quickturn("drag") + while True: + if md.w_robot_moving(): + time.sleep(1) + else: + break + hr.stop_move(1) + hr.switch_motor_state("off") + + # 清除所有告警 + md.r_clear_alarm() + + +initialization() diff --git a/code/openapi.py b/code/openapi.py new file mode 100644 index 0000000..dec4b83 --- /dev/null +++ b/code/openapi.py @@ -0,0 +1,2015 @@ +from json import load, dumps, loads +from os import listdir +from inspect import currentframe +from socket import socket, AF_INET, SOCK_STREAM +from threading import Thread +import selectors +from time import time, sleep +from pymodbus.client.tcp import ModbusTcpClient +# from pymodbus.payload import BinaryPayloadDecoder, BinaryPayloadBuilder +# from pymodbus.constants import Endian +from paramiko import SSHClient, AutoAddPolicy +import clibs + + +class ModbusRequest(object): + def __init__(self): + super().__init__() + self.__c = ModbusTcpClient(host=clibs.ip_addr, port=clibs.modbus_port) + try: + self.__c.connect() + clibs.logger.success("Modbus connection success...") + except Exception as Err: + clibs.logger.error(f"Modbus connection failed...\n{Err}") + + def __reg_high_pulse(self, addr: int) -> None: + self.__c.write_register(addr, 0) + sleep(clibs.interval) + self.__c.write_register(addr, 1) + sleep(clibs.interval+1) + self.__c.write_register(addr, 0) + + def r_clear_alarm(self): # OK + self.__reg_high_pulse(40000) + clibs.logger.info("40000-010 执行清除告警信息") + + def r_reset_estop(self): # OK + self.__reg_high_pulse(40001) + clibs.logger.info("40001-010 执行复位急停状态(非软急停)") + + def r_reset_estop_clear_alarm(self): # NG + clibs.logger.critical("[NG]-40002-010 该指令暂时有问题,运行会导致后台 xCore 崩溃,待修复...") + # self.__reg_high_pulse(40002) + # clibs.logger.info("[NG]-40002-010 执行复位急停状态(非软急停),并清除告警信息") + + def r_motor_off(self): # OK + self.__reg_high_pulse(40003) + clibs.logger.info("40003-010 执行机器人下电") + + def r_motor_on(self): # OK + self.__reg_high_pulse(40004) + clibs.logger.info("40004-010 执行机器人上电") + + def r_motoron_pp2main_start(self): # OK + self.__reg_high_pulse(40005) + clibs.logger.info( + "40005-010 执行机器人上电/pp2main/开始运行程序,需自动模式执行,若运行失败,可清除告警后再次尝试") + + def r_motoron_start(self): # OK + self.__reg_high_pulse(40006) + clibs.logger.info("40006-010 执行机器人上电/开始运行程序,需自动模式执行,若运行失败,可清除告警、执行pp2main后再次尝试") + + def r_pulse_motoroff(self): # OK + self.__reg_high_pulse(40007) + clibs.logger.info("40007-010 执行机器人停止,并下电,手动模式下可停止程序运行,但不能下电,若运行失败,可清除告警后再次尝试") + + def r_pp2main(self): # OK + self.__reg_high_pulse(40008) + clibs.logger.info("40008-010 执行机器人 pp2main,需自动模式执行,若运行失败,可清除告警后再次尝试") + + def r_program_start(self): # OK + self.__reg_high_pulse(40009) + clibs.logger.info("40009-010 执行机器人默认程序运行,需有 pp2main 前置操作,若运行失败,可清除告警后再次尝试") + + def r_program_stop(self): # OK + self.__reg_high_pulse(40010) + clibs.logger.info("40010-010 执行机器人默认程序停止,需有 pp2main 前置操作,若运行失败,可清除告警后再次尝试") + + def r_reduced_mode(self, action: int): # OK + self.__c.write_register(40011, action) + actions = "进入" if action == 1 else "退出" + clibs.logger.info(f"40011-{action} 执行机器人{actions}缩减模式") + sleep(clibs.interval) + + def r_soft_estop(self, action: int): # OK + self.__c.write_register(40012, action) + actions = "解除" if action == 1 else "触发" + clibs.logger.info(f"40012-{action} 执行{actions}急停动作") + sleep(clibs.interval) + + def r_switch_auto_motoron(self): # OK + self.__reg_high_pulse(40013) + clibs.logger.info(f"40013-010 执行切换为自动模式,并上电,初始状态 !!不能是!! 手动上电模式") + + def r_switch_auto(self): # OK + self.__reg_high_pulse(40014) + clibs.logger.info(f"40014-010 执行切换为自动模式") + + def r_switch_manual(self): # OK + self.__reg_high_pulse(40015) + clibs.logger.info(f"40015-010 执行切换为手动模式") + + def r_safe_region01(self, action): # NG + clibs.logger.critical("[NG]-40016-01 该指令暂时有问题,无法实现指定功能,待修复...") + # self.__c.write_register(40016, action) + # actions = "打开" if action == 1 else "关闭" + # clibs.logger.info(f"[NG]-40016-{action} 执行{actions}安全区 safe region 01") + # sleep(clibs.interval) + + def r_safe_region02(self, action): + clibs.logger.critical("[NG]-40017-01 该指令暂时有问题,无法实现指定功能,待修复...") + # self.__c.write_register(40017, action) + # actions = "打开" if action == 1 else "关闭" + # clibs.logger.info(f"[NG]-40017-{action} 执行{actions}安全区 safe region 02") + # sleep(clibs.interval) + + def r_safe_region03(self, action): + clibs.logger.critical("[NG]-40018-01 该指令暂时有问题,无法实现指定功能,待修复...") + # self.__c.write_register(40018, action) + # actions = "打开" if action == 1 else "关闭" + # clibs.logger.info(f"[NG]-40018-{action} 执行{actions}安全区 safe region 03") + # sleep(clibs.interval) + + def w_alarm_state(self): # OK + res = self.__c.read_holding_registers(40500, 1).registers[0] + clibs.logger.info(f"40500 获取告警状态,结果为 {res} :--: 0 表示无告警, 1 表示有告警") + return res + + def w_collision_alarm_state(self): # OK + res = self.__c.read_holding_registers(40501, 1).registers[0] + clibs.logger.info(f"40501 获取碰撞告警状态,结果为 {res} :--: 0 表示未触发 1 表示已触发") + return res + + def w_collision_open_state(self): # OK + res = self.__c.read_holding_registers(40502, 1).registers[0] + clibs.logger.info(f"40502 获取碰撞检测开启状态,结果为 {res} :--: 0 表示关闭 1 表示开启") + return res + + def w_controller_is_running(self): # OK + res = self.__c.read_holding_registers(40503, 1).registers[0] + clibs.logger.info(f"40503 获取控制器运行状态,结果为 {res} :--: 0 表示运行异常 1 表示运行正常") + return res + + def w_encoder_low_battery(self): # OK + res = self.__c.read_holding_registers(40504, 1).registers[0] + clibs.logger.info(f"40504 获取编码器低电压状态,结果为 {res} :--: 0 表示非低电压 1 表示低电压 需关注") + return res + + def w_estop_state(self): # OK + res = self.__c.read_holding_registers(40505, 1).registers[0] + clibs.logger.info(f"40505 获取机器人急停状态(非软急停),结果为 {res} :--: 0 表示未触发 1 表示已触发") + return res + + def w_motor_state(self): # OK + res = self.__c.read_holding_registers(40506, 1).registers[0] + clibs.logger.info(f"40506 获取机器人上电状态,结果为 {res} :--: 0 表示未上电 1 表示已上电") + return res + + def w_operation_mode(self): # OK + res = self.__c.read_holding_registers(40507, 1).registers[0] + clibs.logger.info(f"40507 获取机器人操作模式,结果为 {res} :--: 0 表示手动模式 1 表示自动模式") + return res + + def w_program_state(self): # OK + res = self.__c.read_holding_registers(40508, 1).registers[0] + clibs.logger.info(f"40508 获取程序的运行状态,结果为 {res} :--: 0 表示未运行 1 表示正在运行") + return res + + def w_program_not_run(self): # OK + res = self.__c.read_holding_registers(40509, 1).registers[0] + clibs.logger.info(f"40509 判定程序为未运行状态,结果为 {res} :--: 0 表示正在运行 1 表示未运行") + return res + + def w_program_reset(self): # OK + res = self.__c.read_holding_registers(40510, 1).registers[0] + clibs.logger.info(f"40510 判定程序指针为 pp2main 状态,结果为 {res} :--: 0 表示指针不在 main 函数 1 表示指针在 main 函数") + return res + + def w_reduce_mode_state(self): # OK + res = self.__c.read_holding_registers(40511, 1).registers[0] + clibs.logger.info(f"40511 获取机器人缩减模式状态,结果为 {res} :--: 0 表示非缩减模式 1 表示缩减模式") + return res + + def w_robot_is_busy(self): # OK + res = self.__c.read_holding_registers(40512, 1).registers[0] + clibs.logger.info(f"40512 获取机器人是否处于 busy 状态,结果为 {res} :--: 0 表示未处于 busy 状态 1 表示处于 busy 状态") + return res + + def w_robot_moving(self): # OK + res = self.__c.read_holding_registers(40513, 1).registers[0] + clibs.logger.info(f"40513 获取机器人是否处于运动状态,结果为 {res} :--: 0 表示为运动 1 表示正在运动") + return res + + def w_safe_door_state(self): # OK + res = self.__c.read_holding_registers(40514, 1).registers[0] + clibs.logger.info(f"40514 获取机器人是否处于安全门打开状态,需自动模式下执行,结果为 {res} :--: 0 表示未触发安全门 1 表示已触发安全门") + return res + + def w_safe_region01(self): # NG + clibs.logger.critical(f"40515 获取安全区域 safe region01 功能咱不可用,待修复...") + # res = self.__c.read_holding_registers(40515, 1).registers[0] + # clibs.logger.info(f"40515 获取安全区域 safe region01 是否处于打开状态,结果为 {res}") + # return res + + def w_safe_region02(self): # NG + clibs.logger.critical(f"40516 获取安全区域 safe region02 功能咱不可用,待修复...") + # res = self.__c.read_holding_registers(40516, 1).registers[0] + # clibs.logger.info(f"40516 获取安全区域 safe region02 是否处于打开状态,结果为 {res}") + # return res + + def w_safe_region03(self): # NG + clibs.logger.critical(f"40517 获取安全区域 safe region03 功能咱不可用,待修复...") + # res = self.__c.read_holding_registers(40517, 1).registers[0] + # clibs.logger.info(f"40517 获取安全区域 safe region03 是否处于打开状态,结果为 {res}") + # return res + + def w_soft_estop_state(self): # OK + res = self.__c.read_holding_registers(40518, 1).registers[0] + clibs.logger.info(f"40518 获取机器人软急停状态,结果为 {res} :--: 0 表示未触发软急停 1 表示已触发软急停") + return res + + def io_write_coils(self, addr, action): # OK | 名字叫写线圈,其实是写 modbus 的 discrete inputs(DI) + # e.g. io_write_coils(0, 1) + # e.g. io_write_coils(1, 1) + # e.g. io_write_coils(0, [1, 1, 1]) + self.__c.write_coils(addr, action) + clibs.logger.info(f"Modbus 执行给 DI 地址 {addr} 赋值为 {action},可根据情况传递列表,实现一次性赋值多个") + sleep(clibs.interval) + + def io_read_coils(self): # OK | 读 modbus 的 16 个 discrete inputs(DI) + res = self.__c.read_coils(0, 16).bits + clibs.logger.info(f"Modbus 执行读取所有 DI 的结果为 {res}") + return res + + def io_read_discretes(self): # OK | 读 modbus 的 coil outputs(DO) + res = self.__c.read_discrete_inputs(0, 16).bits + clibs.logger.info(f"Modbus 执行读取所有 DO 的结果为 {res}") + return res + + +class HmiRequest(object): + def __init__(self): + super().__init__() + self.__c = None + self.__c_xs = None + self.c_msg = [] + self.c_msg_xs = [] + self.__flag = 0 + self.__response = "" + self.__leftover = 0 + self.__flag_xs = 0 + self.__response_xs = "" + self.__t_bool = True + self.__pkg_size = 0 + self.__broke = 0 + self.__half = 0 + self.__half_length = 0 + self.__index = 0 + self.__reset_index = 0 + + self.__sock_conn() + self.__t_heartbeat = Thread(target=self.__heartbeat) + self.__t_heartbeat.daemon = True + self.__t_heartbeat.start() + self.__t_unpackage = Thread(target=self.__unpackage, args=(self.__c,)) + self.__t_unpackage.daemon = True + self.__t_unpackage.start() + self.__t_unpackage_xs = Thread(target=self.__unpackage_xs, args=(self.__c_xs,)) + self.__t_unpackage_xs.daemon = True + self.__t_unpackage_xs.start() + + def __sock_conn(self): + try: + self.__c = socket(AF_INET, SOCK_STREAM) + self.__c.connect((clibs.ip_addr, clibs.socket_port)) + self.__c.setblocking(True) + self.__c_xs = socket(AF_INET, SOCK_STREAM) + self.__c_xs.connect((clibs.ip_addr, clibs.xService_port)) + self.__c_xs.setblocking(True) + + # 尝试连续三次发送心跳包,确认建联成功 + for _ in range(3): + self.execution("controller.heart") + sleep(clibs.interval) + + clibs.logger.success("HMI connection success...") + except Exception as Err: + clibs.logger.error(f"HMI connection failed...{Err}") + self.__sth_wrong(9) + + def __sth_wrong(self, ex_code): + self.__t_bool = False + clibs.logger.error(f"[{ex_code}] Something wrong happened!!! " + f"可能是HMI无法连接到 {clibs.ip_addr}:{clibs.socket_port},也可能是其他问题... " + f"确认无问题后,可尝试重新运行!") + exit(ex_code) + + def __header_check(self, index, data): + if index + 8 < len(data): + _frame_size = int.from_bytes(data[index:index + 2], byteorder="big") + _pkg_size = int.from_bytes(data[index + 2:index + 6], byteorder="big") + _protocol = int.from_bytes(data[index + 6:index + 7], byteorder="big") + _reserved = int.from_bytes(data[index + 7:index + 8], byteorder="big") + + if _reserved == 0 and _protocol == 2: + return index + 8, _frame_size, _pkg_size + else: + print(data) + clibs.logger.critical("Header Check: 解包数据有误,需要确认!") + self.__sth_wrong(6) + else: + self.__half_length = len(data) - index + self.__half = data[index:] + self.__broke = 100 + index += clibs.MAX_FRAME_SIZE + return index, 0, 0 + + def __heartbeat(self): + while self.__t_bool: + self.execution("controller.heart") + sleep(clibs.heartbeat_interval) + + @staticmethod + def __gen_id(command): + _now = time() + _id = f"{command}-{_now}" + return _id + + def get_from_id(self, msg_id, flag=0): + def find_response(log_data): + with open(log_data, mode="r", encoding="utf-8") as f_log: + for line in f_log: + if line.split("|")[1].strip() != "DEBUG": + continue + if msg_id in line.strip(): + error_code = int(eval(line.split("|")[-1].strip()).get("error_code", 0)) + if not error_code: + return eval(line.split("|")[-1].strip()) + else: + clibs.logger.error(f"请求 {msg_id} 的返回错误码为 {error_code}") + self.__sth_wrong(7) + + if flag == 0: + for _ in range(3): + res = find_response(clibs.log_data_debug) + if res is not None: + return res["data"] + sleep(clibs.interval) + else: # 尝试在上一次分割的日志中查找,只做一次 + res = find_response("".join([clibs.log_path, listdir(clibs.log_path)[0]])) + if res is not None: + return res["data"] + elif flag == 1: + sleep(1) + with open(clibs.log_data_debug, mode="r", encoding="utf-8") as f_log: + for line in reversed(f_log.readlines()): + if line.split("|")[1].strip() != "DEBUG": + continue + if msg_id in line.strip(): + return eval(line.split("|")[-1].strip()) + else: + with open("".join([clibs.log_path, listdir(clibs.log_path)[0]]), mode="r", encoding="utf-8") as f_log: + for line in reversed(f_log.readlines()): + if line.split("|")[1].strip() != "DEBUG": + continue + if msg_id in line.strip(): + return eval(line.split("|")[-1].strip()) + else: + clibs.logger.error(f"无法找到 xService 请求 {msg_id} 的返回结果") + self.__sth_wrong(11) + + def __msg_storage(self, response, flag=0): + # response是解码后的字符串 + clibs.logger.debug(f"{loads(response)}") + messages = self.c_msg if flag == 0 else self.c_msg_xs + if "move.monitor" in response: + pass + elif len(messages) < 10000: + messages.insert(0, response) + else: + messages.insert(0, response) + while len(messages) >= 10000: + messages.pop() + + def __get_response(self, data): + _frame_size = 0 + # 流式获取单次请求的响应 + if self.__broke == 100: + _half_1 = self.__half + _half_2 = data[:8 - self.__half_length] + _full = _half_1 + _half_2 + + _frame_size = int.from_bytes(_full[:2], byteorder="big") + _pkg_size = int.from_bytes(_full[2:6], byteorder="big") + _protocol = int.from_bytes(_full[6:7], byteorder="big") + _reserved = int.from_bytes(_full[7:8], byteorder="big") + if _reserved != 0 or _protocol != 2: + print(data) + clibs.logger.critical("in get_response: 解包数据有误,需要确认!") + self.__sth_wrong(10) + + self.__pkg_size = _pkg_size + self.__index = 8 - self.__half_length + else: + if self.__reset_index == 1: + self.__index = 0 + + while self.__index < len(data): + # flag 为 0,则说明是一次新的请求对应的一次新的相应,也就是需要首次解包 + if self.__flag == 0: + if self.__broke == 100: + self.__broke = 0 + else: + self.__index, _frame_size, self.__pkg_size = self.__header_check(self.__index, data) + if self.__index > clibs.MAX_FRAME_SIZE: + break + # 详见解包原理数据.txt,self.__pkg_size 永远是除了当前data之外剩余未处理的数据大小 + if self.__pkg_size <= len(data) - self.__index: + # 说明剩余部分的数据就在当前data内,没有被分割 + self.__response = data[self.__index:self.__index + self.__pkg_size].decode() + self.__msg_storage(flag=0, response=self.__response) + self.__index += self.__pkg_size + self.__flag = 0 + self.__response = "" + self.__leftover = 0 + self.__pkg_size = 0 + self.__reset_index = 0 if self.__index < len(data) else 1 + elif self.__pkg_size > len(data) - self.__index: + # 执行到这里说明该data是首包,且有有分包的情况发生了也就是该响应数据量稍微比较大 + # 分散在了相邻的两个及以上的data中,需要flag=1的处理 + self.__flag = 1 + if self.__index + _frame_size - 6 <= len(data): + self.__response = data[self.__index:self.__index + _frame_size - 6].decode() + self.__index += (_frame_size - 6) + self.__pkg_size -= (_frame_size - 6) # 详见解包原理数据.txt,self.__pkg_size + self.__reset_index = 0 + + if self.__index + 2 < len(data): + self.__leftover = int.from_bytes(data[self.__index:self.__index + 2], byteorder="big") + self.__index += 2 + self.__reset_index = 0 + else: + if self.__index + 2 == len(data): + self.__broke = 1 + self.__half = data[-2:] + elif self.__index + 1 == len(data): + self.__broke = 2 + self.__half = data[-1:] + elif self.__index == len(data): + self.__broke = 3 + + self.__index += clibs.MAX_FRAME_SIZE + self.__reset_index = 1 + break # 因为 index + 2 的大小超过 clibs.MAX_FRAME_SIZE + + elif self.__index + _frame_size - 6 > len(data): + self.__response = data[self.__index:].decode() + self.__pkg_size -= (len(data) - self.__index) # 详见解包原理数据.txt,self.__pkg_size + self.__leftover = (_frame_size - 6 - (len(data) - self.__index)) + self.__index += clibs.MAX_FRAME_SIZE + self.__reset_index = 1 + + elif self.__flag == 1: + # 继续处理之前为接收完的数据,处理完之后将flag重置为0 + # !!!需要注意的是,包头/帧头也是有可能被分割开的!!!但是目前该程序未实现此种情况!!! + if self.__broke == 1: + self.__index = 0 + self.__leftover = int.from_bytes(self.__half, byteorder="big") + self.__broke = 0 + elif self.__broke == 2: + self.__leftover = int.from_bytes(self.__half + data[:1], byteorder="big") + self.__index = 1 + self.__broke = 0 + if self.__broke == 3: + self.__leftover = int.from_bytes(data[:2], byteorder="big") + self.__index = 2 + self.__broke = 0 + while self.__pkg_size > 0: + if self.__index + self.__leftover <= len(data): + self.__response += data[self.__index:self.__index + self.__leftover].decode() + self.__pkg_size -= self.__leftover + if self.__pkg_size == 0: + self.__msg_storage(flag=0, response=self.__response) + self.__index += self.__leftover + self.__flag = 0 + self.__response = "" + self.__leftover = 0 + self.__pkg_size = 0 + self.__reset_index = 0 if self.__index < len(data) else 1 + break + + self.__index += self.__leftover + if self.__index + 2 < len(data): + self.__leftover = int.from_bytes(data[self.__index:self.__index + 2], byteorder="big") + self.__index += 2 + self.__reset_index = 0 + else: + if self.__index + 2 == len(data): + self.__broke = 1 + self.__half = data[-2:] + elif self.__index + 1 == len(data): + self.__broke = 2 + self.__half = data[-1:] + elif self.__index == len(data): + self.__broke = 3 + + self.__index += clibs.MAX_FRAME_SIZE + self.__reset_index = 1 + break # 因为 index + 2 的大小超过 clibs.MAX_FRAME_SIZE + else: + self.__response += data[self.__index:].decode() + self.__leftover -= (len(data) - self.__index) + self.__pkg_size -= (len(data) - self.__index) + self.__index += clibs.MAX_FRAME_SIZE + self.__reset_index = 1 + break # 该data内数据已经处理完毕,需要跳出大循环,通过break和index + + def __get_response_xs(self, data): + char, response = "", self.__response_xs + for char in data.decode(): + if char != "\r": + response += char + else: + self.__msg_storage(flag=1, response=response) + response = "" + else: + self.__response_xs = response if char != "\r" else "" + + @staticmethod + def __package(cmd): + _frame_head = (len(cmd) + 6).to_bytes(length=2, byteorder="big") + _pkg_head = len(cmd).to_bytes(length=4, byteorder="big") + _protocol = int(2).to_bytes(length=1, byteorder="big") + _reserved = int(0).to_bytes(length=1, byteorder="big") + return _frame_head + _pkg_head + _protocol + _reserved + cmd.encode() + + @staticmethod + def __package_xs(cmd): + return f"{dumps(cmd, separators=(",", ":"))}\r".encode() + + def __unpackage(self, sock): + def to_read(conn, mask): + data = conn.recv(clibs.MAX_FRAME_SIZE) + if data: + # print(data) + self.__get_response(data) + else: + print("closing", conn) + sel.unregister(conn) + conn.close() + + try: + sel = selectors.DefaultSelector() + sel.register(sock, selectors.EVENT_READ, to_read) + + while self.__t_bool: + events = sel.select() + for key, mask in events: + callback = key.data + callback(key.fileobj, mask) + except Exception as Err: + clibs.logger.error(Err) + self.__sth_wrong(3) + + def __unpackage_xs(self, sock): + def to_read(conn, mask): + data = conn.recv(1024) # Should be ready + if data: + # print(data) + self.__get_response_xs(data) + else: + print("closing", conn) + sel.unregister(conn) + conn.close() + + try: + sel = selectors.DefaultSelector() + sel.register(sock, selectors.EVENT_READ, to_read) + + while self.__t_bool: + events = sel.select() + for key, mask in events: + callback = key.data + callback(key.fileobj, mask) + except Exception as Err: + clibs.logger.error(Err) + self.__sth_wrong(8) + + def execution(self, command, protocol_flag=0, **kwargs): + if protocol_flag == 0: # for old protocols + req = None + try: + with open(f"{clibs.PREFIX}/json/{command}.json", encoding="utf-8", mode="r") as f_json: + req = load(f_json) + except Exception as Err: + clibs.logger.info(f"暂不支持 {command} 功能,或确认该功能存在...\n{Err}") + self.__sth_wrong(5) + + match command: + case "state.set_tp_mode": + req["data"]["tp_mode"] = kwargs["tp_mode"] + case "overview.set_autoload": + req["data"]["autoload_prj_path"] = kwargs["autoload_prj_path"] + case "overview.reload": + req["data"]["prj_path"] = kwargs["prj_path"] + req["data"]["tasks"] = kwargs["tasks"] + case "rl_task.pp_to_main" | "rl_task.run" | "rl_task.stop": + req["data"]["tasks"] = kwargs["tasks"] + case "rl_task.set_run_params": + req["data"]["loop_mode"] = kwargs["loop_mode"] + req["data"]["override"] = kwargs["override"] + case "diagnosis.set_params": + req["data"]["display_pdo_params"] = kwargs["display_pdo_params"] + req["data"]["frequency"] = kwargs["frequency"] + req["data"]["version"] = kwargs["version"] + case "diagnosis.open": + req["data"]["open"] = kwargs["open"] + req["data"]["display_open"] = kwargs["display_open"] + req["data"]["overrun"] = kwargs["overrun"] + req["data"]["turn_area"] = kwargs["turn_area"] + req["data"]["delay_motion"] = kwargs["delay_motion"] + case "register.set_value": + req["data"]["name"] = kwargs["name"] + req["data"]["type"] = kwargs["type"] + req["data"]["bias"] = kwargs["bias"] + req["data"]["value"] = kwargs["value"] + case "diagnosis.save": + req["data"]["save"] = kwargs["save"] + case "socket.set_params": + req["data"]["enable"] = kwargs["enable"] + req["data"]["ip"] = kwargs["ip"] + req["data"]["name"] = kwargs["name"] + req["data"]["port"] = kwargs["port"] + req["data"]["suffix"] = kwargs["suffix"] + req["data"]["type"] = kwargs["type"] + req["data"]["reconnect_flag"] = kwargs["reconnect_flag"] + req["data"]["disconnection_triggering_behavior"] = kwargs["disconnection_triggering_behavior"] + req["data"]["disconnection_detection_time"] = kwargs["disconnection_detection_time"] + case "fieldbus_device.set_params": + req["data"]["device_name"] = kwargs["device_name"] + req["data"]["enable"] = kwargs["enable"] + case "soft_limit.set_params": + req["data"]["enable"] = kwargs["enable"] + req["data"]["upper"] = kwargs["upper"] + req["data"]["lower"] = kwargs["lower"] + req["data"]["reduced_upper"] = kwargs["reduced_upper"] + req["data"]["reduced_lower"] = kwargs["reduced_lower"] + case "move.set_quickturn_pos": + req["data"]["enable_home"] = kwargs["enable_home"] + req["data"]["enable_drag"] = kwargs["enable_drag"] + req["data"]["enable_transport"] = kwargs["enable_transport"] + req["data"]["joint_home"] = kwargs["joint_home"] + req["data"]["joint_drag"] = kwargs["joint_drag"] + req["data"]["joint_transport"] = kwargs["joint_transport"] + req["data"]["end_posture"] = kwargs["end_posture"] + req["data"]["home_error_range"] = kwargs["home_error_range"] + case "move.quick_turn": + req["data"]["name"] = kwargs["name"] + case "move.stop": + req["data"]["stoptype"] = kwargs["stoptype"] + case "jog.start": + req["data"]["index"] = kwargs["index"] + req["data"]["direction"] = kwargs["direction"] + req["data"]["is_ext"] = kwargs["is_ext"] + case "jog.set_params": + req["data"]["step"] = kwargs["step"] + req["data"]["override"] = kwargs["override"] + req["data"]["space"] = kwargs["space"] + case "diagnosis.get_params": + req["data"]["version"] = kwargs["version"] + case "system_io.update_configuration": + req["data"]["input_system_io"] = kwargs["input_system_io"] + req["data"]["output_system_io"] = kwargs["output_system_io"] + case "modbus.set_params": + req["data"]["enable_slave"] = kwargs["enable_slave"] + req["data"]["ip"] = kwargs["ip"] + req["data"]["port"] = kwargs["port"] + req["data"]["slave_id"] = kwargs["slave_id"] + req["data"]["enable_master"] = kwargs["enable_master"] + case "modbus.get_values": + req["data"]["mode"] = kwargs["mode"] + case "move.set_monitor_cfg": + req["data"]["ref_coordinate"] = kwargs["ref_coordinate"] + case "move.set_params": + req["data"]["JOINT_MAX_SPEED"] = kwargs["JOINT_MAX_SPEED"] + req["data"]["JOINT_MAX_ACC"] = kwargs["JOINT_MAX_ACC"] + req["data"]["JOINT_MAX_JERK"] = kwargs["JOINT_MAX_JERK"] + req["data"]["TCP_MAX_SPEED"] = kwargs["TCP_MAX_SPEED"] + req["data"]["DEFAULT_ACC_PARAMS"] = kwargs["DEFAULT_ACC_PARAMS"] + req["data"]["VEL_SMOOTH_FACTOR"] = kwargs["VEL_SMOOTH_FACTOR"] + req["data"]["ACC_RAMPTIME_JOG"] = kwargs["ACC_RAMPTIME_JOG"] + case "move.set_quickstop_distance": + req["data"]["distance"] = kwargs["distance"] + case "collision.set_params": + req["data"]["enable"] = kwargs["enable"] + req["data"]["mode"] = kwargs["mode"] + req["data"]["action"] = kwargs["action"] + req["data"]["percent"] = kwargs["percent"] + req["data"]["coeff"] = kwargs["coeff"] + req["data"]["coeff_level"] = kwargs["coeff_level"] + req["data"]["percent_axis"] = kwargs["percent_axis"] + req["data"]["fallback_distance"] = kwargs["fallback_distance"] + req["data"]["compliance"] = kwargs["compliance"] + req["data"]["reduced_percent"] = kwargs["reduced_percent"] + req["data"]["reduced_percent_axis"] = kwargs["reduced_percent_axis"] + case "collision.set_state": + req["data"]["collision_state"] = kwargs["collision_state"] + case "controller.set_params": + req["data"]["time"] = kwargs["time"] + case "drag.set_params": + req["data"]["enable"] = kwargs["enable"] + req["data"]["space"] = kwargs["space"] + req["data"]["type"] = kwargs["type"] + case _: + pass + + req["id"] = self.__gen_id(command) + cmd = dumps(req, separators=(",", ":")) + try: + self.__c.send(self.__package(cmd)) + sleep(clibs.interval*2) + except Exception as Err: + clibs.logger.error(f"{Err} 请求发送失败:{cmd}") + self.__sth_wrong(4) + return req["id"] + elif protocol_flag == 1: # for xService + req = None + try: + with open(f"{clibs.PREFIX}/json/{command}.json", encoding="utf-8", mode="r") as f_json: + req = load(f_json) + except Exception as Err: + clibs.logger.info(f"暂不支持 {command} 功能,或确认该功能存在...\n{Err}") + self.__sth_wrong(1) + + match command: + case "safety.safety_area.signal_enable": + req["c"]["safety.safety_area.signal_enable"]["signal"] = kwargs["signal"] + case "safety.safety_area.overall_enable": + req["c"]["safety.safety_area.overall_enable"]["enable"] = kwargs["enable"] + case "log_code.data.code_list": + req["s"]["log_code.data"]["code_list"] = kwargs["code_list"] + case "safety.safety_area.safety_area_enable": + req["c"]["safety.safety_area.safety_area_enable"]["id"] = kwargs["id"] + req["c"]["safety.safety_area.safety_area_enable"]["enable"] = kwargs["enable"] + case _: + pass + try: + self.__c_xs.send(self.__package_xs(req)) + sleep(clibs.interval*2) + except Exception as Err: + clibs.logger.error(f"{Err} 请求发送失败:{req}") + self.__sth_wrong(2) + return command + + # =================================== ↓↓↓ specific functions ↓↓↓ =================================== + + def switch_motor_state(self, state: str): + """ + 切换上电/下电的状态 + :param state: on/off + :return: None + """ + match state: + case "on": + self.execution("state.switch_motor_on") + case "off": + self.execution("state.switch_motor_off") + case _: + clibs.logger.error(f"switch_motor_state 参数错误\n{state}: 非法参数,只接受 on/off") + + def switch_operation_mode(self, mode: str): + """ + 切换自动/手动操作模式 + :param mode: auto/manual + :return: None + """ + match mode: + case "auto": + self.execution("state.switch_auto") + case "manual": + self.execution("state.switch_manual") + case _: + clibs.logger.error("switch_operation_mode 参数错误\n非法参数,只接受 auto/manual") + + def reload_project(self, prj_name: str, tasks: list): + """ + 重新加载指定工程 + :param prj_name: 工程名,也即 zip 文件的名字 + :param tasks: 要加载的任务列表 + :return: None + """ + prj_path = f"{prj_name}/_build/{prj_name}.prj" + self.execution("overview.reload", prj_path=prj_path, tasks=tasks) + + def set_project_auto_reload(self, prj_name: str): + """ + 将指定工程设置为开机自动加载,也即默认工程 + :param prj_name: 工程名,也即 zip 文件的名字 + :return: None + """ + autoload_prj_path = f"{prj_name}/_build/{prj_name}.prj" + self.execution("overview.set_autoload", autoload_prj_path=autoload_prj_path) + + def pp_to_main(self, tasks: list): + """ + 将指定的任务列表的指针,指向 main 函数 + :param tasks: 任务列表 + :return: None + """ + self.execution("rl_task.pp_to_main", tasks=tasks) + + def program_start(self, tasks: list): + """ + 开始执行程序任务,必须是自动模式下执行 + :param tasks: 任务列表 + :return: None + """ + self.execution("rl_task.run", tasks=tasks) + + def program_stop(self, tasks: list): + """ + 停止执行程序任务 + :param tasks: 人物列表 + :return: None + """ + self.execution("rl_task.stop", tasks=tasks) + + def set_program_loop_speed(self, loop_mode: bool, override: float): + """ + :param loop_mode: True为循环模式,False为单次模式 + :param override: HMI 左下方的速度滑块,取值范围 [0, 1] + :return: None + """ + self.execution("rl_task.set_run_params", loop_mode=loop_mode, override=override) + + def clear_alarm(self): + """ + 清除伺服告警 + :return: None + """ + self.execution("servo.clear_alarm") + + def reboot_robot(self): + """ + 重启控制器 + :return: None + """ + self.execution("controller.reboot") + + def reload_io(self): + """ + 触发控制器重新加载 IO 设备列表 + :return: None + """ + self.execution("io_device.load_cfg") + + def get_quickturn_pos(self): + """ + 获取机器人的home位姿、拖动位姿和发货位姿,轴关节角度,end_posture 取值如下: + 0 法兰平面与地面平行 + 1 工具坐标系X轴与地面垂直,正向朝下 + 2 工具坐标系X轴与地面垂直,正向朝上 + 3 工具坐标系Y轴与地面垂直,正向朝下 + 4 工具坐标系Y轴与地面垂直,正向朝上 + 5 工具坐标系Z轴与地面垂直,正向朝下 + 6 工具坐标系Z轴与地面垂直,正向朝上 + :return: as below + { + "enable_home": false, + "enable_drag": false, + "enable_transport": false, + "joint_home": [0.0,0.0,0.0,0.0,0.0,0.0,0.0], + "joint_drag": [0.0,0.0,0.0,0.0,0.0,0.0,0.0], + "joint_transport": [0.0,0.0,0.0,0.0,0.0,0.0,0.0], + "end_posture":0, + "home_error_range":[0.0,0.0,0.0,0.0,0.0,0.0,0.0] + } + """ + return self.__get_data(currentframe().f_code.co_name, "move.get_quickturn_pos") + + def set_quickturn_pos(self, enable_home: bool=False, enable_drag: bool=False, enable_transport: bool=False, + joint_home: list=[0.0,0.0,0.0,0.0,0.0,0.0,0.0], joint_drag: list=[0.0,0.0,0.0,0.0,0.0,0.0,0.0], + joint_transport: list=[0.0,0.0,0.0,0.0,0.0,0.0,0.0], end_posture: int=0, + home_error_range: list=[0.0,0.0,0.0,0.0,0.0,0.0,0.0]): + """ + 设置机器人的home位姿、拖动位姿、发货位姿,轴关节角度,Home点误差范围,详见上一个 get_quickturn_pos 功能实现 + :param enable_home: 是否开启 home 点快速调整 + :param enable_drag: 是否开启拖动位姿点快速调整 + :param enable_transport:是否开启发货位姿点快速调整 + :param joint_home: home 位姿的关节角度 + :param joint_drag: 拖动位姿的关节角度 + :param joint_transport: 发货位姿的关节角度 + :param end_posture: 末端姿态的调整方式,取值 0-6,详见 get_quickturn_pos 注释 + :param home_error_range: home点误差范围 + :return: None + """ + self.execution("move.set_quickturn_pos", enable_home=enable_home, enable_drag=enable_drag, enable_transport=enable_transport, joint_home=joint_home, joint_drag=joint_drag, joint_transport=joint_transport, end_posture=end_posture, home_error_range=home_error_range) + + def move2quickturn(self, name: str): + """ + 运动到指定的快速调整位姿 + :param name: 指定快速调整的名称,home/drag/transport + :return: None + """ + self.execution("move.quick_turn", name=name) + + def stop_move(self, stoptype=0): + """ + 停止运动 + TS_READY | TS_JOG | TS_LOADIDENTIFY | TS_DYNAMICIDENTIFY | TS_DRAG | TS_PROGRAM | TS_DEMO | TS_RCI | TS_DEBUG | TS_FRICTIONIDENTIFY + :param stoptype: 对应控制器的任务空间类型TaskSpace的枚举值,0-7 + :return: None + """ + self.execution("move.stop", stoptype=stoptype) + + def get_jog_params(self): + """ + 获取JOG的参数 + 世界坐标系 WORLD_COORDINATE 0 + 法兰盘坐标系 FLANGE_COORDINATE 1 + 基坐标系 BASE_COORDINATE 2 + 工具坐标系 TOOL_COORDINATE 3 + 工件坐标系 FRAME_COORDINATE 4 + 关节空间 JOINT_SPACE 5 + :return: + { + "step": 1000 [1000-连续] [10/1/0.1/0.001-点动] + "override": 0.2 速度比率 + "space": 5 JOG的空间 + } + """ + return self.__get_data(currentframe().f_code.co_name, "jog.get_params") + + def set_jog_params(self, step, override, space): + """ + 设置JOG的参数,包含步长,空间,速度倍率 + :param step: [1000-连续] [10/1/0.1/0.001-点动] + :param override: 速度比率 + :param space: JOG的空间 + :return: None + """ + self.execution("jog.set_params", step=step, override=override, space=space) + + def start_jog(self, index: int, direction: bool=False, is_ext: bool=False): + """ + 开始 JOG 运动 + :param index: 0-6,若选轴空间,则 0-6 对应 1-7 轴,若选笛卡尔空间,则 0-6 对应 xyzabc elb + :param direction: True 正方向,False 反方向 + :param is_ext: 是否是外部轴 jog + :return: None + """ + self.execution("jog.start", index=index, direction=direction, is_ext=is_ext) + + def get_socket_params(self): + """ + 获取socket参数 + :return: + { + "auto_connect": true, + "disconnection_detection_time": 10, + "disconnection_triggering_behavior": 0, + "enable": true, + "ip": "", + "name": "name", + "port": "8080", + "reconnect_flag": true, + "suffix": "\r", + "type": 1 + } + """ + return self.__get_data(currentframe().f_code.co_name, "socket.get_params") + + def set_socket_params(self, enable: bool, ip: str, name: str, port: str, suffix: str, type: int, reconnect_flag: bool, auto_connect: bool, disconnection_triggering_behavior: int, disconnection_detection_time: int): + """ + 设置 socket 参数 + :param enable: True 开启或者 False 关闭 + :param ip: 仅限于客户端,用于指定服务端 IP;当作为服务端时,该参数设置为空字符串,否则会报错!!! + :param name: 连接名字 + :param port: 连接端口 + :param suffix: 指定发送分隔符 + :param type: 0 client | 1 server + :param reconnect_flag: True 自动重连,False 不自动重连 + :param auto_connect: True 开机启动,False 不开机启动 + :param disconnection_triggering_behavior: 断开连接触发行为 0无动作 1暂停程序 2暂停并下电 + :param disconnection_detection_time: 链接断开检测周期(s) + :return: None + """ + self.execution("socket.set_params", enable=enable, ip=ip, name=name, port=port, suffix=suffix, type=type, reconnect_flag=reconnect_flag, auto_connect=auto_connect, disconnection_triggering_behavior=disconnection_triggering_behavior, disconnection_detection_time=disconnection_detection_time) + + def get_diagnosis_params(self, version="1.4.1"): + """ + 获取诊断功能开启状态,以及相应其他信息 + :param version: 指定诊断工具版本 + :return: + { + "state": true, + "display_open": false, + "display_pdo_params": [ + { + "name": "count", + "channel": 0 + }, + { + "name": "servo_error_code", + "channel": 5 + }, + { + "name": "rci_data05", + "channel": 11 + } + ], + "frequency": 50, + "pdo_params": [ + { + "name": "count", + "array": 1 + }, + { + "name": "current_A", + "array": 7 + }, + { + "name": "keypad_status", + "array": 1 + }, + { + "name": "rci_data05", + "array": 12 + } + ], + "overrun": true, + "turn_area": true + } + """ + return self.__get_data(currentframe().f_code.co_name, "diagnosis.get_params", version=version) + + def set_diagnosis_params(self, display_pdo_params: list, frequency: int = 50, version: str = "1.4.1"): + """ + 设置诊断功能显示参数 + :param display_pdo_params: 指定要采集的曲线名称,具体可通过 get_diagnosis_params 函数功能获取所有目前已支持的曲线 + :param frequency: 采样频率,默认 50ms + :param version: xDiagnose的版本号 + :return: None + """ + self.execution("diagnosis.set_params", display_pdo_params=display_pdo_params, frequency=frequency, version=version) + + def open_diagnosis(self, open: bool, display_open: bool, overrun: bool, turn_area: bool, delay_motion: bool): + """ + 打开或者关闭诊断曲线,并定义其他功能的开关(调试相关功能,比如是否开启线程超时监控和上报,转弯区以及运动延迟等) + :param open: 诊断功能 + :param display_open: 诊断显示功能 + :param overrun: 实时线程超时监控上报 + :param turn_area: 转弯区上报 + :param delay_motion: 延迟运动 + :return: None + """ + self.execution("diagnosis.open", open=open, display_open=display_open, overrun=overrun, turn_area=turn_area, delay_motion=delay_motion) + + def save_diagnosis(self, save: bool): + """ + 保存诊断数据 + :param save: 保存数据开关,对应诊断曲线内容的 switch 开关 + :return: None + """ + self.execution("diagnosis.save", save=save) + + def qurry_system_io_configuration(self): + """ + 系统IO配置的查询协议,trigger 参数取值参照如下: + FLANKS 0, //边缘触发 + POS_FLANK 1, //上升沿 + NEG_FLANK 2, //下降沿 + HIGH_LEVEL 3, //高电平 + LOW_LEVEL 4 //低电平 + :return: + { + "input_system_io": { + "motor_on": { + "signal":"DI0_0", + "trigger":1 + }, + "motor_off": { + "signal":"DI0_0", + "trigger":2 + } + }, + "output_system_io": { + "sta_motor_on": { + "signal":"DO0_0" + }, + "sta_robot_running": { + "signal":"DO0_1" + } + } + } + """ + return self.__get_data(currentframe().f_code.co_name, "system_io.query_configuration") + + def qurry_system_io_event_configuration(self): + """ + 查询当前系统支持的系统IO事件列表,包括事件key、名称、支持的触发方式等配置 + :return: + { + "input_system_event": [ + { + "key": "ctrl_motor_on", + "name": "上电", + "trigger_types": [ + 1, + 2 + ] + }, + { + "key": "ctrl_motor_off", + "name": "下电", + "trigger_types": [ + 1, + 2 + ] + } + ], + "output_system_event": [ + { + "key": "sta_motor_on", + "name": "上下电状态" + }, + { + "key": "sta_program", + "name": "运行状态" + } + ], + "input_mutex_event": [ + { + "key0": "ctrl_motor_on", + "key1": "ctrl_motor_off" + }, + { + "key0": "ctrl_switch_auto", + "key1": "ctrl_switch_manu" + } + ] + } + """ + return self.__get_data(currentframe().f_code.co_name, "system_io.query_configuration") + + def update_system_io_configuration(self, i_funcs, o_funcs, i_signals, o_signals, trig_types): + """ + 配置系统 IO + :param i_funcs: 输入,只写功能码列表 + :param o_funcs: 输出,只读功能码列表 + :param i_signals: DI 信号列表 + :param o_signals: DO 信号列表 + :param trig_types: 触发条件列表,可参考 qurry_system_io_configuration 中的触发条件 + :return: None + """ + input_system_io, output_system_io = {}, {} + for i_func in i_funcs: + _index = i_funcs.index(i_func) + input_system_io[i_func] = {"signal": i_signals[_index], "trigger": trig_types[_index]} + for o_func in o_funcs: + _index = o_funcs.index(o_func) + output_system_io[o_func] = {"signal": o_signals[_index]} + self.execution("system_io.update_configuration", input_system_io=input_system_io, output_system_io=output_system_io) + + def get_fieldbus_device_params(self): + """ + 获取设备列表的开关状态 + :return: + { + "device_list": [ + { + "device_name": "modbus_1", + "enable": true + }, { + "device_name": "modbus_2", + "enable": false + } + ] + } + """ + return self.__get_data(currentframe().f_code.co_name, "fieldbus_device.get_params") + + def set_fieldbus_device_params(self, device_name: str, enable: bool): + """ + 定义开关设备的协议,一次只能打开一个设备 + :param device_name: 设备列表中的名称 + :param enable: 是否开启 + :return: None + """ + self.execution("fieldbus_device.set_params", device_name=device_name, enable=enable) + + def reload_fieldbus(self): + """ + 触发控制器重新加载总线设备 + :return: None + """ + self.execution("fieldbus_device.load_cfg") + + def get_modbus_params(self): + """ + 获取modbus参数 + :return: + { + "enable_slave":true, + "ip":"192.168.0.160", + "port":502, + "slave_id":0, + "enable_master":false + } + """ + return self.__get_data(currentframe().f_code.co_name, "modbus.get_params") + + def set_modbus_params(self, enable_slave: bool, ip: str, port: int, slave_id: int, enable_master): + """ + 设置modbus参数 + :param enable_slave: Modbus从站是否自动开启 + :param ip: ip 地址 + :param port: 端口 + :param slave_id: 从站 ID + :param enable_master: Modbus主站是否自动开启 + :return: + """ + self.execution("modbus.set_params", enable_slave=enable_slave, ip=ip, port=port, slave_id=slave_id, enable_master=enable_master) + + def reload_registers(self): + """ + 触发控制器重新加载寄存器列表 + :return: None + """ + self.execution("modbus.load_cfg") + + def get_modbus_values(self, mode): + """ + 用于获取 modbus 寄存器变量值的更新信息,展示在状态监控界面 + :param mode: all/change + :return: + """ + return self.__get_data(currentframe().f_code.co_name, "modbus.get_values", mode=mode) + + def get_soft_limit_params(self): + """ + 获取软限位参数 + :return: + { + "enable":true + "upper":[0,0,0,0,0,0,0], + "lower":[0,0,0,0,0,0,0], + "reduced_upper":[0,0,0,0,0,0,0], + "reduced_lower":[0,0,0,0,0,0,0] + } + """ + return self.__get_data(currentframe().f_code.co_name, "soft_limit.get_params") + + def set_soft_limit_params(self, enable: bool, upper: list, lower: list, reduced_upper: list, reduced_lower: list): + """ + 设定软限位参数 + :param enable: 是否启用软限位 + :param upper: 软限位上限 + :param lower: 软限位下限 + :param reduced_upper: 缩减模式软限位上限 + :param reduced_lower: 缩减模式软限位下限 + :return: None + """ + self.execution("soft_limit.set_params", enable=enable, upper=upper, lower=lower, reduced_upper=reduced_upper, reduced_lower=reduced_lower) + + def get_device_params(self): + """ + 获取设备信息 + :return: + """ + return self.__get_data(currentframe().f_code.co_name, "device.get_params") + + def get_cart_pos(self): + """ + 获取机器人的当前位姿:包括轴关节角度,笛卡尔关节角度,四元数,欧拉角(臂角) + :return: + { + "joint":[0.0,0.0,0.0,0.0,0.0,0.0], + "position":[0.0,0.0,0.0,0.0,0.0,0.0], + "euler":[0.0,0.0,0.0], + "quaternion"[0.0,0.0,0.0,0.0], + "elb":0.0, // 可缺省 + "ext_joint":[0.0,0.0,0.0,0.0,0.0] + } + """ + return self.__get_data(currentframe().f_code.co_name, "move.get_pos") + + def get_joint_pos(self): + """ + 获取机器人的当前关节角度:包括内部轴和外部轴 + :return: + { + "inner_pos": [0,0,0,0,0,0,0], + "extern_pos": [0,0,0,0,0,0,0] + } + """ + return self.__get_data(currentframe().f_code.co_name, "move.get_joint_pos") + + def get_monitor_cfg(self): + """ + 获取机器人的监控配置参数,RefCoordinateType 类型数据,表示当前控制器位置监测的相对坐标系 + 基坐标系 REF_COORDINATE_BASE 0 + 世界坐标系 REF_COORDINATE_WORLD 1 + 工件坐标系 REF_COORDINATE_WOBJ 2 + :return: + { + "ref_coordinate": 0 + } + """ + return self.__get_data(currentframe().f_code.co_name, "move.get_monitor_cfg") + + def set_monitor_cfg(self, ref_coordinate): + """ + 设置机器人的监控配置参数 + :ref_coordinate: RefCoordinateType类型数据,用来设置当前控制器位置监测的相对坐标系 + :return: None + """ + self.execution("move.set_monitor_cfg", ref_coordinate=ref_coordinate) + + def get_move_params(self): + """ + 获取机器人的运动参数:包括减速比、耦合比、最大速度、加速度、加加速度、acc ramp time、规划步长等信息 + :return: + { + "MOTION":{ + "JOINT_MAX_SPEED": [90, 90, 120, 120, 120, 120, 120], + "JOINT_MAX_ACC": [200, 200, 200, 200, 200, 200, 200], + "JOINT_MAX_JERK": [2000, 2000, 2000, 2000, 2000, 2000, 2000], + "TCP_MAX_SPEED": 500, + "TCP_MAX_ACC": 5000, + "TCP_MAX_JERK": 10000, + "TCP_ROTATE_MAX_SPEED": 180, + "TCP_ROTATE_MAX_ACC": 1800, + "TCP_ROTATE_MAX_JERK": 3600, + "JERK_LIMIT_CART": 0, + "JERK_LIMIT_ROT": 0, + "JERK_LIMIT_JOINT": 0, + "MAX_ACC_PARAMS": [1.0, 0.1], + "MIN_ACC_PARAMS": [0.3, 0.5], + "DEFAULT_ACC_PARAMS": [1.0, 0.35], + "VEL_SMOOTH_FACTOR": 3.33, + "VEL_SMOOTH_FACTOR_RANGE": [1.0, 10.0], + "ACC_RAMPTIME_JOG": 0.01 + } + } + """ + return self.__get_data(currentframe().f_code.co_name, "move.get_params") + + def set_move_params(self, JOINT_MAX_SPEED, JOINT_MAX_ACC, JOINT_MAX_JERK, TCP_MAX_SPEED, DEFAULT_ACC_PARAMS, VEL_SMOOTH_FACTOR, ACC_RAMPTIME_JOG): + """ + 设置机器人的运动参数:轴最大速度、轴最大加加速度、速度、加加速度、加速度、加加速度、acc ramp time、规划步长等信息 + :param JOINT_MAX_SPEED: + :param JOINT_MAX_ACC: + :param JOINT_MAX_JERK: + :param TCP_MAX_SPEED: + :param DEFAULT_ACC_PARAMS: + :param VEL_SMOOTH_FACTOR: + :param ACC_RAMPTIME_JOG: + :return: + """ + self.execution("move.set_params", JOINT_MAX_SPEED=JOINT_MAX_SPEED, JOINT_MAX_ACC=JOINT_MAX_ACC, JOINT_MAX_JERK=JOINT_MAX_JERK, TCP_MAX_SPEED=TCP_MAX_SPEED, DEFAULT_ACC_PARAMS=DEFAULT_ACC_PARAMS, VEL_SMOOTH_FACTOR=VEL_SMOOTH_FACTOR, ACC_RAMPTIME_JOG=ACC_RAMPTIME_JOG) + + def get_quick_stop_distance(self): + """ + 获取机器人 search 指令最大停止距离 + :return: + { + "distance":2.0 + } + """ + return self.__get_data(currentframe().f_code.co_name, "move.get_quickstop_distance") + + def set_quick_stop_distance(self, distance): + """ + 设置机器人 search 指令最大停止距离 + :param distance: 停止距离,单位 mm + :return: None + """ + self.execution("move.set_quickstop_distance", distance=distance) + + def get_collision_params(self): + """ + 获取碰撞检测相关参数 + :return: + { + "action": 1, // 触发行为 - 1 安全停止 2 暂停停止 3 柔顺停止 + "coeff": [100, 100, 100, 100, 100, 100], + "coeff_level": 0, + "compliance": 0, + "enable": true, + "fallback_distance": 3, + "mode": 0, + "percent": 100, + "percent_axis": [100, 100, 100, 100, 100, 100], + "reduced_percent": 100, + "reduced_percent_axis": [100, 100, 100, 100, 100, 100] + } + """ + return self.__get_data(currentframe().f_code.co_name, "collision.get_params") + + def set_collision_params(self, enable, mode, action, percent, coeff=0, coeff_level=0, + percent_axis=[100, 100, 100, 100, 100, 100], fallback_distance=5, compliance=0, + reduced_percent=100, reduced_percent_axis=[100, 100, 100, 100, 100, 100]): + """ + 设置碰撞检测相关参数 + :param enable: 功能使能开关 + :param mode: 力传感器系数,0 整机 1 单轴 + :param coeff: 0-整机灵敏度百分比,1-使用单轴灵敏度百分比,2-使用单轴和整机灵敏度百分比 + :param coeff_level: 灵敏度等级:0-低,1-中,2-高 + :param action: 触发行为:1-安全停止;2-触发暂停;3-柔顺停止; + :param percent: 0-200,整机灵敏度百分比 + :param percent_axis: 0-200,单轴灵敏度百分比 + :param fallback_distance: 回退距离 + :param compliance: 柔顺功能比例系数,[0-1] + :param reduced_percent: 0-200,整机缩减模式灵敏度百分比 + :param reduced_percent_axis: 0-200,单轴缩减模式灵敏度百分比 + :return: + """ + self.execution("collision.set_params", enable=enable, mode=mode, action=action, percent=percent, coeff=coeff, coeff_level=coeff_level, percent_axis=percent_axis, fallback_distance=fallback_distance, compliance=compliance, reduced_percent=reduced_percent, reduced_percent_axis=reduced_percent_axis) + + def set_collision_state(self, collision_state: bool): + """ + 开启或者关闭碰撞检测,测试该函数功能无效!!! + :param collision_state: 碰撞检测的开关状态 + :return: None + """ + self.execution("collision.set_state", collision_state=collision_state) + + def get_robot_state(self): + """ + { + "rc_state":"normal", # "fatal" 、"error"、"block"、"normal" + "engine":"on", # "fatal" 、"error"、"GStop"、"EStop"、"on"、"off" + "servo_mode":"position", # "torque"、"position" + "operate": "auto", # "auto"、"manual" + "task_space": "program", # "jog"、"drag"、"ready"、"load_identify"、"demo"、"rci"、"dynamic_identify"、"program"、"debug" + "robot_action": "idle", # "idle"、"busy" + "safety_mode": "collision" # "normal"、"collision"、"collaboration" + } + """ + return self.__get_data(currentframe().f_code.co_name, "state.get_state") + + def set_controller_params(self, robot_time: str): + """ + 设置控制器系统时间 + :param robot_time: 系统时间,"2020-02-28 15:28:30" + :return: None + """ + self.execution("controller.set_params", time=robot_time) + + def get_robot_params(self): + """ + "alias": "", + "auth_state": + "controller_type": "XBC_XMATE", + "controller_types": ["XBC_3", "XBC_5", "XBC_XMATE"], + "disk_serial_number": "2338020401535", + "mac_addr": "34:df:20:03:1b:45", + "model":, + "nic_list": ["enp1s0", "enp2s0"], + "occupied_addr": "192.168.2.123:49269", + "period": 0.002, + "period_types": [0.001, 0.002, 0.003, 0.004], + "robot_template": 10, + "robot_type": "XMC12-R1300-W7G3B1C", + "robot_types": ["XMC12-R1300-B7S3B0C", "XMC12-R1300-W7G3B1C", "XMC17_5-R1900-W7G3B1C", "XMC20-R1650-B7G3Z0C"], + "security_type": "ROKAE_RSC", + "security_types": ["ROKAE_MINI", "ROKAE_RSC"], + "time": "2024-09-13 12:36:38", + "version": "2.3.0.4" + """ + return self.__get_data(currentframe().f_code.co_name, "controller.get_params") + + def switch_tp_mode(self, mode: str): + """ + 切换示教器模式 + :param mode: with/without + :return: None + """ + match mode: + case "with": + self.execution("state.set_tp_mode", tp_mode="with") + case "without": + self.execution("state.set_tp_mode", tp_mode="without") + case _: + clibs.logger.error("switch_tp_mode 参数错误\n非法参数,只接受 with/without") + + def get_tp_mode(self): + """ + 获取示教器连接状态 + :return: + { + "tp_mode":"with" + } + """ + return self.__get_data(currentframe().f_code.co_name, "state.get_tp_mode") + + def get_drag_params(self): + """ + 获取拖动模式参数 + :return: + { + "enable": true, + "space": 0, + "type": 0 + } + """ + return self.__get_data(currentframe().f_code.co_name, "drag.get_params") + + def set_drag_params(self, enable: bool, space: int, type: int): + """ + 设置拖动模式开关以及参数 + :param enable: 是否启用拖动 + :param space: 拖动空间 - 0 代表关节 1 代表笛卡尔 + :param type: 拖动类型 - 0 只平移 1 只旋转 2 自由拖动 + :return: None + """ + self.execution("drag.set_params", enable=enable, space=space, type=type) + + def set_safety_area_signal(self, signal: bool): + """ + 设置安全区域信号控制使能开关 + :param signal: True 打开 False 关闭 + :return: None + """ + self.execution("safety.safety_area.signal_enable", protocol_flag=1, signal=signal) + + def set_safety_area_overall(self, enable: bool): + """ + 设置安全区域整体控制使能开关 + :param enable: True 打开 False 关闭 + :return: None + """ + self.execution("safety.safety_area.overall_enable", protocol_flag=1, enable=enable) + + def get_safety_area_params(self): + """ + 获取安全区所有的配置信息 + :return: + "g": { + "safety_area_data": { + "overall_enable": true, + "safety_area_setting": [ + { + "box": { + "Lx": 100.0, + "Ly": 100.0, + "Lz": 100.0, + "direction": false, + "ori": { + "euler": { + "a": 179.9963851353547, + "b": -0.006653792532429416, + "c": 179.9934560302729 + }, + "quaternion": { + "q1": 0.0, + "q2": 0.0, + "q3": 0.0, + "q4": 0.0 + } + }, + "pos": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + } + }, + "enable": false, + "id": 0, + "name": "region1", + "plane": { + "direction": true, + "point": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "vector": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + } + }, + "shape": 0, + "shared_bind_di": "", + "shared_bind_do": "", + "sphere": { + "ori": { + "euler": { + "a": 0.0, + "b": 0.0, + "c": 0.0 + }, + "quaternion": { + "q1": 0.0, + "q2": 0.0, + "q3": 0.0, + "q4": 0.0 + } + }, + "pos": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "radius": 0.0 + }, + "state": true, + "trigger": 0, + "type": 0, + "vertebral": { + "high": 0.0, + "ori": { + "euler": { + "a": 0.0, + "b": 0.0, + "c": 0.0 + }, + "quaternion": { + "q1": 0.0, + "q2": 0.0, + "q3": 0.0, + "q4": 0.0 + } + }, + "pos": { + "x": 0.0, + "y": 0.0, + "z": 0.0 + }, + "radius": 0.0 + } + }, + ... // 剩余 9 个安全区域的配置信息 + ], + "signal_enable": true + } + } + } + """ + return self.__get_data(currentframe().f_code.co_name, "safety_area_data", flag=1) + + def set_safety_area_enable(self, id: int, enable: bool, **kwargs): + """ + 设置每个安全区域的开关 + :param id: 安全区域开关,0-9 + :param enable: True 打开,False 关闭 + :return: None + """ + self.execution("safety.safety_area.safety_area_enable", protocol_flag=1, id=id, enable=enable, **kwargs) + + def get_filtered_error_code(self): + """ + 获取已设定的错误码过滤列表 + :return: + { + "g": { + "log_code.data": { + "code_list": [ + { + "id": 100, + "title": "DEMO\\u610f\\u5916\\u505c\\u6b62" + }, + { + "id": 10000, + "title": "HMI\\u8bf7\\u6c42\\u5305\\u89e3\\u6790\\u9519\\u8bef" + }, + { + "id": 10002, + "title": "\\u5feb\\u901f\\u8c03\\u6574\\u542f\\u52a8\\u5931\\u8d25" + } + ], + "version": 1 + } + } + } + """ + return self.__get_data(currentframe().f_code.co_name, "log_code.data", flag=1) + + def set_filtered_error_code(self, action: str, code_list: list): + origin_code_list = self.get_filtered_error_code()["g"]["log_code.data"]["code_list"] + # [{'id': 10000, 'title': 'HMI请求包解析错误'}, {'id': 10002, 'title': '快速调整启动失败'}] + if action == "clear": + code_list = [] + elif action == "add": + for error_code in code_list: + for item in origin_code_list: + if error_code == item["id"]: + break + else: + origin_code_list.append({"id": error_code, "title": ""}) + code_list = origin_code_list + elif action == "remove": + for error_code in code_list: + for item in origin_code_list: + if error_code == item["id"]: + origin_code_list.remove(item) + code_list = origin_code_list + + self.execution("log_code.data.code_list", protocol_flag=1, code_list=code_list) + + @staticmethod + def __cannot_find_response(func_name, req_id): + # 无法获取响应信息时,记录错误信息,并退出 + clibs.logger.error(f"[{func_name}] 无法找到 {req_id} 的响应信息,执行失败,退出...") + exit() + + def __get_data(self, upper_func, command, flag=0, **kwargs): + r_id = self.execution(command, protocol_flag=flag, **kwargs) + res = self.get_from_id(r_id, flag=flag) + if res is not None: + return res + else: + self.__cannot_find_response(upper_func, r_id) + # =================================== ↑↑↑ specific functions ↑↑↑ =================================== + + +class ExternalCommunication(object): + def __init__(self): + self.__c = None + self.suffix = "\r" + + def socket_client(self): + self.__c = socket(AF_INET, SOCK_STREAM) + try: + self.__c.connect((clibs.ip_addr, clibs.socket_port)) + clibs.logger.success(f"外部通信连接成功...") + return self.__c + except Exception as Err: + clibs.logger.error(f"外部通信连接失败...\n{Err}") + + def s_string(self, directive): + order = "".join([directive, self.suffix]) + self.__c.send(order.encode()) + sleep(clibs.interval) + + def r_string(self): + result, char = "", "" + while char != self.suffix: + char = self.__c.recv(1).decode(encoding="unicode_escape") + result = "".join([result, char]) + sleep(clibs.interval) + return result + + # =================================== ↓↓↓ specific functions ↓↓↓ =================================== + def motor_on(self): + return self.__exec_cmd("motor_on", "电机上电") + + def motor_off(self): + return self.__exec_cmd("motor_off", "电机下电") + + def pp_to_main(self): + return self.__exec_cmd("pp_to_main", "程序指针到") + + def program_start(self): + return self.__exec_cmd("start", "程序启动") + + def program_stop(self): + return self.__exec_cmd("stop", "程序停止") + + def clear_alarm(self): + return self.__exec_cmd("clear_alarm", "清除伺服报警") + + def switch_operation_auto(self): + return self.__exec_cmd("switch_mode:auto", "切换到自动模式") + + def switch_operation_manual(self): + return self.__exec_cmd("switch_mode:manual", "切换到手动模式") + + def open_drag_mode(self): + return self.__exec_cmd("open_drag", "打开拖动") + + def close_drag_mode(self): + return self.__exec_cmd("close_drag", "关闭拖动") + + def get_program_list(self): + return self.__exec_cmd("list_prog", "获取工程列表") + + def get_current_program(self): + return self.__exec_cmd("current_prog", "当前工程") + + def load_program(self, program_name): + return self.__exec_cmd(f"load_prog:{program_name}", "加载工程") + + def estop_reset(self): + return self.__exec_cmd("estop_reset", "急停复位") + + def estopreset_and_clearalarm(self): + return self.__exec_cmd("estopreset_and_clearalarm", "急停复位并清除报警") + + def motoron_pp2main_start(self): + return self.__exec_cmd("motoron_pptomain_start", "依次执行上电,程序指针到main,启动程序") + + def motoron_start(self): + return self.__exec_cmd("motoron_start", "依次执行上电,启动程序") + + def pause_motoroff(self): + return self.__exec_cmd("pause_motoroff", "暂停程序并下电") + + def set_program_speed(self, speed): + return self.__exec_cmd(f"set_program_speed:{speed}", "设置程序运行速率") + + def trigger_soft_estop(self): + return self.__exec_cmd("soft_estop", "触发机器人软急停") + + def switch_auto_motoron(self): + return self.__exec_cmd("switch_auto_motoron", "切换自动模式并上电") + + def open_safe_region(self, number): + return self.__exec_cmd(f"open_safe_region:{number}", f"打开第 {number} 个安全区域") + + def close_safe_region(self, number): + return self.__exec_cmd(f"close_safe_region:{number}", f"打开第 {number} 个安全区域") + + def open_reduced_mode(self): + return self.__exec_cmd("open_reduced_mode", "开启缩减模式") + + def close_reduced_mode(self): + return self.__exec_cmd("close_reduced_mode", "关闭缩减模式") + + def setDO_value(self, DO, value): + return self.__exec_cmd(f"setdo:{DO}, {value}", f"设置 {DO} 的值为 {value}") + + def modify_system_time(self, robot_time): + return self.__exec_cmd(f"set_robot_time:{robot_time}", f"修改控制器和示教器的时间为 {robot_time}") + + # -------------------------------------------------------------------------------------------------- + def motor_on_state(self): + return self.__exec_cmd("motor_on_state", "电机上电状态") + + def robot_running_state(self): + return self.__exec_cmd("robot_running_state", "程序运行状态") + + def estop_state(self): + return self.__exec_cmd("estop_state", "急停状态") + + def operation_mode(self): + return self.__exec_cmd("operating_mode", "工作模式") + + def home_state(self): + return self.__exec_cmd("home_state", "HOME 输出状态") + + def fault_state(self): + return self.__exec_cmd("fault_state", "故障状态") + + def collision_state(self): + return self.__exec_cmd("collision_state", "碰撞检测状态") + + def task_state(self): + return self.__exec_cmd("collision_state", "获取机器人运行任务状态") + + def get_cart_pos(self): # TBD + return self.__exec_cmd("cart_pos/cart_pos_name", "获取笛卡尔位置") + + def get_joint_pos(self): # TBD + return self.__exec_cmd("jnt_pos/jnt_pos_name", "获取轴位置") + + def get_axis_vel(self): # TBD + return self.__exec_cmd("jnt_vel/jnt_vel_name", "获取轴速度") + + def get_axis_trq(self): # TBD + return self.__exec_cmd("jnt_trq/jnt_trq_name", "获取轴力矩") + + def reduced_mode_state(self): + return self.__exec_cmd("reduced_mode_state", "获取缩减模式状态") + + def get_io_state(self, io_list): + return self.__exec_cmd(f"io_state:{io_list}", "获取 IO 状态") + + def alarm_state(self): + return self.__exec_cmd("alarm_state", "获取报警状态") + + def collision_alarm_state(self): + return self.__exec_cmd("collision_alarm_state", "获取碰撞检测报警状态") + + def collision_open_state(self): + return self.__exec_cmd("collision_open_state", "获取碰撞检测开启状态") + + def controller_is_running(self): + return self.__exec_cmd("controller_is_running", "判断控制器是否开机") + + def encoder_low_battery_state(self): + return self.__exec_cmd("encoder_low_battery_state", "编码器低电压报警状态") + + def robot_error_code(self): + return self.__exec_cmd("robot_error_code", "获取机器人错误码") + + def get_rl_pause_state(self): + return self.__exec_cmd("program_full", "获取 RL 的暂停状态") + + def program_reset_state(self): + return self.__exec_cmd("program_reset_state", "获取程序复位状态") + + def program_speed(self): + return self.__exec_cmd("program_speed", "获取程序运行速度") + + def robot_is_busy(self): + return self.__exec_cmd("robot_is_busy", "获取程序忙碌状态") + + def robot_is_moving(self): + return self.__exec_cmd("robot_is_moving", "获取程序运行状态") + + def safe_door_state(self): + return self.__exec_cmd("safe_door_state", "获取安全门状态") + + def soft_estop_state(self): + return self.__exec_cmd("soft_estop_state", "获取软急停状态") + + def get_cart_vel(self): + return self.__exec_cmd("cart_vel", "获取笛卡尔速度") + + def get_tcp_pos(self): + return self.__exec_cmd("tcp_pos", "获取 TCP 位姿") + + def get_tcp_vel(self): + return self.__exec_cmd("tcp_vel", "获取 TCP 速度") + + def get_tcp_vel_mag(self): + return self.__exec_cmd("tcp_vel_mag", "获取 TCP 合成线速度") + + def ext_estop_state(self): + return self.__exec_cmd("ext_estop_state", "获取外部轴急停状态") + + def hand_estop_state(self): + return self.__exec_cmd("hand_estop_state", "获取手持急停状态") + + def collaboration_state(self): # TBD + return self.__exec_cmd("collaboration_state", "获取协作模式状态") + + def __exec_cmd(self, directive, description): + self.s_string(directive) + result = self.r_string() + clibs.logger.info(f"外部通信:执行{description} {directive} 指令,返回值为 {result}") + return result + + +class PreDos(object): + def __init__(self): + self.__ssh = None + self.__sftp = None + + def __ssh2server(self): + try: + self.__ssh = SSHClient() + self.__ssh.set_missing_host_key_policy(AutoAddPolicy()) + self.__ssh.connect(clibs.ip_addr, clibs.ssh_port, username=clibs.username, password=clibs.password) + self.__sftp = self.__ssh.open_sftp() + except Exception as Err: + clibs.logger.error(f"SSH 无法连接到 {clibs.ip_addr}:{clibs.ssh_port},需检查网络连通性或者登录信息是否正确。\n{Err}") + exit(110) + + def push_prj_to_server(self, prj_file): + # prj_file:本地工程完整路径 + self.__ssh2server() + prj_name = prj_file.split("\\")[-1].split("/")[-1].split(".")[0] + self.__sftp.put(prj_file, f"/tmp/{prj_name}.zip") + cmd = f"cd /tmp; mkdir {prj_name}; unzip -d {prj_name} -q {prj_name}.zip; rm -rf /tmp/{prj_name}.zip; " + cmd += f"sudo rm -rf /home/luoshi/bin/controller/projects/{prj_name}; " + cmd += f"sudo mv /tmp/{prj_name}/ /home/luoshi/bin/controller/projects/" + stdin, stdout, stderr = self.__ssh.exec_command(cmd, get_pty=True) + stdin.write(clibs.password + "\n") + stdout.read().decode() # 需要read一下才能正常执行 + stderr.read().decode() + self.__ssh.close() + + def pull_prj_from_server(self, prj_name, local_prj_path): # NG | 可以拉取文件,但是导入之后,有问题 + # prj_name:要拉取的服务端工程名 + # local_prj_path:本地工程文件的完整路径 + self.__ssh2server() + cmd = f"cd /tmp/; sudo rm -rf {prj_name}*; sudo cp -rf /home/luoshi/bin/controller/projects/{prj_name} .; " + cmd += f"sudo zip -q -r {prj_name}.zip {prj_name}/; sudo rm -rf {prj_name}" + stdin, stdout, stderr = self.__ssh.exec_command(cmd, get_pty=True) + stdin.write(clibs.password + "\n") + print(stdout.read().decode()) # 需要read一下才能正常执行 + print(stderr.read().decode()) + + self.__sftp.get(f"/tmp/{prj_name}.zip", local_prj_path) + cmd = f"sudo rm -rf /tmp/{prj_name}.zip" + stdin, stdout, stderr = self.__ssh.exec_command(cmd, get_pty=True) + stdin.write(clibs.password + "\n") + print(stdout.read().decode()) # 需要read一下才能正常执行 + print(stderr.read().decode()) + + self.__ssh.close() + + def push_file_to_server(self, local_file, server_file): + # local_file:本地文件完整路径 + # server_file:服务端文件完整路径 + self.__ssh2server() + filename = local_file.split("\\")[-1].split("/")[-1] + self.__sftp.put(local_file, f"/tmp/{filename}") + cmd = f"sudo mv /tmp/{filename} {server_file}" + stdin, stdout, stderr = self.__ssh.exec_command(cmd, get_pty=True) + stdin.write(clibs.password + "\n") + stdout.read().decode() # 需要read一下才能正常执行 + stderr.read().decode() + self.__ssh.close() + + def pull_file_from_server(self, server_file, local_file): + # local_file:本地文件完整路径 + # server_file:服务端文件完整路径 + self.__ssh2server() + cmd = f"sudo cp {server_file} /tmp/" + stdin, stdout, stderr = self.__ssh.exec_command(cmd, get_pty=True) + stdin.write(clibs.password + "\n") + stdout.read().decode() # 需要read一下才能正常执行 + stderr.read().decode() + filename = server_file.split("/")[-1] + self.__sftp.get(f"/tmp/{filename}", f"{local_file}") + cmd = f"sudo rm -rf /tmp/{filename}" + stdin, stdout, stderr = self.__ssh.exec_command(cmd, get_pty=True) + stdin.write(clibs.password + "\n") + stdout.read().decode() # 需要read一下才能正常执行 + stderr.read().decode() + self.__ssh.close()