├── .gitignore ├── .readthedocs.yaml ├── LICENSE ├── Pipfile ├── Pipfile.lock ├── README.md ├── __init__.py ├── docs ├── .gitignore ├── Makefile ├── api.rst ├── conf.py ├── index.rst ├── make.bat ├── requirements.in ├── requirements.txt └── usage.rst ├── pyRobotiqGripper.py ├── pyproject.toml ├── requirements.txt └── setup.py /.gitignore: -------------------------------------------------------------------------------- 1 | venv 2 | __pycache__ 3 | pyRobotiqGripper.egg-info/ 4 | dist/ -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | # .readthedocs.yaml 2 | # Read the Docs configuration file 3 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 4 | 5 | # Required 6 | version: 2 7 | 8 | # Set the OS, Python version and other tools you might need 9 | build: 10 | os: ubuntu-22.04 11 | tools: 12 | python: "3.12" 13 | # You can also specify other tool versions: 14 | # nodejs: "19" 15 | # rust: "1.64" 16 | # golang: "1.19" 17 | 18 | # Build documentation in the "docs/" directory with Sphinx 19 | sphinx: 20 | configuration: docs/conf.py 21 | 22 | # Optionally build your docs in additional formats such as PDF and ePub 23 | # formats: 24 | # - pdf 25 | # - epub 26 | 27 | # Optional but recommended, declare the Python requirements required 28 | # to build your documentation 29 | # See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html 30 | python: 31 | install: 32 | - requirements: docs/requirements.txt -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) [2024] [Benoit CASTETS] 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /Pipfile: -------------------------------------------------------------------------------- 1 | [[source]] 2 | url = "https://pypi.org/simple" 3 | verify_ssl = true 4 | name = "pypi" 5 | 6 | [packages] 7 | requests = "*" 8 | 9 | [dev-packages] 10 | 11 | [requires] 12 | python_version = "3.12" 13 | -------------------------------------------------------------------------------- /Pipfile.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "hash": { 4 | "sha256": "1977acb1ba9778abb66054090e2618a0a1f1759b1b3b32afd8a7d404ba18b4fb" 5 | }, 6 | "pipfile-spec": 6, 7 | "requires": { 8 | "python_version": "3.12" 9 | }, 10 | "sources": [ 11 | { 12 | "name": "pypi", 13 | "url": "https://pypi.org/simple", 14 | "verify_ssl": true 15 | } 16 | ] 17 | }, 18 | "default": { 19 | "certifi": { 20 | "hashes": [ 21 | "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f", 22 | "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1" 23 | ], 24 | "markers": "python_version >= '3.6'", 25 | "version": "==2024.2.2" 26 | }, 27 | "charset-normalizer": { 28 | "hashes": [ 29 | "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027", 30 | "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087", 31 | "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786", 32 | "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8", 33 | "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09", 34 | "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185", 35 | "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574", 36 | "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e", 37 | "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519", 38 | "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898", 39 | "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269", 40 | "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3", 41 | "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f", 42 | "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6", 43 | "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8", 44 | "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a", 45 | "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73", 46 | "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc", 47 | "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714", 48 | "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2", 49 | "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc", 50 | "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce", 51 | "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d", 52 | "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e", 53 | "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6", 54 | "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269", 55 | "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96", 56 | "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d", 57 | "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a", 58 | "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4", 59 | "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77", 60 | "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d", 61 | "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0", 62 | "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed", 63 | "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068", 64 | "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac", 65 | "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25", 66 | "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8", 67 | "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab", 68 | "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26", 69 | "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2", 70 | "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db", 71 | "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f", 72 | "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5", 73 | "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99", 74 | "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c", 75 | "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d", 76 | "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811", 77 | "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa", 78 | "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a", 79 | "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03", 80 | "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b", 81 | "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04", 82 | "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c", 83 | "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001", 84 | "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458", 85 | "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389", 86 | "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99", 87 | "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985", 88 | "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537", 89 | "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238", 90 | "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f", 91 | "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d", 92 | "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796", 93 | "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a", 94 | "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143", 95 | "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8", 96 | "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c", 97 | "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5", 98 | "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5", 99 | "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711", 100 | "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4", 101 | "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6", 102 | "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c", 103 | "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7", 104 | "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4", 105 | "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b", 106 | "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae", 107 | "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12", 108 | "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c", 109 | "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae", 110 | "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8", 111 | "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887", 112 | "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b", 113 | "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4", 114 | "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f", 115 | "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5", 116 | "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33", 117 | "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519", 118 | "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561" 119 | ], 120 | "markers": "python_full_version >= '3.7.0'", 121 | "version": "==3.3.2" 122 | }, 123 | "idna": { 124 | "hashes": [ 125 | "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc", 126 | "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0" 127 | ], 128 | "markers": "python_version >= '3.5'", 129 | "version": "==3.7" 130 | }, 131 | "requests": { 132 | "hashes": [ 133 | "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f", 134 | "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1" 135 | ], 136 | "index": "pypi", 137 | "markers": "python_version >= '3.7'", 138 | "version": "==2.31.0" 139 | }, 140 | "urllib3": { 141 | "hashes": [ 142 | "sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d", 143 | "sha256:d0570876c61ab9e520d776c38acbbb5b05a776d3f9ff98a5c8fd5162a444cf19" 144 | ], 145 | "markers": "python_version >= '3.8'", 146 | "version": "==2.2.1" 147 | } 148 | }, 149 | "develop": {} 150 | } 151 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | pyRobotiqGripper 2 | ================= 3 | 4 | Python Driver for Robotiq Grippers via Modbus RTU 5 | 6 | pyRobotiqGripper is a Python library designed to facilitate control of Robotiq grippers using Modbus RTU communication via serial port. 7 | It is compatible with 2F85, 2F140, and Hande. 8 | 9 | Documentation: `pyRobotiqGripper Documentation `_ 10 | 11 | Disclaimer 12 | ---------- 13 | 14 | This library can be seen as a starting point for a Robotiq integration project. 15 | You are responsible for what you do with this library. 16 | The author takes no responsibility for any malfunction. 17 | 18 | Note: This library is not maintained by Robotiq. 19 | 20 | How to Install 21 | -------------- 22 | 23 | Install the pyRobotiqGripper python package using PIP. 24 | 25 | ```bash 26 | 27 | python -m pip install pyRobotiqGripper 28 | ``` 29 | Typical Usage 30 | ------------- 31 | 32 | Import the pyRobotiqGripper module. 33 | 34 | ```python 35 | import pyRobotiqGripper 36 | ``` 37 | Create a Robotiq gripper object. 38 | 39 | ```python 40 | gripper = pyRobotiqGripper() 41 | ``` 42 | By default, the serial port on which the gripper is connected is automatically detected. However, you can manually specify the serial port name if you want to. Refer to the API documentation for more information. 43 | You can now activate the gripper and eventually calibrate the gripper if you want to control the opening in mm instead of bit. 44 | 45 | Note: During activation, the gripper is going to fully open and close. Do not disturb this process. Do not place an object inside the gripper. 46 | 47 | Note: The gripper finger position varies from 0 to 255. It is coded on 8 bits. 48 | 49 | ```python 50 | gripper.activate() 51 | gripper.calibrate(0, 40) 52 | ``` 53 | You can now do whatever you want with the gripper: open, close, get position feedback, etc. 54 | 55 | ```python 56 | gripper.open() 57 | gripper.close() 58 | gripper.goTo(100) 59 | position_in_bit = gripper.getPosition() 60 | print(position_in_bit) 61 | gripper.goTomm(25) 62 | position_in_mm = gripper.getPositionmm() 63 | print(position_in_mm) 64 | ``` 65 | 66 | You can print the current status of gripper registers using printInfo. 67 | 68 | ```python 69 | gripper.printInfo() 70 | ``` -------------------------------------------------------------------------------- /__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/castetsb/pyRobotiqGripper/5052fef0387e9f23b7b602967cb3ffd4e357ab67/__init__.py -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | _build/ 2 | _themes/ 3 | .static 4 | pyRobotiqGripper.egg-info/ 5 | dist/ -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = . 9 | BUILDDIR = _build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /docs/api.rst: -------------------------------------------------------------------------------- 1 | .. _api: 2 | 3 | API 4 | === 5 | 6 | .. automodule:: pyRobotiqGripper 7 | :members: 8 | :undoc-members: 9 | :show-inheritance: 10 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | # Configuration file for the Sphinx documentation builder. 2 | # 3 | # For the full list of built-in configuration values, see the documentation: 4 | # https://www.sphinx-doc.org/en/master/usage/configuration.html 5 | 6 | # -- Project information ----------------------------------------------------- 7 | # https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information 8 | 9 | import os 10 | import sys 11 | 12 | # Get the project root dir, which is the parent dir of this 13 | cwd = os.getcwd() 14 | project_root = os.path.dirname(cwd) 15 | 16 | 17 | 18 | # Insert the project root dir as the first element in the PYTHONPATH. 19 | # This lets us ensure that the source package is imported, and that its 20 | # version is used. 21 | sys.path.insert(0, project_root) 22 | 23 | project = 'pyRobotiqGripper' 24 | copyright = '2024, Benoit CASTETS' 25 | author = 'Benoit CASTETS' 26 | release = '1.0' 27 | 28 | # -- General configuration --------------------------------------------------- 29 | # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration 30 | 31 | extensions = [ 32 | "sphinx.ext.todo", 33 | "sphinx.ext.viewcode", 34 | "sphinx.ext.autodoc", 35 | "sphinx.ext.autosummary", 36 | "sphinx.ext.duration"] 37 | 38 | templates_path = ['_templates'] 39 | exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] 40 | 41 | 42 | 43 | # -- Options for HTML output ------------------------------------------------- 44 | # https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output 45 | 46 | html_theme = 'sphinx_rtd_theme' 47 | html_static_path = ['_static'] 48 | 49 | """ 50 | Tells the project to use sphinx pygments for color coding code examples. 51 | """ 52 | 53 | pygments_style = 'sphinx' 54 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | .. pyRobotiqGripper documentation master file, created by 2 | sphinx-quickstart on Sat Apr 27 22:18:12 2024. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | .. include:: ../README.md 7 | 8 | .. toctree:: 9 | :maxdepth: 2 10 | :caption: Contents: 11 | 12 | Home 13 | api 14 | 15 | Indices and tables 16 | ================== 17 | 18 | * :ref:`genindex` 19 | * :ref:`modindex` 20 | * :ref:`search` 21 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=. 11 | set BUILDDIR=_build 12 | 13 | %SPHINXBUILD% >NUL 2>NUL 14 | if errorlevel 9009 ( 15 | echo. 16 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 17 | echo.installed, then set the SPHINXBUILD environment variable to point 18 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 19 | echo.may add the Sphinx directory to PATH. 20 | echo. 21 | echo.If you don't have Sphinx installed, grab it from 22 | echo.https://www.sphinx-doc.org/ 23 | exit /b 1 24 | ) 25 | 26 | if "%1" == "" goto help 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /docs/requirements.in: -------------------------------------------------------------------------------- 1 | sphinx 2 | sphinx_rtd_theme 3 | minimalmodbus -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | # 2 | # This file is autogenerated by pip-compile with Python 3.12 3 | # by the following command: 4 | # 5 | # pip-compile docs/requirements.in 6 | # 7 | alabaster==0.7.16 8 | # via sphinx 9 | babel==2.14.0 10 | # via sphinx 11 | certifi==2024.2.2 12 | # via requests 13 | charset-normalizer==3.3.2 14 | # via requests 15 | colorama==0.4.6 16 | # via sphinx 17 | docutils==0.20.1 18 | # via 19 | # sphinx 20 | # sphinx-rtd-theme 21 | idna==3.7 22 | # via requests 23 | imagesize==1.4.1 24 | # via sphinx 25 | jinja2==3.1.3 26 | # via sphinx 27 | markupsafe==2.1.5 28 | # via jinja2 29 | minimalmodbus==2.1.1 30 | # via -r docs/requirements.in 31 | packaging==24.0 32 | # via sphinx 33 | pygments==2.17.2 34 | # via sphinx 35 | pyserial==3.5 36 | # via minimalmodbus 37 | requests==2.31.0 38 | # via sphinx 39 | snowballstemmer==2.2.0 40 | # via sphinx 41 | sphinx==7.3.7 42 | # via 43 | # -r docs/requirements.in 44 | # sphinx-rtd-theme 45 | # sphinxcontrib-jquery 46 | sphinx-rtd-theme==2.0.0 47 | # via -r docs/requirements.in 48 | sphinxcontrib-applehelp==1.0.8 49 | # via sphinx 50 | sphinxcontrib-devhelp==1.0.6 51 | # via sphinx 52 | sphinxcontrib-htmlhelp==2.0.5 53 | # via sphinx 54 | sphinxcontrib-jquery==4.1 55 | # via sphinx-rtd-theme 56 | sphinxcontrib-jsmath==1.0.1 57 | # via sphinx 58 | sphinxcontrib-qthelp==1.0.7 59 | # via sphinx 60 | sphinxcontrib-serializinghtml==1.1.10 61 | # via sphinx 62 | urllib3==2.2.1 63 | # via requests 64 | -------------------------------------------------------------------------------- /docs/usage.rst: -------------------------------------------------------------------------------- 1 | Usage 2 | ===== 3 | 4 | 5 | .. _installation: 6 | 7 | Installation 8 | ------------ 9 | 10 | Under construction. 11 | -------------------------------------------------------------------------------- /pyRobotiqGripper.py: -------------------------------------------------------------------------------- 1 | """pyRobotiqGripper: Python Driver for Robotiq Grippers via Modbus RTU 2 | 3 | pyRobotiqGripper is a Python library designed to facilitate control of Robotiq\ 4 | grippers using Modbus RTU communication via serial port. 5 | 6 | This module provides documentation in two formats: 7 | 8 | - Docstrings: Embedded within the code for easy access. 9 | - Online Documentation: Extensive documentation available at\ 10 | . 11 | """ 12 | 13 | #General information 14 | __author__ = "Benoit CASTETS" 15 | __email__ = "opensourceeng@robotiq.com" 16 | __license__ = "Apache License, Version 2.0" 17 | __url__ = "https://github.com/castetsb/pyRobotiqGripper" 18 | __version__ = "1.0.0" 19 | 20 | #Iport libraries 21 | import minimalmodbus as mm 22 | import time 23 | import serial 24 | import serial.tools.list_ports 25 | 26 | #Constants 27 | BAUDRATE=115200 28 | BYTESIZE=8 29 | PARITY="N" 30 | STOPBITS=1 31 | TIMEOUT=0.2 32 | AUTO_DETECTION="auto" 33 | 34 | class RobotiqGripper( mm.Instrument ): 35 | """Object control Robotiq grippers (2F85, 2F140 or hande). 36 | 37 | Suppose that the gripper is connected via the USB/RS485 adapter to the PC\ 38 | executing this code. 39 | 40 | Modbus RTU function code supported by robotiq gripper 41 | 42 | ======================================= ==================== 43 | Description Modbus function code 44 | ======================================= ==================== 45 | Read registers 4 46 | Write registers 16 47 | Master read & write multiple registers 23 48 | ======================================= ==================== 49 | 50 | For more information for gripper communication please check gripper manual 51 | on Robotiq website. 52 | https://robotiq.com/support/2f-85-2f-140 53 | 54 | .. note:: 55 | This object cannot be use to control epick, 3F or powerpick. 56 | """ 57 | 58 | def __init__(self, portname=AUTO_DETECTION,slaveAddress=9): 59 | """Create a RobotiqGripper object whic can be use to control Robotiq\ 60 | grippers using modbus RTU protocol USB/RS485 connection. 61 | 62 | Args: 63 | - portname (str, optional): The serial port name, for example\ 64 | /dev/ttyUSB0 (Linux), /dev/tty.usbserial (OS X) or COM4\ 65 | (Windows). It is necesary to allowpermission to access this\ 66 | connection using the bash comman sudo chmod 666 /dev/ttyUSB0.\ 67 | By default the portname is set to "auto". In this case the\ 68 | connection is done with the first gripper found as connected\ 69 | to the PC. 70 | - slaveaddress (int, optional): Address of the gripper (integer)\ 71 | usually 9. 72 | """ 73 | #Gripper salve address 74 | self.slaveAddress=slaveAddress 75 | 76 | #Port on which is connected the gripper 77 | if portname == "auto": 78 | self.portname=self._autoConnect() 79 | if self.portname is None: 80 | raise Exception("No gripper detected") 81 | else: 82 | self.portname=portname 83 | 84 | #Create a pyserial object to connect to the gripper 85 | ser=serial.Serial(self.portname, 86 | BAUDRATE, 87 | BYTESIZE, 88 | PARITY, 89 | STOPBITS, 90 | TIMEOUT) 91 | 92 | #Create the object using parent class contructor 93 | super().__init__(ser, 94 | self.slaveAddress, 95 | mm.MODE_RTU, 96 | close_port_after_each_call=False, 97 | debug=False) 98 | 99 | #Attribute to monitore if the gripper is processing an action 100 | self.processing=False 101 | 102 | #Maximum allowed time to perform and action 103 | self.timeOut=10 104 | 105 | #Dictionnary where are stored description of each register state 106 | self.registerDic={} 107 | self._buildRegisterDic() 108 | 109 | 110 | #Dictionnary where are stored register values retrived from the gripper 111 | self.paramDic={} 112 | self.readAll() 113 | 114 | #Attributes to store open and close distance state information 115 | 116 | #Distance between the fingers when gripper is closed 117 | self.closemm=None 118 | #Position in bit when gripper is closed 119 | self.closebit=None 120 | 121 | #Distance between the fingers when gripper is open 122 | self.openmm=None 123 | #Position in bit when gripper is open 124 | self.openbit=None 125 | 126 | self._aCoef=None 127 | self._bCoef=None 128 | 129 | def _autoConnect(self): 130 | """Return the name of the port on which is connected the gripper 131 | """ 132 | ports=serial.tools.list_ports.comports() 133 | portName=None 134 | 135 | for port in ports: 136 | try: 137 | # Try opening the port 138 | ser = serial.Serial(port.device,BAUDRATE,BYTESIZE,PARITY,STOPBITS,TIMEOUT) 139 | 140 | device=mm.Instrument(ser,self.slaveAddress,mm.MODE_RTU,close_port_after_each_call=False,debug=False) 141 | 142 | #Try to write the position 100 143 | device.write_registers(1000,[0,100,0]) 144 | 145 | #Try to read the position request eco 146 | registers=device.read_registers(2000,3,4) 147 | posRequestEchoReg3=registers[1] & 0b0000000011111111 148 | 149 | #Check if position request eco reflect the requested position 150 | if posRequestEchoReg3 != 100: 151 | raise Exception("Not a gripper") 152 | portName=port.device 153 | del device 154 | 155 | ser.close() # Close the port 156 | except: 157 | pass # Skip if port cannot be opened 158 | 159 | # If no suitable port is found 160 | return portName 161 | 162 | def _buildRegisterDic(self): 163 | """Build a dictionnary with comment to explain each register variable. 164 | 165 | Dictionnary key are variable names. Dictionnary value are dictionnary\ 166 | with comments about each statut of the variable (key=variable value,\ 167 | value=comment) 168 | """ 169 | ###################################################################### 170 | #input register variable 171 | self.registerDic.update({"gOBJ":{},"gSTA":{},"gGTO":{},"gACT":{}, 172 | "kFLT":{},"gFLT":{},"gPR":{},"gPO":{},"gCU":{}}) 173 | 174 | #gOBJ 175 | gOBJdic=self.registerDic["gOBJ"] 176 | 177 | gOBJdic[0]="Fingers are in motion towards requested position. No\ 178 | object detected." 179 | gOBJdic[1]="Fingers have stopped due to a contact while opening before\ 180 | requested position. Object detected opening." 181 | gOBJdic[2]="Fingers have stopped due to a contact while closing before\ 182 | requested position. Object detected closing." 183 | gOBJdic[3]="Fingers are at requested position. No object detected or\ 184 | object has been loss / dropped." 185 | 186 | #gSTA 187 | gSTAdic=self.registerDic["gSTA"] 188 | 189 | gSTAdic[0]="Gripper is in reset ( or automatic release ) state. See\ 190 | Fault Status if Gripper is activated." 191 | gSTAdic[1]="Activation in progress." 192 | gSTAdic[3]="Activation is completed." 193 | 194 | #gGTO 195 | gGTOdic=self.registerDic["gGTO"] 196 | 197 | gGTOdic[0]="Stopped (or performing activation / automatic release)." 198 | gGTOdic[1]="Go to Position Request." 199 | gGTOdic[2]="Unknown status" 200 | gGTOdic[3]="Unknown status" 201 | 202 | #gACT 203 | gACTdic=self.registerDic["gACT"] 204 | 205 | gACTdic[0]="Gripper reset." 206 | gACTdic[1]="Gripper activation." 207 | 208 | #kFLT 209 | kFLTdic=self.registerDic["kFLT"] 210 | i=0 211 | while i<256: 212 | kFLTdic[i]=i 213 | i+=1 214 | 215 | #See your optional Controller Manual (input registers & status). 216 | 217 | #gFLT 218 | gFLTdic=self.registerDic["gFLT"] 219 | i=0 220 | while i<256: 221 | gFLTdic[i]=i 222 | i+=1 223 | gFLTdic[0]="No fault (LED is blue)" 224 | gFLTdic[5]="Priority faults (LED is blue). Action delayed, activation\ 225 | (reactivation) must be completed prior to perfmoring the action." 226 | gFLTdic[7]="Priority faults (LED is blue). The activation bit must be\ 227 | set prior to action." 228 | gFLTdic[8]="Minor faults (LED continuous red). Maximum operating\ 229 | temperature exceeded, wait for cool-down." 230 | gFLTdic[9]="Minor faults (LED continuous red). No communication during\ 231 | at least 1 second." 232 | gFLTdic[10]="Major faults (LED blinking red/blue) - Reset is required\ 233 | (rising edge on activation bit rACT needed). Under minimum\ 234 | operating voltage." 235 | gFLTdic[11]="Major faults (LED blinking red/blue) - Reset is required\ 236 | (rising edge on activation bit rACT needed). Automatic release in\ 237 | progress." 238 | gFLTdic[12]="Major faults (LED blinking red/blue) - Reset is required\ 239 | (rising edge on activation bit rACT needed). Internal fault;\ 240 | contact support@robotiq.com." 241 | gFLTdic[13]="Major faults (LED blinking red/blue) - Reset is required\ 242 | (rising edge on activation bit rACT needed). Activation fault,\ 243 | verify that no interference or other error occurred." 244 | gFLTdic[14]="Major faults (LED blinking red/blue) - Reset is required\ 245 | (rising edge on activation bit rACT needed). Overcurrent triggered." 246 | gFLTdic[15]="Major faults (LED blinking red/blue) - Reset is required\ 247 | (rising edge on activation bit rACT needed). Automatic release\ 248 | completed." 249 | 250 | #gPR 251 | gPRdic=self.registerDic["gPR"] 252 | 253 | i=0 254 | while i<256: 255 | gPRdic[i]="Echo of the requested position for the Gripper:\ 256 | {}/255".format(i) 257 | i+=1 258 | 259 | #gPO 260 | gPOdic=self.registerDic["gPO"] 261 | i=0 262 | while i<256: 263 | gPOdic[i]="Actual position of the Gripper obtained via the encoders:\ 264 | {}/255".format(i) 265 | i+=1 266 | 267 | #gCU 268 | gCUdic=self.registerDic["gCU"] 269 | i=0 270 | while i<256: 271 | current=i*10 272 | gCUdic[i]="The current is read instantaneously from the motor\ 273 | drive, approximate current: {} mA".format(current) 274 | i+=1 275 | 276 | 277 | ###################################################################### 278 | #output register variable 279 | self.registerDic.update({"rARD":{}, 280 | "rATR":{}, 281 | "rGTO":{}, 282 | "rACT":{}, 283 | "rPR":{}, 284 | "rFR":{}, 285 | "rSP":{}}) 286 | 287 | ###################################################################### 288 | 289 | def readAll(self): 290 | """Retrieve gripper output register information and save it in the\ 291 | parameter dictionary. 292 | 293 | The dictionary keys are as follows: 294 | 295 | - gOBJ: Object detection status. This built-in feature provides\ 296 | information on possible object pick-up. Ignore if gGTO == 0. 297 | - gSTA: Gripper status. Returns the current status and motion of the\ 298 | gripper fingers. 299 | - gGTO: Action status. Echo of the rGTO bit (go-to bit). 300 | - gACT: Activation status. Echo of the rACT bit (activation bit). 301 | - kFLT: See your optional controller manual for input registers and\ 302 | status. 303 | - gFLT: Fault status. Returns general error messages useful for\ 304 | troubleshooting. A fault LED (red) is present on the gripper\ 305 | chassis. The LED can be blue, red, or both, and can be solid\ 306 | or blinking. 307 | - gPR: Echo of the requested position for the gripper. Value between\ 308 | 0x00 and 0xFF. 309 | - gPO: Actual position of the gripper obtained via the encoders.\ 310 | Value between 0x00 and 0xFF. 311 | - gCU: The current is read instantaneously from the motor drive. Value\ 312 | between 0x00 and 0xFF. Approximate current equivalent is 10 times\ 313 | the value read in mA. 314 | """ 315 | #Clear parameter dictionnary data 316 | self.paramDic={} 317 | 318 | #Read 3 16bits registers starting from register 2000 319 | registers=self.read_registers(2000,3) 320 | 321 | ######################################### 322 | #Register 2000 323 | #First Byte: gripperStatus 324 | #Second Byte: RESERVED 325 | 326 | #First Byte: gripperStatus 327 | gripperStatusReg0=(registers[0] >> 8) & 0b11111111 #xxxxxxxx00000000 328 | ######################################### 329 | #Object detection 330 | self.paramDic["gOBJ"]=(gripperStatusReg0 >> 6) & 0b11 #xx000000 331 | #Gripper status 332 | self.paramDic["gSTA"]=(gripperStatusReg0 >> 4) & 0b11 #00xx0000 333 | #Action status. echo of rGTO (go to bit) 334 | self.paramDic["gGTO"]=(gripperStatusReg0 >> 3) & 0b1 #0000x000 335 | #Activation status 336 | self.paramDic["gACT"]=gripperStatusReg0 & 0b00000001 #0000000x 337 | 338 | ######################################### 339 | #Register 2001 340 | #First Byte: Fault status 341 | #Second Byte: Pos request echo 342 | 343 | #First Byte: fault status 344 | faultStatusReg2= (registers[1] >>8) & 0b11111111 #xxxxxxxx00000000 345 | ######################################### 346 | #Universal controler 347 | self.paramDic["kFLT"]=(faultStatusReg2 >> 4) & 0b1111 #xxxx0000 348 | #Fault 349 | self.paramDic["gFLT"]=faultStatusReg2 & 0b00001111 #0000xxxx 350 | 351 | 352 | ######################################### 353 | #Second Byte: Pos request echo 354 | posRequestEchoReg3=registers[1] & 0b11111111 #00000000xxxxxxxx 355 | ######################################### 356 | #Echo of request position 357 | self.paramDic["gPR"]=posRequestEchoReg3 358 | 359 | ######################################### 360 | #Register 2002 361 | #First Byte: Position 362 | #Second Byte: Current 363 | 364 | #First Byte: Position 365 | positionReg4=(registers[2] >> 8) & 0b11111111 #xxxxxxxx00000000 366 | 367 | ######################################### 368 | #Actual position of the gripper 369 | self.paramDic["gPO"]=positionReg4 370 | 371 | ######################################### 372 | #Second Byte: Current 373 | currentReg5=registers[2] & 0b0000000011111111 #00000000xxxxxxxx 374 | ######################################### 375 | #Current 376 | self.paramDic["gCU"]=currentReg5 377 | 378 | def reset(self): 379 | """Reset the gripper (clear previous activation if any) 380 | """ 381 | #Reset the gripper 382 | self.write_registers(1000,[0,0,0]) 383 | 384 | def activate(self): 385 | """If not already activated, activate the gripper. 386 | 387 | .. warning:: 388 | When you execute this function the gripper is going to fully open\ 389 | and close. During this operation the gripper must be able to freely\ 390 | move. Do not place object inside the gripper. 391 | """ 392 | #Turn the variable which indicate that the gripper is processing 393 | #an action to True 394 | self.processing=True 395 | 396 | #Activate the gripper 397 | #rACT=1 Activate Gripper (must stay on after activation routine is 398 | #completed). 399 | self.write_registers(1000,[0b0000000100000000,0,0]) 400 | 401 | #Waiting for activation to complete 402 | activationStartTime=time.time() 403 | activationCompleted=False 404 | activationTime=0 405 | 406 | while (not activationCompleted) and activationTime < self.timeOut: 407 | activationTime = time.time() - activationStartTime 408 | 409 | self.readAll() 410 | gSTA=self.paramDic["gSTA"] 411 | 412 | if gSTA==3: 413 | activationCompleted=True 414 | print("Activation completed. Activation time : " 415 | , activationTime) 416 | if activationTime > self.timeOut: 417 | raise Exception("Activation did not complete without timeout.") 418 | 419 | self.processing=False 420 | 421 | def resetActivate(self): 422 | """Reset the gripper (clear previous activation if any) and activat\ 423 | the gripper. During this operation the gripper will open and close. 424 | """ 425 | #Reset the gripper 426 | self.reset() 427 | #Activate the gripper 428 | self.activate() 429 | 430 | def goTo(self,position,speed=255,force=255): 431 | """Go to the position with determined speed and force. 432 | 433 | Args: 434 | - position (int): Position of the gripper. Integer between 0 and 255.\ 435 | 0 being the open position and 255 being the close position. 436 | - speed (int): Gripper speed between 0 and 255 437 | - force (int): Gripper force between 0 and 255 438 | 439 | Returns: 440 | - objectDetected (bool): True if object detected 441 | - position (int): End position of the gripper in bits 442 | """ 443 | position=int(position) 444 | speed=int(speed) 445 | force=int(force) 446 | 447 | 448 | #Check if the grippre is activated 449 | if self.isActivated == False: 450 | raise Exception ("Gripper must be activated before requesting\ 451 | an action.") 452 | 453 | #Check input value 454 | if position>255: 455 | raise Exception("Position value cannot exceed 255") 456 | elif position<0: 457 | raise Exception("Position value cannot be under 0") 458 | 459 | self.processing=True 460 | 461 | 462 | #rARD(5) rATR(4) rGTO(3) rACT(0) 463 | #gACT=1 (Gripper activation.) and gGTO=1 (Go to Position Request.) 464 | self.write_registers(1000,[0b0000100100000000, 465 | position, 466 | speed * 0b100000000 + force]) 467 | 468 | #Waiting for activation to complete 469 | motionStartTime=time.time() 470 | motionCompleted=False 471 | motionTime=0 472 | objectDetected=False 473 | 474 | while (not objectDetected) and (not motionCompleted)\ 475 | and (motionTimeself.timeOut: 494 | raise Exception("Gripper never reach its requested position and\ 495 | no object have been detected") 496 | 497 | position=self.paramDic["gPO"] 498 | 499 | return position, objectDetected 500 | 501 | def close(self,speed=255,force=255): 502 | """Close the gripper. 503 | 504 | Args: 505 | - speed (int, optional): Gripper speed between 0 and 255.\ 506 | Default is 255. 507 | - force (int, optional): Gripper force between 0 and 255.\ 508 | Default is 255. 509 | """ 510 | self.goTo(255,speed,force) 511 | 512 | def open(self,speed=255,force=255): 513 | """Open the gripper 514 | 515 | Args: 516 | - speed (int, optional): Gripper speed between 0 and 255.\ 517 | Default is 255. 518 | - force (int, optional): Gripper force between 0 and 255.\ 519 | Default is 255. 520 | """ 521 | self.goTo(0,force,speed) 522 | 523 | def goTomm(self,positionmm,speed=255,force=255): 524 | """Go to the requested opening expressed in mm 525 | 526 | Args: 527 | - positionmm (float): Gripper opening in mm. 528 | - speed (int, optional): Gripper speed between 0 and 255.\ 529 | Default is 255. 530 | - force (int, optional): Gripper force between 0 and 255.\ 531 | Default is 255. 532 | 533 | .. note:: 534 | Calibration is needed to use this function.\n 535 | Execute the function calibrate at least 1 time before using this function. 536 | """ 537 | if self.isCalibrated == False: 538 | raise Exception("The gripper must be calibrated before been requested to go to a position in mm") 539 | 540 | if positionmm>self.openmm: 541 | raise Exception("The maximum opening is {}".format(self.openmm)) 542 | 543 | position=int(self._mmToBit(positionmm)) 544 | self.goTo(position,speed,force) 545 | 546 | def getPosition(self): 547 | """Return the position of the gripper in bits 548 | 549 | Returns: 550 | - int: Position of the gripper in bits. 551 | """ 552 | self.readAll() 553 | 554 | position=self.paramDic["gPO"] 555 | 556 | return position 557 | 558 | def _mmToBit(self,mm): 559 | """Convert a mm gripper opening in bit opening. 560 | 561 | .. note:: 562 | Calibration is needed to use this function.\n 563 | Execute the function calibrate at least 1 time before using this function. 564 | """ 565 | bit=(mm-self._bCoef)/self._aCoef 566 | 567 | return bit 568 | 569 | def _bitTomm(self,bit): 570 | """Convert a bit gripper opening in mm opening. 571 | 572 | Returns: 573 | float: Gripper position converted in mm 574 | 575 | .. note:: 576 | Calibration is needed to use this function.\n 577 | Execute the function calibrate at least 1 time before using this function. 578 | """ 579 | mm=self._aCoef*bit+self._bCoef 580 | 581 | return mm 582 | 583 | def getPositionmm(self): 584 | """Return the position of the gripper in mm. 585 | 586 | Returns: 587 | float: Current gripper position in mm 588 | 589 | .. note:: 590 | Calibration is needed to use this function.\n 591 | Execute the function calibrate at least 1 time before using this function. 592 | """ 593 | position=self.getPosition() 594 | 595 | positionmm=self._bitTomm(position) 596 | return positionmm 597 | 598 | def calibrate(self,closemm,openmm): 599 | """Calibrate the gripper for mm positionning. 600 | 601 | Once the calibration is done it is possible to control the gripper in\ 602 | mm. 603 | 604 | Args: 605 | - closemm (float): Distance between the fingers when the gripper is\ 606 | fully closed. 607 | - openmm (float): Distance between the fingers when the gripper is\ 608 | fully open. 609 | """ 610 | self.closemm=closemm 611 | self.openmm=openmm 612 | 613 | self.openGripper() 614 | #get open bit 615 | self.openbit=self.getPosition() 616 | obit=self.openbit 617 | 618 | self.closeGripper() 619 | #get close bit 620 | self.closebit=self.getPosition() 621 | cbit=self.closebit 622 | 623 | self._aCoef=(closemm-openmm)/(cbit-obit) 624 | self._bCoef=(openmm*cbit-obit*closemm)/(cbit-obit) 625 | 626 | def printInfo(self): 627 | """Print gripper register info in the python terminal 628 | """ 629 | self.readAll() 630 | for key,value in self.paramDic.items(): 631 | print("{} : {}".format(key,value)) 632 | print(self.registerDic[key][value]) 633 | 634 | def isActivated(self): 635 | """Tells if the gripper is activated 636 | 637 | Returns: 638 | bool: True if the gripper is activated. False otherwise. 639 | """ 640 | 641 | self.readAll() 642 | is_activated = (self.paramDic["gSTA"]==3) 643 | 644 | return is_activated 645 | 646 | def isCalibrated(self): 647 | """Return if the gripper is qualibrated 648 | 649 | Returns: 650 | bool: True if the gripper is calibrated. False otherwise. 651 | """ 652 | is_calibrated = False 653 | if (self.openmm is None) or (self.closemm is None): 654 | is_calibrated = False 655 | else: 656 | is_calibrated=True 657 | 658 | return is_calibrated 659 | 660 | #Test 661 | if False: 662 | grip=RobotiqGripper() 663 | grip.resetActivate() 664 | #grip.reset() 665 | #grip.goTo(0) 666 | #grip.goTo(255) 667 | #grip.printInfo() 668 | #grip.goTo(255) 669 | #time.sleep(5) 670 | #grip.printInfo() 671 | #grip.activate() 672 | #grip.printInfo() 673 | 674 | #grip.goTo(20) 675 | #grip.goTo(230) 676 | #grip.goTo(40) 677 | #grip.goTo(80) 678 | 679 | #grip.calibrate(0,36) 680 | #grip.goTomm(10,255,255) 681 | #grip.goTomm(40,1,255) 682 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["hatchling"] 3 | build-backend = "hatchling.build" 4 | 5 | [project] 6 | name = "pyRobotiqGripper" 7 | version = "1.0.0" 8 | authors = [ 9 | { name="Benoit CASTETS", email="opensourceeng@gmail.com" }, 10 | ] 11 | description = "Python Driver for Robotiq Grippers via Modbus RTU" 12 | readme = "README.md" 13 | requires-python = ">=3.8" 14 | classifiers = [ 15 | "Programming Language :: Python :: 3", 16 | "License :: OSI Approved :: MIT License", 17 | "Operating System :: OS Independent", 18 | ] 19 | 20 | [project.urls] 21 | Homepage = "https://github.com/castetsb/pyRobotiqGripper" 22 | Issues = "https://github.com/castetsb/pyRobotiqGripper/issues" -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | # 2 | # This file is autogenerated by pip-compile with Python 3.12 3 | # by the following command: 4 | # 5 | # pip-compile setup.py 6 | # 7 | minimalmodbus==2.1.1 8 | # via pyRobotiqGripper (setup.py) 9 | pyserial==3.5 10 | # via minimalmodbus 11 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | 3 | setup( 4 | name='pyRobotiqGripper', 5 | version='1.0.0', 6 | packages=find_packages(), 7 | install_requires=[ 8 | 'minimalmodbus' 9 | ], 10 | author='Benoit CASTETS', 11 | author_email='opensourceeng@email.com', 12 | description='Python Driver for Robotiq Grippers via Modbus RTU', 13 | long_description=open('README.md').read(), 14 | long_description_content_type='text/markdown', 15 | url='https://github.com/castetsb/pyRobotiqGripper', 16 | classifiers=[ 17 | 'Programming Language :: Python :: 3', 18 | # Add more classifiers as needed 19 | ], 20 | ) 21 | --------------------------------------------------------------------------------