urkit 0.3.24__tar.gz → 0.3.26__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.3.24 → urkit-0.3.26}/PKG-INFO +251 -111
- {urkit-0.3.24 → urkit-0.3.26}/README.md +250 -110
- {urkit-0.3.24 → urkit-0.3.26}/pyproject.toml +1 -1
- {urkit-0.3.24 → urkit-0.3.26}/src/urkit/__init__.py +3 -5
- {urkit-0.3.24 → urkit-0.3.26}/src/urkit/cli/points.py +1 -1
- {urkit-0.3.24 → urkit-0.3.26}/src/urkit/cli/teach.py +4 -6
- {urkit-0.3.24 → urkit-0.3.26}/src/urkit/config.py +7 -12
- {urkit-0.3.24 → urkit-0.3.26}/src/urkit/robot.py +2 -2
- {urkit-0.3.24 → urkit-0.3.26}/src/urkit.egg-info/PKG-INFO +251 -111
- {urkit-0.3.24 → urkit-0.3.26}/setup.cfg +0 -0
- {urkit-0.3.24 → urkit-0.3.26}/src/urkit/__main__.py +0 -0
- {urkit-0.3.24 → urkit-0.3.26}/src/urkit/cli/__init__.py +0 -0
- {urkit-0.3.24 → urkit-0.3.26}/src/urkit/cli/colors.py +0 -0
- {urkit-0.3.24 → urkit-0.3.26}/src/urkit/cli/connection_monitor.py +0 -0
- {urkit-0.3.24 → urkit-0.3.26}/src/urkit/connection.py +0 -0
- {urkit-0.3.24 → urkit-0.3.26}/src/urkit/exceptions.py +0 -0
- {urkit-0.3.24 → urkit-0.3.26}/src/urkit/geometry.py +0 -0
- {urkit-0.3.24 → urkit-0.3.26}/src/urkit/gripper/__init__.py +0 -0
- {urkit-0.3.24 → urkit-0.3.26}/src/urkit/gripper/base.py +0 -0
- {urkit-0.3.24 → urkit-0.3.26}/src/urkit/gripper/digital.py +0 -0
- {urkit-0.3.24 → urkit-0.3.26}/src/urkit/gripper/presets.py +0 -0
- {urkit-0.3.24 → urkit-0.3.26}/src/urkit/gripper/robotiq.py +0 -0
- {urkit-0.3.24 → urkit-0.3.26}/src/urkit/gripper/robotiq_preamble.py +0 -0
- {urkit-0.3.24 → urkit-0.3.26}/src/urkit/io.py +0 -0
- {urkit-0.3.24 → urkit-0.3.26}/src/urkit/motion.py +0 -0
- {urkit-0.3.24 → urkit-0.3.26}/src/urkit/points.py +0 -0
- {urkit-0.3.24 → urkit-0.3.26}/src/urkit/telemetry.py +0 -0
- {urkit-0.3.24 → urkit-0.3.26}/src/urkit.egg-info/SOURCES.txt +0 -0
- {urkit-0.3.24 → urkit-0.3.26}/src/urkit.egg-info/dependency_links.txt +0 -0
- {urkit-0.3.24 → urkit-0.3.26}/src/urkit.egg-info/entry_points.txt +0 -0
- {urkit-0.3.24 → urkit-0.3.26}/src/urkit.egg-info/requires.txt +0 -0
- {urkit-0.3.24 → urkit-0.3.26}/src/urkit.egg-info/top_level.txt +0 -0
- {urkit-0.3.24 → urkit-0.3.26}/tests/test_exceptions.py +0 -0
- {urkit-0.3.24 → urkit-0.3.26}/tests/test_geometry.py +0 -0
- {urkit-0.3.24 → urkit-0.3.26}/tests/test_gripper.py +0 -0
- {urkit-0.3.24 → urkit-0.3.26}/tests/test_gripper_factory.py +0 -0
- {urkit-0.3.24 → urkit-0.3.26}/tests/test_gripper_presets.py +0 -0
- {urkit-0.3.24 → urkit-0.3.26}/tests/test_move_sequence.py +0 -0
- {urkit-0.3.24 → urkit-0.3.26}/tests/test_points.py +0 -0
- {urkit-0.3.24 → urkit-0.3.26}/tests/test_robot_integration.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: urkit
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.26
|
|
4
4
|
Summary: Universal Robots e-Series control toolkit built on ur_rtde
|
|
5
5
|
Author: URKit Contributors
|
|
6
6
|
License: MIT
|
|
@@ -37,6 +37,12 @@ Built on [`ur_rtde`](https://sdurobotics.gitlab.io/ur_rtde/), it packages the op
|
|
|
37
37
|
## Table of Contents
|
|
38
38
|
|
|
39
39
|
- [Quick Start](#quick-start)
|
|
40
|
+
- [Configuration](#configuration)
|
|
41
|
+
- [Location](#location)
|
|
42
|
+
- [Keys](#keys)
|
|
43
|
+
- [Gripper Config](#gripper-config)
|
|
44
|
+
- [Saving Config](#saving-config)
|
|
45
|
+
- [Programmatic](#programmatic)
|
|
40
46
|
- [Interactive CLI](#interactive-cli)
|
|
41
47
|
- [Teach Mode](#teach-mode)
|
|
42
48
|
- [Points Explorer](#points-explorer)
|
|
@@ -46,8 +52,10 @@ Built on [`ur_rtde`](https://sdurobotics.gitlab.io/ur_rtde/), it packages the op
|
|
|
46
52
|
- [Grippers](#grippers)
|
|
47
53
|
- [Points & Motion](#points--motion)
|
|
48
54
|
- [Telemetry](#telemetry)
|
|
55
|
+
- [More API](#more-api)
|
|
49
56
|
- [Digital I/O](#digital-io)
|
|
50
|
-
- [
|
|
57
|
+
- [Geometry](#geometry)
|
|
58
|
+
- [Robot Lifecycle](#robot-lifecycle)
|
|
51
59
|
- [Advanced](#advanced)
|
|
52
60
|
- [Raw RTDE Access](#raw-rtde-access)
|
|
53
61
|
- [Connection Lifecycle](#connection-lifecycle)
|
|
@@ -102,6 +110,100 @@ The typical workflow:
|
|
|
102
110
|
|
|
103
111
|
---
|
|
104
112
|
|
|
113
|
+
## Configuration
|
|
114
|
+
|
|
115
|
+
URKit uses a YAML config file (`config.yaml`) to persist settings between sessions.
|
|
116
|
+
|
|
117
|
+
### Location
|
|
118
|
+
|
|
119
|
+
URKit searches for `config.yaml` in the current working directory, or an explicit path via `--config`.
|
|
120
|
+
|
|
121
|
+
### Keys
|
|
122
|
+
|
|
123
|
+
| Key | Description | Example |
|
|
124
|
+
|-----|-------------|---------|
|
|
125
|
+
| `robot_ip` | Robot IP address | `192.168.1.50` |
|
|
126
|
+
| `points_path` | Path to SQLite points database | `points.db` |
|
|
127
|
+
| `gripper` | Gripper preset name | `hand-e`, `2f-85`, `2f-140`, `digital` |
|
|
128
|
+
| `ik_reference` | IK reference posture (prevents elbow flipping) | `home` |
|
|
129
|
+
| `default_vel` | Default linear velocity (m/s) | `0.5` |
|
|
130
|
+
| `default_acc` | Default linear acceleration (m/s²) | `0.3` |
|
|
131
|
+
| `expert_mode` | Disable safety speed clamping | `false` |
|
|
132
|
+
|
|
133
|
+
### Gripper Config
|
|
134
|
+
|
|
135
|
+
Built-in preset with overrides:
|
|
136
|
+
|
|
137
|
+
```yaml
|
|
138
|
+
gripper: hand-e
|
|
139
|
+
gripper_config:
|
|
140
|
+
force: 50
|
|
141
|
+
speed: 80
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Digital I/O gripper:
|
|
145
|
+
|
|
146
|
+
```yaml
|
|
147
|
+
gripper: digital
|
|
148
|
+
gripper_config:
|
|
149
|
+
pin: 3
|
|
150
|
+
close_on_high: true
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Custom gripper (arbitrary payload + TCP offset, no backend):
|
|
154
|
+
|
|
155
|
+
```yaml
|
|
156
|
+
gripper:
|
|
157
|
+
mass: 0.5
|
|
158
|
+
center_of_gravity: [0.0, 0.0, 0.0]
|
|
159
|
+
tcp_offset: [0.0, 0.0, 0.175, 0.0, 0.0, 0.0]
|
|
160
|
+
backend: none
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Override physical properties on a built-in preset:
|
|
164
|
+
|
|
165
|
+
```yaml
|
|
166
|
+
gripper: 2f-85
|
|
167
|
+
gripper_config:
|
|
168
|
+
mass: 1.2
|
|
169
|
+
center_of_gravity: [0.0, 0.0, 0.07]
|
|
170
|
+
tcp_offset: [0.0, 0.0, 0.200, 0.0, 0.0, 0.0]
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### CLI Override Precedence
|
|
174
|
+
|
|
175
|
+
1. **CLI flags.** `urkit teach 192.168.1.50 --gripper none`
|
|
176
|
+
2. **Config file.** Values from `config.yaml`
|
|
177
|
+
3. **Built-in defaults.** `points.db`, no gripper, 0.5 m/s velocity
|
|
178
|
+
|
|
179
|
+
### Saving Config
|
|
180
|
+
|
|
181
|
+
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.
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
urkit teach 192.168.1.50 --gripper hand-e # test, then press Y
|
|
185
|
+
urkit teach # next time: reads from config
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
Multiple workcells:
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
urkit teach --config station_a.yaml # press Y to save
|
|
192
|
+
urkit teach --config station_b.yaml # separate config
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### Programmatic
|
|
196
|
+
|
|
197
|
+
```python
|
|
198
|
+
from urkit import URRobot
|
|
199
|
+
|
|
200
|
+
robot = URRobot.from_config("config.yaml")
|
|
201
|
+
robot = URRobot.from_config("config.yaml", ip="10.0.0.50") # override IP
|
|
202
|
+
robot = URRobot.from_config({"robot_ip": "192.168.1.50", "gripper": "2f-85"}) # dict, no file
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
---
|
|
206
|
+
|
|
105
207
|
## Interactive CLI
|
|
106
208
|
|
|
107
209
|
URKit provides two CLI tools: **teach** for interactive robot control, and **points** for browsing saved waypoints.
|
|
@@ -192,7 +294,6 @@ All movement and orientation keys support **hold-to-repeat**.
|
|
|
192
294
|
<tr><td><code>V</code></td><td>Set position (mm)</td></tr>
|
|
193
295
|
<tr><td><code>6</code></td><td>Set speed (0-100)</td></tr>
|
|
194
296
|
<tr><td><code>7</code></td><td>Set force (0-100)</td></tr>
|
|
195
|
-
<tr><td colspan="3">Gripper line shows: `Connected 25.0mm (50%) F=100 S=100`</td></tr>
|
|
196
297
|
</table>
|
|
197
298
|
</td>
|
|
198
299
|
<td align="center" style="width:33%">
|
|
@@ -211,7 +312,7 @@ All movement and orientation keys support **hold-to-repeat**.
|
|
|
211
312
|
<tr><td><code>F</code></td><td>Freedrive (OFF → ALL → XYZ+Rz)</td></tr>
|
|
212
313
|
<tr><td><code>M</code></td><td>Toggle frame (BASE / TOOL)</td></tr>
|
|
213
314
|
<tr><td><code>N</code></td><td>Go To mode (Cartesian / Joint)</td></tr>
|
|
214
|
-
<tr><td><code>T</code></td><td>
|
|
315
|
+
<tr><td><code>T</code></td><td>Open TCP orient submenu (6 directions)</td></tr>
|
|
215
316
|
<tr><td><code>Y</code></td><td>Save config to file</td></tr>
|
|
216
317
|
<tr><td><code>ESC</code></td><td>Exit</td></tr>
|
|
217
318
|
</table>
|
|
@@ -224,10 +325,10 @@ All movement and orientation keys support **hold-to-repeat**.
|
|
|
224
325
|
The teach pendant shows live joint angles alongside TCP position and orientation:
|
|
225
326
|
|
|
226
327
|
```
|
|
227
|
-
Position
|
|
228
|
-
Orientation
|
|
229
|
-
Joints
|
|
230
|
-
|
|
328
|
+
Position X=+0.432 Y=+0.111 Z=+0.227
|
|
329
|
+
Orientation R=+131.3 P=-121.0 Y= +8.0
|
|
330
|
+
Joints J1=+150.0 J2=+ 20.0 J3=+160.0
|
|
331
|
+
J4=+ 50.0 J5=- 80.0 J6=+157.0
|
|
231
332
|
```
|
|
232
333
|
|
|
233
334
|
Joint angles color-code proximity to mechanical limits:
|
|
@@ -237,20 +338,20 @@ Joint angles color-code proximity to mechanical limits:
|
|
|
237
338
|
|
|
238
339
|
UR e-Series joint limits:
|
|
239
340
|
|
|
240
|
-
| Joint | Range |
|
|
241
|
-
|
|
242
|
-
| J1 (shoulder pan) | ±360° |
|
|
243
|
-
| J2 (shoulder lift) | ±360° |
|
|
244
|
-
| J3 (elbow) | ±
|
|
245
|
-
| J4 (wrist 1) | ±360° |
|
|
246
|
-
| J5 (wrist 2) | ±360° |
|
|
247
|
-
| J6 (wrist 3) | ±360° |
|
|
341
|
+
| Joint | Range |
|
|
342
|
+
|-------|-------|
|
|
343
|
+
| J1 (shoulder pan) | ±360° |
|
|
344
|
+
| J2 (shoulder lift) | ±360° |
|
|
345
|
+
| J3 (elbow) | ±360° |
|
|
346
|
+
| J4 (wrist 1) | ±360° |
|
|
347
|
+
| J5 (wrist 2) | ±360° |
|
|
348
|
+
| J6 (wrist 3) | ±360° |
|
|
349
|
+
|
|
248
350
|
|
|
249
|
-
Thresholds scale with each joint's range, so warning zones feel proportional across all joints.
|
|
250
351
|
|
|
251
352
|
### Safety
|
|
252
353
|
|
|
253
|
-
By default, **Go To** and **TCP
|
|
354
|
+
By default, **Go To** and **TCP orient** movements use a slow velocity (0.125 m/s) so its safer for anyone standing near the robot. The user's speed slider still applies as a global multiplier on top of this.
|
|
254
355
|
|
|
255
356
|
Delta movements (W/S/A/D/Q/E) use step-size-based velocities that scale with the speed slider set by the user.
|
|
256
357
|
|
|
@@ -289,12 +390,9 @@ robot = URRobot(
|
|
|
289
390
|
)
|
|
290
391
|
```
|
|
291
392
|
|
|
292
|
-
|
|
393
|
+
See [Configuration](#configuration) for `from_config()` usage.
|
|
293
394
|
|
|
294
|
-
|
|
295
|
-
robot = URRobot.from_config("config.yaml")
|
|
296
|
-
robot = URRobot.from_config("config.yaml", ip="10.0.0.50") # override IP
|
|
297
|
-
```
|
|
395
|
+
The constructor takes a few seconds on first call: it validates the connection, checks remote mode, powers on the robot, releases brakes, and connects RTDE. Subsequent calls are faster if the robot is already running.
|
|
298
396
|
|
|
299
397
|
### Grippers
|
|
300
398
|
|
|
@@ -302,21 +400,25 @@ Three built-in presets:
|
|
|
302
400
|
|
|
303
401
|
| Preset | Description |
|
|
304
402
|
|--------|-------------|
|
|
305
|
-
| `ROBOTIQ_HAND_E` | Robotiq
|
|
403
|
+
| `ROBOTIQ_HAND_E` | Robotiq Hand-E (2F-85-E) |
|
|
306
404
|
| `ROBOTIQ_2F_85` | Robotiq 2F-85 |
|
|
307
405
|
| `ROBOTIQ_2F_140` | Robotiq 2F-140 |
|
|
308
406
|
|
|
309
407
|
```python
|
|
310
408
|
robot.gripper.activate() # required before open/close (Robotiq only)
|
|
409
|
+
robot.gripper.deactivate() # deactivate (Robotiq only)
|
|
311
410
|
robot.gripper.is_activated() # check activation state
|
|
312
411
|
|
|
313
412
|
robot.gripper.open() # fully open (blocking by default)
|
|
314
413
|
robot.gripper.close() # fully closed, stops on contact
|
|
315
|
-
robot.gripper.open(wait=False) # non-blocking return
|
|
316
|
-
robot.gripper.set_position_mm(20) # 20mm open (Robotiq only, 0 = closed)
|
|
317
|
-
robot.gripper.set_position_percent(50) # 50% open (Robotiq only, 0 = open, 100 = closed)
|
|
414
|
+
robot.gripper.open(wait=False) # non-blocking return (waits for position)
|
|
415
|
+
robot.gripper.set_position_mm(20) # 20mm open (Robotiq only, 0 = fully closed)
|
|
416
|
+
robot.gripper.set_position_percent(50) # 50% open (Robotiq only, 0 = fully open, 100 = fully closed)
|
|
318
417
|
robot.gripper.set_force(50) # grip force: 0-100 (Robotiq only)
|
|
319
418
|
robot.gripper.set_speed(80) # movement speed: 0-100 (Robotiq only)
|
|
419
|
+
|
|
420
|
+
robot.gripper.get_position_mm() # last commanded position in mm
|
|
421
|
+
robot.gripper.max_travel_mm() # max finger travel (e.g. 85.0 for 2F-85)
|
|
320
422
|
```
|
|
321
423
|
|
|
322
424
|
Override preset values for custom fingers:
|
|
@@ -325,6 +427,19 @@ Override preset values for custom fingers:
|
|
|
325
427
|
robot = URRobot(ip="192.168.1.50", points="points.db", gripper=ROBOTIQ_HAND_E, max_mm=120)
|
|
326
428
|
```
|
|
327
429
|
|
|
430
|
+
Override physical properties (e.g., custom fingers or added hardware change the weight):
|
|
431
|
+
|
|
432
|
+
```python
|
|
433
|
+
robot = URRobot(
|
|
434
|
+
ip="192.168.1.50",
|
|
435
|
+
points="points.db",
|
|
436
|
+
gripper=ROBOTIQ_HAND_E,
|
|
437
|
+
mass=1.2, # override preset mass
|
|
438
|
+
center_of_gravity=[0.0, 0.0, 0.07], # override CoG
|
|
439
|
+
tcp_offset=[0.0, 0.0, 0.180, 0, 0, 0], # override TCP offset
|
|
440
|
+
)
|
|
441
|
+
```
|
|
442
|
+
|
|
328
443
|
#### Digital I/O Grippers
|
|
329
444
|
|
|
330
445
|
Robotiq grippers use a serial protocol over the robot's RS485 port. If you have a suction cup, solenoid, or any actuator controlled by a single digital output pin, use `DigitalGripperConfig` instead. It just turns that pin on (close) and off (open).
|
|
@@ -360,6 +475,7 @@ robot.move_to("pick") # linear move (default)
|
|
|
360
475
|
robot.move_to("pick", linear=False) # joint move
|
|
361
476
|
robot.move_to("pick", vel=1.0, acc=0.5) # override speed
|
|
362
477
|
robot.move_to("pick", asynchronous=True) # non-blocking, returns immediately
|
|
478
|
+
robot.move_to([0.5, 0, 0.3, 0, 0, 0]) # raw pose (no points DB needed)
|
|
363
479
|
```
|
|
364
480
|
|
|
365
481
|
- **Linear (moveL):** TCP moves in a straight line. Predictable path, slower near complex orientations.
|
|
@@ -377,11 +493,11 @@ robot.move_to("pick", asynchronous=True)
|
|
|
377
493
|
while robot.is_moving():
|
|
378
494
|
time.sleep(0.01)
|
|
379
495
|
|
|
380
|
-
# Or cancel mid-move
|
|
496
|
+
# Or cancel mid-move (see [Speed Control](#speed-control) for `stop()`)
|
|
381
497
|
robot.move_to("pick", asynchronous=True)
|
|
382
498
|
while robot.is_moving():
|
|
383
499
|
if should_cancel:
|
|
384
|
-
robot.stop()
|
|
500
|
+
robot.stop()
|
|
385
501
|
break
|
|
386
502
|
time.sleep(0.01)
|
|
387
503
|
```
|
|
@@ -461,12 +577,10 @@ robot.move_to("back", ik_reference="current") # use current joints
|
|
|
461
577
|
|
|
462
578
|
**When to use it:** Almost always. If you've ever seen the robot move in a way that looked "wrong" or flipped its elbow unexpectedly, this is what fixes it. Set it once in config.yaml and forget about it.
|
|
463
579
|
|
|
464
|
-
#### Points are tool-agnostic
|
|
465
|
-
|
|
466
|
-
Points are stored in the active TCP frame, so they work with any tool. If you swap grippers and set the correct TCP offset, your saved points remain valid.
|
|
467
|
-
|
|
468
580
|
#### Point Management
|
|
469
581
|
|
|
582
|
+
Points are stored in the active TCP frame, so they work with any tool — swap grippers and your saved points stay valid.
|
|
583
|
+
|
|
470
584
|
```python
|
|
471
585
|
robot.save_point("here")
|
|
472
586
|
robot.point_names() # ["home", "pick", "place"]
|
|
@@ -481,9 +595,21 @@ robot.import_points("backup.json")
|
|
|
481
595
|
```python
|
|
482
596
|
robot.move_relative(delta_y=0.01) # 1cm along Y
|
|
483
597
|
robot.move_relative(delta_z=0.05, frame=MoveFrame.TOOL) # 5cm along tool Z
|
|
484
|
-
robot.move_relative([0, 0.01, 0, 0, 0, 0])
|
|
598
|
+
robot.move_relative([0, 0.01, 0, 0, 0, 0]) # full 6-element delta
|
|
599
|
+
```
|
|
600
|
+
|
|
601
|
+
Individual delta parameters (`delta_x`, `delta_y`, `delta_z`, `delta_rx`, `delta_ry`, `delta_rz`) are mutually exclusive with the `delta` list — use one or the other.
|
|
602
|
+
|
|
603
|
+
#### Sequences
|
|
604
|
+
|
|
605
|
+
```python
|
|
606
|
+
robot.move_relative(delta_y=0.01) # 1cm along Y
|
|
607
|
+
robot.move_relative(delta_z=0.05, frame=MoveFrame.TOOL) # 5cm along tool Z
|
|
608
|
+
robot.move_relative([0, 0.01, 0, 0, 0, 0]) # full 6-element delta
|
|
485
609
|
```
|
|
486
610
|
|
|
611
|
+
Individual delta parameters (`delta_x`, `delta_y`, `delta_z`, `delta_rx`, `delta_ry`, `delta_rz`) are mutually exclusive with the `delta` list — use one or the other.
|
|
612
|
+
|
|
487
613
|
#### Sequences
|
|
488
614
|
|
|
489
615
|
```python
|
|
@@ -491,6 +617,24 @@ robot.move_relative([0, 0.01, 0, 0, 0, 0])
|
|
|
491
617
|
robot.move_sequence(["a", "b", "c"])
|
|
492
618
|
```
|
|
493
619
|
|
|
620
|
+
With **IK reference** (recommended), all poses resolve to joints using chained inverse kinematics — the first pose resolves relative to the reference, the second relative to the first's resolved joints, and so on. This keeps the arm configuration consistent throughout the sequence:
|
|
621
|
+
|
|
622
|
+
```python
|
|
623
|
+
robot.ik_reference = "home"
|
|
624
|
+
robot.move_sequence(["a", "b", "c"]) # chained IK, no elbow flipping
|
|
625
|
+
```
|
|
626
|
+
|
|
627
|
+
With **blend_radius**, the robot rounds corners instead of stopping at each waypoint:
|
|
628
|
+
|
|
629
|
+
```python
|
|
630
|
+
robot.move_sequence(
|
|
631
|
+
["a", "b", "c"],
|
|
632
|
+
blend_radius=0.02, # 2cm blend between waypoints
|
|
633
|
+
)
|
|
634
|
+
```
|
|
635
|
+
|
|
636
|
+
`move_sequence` requires at least 2 targets. Without `ik_reference`, it falls back to individual `moveL` calls (legacy behavior, no blending).
|
|
637
|
+
|
|
494
638
|
#### Contact Detection
|
|
495
639
|
|
|
496
640
|
```python
|
|
@@ -514,7 +658,7 @@ for _ in range(3):
|
|
|
514
658
|
if robot.move_until_contact(speed_z=-0.02, timeout=10.0, max_distance=0.2):
|
|
515
659
|
break # contact detected
|
|
516
660
|
# No contact — back off and retry
|
|
517
|
-
robot.
|
|
661
|
+
robot.move_relative(delta_z=0.01)
|
|
518
662
|
|
|
519
663
|
# Manual zero (e.g. before custom force-based logic)
|
|
520
664
|
robot.zero_ft_sensor()
|
|
@@ -564,8 +708,6 @@ robot.default_vel # read current velocity (m/s)
|
|
|
564
708
|
robot.default_acc # read current acceleration (m/s²)
|
|
565
709
|
```
|
|
566
710
|
|
|
567
|
-
Soft warnings log when values exceed typical robot limits (> 2 m/s for velocity, > 6 m/s² for acceleration). The controller may clamp aggressive values based on payload and configuration.
|
|
568
|
-
|
|
569
711
|
#### Inverse Kinematics
|
|
570
712
|
|
|
571
713
|
```python
|
|
@@ -580,116 +722,121 @@ joints = robot.get_joint_positions() # [j0..j5]
|
|
|
580
722
|
force = robot.get_tcp_force() # [fx, fy, fz, mx, my, mz]
|
|
581
723
|
mode = robot.get_robot_mode() # "REMOTE_CONTROL", "SERVOING", etc.
|
|
582
724
|
payload = robot.get_payload() # kg
|
|
583
|
-
robot.
|
|
725
|
+
robot.current_point() # {"pose": [...], "joints": [...]}
|
|
584
726
|
robot.is_protective_stopped() # bool
|
|
585
727
|
robot.is_emergency_stopped() # bool
|
|
586
|
-
robot.
|
|
587
|
-
robot.
|
|
588
|
-
robot.is_at_joints(target) # bool — all joints within 0.001 rad
|
|
728
|
+
robot.is_remote_mode() # bool — check remote control state
|
|
729
|
+
robot.get_polyscope_version() # e.g. "5.25.0" or None
|
|
589
730
|
```
|
|
590
731
|
|
|
591
|
-
|
|
732
|
+
#### Arrival Detection
|
|
733
|
+
|
|
734
|
+
`is_moving()` tracks the target pose or joints stored by `move_to()` and compares against the current position. Returns `False` when within tolerance:
|
|
592
735
|
|
|
593
736
|
```python
|
|
594
737
|
robot.move_to("pick", asynchronous=True)
|
|
595
738
|
|
|
596
|
-
#
|
|
739
|
+
# Wait until arrived (default tolerances: 2mm position, ~2° orientation)
|
|
597
740
|
while robot.is_moving():
|
|
598
741
|
time.sleep(0.01)
|
|
599
742
|
|
|
600
|
-
#
|
|
601
|
-
while
|
|
743
|
+
# Tighter tolerances
|
|
744
|
+
while robot.is_moving(position_tolerance=0.001, orientation_tolerance=0.017):
|
|
745
|
+
time.sleep(0.01)
|
|
746
|
+
|
|
747
|
+
# Joint moves — tighter joint tolerance
|
|
748
|
+
while robot.is_moving(joint_tolerance=0.001):
|
|
602
749
|
time.sleep(0.01)
|
|
603
750
|
```
|
|
604
751
|
|
|
752
|
+
For joint-space moves (when `ik_reference` is active or `linear=False`), `is_moving()` compares joint angles. For Cartesian moves, it compares TCP pose. When no target is set (e.g., after a relative move without `move_to`), it returns `False`.
|
|
753
|
+
|
|
754
|
+
---
|
|
755
|
+
|
|
756
|
+
## More API
|
|
757
|
+
|
|
758
|
+
Less common but useful when you need them.
|
|
759
|
+
|
|
605
760
|
### Digital I/O
|
|
606
761
|
|
|
762
|
+
Pins 0–7 are standard, 8–15 configurable, 16–17 tool.
|
|
763
|
+
|
|
607
764
|
```python
|
|
765
|
+
# Outputs
|
|
608
766
|
robot.set_digital_output(0, True)
|
|
609
767
|
robot.set_digital_outputs({0: True, 1: False, 8: True})
|
|
610
|
-
robot.set_digital_outputs(False) # clear all
|
|
768
|
+
robot.set_digital_outputs(False) # clear all pins 0–15
|
|
769
|
+
robot.get_digital_output(0) # read back output state
|
|
611
770
|
|
|
771
|
+
# Inputs
|
|
612
772
|
robot.get_digital_input(0)
|
|
613
|
-
robot.get_analog_input(0)
|
|
614
|
-
robot.get_tool_input(0)
|
|
615
|
-
|
|
616
773
|
robot.wait_for_input(0, True, timeout=10.0) # block until pin 0 goes high
|
|
617
|
-
```
|
|
618
|
-
|
|
619
|
-
---
|
|
620
774
|
|
|
621
|
-
|
|
775
|
+
# Analog
|
|
776
|
+
robot.get_analog_input(0) # read analog input (pin 0–1)
|
|
777
|
+
robot.get_analog_output(0) # read analog output (pin 0–1)
|
|
622
778
|
|
|
623
|
-
|
|
779
|
+
# Tool I/O
|
|
780
|
+
robot.get_tool_input(0) # tool digital input (pin 0–1)
|
|
781
|
+
robot.get_tool_output(0) # tool digital output (pin 0–1)
|
|
782
|
+
```
|
|
624
783
|
|
|
625
|
-
###
|
|
784
|
+
### Geometry
|
|
626
785
|
|
|
627
|
-
|
|
628
|
-
1. Explicit path via `--config` flag or `load_config("path")`
|
|
629
|
-
2. Project root (where `src/urkit` lives)
|
|
630
|
-
3. Current working directory
|
|
786
|
+
Conversion utilities for rotation vectors, quaternions, and RPY angles (rxyz convention, same as UR teach pendant):
|
|
631
787
|
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
| `default_acc` | Default linear acceleration (m/s²) | `0.3` |
|
|
642
|
-
| `expert_mode` | Disable safety speed clamping | `false` |
|
|
788
|
+
```python
|
|
789
|
+
from urkit import (
|
|
790
|
+
orient_tcp,
|
|
791
|
+
orient_tcp_down,
|
|
792
|
+
quat_to_rotvec,
|
|
793
|
+
quat_to_rpy,
|
|
794
|
+
rpy_to_quat,
|
|
795
|
+
rotvec_to_quat,
|
|
796
|
+
)
|
|
643
797
|
|
|
644
|
-
|
|
798
|
+
# Orient TCP along an arbitrary direction (minimal rotation)
|
|
799
|
+
new_pose = orient_tcp(current_pose, [0, 0, -1]) # point down
|
|
800
|
+
new_pose = orient_tcp(current_pose, [1, 0, 0]) # point forward
|
|
645
801
|
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
gripper_config:
|
|
649
|
-
pin: 3
|
|
650
|
-
close_on_high: true
|
|
651
|
-
```
|
|
802
|
+
# Orient TCP straight down (convenience wrapper)
|
|
803
|
+
new_pose = orient_tcp_down(current_pose)
|
|
652
804
|
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
805
|
+
# Rotation conversions
|
|
806
|
+
q = rotvec_to_quat([0, 0, 1.57]) # rotvec → quaternion (x, y, z, w)
|
|
807
|
+
rv = quat_to_rotvec(q) # quaternion → rotvec
|
|
808
|
+
rpy = quat_to_rpy(q) # quaternion → RPY (radians)
|
|
809
|
+
q = rpy_to_quat(0, 0, 1.57) # RPY → quaternion
|
|
658
810
|
```
|
|
659
811
|
|
|
660
|
-
###
|
|
812
|
+
### Robot Lifecycle
|
|
661
813
|
|
|
662
|
-
|
|
663
|
-
2. **Config file.** Values from `config.yaml`
|
|
664
|
-
3. **Built-in defaults.** `points.db`, no gripper, 0.5 m/s velocity
|
|
665
|
-
|
|
666
|
-
### Saving Config
|
|
667
|
-
|
|
668
|
-
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.
|
|
814
|
+
Manual power and brake control via the Dashboard:
|
|
669
815
|
|
|
670
|
-
```
|
|
671
|
-
|
|
672
|
-
|
|
816
|
+
```python
|
|
817
|
+
robot.power_on() # power on (skips if already on)
|
|
818
|
+
robot.release_brakes() # release brakes (enable control)
|
|
819
|
+
robot.recover() # clear protective stop
|
|
820
|
+
robot.power_off() # power off
|
|
673
821
|
```
|
|
674
822
|
|
|
675
|
-
|
|
823
|
+
The constructor handles all of this automatically. Use these methods when you need fine-grained control (e.g., recovering from a safety stop without recreating the robot).
|
|
676
824
|
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
825
|
+
TCP and payload can be set manually (gripper presets do this automatically):
|
|
826
|
+
|
|
827
|
+
```python
|
|
828
|
+
robot.set_tcp_offset([0, 0, 0.15, 0, 0, 0])
|
|
829
|
+
robot.set_payload(1.5, [0, 0, 0.05]) # mass (kg), center of gravity [x, y, z]
|
|
680
830
|
```
|
|
681
831
|
|
|
682
|
-
|
|
832
|
+
Clean shutdown:
|
|
683
833
|
|
|
684
834
|
```python
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
config = load_config() # auto-resolve
|
|
688
|
-
config = load_config("/path/to/my.yaml") # explicit path
|
|
689
|
-
path = resolve_config() # returns Path or None
|
|
690
|
-
robot = URRobot.from_config({"robot_ip": "192.168.1.50", "gripper": "2f-85"})
|
|
835
|
+
robot.disconnect() # close RTDE, Dashboard, points DB, gripper
|
|
691
836
|
```
|
|
692
837
|
|
|
838
|
+
`disconnect()` is called automatically on garbage collection. Call it explicitly to release resources immediately.
|
|
839
|
+
|
|
693
840
|
---
|
|
694
841
|
|
|
695
842
|
## Advanced
|
|
@@ -713,8 +860,6 @@ robot.connection_lost # bool: check if RTDE dropped
|
|
|
713
860
|
robot.reconnect_rtde() # reconnect after a drop
|
|
714
861
|
```
|
|
715
862
|
|
|
716
|
-
`disconnect()` is called automatically when the robot object is garbage collected.
|
|
717
|
-
|
|
718
863
|
### Error Handling
|
|
719
864
|
|
|
720
865
|
```python
|
|
@@ -742,13 +887,8 @@ Common runtime errors:
|
|
|
742
887
|
|
|
743
888
|
When the robot enters protective stop or the RTDE connection drops, motion commands raise `URKitConnectionError` and the program should exit. The CLI handles this automatically.
|
|
744
889
|
|
|
745
|
-
### Connection Notes
|
|
746
|
-
|
|
747
|
-
The `URRobot` constructor takes a few seconds on first call: it validates the connection, checks remote mode, powers on the robot, releases brakes, and connects RTDE. Subsequent calls are faster if the robot is already running.
|
|
748
|
-
|
|
749
890
|
---
|
|
750
891
|
|
|
751
892
|
## Changelog
|
|
752
893
|
|
|
753
894
|
See [CHANGELOG.md](CHANGELOG.md) for the full version history.
|
|
754
|
-
|