urkit 0.1.1__tar.gz → 0.2.0__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.
- urkit-0.2.0/PKG-INFO +541 -0
- urkit-0.2.0/README.md +515 -0
- {urkit-0.1.1 → urkit-0.2.0}/pyproject.toml +1 -1
- urkit-0.2.0/src/urkit.egg-info/PKG-INFO +541 -0
- urkit-0.1.1/PKG-INFO +0 -707
- urkit-0.1.1/README.md +0 -681
- urkit-0.1.1/src/urkit.egg-info/PKG-INFO +0 -707
- {urkit-0.1.1 → urkit-0.2.0}/setup.cfg +0 -0
- {urkit-0.1.1 → urkit-0.2.0}/src/urkit/__init__.py +0 -0
- {urkit-0.1.1 → urkit-0.2.0}/src/urkit/__main__.py +0 -0
- {urkit-0.1.1 → urkit-0.2.0}/src/urkit/cli/__init__.py +0 -0
- {urkit-0.1.1 → urkit-0.2.0}/src/urkit/cli/colors.py +0 -0
- {urkit-0.1.1 → urkit-0.2.0}/src/urkit/cli/connection_monitor.py +0 -0
- {urkit-0.1.1 → urkit-0.2.0}/src/urkit/cli/points.py +0 -0
- {urkit-0.1.1 → urkit-0.2.0}/src/urkit/cli/teach.py +0 -0
- {urkit-0.1.1 → urkit-0.2.0}/src/urkit/config.py +0 -0
- {urkit-0.1.1 → urkit-0.2.0}/src/urkit/connection.py +0 -0
- {urkit-0.1.1 → urkit-0.2.0}/src/urkit/exceptions.py +0 -0
- {urkit-0.1.1 → urkit-0.2.0}/src/urkit/geometry.py +0 -0
- {urkit-0.1.1 → urkit-0.2.0}/src/urkit/gripper/__init__.py +0 -0
- {urkit-0.1.1 → urkit-0.2.0}/src/urkit/gripper/base.py +0 -0
- {urkit-0.1.1 → urkit-0.2.0}/src/urkit/gripper/digital.py +0 -0
- {urkit-0.1.1 → urkit-0.2.0}/src/urkit/gripper/presets.py +0 -0
- {urkit-0.1.1 → urkit-0.2.0}/src/urkit/gripper/robotiq.py +0 -0
- {urkit-0.1.1 → urkit-0.2.0}/src/urkit/gripper/robotiq_preamble.py +0 -0
- {urkit-0.1.1 → urkit-0.2.0}/src/urkit/io.py +0 -0
- {urkit-0.1.1 → urkit-0.2.0}/src/urkit/motion.py +0 -0
- {urkit-0.1.1 → urkit-0.2.0}/src/urkit/points.py +0 -0
- {urkit-0.1.1 → urkit-0.2.0}/src/urkit/robot.py +0 -0
- {urkit-0.1.1 → urkit-0.2.0}/src/urkit/telemetry.py +0 -0
- {urkit-0.1.1 → urkit-0.2.0}/src/urkit.egg-info/SOURCES.txt +0 -0
- {urkit-0.1.1 → urkit-0.2.0}/src/urkit.egg-info/dependency_links.txt +0 -0
- {urkit-0.1.1 → urkit-0.2.0}/src/urkit.egg-info/entry_points.txt +0 -0
- {urkit-0.1.1 → urkit-0.2.0}/src/urkit.egg-info/requires.txt +0 -0
- {urkit-0.1.1 → urkit-0.2.0}/src/urkit.egg-info/top_level.txt +0 -0
- {urkit-0.1.1 → urkit-0.2.0}/tests/test_exceptions.py +0 -0
- {urkit-0.1.1 → urkit-0.2.0}/tests/test_geometry.py +0 -0
- {urkit-0.1.1 → urkit-0.2.0}/tests/test_gripper.py +0 -0
- {urkit-0.1.1 → urkit-0.2.0}/tests/test_gripper_factory.py +0 -0
- {urkit-0.1.1 → urkit-0.2.0}/tests/test_gripper_presets.py +0 -0
- {urkit-0.1.1 → urkit-0.2.0}/tests/test_points.py +0 -0
- {urkit-0.1.1 → urkit-0.2.0}/tests/test_robot_integration.py +0 -0
urkit-0.2.0/PKG-INFO
ADDED
|
@@ -0,0 +1,541 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: urkit
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Universal Robots e-Series control toolkit built on ur_rtde
|
|
5
|
+
Author: URKit Contributors
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Repository, https://github.com/rodolfo-verde/urkit
|
|
8
|
+
Keywords: universal-robots,ur3e,ur5e,ur7e,ur10e,ur12e,ur16e,ur8,ur15,ur18,ur20,ur30,rtde,robotics,industrial-robot
|
|
9
|
+
Classifier: Development Status :: 3 - Alpha
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
19
|
+
Classifier: Topic :: Scientific/Engineering :: Human Machine Interfaces
|
|
20
|
+
Requires-Python: >=3.8
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
Requires-Dist: ur_rtde>=1.4.0
|
|
23
|
+
Requires-Dist: pyyaml>=6.0
|
|
24
|
+
Requires-Dist: colorama>=0.4.6
|
|
25
|
+
Requires-Dist: rich>=13.0.0
|
|
26
|
+
|
|
27
|
+
# URKit
|
|
28
|
+
|
|
29
|
+
[](https://pypi.org/project/urkit/)
|
|
30
|
+
|
|
31
|
+
**URKit** is a Python toolkit for [Universal Robots](https://www.universal-robots.com/) e-Series robots that makes the common stuff simple and gets out of the way for everything else.
|
|
32
|
+
|
|
33
|
+
Built on [`ur_rtde`](https://sdurobotics.gitlab.io/ur_rtde/), it packages the operations you reach for most: connecting, moving to named points, gripper control, telemetry, and I/O, while exposing the raw RTDE interfaces for anything deeper.
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Table of Contents
|
|
38
|
+
|
|
39
|
+
- [Quick Start](#quick-start)
|
|
40
|
+
- [Interactive CLI](#interactive-cli)
|
|
41
|
+
- [Teach Mode](#teach-mode)
|
|
42
|
+
- [Points Explorer](#points-explorer)
|
|
43
|
+
- [Key Map](#key-map)
|
|
44
|
+
- [API Reference](#api-reference)
|
|
45
|
+
- [Connecting](#connecting)
|
|
46
|
+
- [Grippers](#grippers)
|
|
47
|
+
- [Points & Motion](#points--motion)
|
|
48
|
+
- [Telemetry](#telemetry)
|
|
49
|
+
- [Digital I/O](#digital-io)
|
|
50
|
+
- [Configuration](#configuration)
|
|
51
|
+
- [Advanced](#advanced)
|
|
52
|
+
- [Raw RTDE Access](#raw-rtde-access)
|
|
53
|
+
- [Connection Lifecycle](#connection-lifecycle)
|
|
54
|
+
- [Error Handling](#error-handling)
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## Quick Start
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
pip install urkit
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Requires Python 3.8+ and a Universal Robots e-Series (UR3e to UR30).
|
|
65
|
+
|
|
66
|
+
### Robot Setup (one-time)
|
|
67
|
+
|
|
68
|
+
1. **Network**: `☰` → `System` → `Network`: set the robot's IP and subnet.
|
|
69
|
+
2. **Remote Control**: `☰` → `System` → `Remote Control`: Enable. Press the remote/local button on the pendant.
|
|
70
|
+
3. **Security**: `☰` → `Security` → `Services`: enable RTDE and disable EtherNet/IP, PROFINET, or MODBUS if they're claiming RTDE registers. Save and restart.
|
|
71
|
+
|
|
72
|
+
That's it. No `.urp` files to run, no extra programs needed.
|
|
73
|
+
|
|
74
|
+
### Robotiq Grippers (optional)
|
|
75
|
+
|
|
76
|
+
Install the **Robotiq Gripper Control** URCap: download from [robotiq.com/support](https://robotiq.com/support), copy the `.urcap` to a USB drive, mount on the robot, and install via `☰` → `Settings` → `System` → `URCaps`.
|
|
77
|
+
|
|
78
|
+
### Hello World
|
|
79
|
+
|
|
80
|
+
```python
|
|
81
|
+
from urkit import URRobot, ROBOTIQ_HAND_E
|
|
82
|
+
|
|
83
|
+
robot = URRobot(ip="172.31.1.200", points="points.db", gripper=ROBOTIQ_HAND_E)
|
|
84
|
+
robot.gripper.activate()
|
|
85
|
+
|
|
86
|
+
robot.move_to("home")
|
|
87
|
+
robot.move_to("pick", offset=[0, 0, 0.05, 0, 0, 0])
|
|
88
|
+
robot.gripper.close()
|
|
89
|
+
robot.move_to("place")
|
|
90
|
+
robot.gripper.open()
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
The typical workflow:
|
|
94
|
+
|
|
95
|
+
1. **Teach points** — use the CLI to position the robot and save named waypoints.
|
|
96
|
+
2. **Write code** — create a robot, move to points by name, apply offsets, run sequences.
|
|
97
|
+
3. **Iterate** — add more points, tweak your code, repeat.
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## Interactive CLI
|
|
102
|
+
|
|
103
|
+
URKit provides two CLI tools: **teach** for interactive robot control, and **points** for browsing saved waypoints.
|
|
104
|
+
|
|
105
|
+
### Teach Mode
|
|
106
|
+
|
|
107
|
+
The interactive teach pendant for moving the robot, saving points, and checking telemetry:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
urkit teach 172.31.1.200 # with robot IP
|
|
111
|
+
urkit teach # reads IP from config.yaml
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
**Flags:**
|
|
115
|
+
|
|
116
|
+
| Flag | Description |
|
|
117
|
+
|------|-------------|
|
|
118
|
+
| `ip` | Robot IP address (positional, overrides config) |
|
|
119
|
+
| `--gripper` | Gripper preset: `2f-85`, `2f-140`, `hand-e`, `digital`, `none` |
|
|
120
|
+
| `--gripper-pin` | Digital gripper output pin (default: 0) |
|
|
121
|
+
| `--gripper-force` | Robotiq force 0-100 |
|
|
122
|
+
| `--gripper-speed` | Robotiq speed 0-100 |
|
|
123
|
+
| `--gripper-close-on-high` | Digital polarity: `true` or `false` |
|
|
124
|
+
| `--points` | Path to `points.db` file (overrides config) |
|
|
125
|
+
| `--config` | Path to config file (default: `config.yaml` in project root or CWD) |
|
|
126
|
+
| `-v`, `--verbose` | Show verbose output (debug connection issues) |
|
|
127
|
+
|
|
128
|
+
### Points Explorer
|
|
129
|
+
|
|
130
|
+
Browse saved waypoints with real-time search filtering — no robot connection needed:
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
urkit points # uses default points.db
|
|
134
|
+
urkit points test_points.db # use specific database
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
**Features:**
|
|
138
|
+
- **Type to search** — real-time substring filtering
|
|
139
|
+
- **Fuzzy matching** — type `pk` to find `pick_1` (>60% match)
|
|
140
|
+
- **Smart sorting** — exact prefix matches first, then substring, then fuzzy
|
|
141
|
+
- **Spatial sorting** — points ordered by proximity to "home" point (XYZ distance)
|
|
142
|
+
- **Theme-aware** — automatically adapts colors for light/dark terminals
|
|
143
|
+
- **Arrow keys** — scroll · **ESC** — quit
|
|
144
|
+
|
|
145
|
+
### Key Map
|
|
146
|
+
|
|
147
|
+
All movement and orientation keys support **hold-to-repeat**.
|
|
148
|
+
|
|
149
|
+
<table>
|
|
150
|
+
<tr>
|
|
151
|
+
<th align="center">Movement</th>
|
|
152
|
+
<th align="center">Orientation</th>
|
|
153
|
+
<th align="center">Step Size</th>
|
|
154
|
+
</tr>
|
|
155
|
+
<tr>
|
|
156
|
+
<td align="center" style="width:33%">
|
|
157
|
+
<table>
|
|
158
|
+
<tr><th>Key</th><th>Action</th></tr>
|
|
159
|
+
<tr><td><code>W</code> / <code>S</code></td><td>+X / -X</td></tr>
|
|
160
|
+
<tr><td><code>A</code> / <code>D</code></td><td>+Y / -Y</td></tr>
|
|
161
|
+
<tr><td><code>Q</code> / <code>E</code></td><td>+Z / -Z</td></tr>
|
|
162
|
+
</table>
|
|
163
|
+
</td>
|
|
164
|
+
<td align="center" style="width:33%">
|
|
165
|
+
<table>
|
|
166
|
+
<tr><th>Key</th><th>Action</th></tr>
|
|
167
|
+
<tr><td><code>U</code> / <code>O</code></td><td>Roll - / +</td></tr>
|
|
168
|
+
<tr><td><code>I</code> / <code>K</code></td><td>Pitch - / +</td></tr>
|
|
169
|
+
<tr><td><code>J</code> / <code>L</code></td><td>Yaw - / +</td></tr>
|
|
170
|
+
</table>
|
|
171
|
+
</td>
|
|
172
|
+
<td align="center" style="width:34%">
|
|
173
|
+
<table>
|
|
174
|
+
<tr><th>Key</th><th>Action</th></tr>
|
|
175
|
+
<tr><td><code>1</code></td><td>Set linear step (mm)</td></tr>
|
|
176
|
+
<tr><td><code>2</code></td><td>Set angular step (deg)</td></tr>
|
|
177
|
+
<tr><td><code>.</code></td><td>Reset defaults (5 mm / 2°)</td></tr>
|
|
178
|
+
</table>
|
|
179
|
+
</td>
|
|
180
|
+
</tr>
|
|
181
|
+
</table>
|
|
182
|
+
|
|
183
|
+
<table>
|
|
184
|
+
<tr>
|
|
185
|
+
<th align="center">Gripper</th>
|
|
186
|
+
<th align="center">Points</th>
|
|
187
|
+
<th align="center">Controls</th>
|
|
188
|
+
</tr>
|
|
189
|
+
<tr>
|
|
190
|
+
<td align="center" style="width:33%">
|
|
191
|
+
<table>
|
|
192
|
+
<tr><th>Key</th><th>Action</th></tr>
|
|
193
|
+
<tr><td><code>X</code></td><td>Open</td></tr>
|
|
194
|
+
<tr><td><code>C</code></td><td>Close</td></tr>
|
|
195
|
+
<tr><td><code>V</code></td><td>Set position (mm)</td></tr>
|
|
196
|
+
</table>
|
|
197
|
+
</td>
|
|
198
|
+
<td align="center" style="width:33%">
|
|
199
|
+
<table>
|
|
200
|
+
<tr><th>Key</th><th>Action</th></tr>
|
|
201
|
+
<tr><td><code>B</code></td><td><strong>Save</strong> current position</td></tr>
|
|
202
|
+
<tr><td><code>G</code></td><td>Go to saved point</td></tr>
|
|
203
|
+
<tr><td><code>H</code></td><td>Delete saved point</td></tr>
|
|
204
|
+
<tr><td><code>P</code></td><td>Open points explorer</td></tr>
|
|
205
|
+
<tr><td><code>R</code></td><td>Rename saved point</td></tr>
|
|
206
|
+
</table>
|
|
207
|
+
</td>
|
|
208
|
+
<td align="center" style="width:34%">
|
|
209
|
+
<table>
|
|
210
|
+
<tr><th>Key</th><th>Action</th></tr>
|
|
211
|
+
<tr><td><code>F</code></td><td>Freedrive (OFF → ALL → XYZ+Rz)</td></tr>
|
|
212
|
+
<tr><td><code>M</code></td><td>Toggle frame (BASE / TOOL)</td></tr>
|
|
213
|
+
<tr><td><code>N</code></td><td>Go To mode (Cartesian / Joint)</td></tr>
|
|
214
|
+
<tr><td><code>T</code></td><td>Orient TCP down (180°)</td></tr>
|
|
215
|
+
<tr><td><code>Y</code></td><td>Save config to file</td></tr>
|
|
216
|
+
<tr><td><code>ESC</code></td><td>Exit</td></tr>
|
|
217
|
+
</table>
|
|
218
|
+
</td>
|
|
219
|
+
</tr>
|
|
220
|
+
</table>
|
|
221
|
+
|
|
222
|
+
---
|
|
223
|
+
|
|
224
|
+
## API Reference
|
|
225
|
+
|
|
226
|
+
### Connecting
|
|
227
|
+
|
|
228
|
+
```python
|
|
229
|
+
from urkit import URRobot, ROBOTIQ_HAND_E
|
|
230
|
+
|
|
231
|
+
robot = URRobot(ip="172.31.1.200", points="points.db", gripper=ROBOTIQ_HAND_E)
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
With custom motion defaults:
|
|
235
|
+
|
|
236
|
+
```python
|
|
237
|
+
robot = URRobot(
|
|
238
|
+
ip="172.31.1.200",
|
|
239
|
+
points="points.db",
|
|
240
|
+
gripper=ROBOTIQ_HAND_E,
|
|
241
|
+
default_vel=0.5, # m/s
|
|
242
|
+
default_acc=0.3, # m/s²
|
|
243
|
+
)
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
From a config file:
|
|
247
|
+
|
|
248
|
+
```python
|
|
249
|
+
robot = URRobot.from_config("config.yaml")
|
|
250
|
+
robot = URRobot.from_config("config.yaml", ip="10.0.0.50") # override IP
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
### Grippers
|
|
254
|
+
|
|
255
|
+
Three built-in presets:
|
|
256
|
+
|
|
257
|
+
| Preset | Description |
|
|
258
|
+
|--------|-------------|
|
|
259
|
+
| `ROBOTIQ_HAND_E` | Robotiq 2F-140-E (Hand-E series) |
|
|
260
|
+
| `ROBOTIQ_2F_85` | Robotiq 2F-85 |
|
|
261
|
+
| `ROBOTIQ_2F_140` | Robotiq 2F-140 |
|
|
262
|
+
|
|
263
|
+
```python
|
|
264
|
+
robot.gripper.activate() # required before open/close (Robotiq only)
|
|
265
|
+
robot.gripper.is_activated() # check activation state
|
|
266
|
+
|
|
267
|
+
robot.gripper.open() # fully open (blocking by default)
|
|
268
|
+
robot.gripper.close() # fully closed, stops on contact
|
|
269
|
+
robot.gripper.open(wait=False) # non-blocking return
|
|
270
|
+
robot.gripper.set_position(20) # 20mm open (Robotiq only, 0 = closed)
|
|
271
|
+
robot.gripper.set_force(50) # grip force: 0-100
|
|
272
|
+
robot.gripper.set_speed(80) # movement speed: 0-100
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
Override preset values for custom fingers:
|
|
276
|
+
|
|
277
|
+
```python
|
|
278
|
+
robot = URRobot(ip="172.31.1.200", points="points.db", gripper=ROBOTIQ_HAND_E, max_mm=120)
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
#### Digital I/O Grippers
|
|
282
|
+
|
|
283
|
+
For suction cups, solenoids, or custom actuators:
|
|
284
|
+
|
|
285
|
+
```python
|
|
286
|
+
from urkit import URRobot, DigitalGripperConfig
|
|
287
|
+
|
|
288
|
+
robot = URRobot(
|
|
289
|
+
ip="172.31.1.200",
|
|
290
|
+
points="points.db",
|
|
291
|
+
gripper=DigitalGripperConfig(pin=3),
|
|
292
|
+
)
|
|
293
|
+
|
|
294
|
+
robot.gripper.open() # turn pin off (release)
|
|
295
|
+
robot.gripper.close() # turn pin on (grab)
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
### Points & Motion
|
|
299
|
+
|
|
300
|
+
The points database is optional — create a robot without one and attach later:
|
|
301
|
+
|
|
302
|
+
```python
|
|
303
|
+
robot = URRobot(ip="172.31.1.200")
|
|
304
|
+
robot.points_db = "points.db"
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
#### Moving to Points
|
|
308
|
+
|
|
309
|
+
```python
|
|
310
|
+
robot.move_to("pick") # linear move (default)
|
|
311
|
+
robot.move_to("pick", linear=False) # joint move
|
|
312
|
+
robot.move_to("pick", vel=1.0, acc=0.5) # override speed
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
#### Raw Poses
|
|
316
|
+
|
|
317
|
+
```python
|
|
318
|
+
robot.move_to([0.5, 0, 0.3, 0, 0, 0]) # [x, y, z, rx, ry, rz]
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
#### Offsets
|
|
322
|
+
|
|
323
|
+
```python
|
|
324
|
+
robot.move_to("pick", offset=[0, 0, 0.05, 0, 0, 0]) # 5cm above pick
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
#### Coordinate Frame
|
|
328
|
+
|
|
329
|
+
```python
|
|
330
|
+
from urkit import MoveFrame
|
|
331
|
+
|
|
332
|
+
robot.move_frame = MoveFrame.TOOL # default is BASE
|
|
333
|
+
robot.move_to("pick", offset=[0, 0, 0.05]) # 5cm along tool Z
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
- **BASE** (default): offset relative to robot base
|
|
337
|
+
- **TOOL**: offset relative to TCP orientation
|
|
338
|
+
|
|
339
|
+
#### Point Management
|
|
340
|
+
|
|
341
|
+
```python
|
|
342
|
+
robot.save_point("here")
|
|
343
|
+
robot.point_names() # ["home", "pick", "place"]
|
|
344
|
+
robot.rename_point("old", "new")
|
|
345
|
+
robot.delete_point("old")
|
|
346
|
+
robot.export_points("backup.json")
|
|
347
|
+
robot.import_points("backup.json")
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
#### Relative Moves
|
|
351
|
+
|
|
352
|
+
```python
|
|
353
|
+
robot.move_relative([0, 0.01, 0, 0, 0, 0]) # 1cm along Y
|
|
354
|
+
robot.move_relative([0, 0, 0.05], frame=MoveFrame.TOOL)
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
#### Sequences with Blending
|
|
358
|
+
|
|
359
|
+
```python
|
|
360
|
+
robot.move_sequence(["a", "b", "c"])
|
|
361
|
+
robot.move_sequence(["a", "b", "c"], blend_radius=0.02)
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
#### Contact Detection
|
|
365
|
+
|
|
366
|
+
```python
|
|
367
|
+
robot.move_until_contact([0, 0, -0.02, 0, 0, 0]) # Ctrl+C to stop
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
#### Velocity Control
|
|
371
|
+
|
|
372
|
+
```python
|
|
373
|
+
robot.move_velocity([0, 0, -0.02, 0, 0, 0], duration=1.0)
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
#### Freedrive Mode
|
|
377
|
+
|
|
378
|
+
```python
|
|
379
|
+
from urkit import FreedriveMode
|
|
380
|
+
|
|
381
|
+
robot.enable_freedrive() # all 6 axes free
|
|
382
|
+
robot.enable_freedrive(FreedriveMode.XYZ) # linear axes + Rz rotation
|
|
383
|
+
robot.enable_freedrive(FreedriveMode.ROTATION) # rotation only
|
|
384
|
+
robot.disable_freedrive() # disable before sending motion commands
|
|
385
|
+
robot.is_freedrive_active # check state
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
#### Speed Control
|
|
389
|
+
|
|
390
|
+
```python
|
|
391
|
+
robot.speed_stop() # emergency stop
|
|
392
|
+
robot.set_speed_slider(0.5) # 50% hardware velocity cap
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
The speed slider is a hardware-level multiplier — same as the physical slider on the pendant. It's global, persistent, and affects all motion commands.
|
|
396
|
+
|
|
397
|
+
#### Inverse Kinematics
|
|
398
|
+
|
|
399
|
+
```python
|
|
400
|
+
joints = robot.inverse_kinematics([0.5, 0, 0.3, 0, 0, 0])
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
### Telemetry
|
|
404
|
+
|
|
405
|
+
```python
|
|
406
|
+
pose = robot.get_tcp_pose() # [x, y, z, rx, ry, rz]
|
|
407
|
+
joints = robot.get_joint_positions() # [j0..j5]
|
|
408
|
+
force = robot.get_tcp_force() # [fx, fy, fz, mx, my, mz]
|
|
409
|
+
mode = robot.get_robot_mode() # "REMOTE_CONTROL", "SERVOING", etc.
|
|
410
|
+
scaling = robot.get_speed_scaling() # 0.0-1.0
|
|
411
|
+
payload = robot.get_payload() # kg
|
|
412
|
+
robot.is_protective_stopped() # bool
|
|
413
|
+
robot.is_emergency_stopped() # bool
|
|
414
|
+
robot.current_point() # {"pose": [...], "joints": [...]}
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
### Digital I/O
|
|
418
|
+
|
|
419
|
+
```python
|
|
420
|
+
robot.set_digital_output(0, True)
|
|
421
|
+
robot.set_digital_outputs({0: True, 1: False, 8: True})
|
|
422
|
+
robot.set_digital_outputs(False) # clear all
|
|
423
|
+
|
|
424
|
+
robot.get_digital_input(0)
|
|
425
|
+
robot.get_analog_input(0)
|
|
426
|
+
robot.get_tool_input(0)
|
|
427
|
+
|
|
428
|
+
robot.wait_for_input(0, True, timeout=10.0) # block until pin 0 goes high
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
---
|
|
432
|
+
|
|
433
|
+
## Configuration
|
|
434
|
+
|
|
435
|
+
URKit uses a YAML config file (`config.yaml`) to persist settings between sessions.
|
|
436
|
+
|
|
437
|
+
### Location
|
|
438
|
+
|
|
439
|
+
URKit searches for `config.yaml` in this order:
|
|
440
|
+
1. Explicit path via `--config` flag or `load_config("path")`
|
|
441
|
+
2. Project root (where `src/urkit` lives)
|
|
442
|
+
3. Current working directory
|
|
443
|
+
|
|
444
|
+
### Keys
|
|
445
|
+
|
|
446
|
+
| Key | Description | Example |
|
|
447
|
+
|-----|-------------|---------|
|
|
448
|
+
| `robot_ip` | Robot IP address | `192.168.1.100` |
|
|
449
|
+
| `points_path` | Path to SQLite points database | `points.db` |
|
|
450
|
+
| `gripper` | Gripper preset name | `hand-e`, `2f-85`, `2f-140`, `digital` |
|
|
451
|
+
| `default_vel` | Default linear velocity (m/s) | `0.5` |
|
|
452
|
+
| `default_acc` | Default linear acceleration (m/s²) | `0.3` |
|
|
453
|
+
|
|
454
|
+
### Gripper Config
|
|
455
|
+
|
|
456
|
+
```yaml
|
|
457
|
+
gripper: digital
|
|
458
|
+
gripper_config:
|
|
459
|
+
pin: 3
|
|
460
|
+
close_on_high: true
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
```yaml
|
|
464
|
+
gripper: hand-e
|
|
465
|
+
gripper_config:
|
|
466
|
+
force: 50
|
|
467
|
+
speed: 80
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
### CLI Override Precedence
|
|
471
|
+
|
|
472
|
+
1. **CLI flags** — `urkit teach 172.31.1.200 --gripper none`
|
|
473
|
+
2. **Config file** — values from `config.yaml`
|
|
474
|
+
3. **Built-in defaults** — `points.db`, no gripper, 0.5 m/s velocity
|
|
475
|
+
|
|
476
|
+
### Saving Config
|
|
477
|
+
|
|
478
|
+
The CLI **never** modifies your config file automatically. Press **Y** inside the teach pendant to save. This way you only save settings you've actually tested.
|
|
479
|
+
|
|
480
|
+
```bash
|
|
481
|
+
urkit teach 172.31.1.200 --gripper hand-e # test, then press Y
|
|
482
|
+
urkit teach # next time: reads from config
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
Multiple workcells:
|
|
486
|
+
|
|
487
|
+
```bash
|
|
488
|
+
urkit teach --config station_a.yaml # press Y to save
|
|
489
|
+
urkit teach --config station_b.yaml # separate config
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
### Programmatic
|
|
493
|
+
|
|
494
|
+
```python
|
|
495
|
+
from urkit import load_config, resolve_config
|
|
496
|
+
|
|
497
|
+
config = load_config() # auto-resolve
|
|
498
|
+
config = load_config("/path/to/my.yaml") # explicit path
|
|
499
|
+
path = resolve_config() # returns Path or None
|
|
500
|
+
robot = URRobot.from_config({"robot_ip": "172.31.1.200", "gripper": "2f-85"})
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
---
|
|
504
|
+
|
|
505
|
+
## Advanced
|
|
506
|
+
|
|
507
|
+
### Raw RTDE Access
|
|
508
|
+
|
|
509
|
+
URKit doesn't try to wrap everything. Access the raw `ur_rtde` interfaces for advanced features:
|
|
510
|
+
|
|
511
|
+
```python
|
|
512
|
+
robot.rtde_control.moveUntilContact([0, 0, -0.02, 0, 0, 0])
|
|
513
|
+
robot.rtde_control.forceMode(...)
|
|
514
|
+
robot.rtde_control.servoJ(...)
|
|
515
|
+
robot.rtde_receive.getActualCurrent()
|
|
516
|
+
```
|
|
517
|
+
|
|
518
|
+
Full `ur_rtde` documentation: <https://sdurobotics.gitlab.io/ur_rtde/>
|
|
519
|
+
|
|
520
|
+
### Connection Lifecycle
|
|
521
|
+
|
|
522
|
+
```python
|
|
523
|
+
robot.connection_lost # bool: check if RTDE dropped
|
|
524
|
+
robot.reconnect_rtde() # reconnect after a drop
|
|
525
|
+
robot.disconnect() # clean shutdown
|
|
526
|
+
```
|
|
527
|
+
|
|
528
|
+
### Error Handling
|
|
529
|
+
|
|
530
|
+
```python
|
|
531
|
+
from urkit import URKitError, RobotNotInRemoteModeError, RtdeRegisterConflictError
|
|
532
|
+
|
|
533
|
+
try:
|
|
534
|
+
robot = URRobot(ip="172.31.1.200", points="points.db")
|
|
535
|
+
except RobotNotInRemoteModeError:
|
|
536
|
+
print("Enable remote control on the teach pendant!")
|
|
537
|
+
except RtdeRegisterConflictError:
|
|
538
|
+
print("Disable EtherNet/IP, PROFINET, or MODBUS!")
|
|
539
|
+
except URKitError as e:
|
|
540
|
+
print(f"Error: {e}")
|
|
541
|
+
```
|