pyrobotiqgripper 1.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -0,0 +1,21 @@
|
|
|
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.
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: pyrobotiqgripper
|
|
3
|
+
Version: 1.0.1
|
|
4
|
+
Summary: Python Driver for Robotiq Grippers via Modbus RTU
|
|
5
|
+
Author: Benoit CASTETS
|
|
6
|
+
Author-email: opensourceeng@gmail.com
|
|
7
|
+
Requires-Python: >=3.8.1,<4.0
|
|
8
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
9
|
+
Classifier: Operating System :: OS Independent
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
16
|
+
Requires-Dist: minimalmodbus (>=2.1.1,<3.0.0)
|
|
17
|
+
Project-URL: Homepage, https://github.com/castetsb/pyRobotiqGripper
|
|
18
|
+
Project-URL: Issues, https://github.com/castetsb/pyRobotiqGripper/issues
|
|
19
|
+
Description-Content-Type: text/x-rst
|
|
20
|
+
|
|
21
|
+
pyRobotiqGripper
|
|
22
|
+
================
|
|
23
|
+
|
|
24
|
+
Python Driver for Robotiq Grippers via Modbus RTU
|
|
25
|
+
|
|
26
|
+
pyRobotiqGripper is a Python library designed to facilitate control of Robotiq grippers using Modbus RTU communication via serial port.
|
|
27
|
+
It is compatible with 2F85, 2F140, and Hande.
|
|
28
|
+
|
|
29
|
+
Documentation: `pyRobotiqGripper Documentation <https://pyrobotiqgripper.readthedocs.io/en/latest/>`_
|
|
30
|
+
|
|
31
|
+
Disclaimer
|
|
32
|
+
----------
|
|
33
|
+
|
|
34
|
+
This library can be seen as a starting point for a Robotiq integration project.
|
|
35
|
+
You are responsible for what you do with this library.
|
|
36
|
+
The author takes no responsibility for any malfunction.
|
|
37
|
+
|
|
38
|
+
Note: This library is not maintained by Robotiq.
|
|
39
|
+
|
|
40
|
+
How to Install
|
|
41
|
+
--------------
|
|
42
|
+
|
|
43
|
+
Install the pyRobotiqGripper python package using PIP.
|
|
44
|
+
|
|
45
|
+
.. code-block:: bash
|
|
46
|
+
|
|
47
|
+
python -m pip install minimalmodbus
|
|
48
|
+
python -m pip install pyRobotiqGripper
|
|
49
|
+
|
|
50
|
+
Typical Usage
|
|
51
|
+
-------------
|
|
52
|
+
|
|
53
|
+
Import the pyRobotiqGripper module.
|
|
54
|
+
|
|
55
|
+
.. code-block:: python
|
|
56
|
+
|
|
57
|
+
from pyrobotiqgripper import RobotiqGripper
|
|
58
|
+
|
|
59
|
+
Create a Robotiq gripper object.
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
.. code-block:: python
|
|
63
|
+
|
|
64
|
+
gripper = pyRobotiqGripper.RobotiqGripper()
|
|
65
|
+
|
|
66
|
+
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.
|
|
67
|
+
You can now activate the gripper and eventually calibrate the gripper if you want to control the opening in mm instead of bit.
|
|
68
|
+
|
|
69
|
+
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.
|
|
70
|
+
|
|
71
|
+
Note: The gripper finger position varies from 0 to 255. It is coded on 8 bits.
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
.. code-block:: python
|
|
75
|
+
|
|
76
|
+
gripper.activate()
|
|
77
|
+
gripper.calibrate(0, 40)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
You can now do whatever you want with the gripper: open, close, get position feedback, etc.
|
|
81
|
+
|
|
82
|
+
.. code-block:: python
|
|
83
|
+
|
|
84
|
+
gripper.open()
|
|
85
|
+
gripper.close()
|
|
86
|
+
gripper.goTo(100)
|
|
87
|
+
position_in_bit = gripper.getPosition()
|
|
88
|
+
print(position_in_bit)
|
|
89
|
+
gripper.goTomm(25)
|
|
90
|
+
position_in_mm = gripper.getPositionmm()
|
|
91
|
+
print(position_in_mm)
|
|
92
|
+
|
|
93
|
+
You can print the current status of gripper registers using printInfo.
|
|
94
|
+
|
|
95
|
+
.. code-block:: python
|
|
96
|
+
|
|
97
|
+
gripper.printInfo()
|
|
98
|
+
|
|
@@ -0,0 +1,77 @@
|
|
|
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 <https://pyrobotiqgripper.readthedocs.io/en/latest/>`_
|
|
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
|
+
.. code-block:: bash
|
|
26
|
+
|
|
27
|
+
python -m pip install minimalmodbus
|
|
28
|
+
python -m pip install pyRobotiqGripper
|
|
29
|
+
|
|
30
|
+
Typical Usage
|
|
31
|
+
-------------
|
|
32
|
+
|
|
33
|
+
Import the pyRobotiqGripper module.
|
|
34
|
+
|
|
35
|
+
.. code-block:: python
|
|
36
|
+
|
|
37
|
+
from pyrobotiqgripper import RobotiqGripper
|
|
38
|
+
|
|
39
|
+
Create a Robotiq gripper object.
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
.. code-block:: python
|
|
43
|
+
|
|
44
|
+
gripper = pyRobotiqGripper.RobotiqGripper()
|
|
45
|
+
|
|
46
|
+
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.
|
|
47
|
+
You can now activate the gripper and eventually calibrate the gripper if you want to control the opening in mm instead of bit.
|
|
48
|
+
|
|
49
|
+
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.
|
|
50
|
+
|
|
51
|
+
Note: The gripper finger position varies from 0 to 255. It is coded on 8 bits.
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
.. code-block:: python
|
|
55
|
+
|
|
56
|
+
gripper.activate()
|
|
57
|
+
gripper.calibrate(0, 40)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
You can now do whatever you want with the gripper: open, close, get position feedback, etc.
|
|
61
|
+
|
|
62
|
+
.. code-block:: python
|
|
63
|
+
|
|
64
|
+
gripper.open()
|
|
65
|
+
gripper.close()
|
|
66
|
+
gripper.goTo(100)
|
|
67
|
+
position_in_bit = gripper.getPosition()
|
|
68
|
+
print(position_in_bit)
|
|
69
|
+
gripper.goTomm(25)
|
|
70
|
+
position_in_mm = gripper.getPositionmm()
|
|
71
|
+
print(position_in_mm)
|
|
72
|
+
|
|
73
|
+
You can print the current status of gripper registers using printInfo.
|
|
74
|
+
|
|
75
|
+
.. code-block:: python
|
|
76
|
+
|
|
77
|
+
gripper.printInfo()
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
|
|
2
|
+
[tool.poetry]
|
|
3
|
+
name = "pyrobotiqgripper"
|
|
4
|
+
version = "1.0.1"
|
|
5
|
+
authors = ["Benoit CASTETS <opensourceeng@gmail.com>"]
|
|
6
|
+
description = "Python Driver for Robotiq Grippers via Modbus RTU"
|
|
7
|
+
readme = "README.rst"
|
|
8
|
+
classifiers = [
|
|
9
|
+
"Programming Language :: Python :: 3",
|
|
10
|
+
"License :: OSI Approved :: MIT License",
|
|
11
|
+
"Operating System :: OS Independent",
|
|
12
|
+
]
|
|
13
|
+
packages = [{include = "pyrobotiqgripper"}]
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
[tool.poetry.urls]
|
|
17
|
+
Homepage = "https://github.com/castetsb/pyRobotiqGripper"
|
|
18
|
+
Issues = "https://github.com/castetsb/pyRobotiqGripper/issues"
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
[tool.poetry.dependencies]
|
|
22
|
+
python = ">=3.8.1,<4.0"
|
|
23
|
+
minimalmodbus = "^2.1.1"
|
|
24
|
+
|
|
25
|
+
[build-system]
|
|
26
|
+
requires = ["poetry-core>=1.0.8"]
|
|
27
|
+
build-backend = "poetry.core.masonry.api"
|
|
@@ -0,0 +1,681 @@
|
|
|
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
|
+
<https://pyrobotiqgripper.readthedocs.io/en/latest/>.
|
|
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 (motionTime<self.timeOut):
|
|
476
|
+
|
|
477
|
+
motionTime= time.time()- motionStartTime
|
|
478
|
+
self.readAll()
|
|
479
|
+
#Object detection status, is a built-in feature that provides
|
|
480
|
+
#information on possible object pick-up. Ignore if gGTO == 0.
|
|
481
|
+
gOBJ=self.paramDic["gOBJ"]
|
|
482
|
+
|
|
483
|
+
|
|
484
|
+
if gOBJ==1 or gOBJ==2:
|
|
485
|
+
#Fingers have stopped due to a contact
|
|
486
|
+
objectDetected=True
|
|
487
|
+
|
|
488
|
+
elif gOBJ==3:
|
|
489
|
+
#Fingers are at requested position.
|
|
490
|
+
objectDetected=False
|
|
491
|
+
motionCompleted=True
|
|
492
|
+
|
|
493
|
+
if motionTime>self.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.open()
|
|
614
|
+
#get open bit
|
|
615
|
+
self.openbit=self.getPosition()
|
|
616
|
+
obit=self.openbit
|
|
617
|
+
|
|
618
|
+
self.close()
|
|
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)
|