urkit 0.5.0__tar.gz → 0.6.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.5.0 → urkit-0.6.0}/PKG-INFO +124 -20
- {urkit-0.5.0 → urkit-0.6.0}/README.md +123 -19
- {urkit-0.5.0 → urkit-0.6.0}/pyproject.toml +1 -1
- {urkit-0.5.0 → urkit-0.6.0}/src/urkit/__init__.py +13 -1
- {urkit-0.5.0 → urkit-0.6.0}/src/urkit/__main__.py +6 -3
- {urkit-0.5.0 → urkit-0.6.0}/src/urkit/cli/init.py +9 -2
- {urkit-0.5.0 → urkit-0.6.0}/src/urkit/cli/points.py +1 -2
- {urkit-0.5.0 → urkit-0.6.0}/src/urkit/cli/teach.py +280 -147
- {urkit-0.5.0 → urkit-0.6.0}/src/urkit/cli/terminal.py +0 -14
- {urkit-0.5.0 → urkit-0.6.0}/src/urkit/config.py +61 -5
- {urkit-0.5.0 → urkit-0.6.0}/src/urkit/gripper/__init__.py +14 -0
- {urkit-0.5.0 → urkit-0.6.0}/src/urkit/gripper/base.py +4 -1
- {urkit-0.5.0 → urkit-0.6.0}/src/urkit/gripper/digital.py +15 -0
- urkit-0.6.0/src/urkit/gripper/epick.py +795 -0
- urkit-0.6.0/src/urkit/gripper/presets.py +274 -0
- {urkit-0.5.0 → urkit-0.6.0}/src/urkit/gripper/robotiq.py +13 -0
- {urkit-0.5.0 → urkit-0.6.0}/src/urkit/robot.py +178 -56
- {urkit-0.5.0 → urkit-0.6.0}/src/urkit.egg-info/PKG-INFO +124 -20
- {urkit-0.5.0 → urkit-0.6.0}/src/urkit.egg-info/SOURCES.txt +3 -0
- urkit-0.6.0/tests/test_config.py +100 -0
- {urkit-0.5.0 → urkit-0.6.0}/tests/test_gripper_factory.py +137 -2
- urkit-0.6.0/tests/test_gripper_presets.py +285 -0
- urkit-0.6.0/tests/test_held_payload.py +161 -0
- {urkit-0.5.0 → urkit-0.6.0}/tests/test_robot_integration.py +1 -1
- urkit-0.5.0/src/urkit/gripper/presets.py +0 -113
- urkit-0.5.0/tests/test_gripper_presets.py +0 -152
- {urkit-0.5.0 → urkit-0.6.0}/setup.cfg +0 -0
- {urkit-0.5.0 → urkit-0.6.0}/src/urkit/cli/__init__.py +0 -0
- {urkit-0.5.0 → urkit-0.6.0}/src/urkit/cli/colors.py +0 -0
- {urkit-0.5.0 → urkit-0.6.0}/src/urkit/cli/connection_monitor.py +0 -0
- {urkit-0.5.0 → urkit-0.6.0}/src/urkit/connection.py +0 -0
- {urkit-0.5.0 → urkit-0.6.0}/src/urkit/exceptions.py +0 -0
- {urkit-0.5.0 → urkit-0.6.0}/src/urkit/geometry.py +0 -0
- {urkit-0.5.0 → urkit-0.6.0}/src/urkit/gripper/robotiq_preamble.py +0 -0
- {urkit-0.5.0 → urkit-0.6.0}/src/urkit/io.py +0 -0
- {urkit-0.5.0 → urkit-0.6.0}/src/urkit/motion.py +0 -0
- {urkit-0.5.0 → urkit-0.6.0}/src/urkit/points.py +0 -0
- {urkit-0.5.0 → urkit-0.6.0}/src/urkit/telemetry.py +0 -0
- {urkit-0.5.0 → urkit-0.6.0}/src/urkit.egg-info/dependency_links.txt +0 -0
- {urkit-0.5.0 → urkit-0.6.0}/src/urkit.egg-info/entry_points.txt +0 -0
- {urkit-0.5.0 → urkit-0.6.0}/src/urkit.egg-info/requires.txt +0 -0
- {urkit-0.5.0 → urkit-0.6.0}/src/urkit.egg-info/top_level.txt +0 -0
- {urkit-0.5.0 → urkit-0.6.0}/tests/test_connection_gate.py +0 -0
- {urkit-0.5.0 → urkit-0.6.0}/tests/test_exceptions.py +0 -0
- {urkit-0.5.0 → urkit-0.6.0}/tests/test_freedrive_cycle.py +0 -0
- {urkit-0.5.0 → urkit-0.6.0}/tests/test_geometry.py +0 -0
- {urkit-0.5.0 → urkit-0.6.0}/tests/test_gripper.py +0 -0
- {urkit-0.5.0 → urkit-0.6.0}/tests/test_ik_reference.py +0 -0
- {urkit-0.5.0 → urkit-0.6.0}/tests/test_message_line.py +0 -0
- {urkit-0.5.0 → urkit-0.6.0}/tests/test_move_sequence.py +0 -0
- {urkit-0.5.0 → urkit-0.6.0}/tests/test_points.py +0 -0
- {urkit-0.5.0 → urkit-0.6.0}/tests/test_terminal_input.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: urkit
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.0
|
|
4
4
|
Summary: Universal Robots e-Series control toolkit built on ur_rtde
|
|
5
5
|
Author: URKit Contributors
|
|
6
6
|
License: MIT
|
|
@@ -96,8 +96,8 @@ Requires Python 3.8+ and a Universal Robots e-Series (UR3e to UR30).
|
|
|
96
96
|
|
|
97
97
|
### Platform Support
|
|
98
98
|
|
|
99
|
-
- **Linux,
|
|
100
|
-
- **
|
|
99
|
+
- **Linux, Windows**: fully supported. The interactive CLIs (`urkit teach`, `urkit points`) are tested on both platforms
|
|
100
|
+
- **macOS**: runs the same POSIX terminal code path as Linux (termios/select); there is no macOS-specific code
|
|
101
101
|
|
|
102
102
|
### Robot Setup (one-time)
|
|
103
103
|
|
|
@@ -138,7 +138,7 @@ That's it. No `.urp` files to run, no extra programs needed.
|
|
|
138
138
|
If you have a Robotiq gripper, install the **Robotiq Gripper Control** URCap first: download from [robotiq.com/support](https://robotiq.com/support), copy the `.urcap` to a USB drive, and install via `☰` → `Settings` → `System` → `URCaps`.
|
|
139
139
|
|
|
140
140
|
```python
|
|
141
|
-
from urkit import URRobot, ROBOTIQ_HAND_E # or ROBOTIQ_2F_85, ROBOTIQ_2F_140, or gripper=None
|
|
141
|
+
from urkit import URRobot, ROBOTIQ_HAND_E # or ROBOTIQ_2F_85, ROBOTIQ_2F_140, ROBOTIQ_EPICK_SINGLE_S, or gripper=None
|
|
142
142
|
|
|
143
143
|
robot = URRobot(ip="192.168.1.50", points="points.db", gripper=ROBOTIQ_HAND_E)
|
|
144
144
|
robot.gripper.activate()
|
|
@@ -146,8 +146,10 @@ robot.gripper.activate()
|
|
|
146
146
|
robot.move_to("home")
|
|
147
147
|
robot.move_to("pick", dz=0.05) # 5cm above
|
|
148
148
|
robot.gripper.close()
|
|
149
|
+
robot.set_held_payload(0.05) # picked up 50 g: arm compensates gravity
|
|
149
150
|
robot.move_to("place")
|
|
150
151
|
robot.gripper.open()
|
|
152
|
+
robot.set_held_payload(0) # released: back to gripper-only payload
|
|
151
153
|
```
|
|
152
154
|
|
|
153
155
|
The typical workflow:
|
|
@@ -195,12 +197,14 @@ The CLI auto-loads `config.yaml` from the current working directory. Pass `--con
|
|
|
195
197
|
|-----|-------------|---------|
|
|
196
198
|
| `robot_ip` | Robot IP address | `192.168.1.50` |
|
|
197
199
|
| `points_path` | Path to SQLite points database | `points.db` |
|
|
198
|
-
| `gripper` | Gripper preset name | `hand-e`, `2f-85`, `2f-140`, `digital` |
|
|
200
|
+
| `gripper` | Gripper preset name | `hand-e`, `2f-85`, `2f-140`, `epick-single-s`, `digital` |
|
|
199
201
|
| `ik_reference` | IK reference posture (prevents elbow flipping) | `home` |
|
|
200
202
|
| `default_vel` | Default linear velocity (m/s) | `0.5` |
|
|
201
203
|
| `default_acc` | Default linear acceleration (m/s²) | `0.3` |
|
|
202
204
|
| `expert_mode` | Disable safety speed clamping | `false` |
|
|
203
205
|
|
|
206
|
+
The loader fails loudly with a reason when a config file exists but is wrong: malformed YAML (file + parse error), a document that is not a mapping, or unknown top-level keys (offending keys + the valid ones; usually a typo). The table above is the complete key set. The only silent case is a missing file, where the CLI runs on flags and built-in defaults.
|
|
207
|
+
|
|
204
208
|
### Gripper Config
|
|
205
209
|
|
|
206
210
|
Built-in preset with overrides:
|
|
@@ -291,8 +295,6 @@ urkit init --force # overwrite if exists
|
|
|
291
295
|
|
|
292
296
|
### Teach Mode
|
|
293
297
|
|
|
294
|
-
### Teach Mode
|
|
295
|
-
|
|
296
298
|
The interactive teach pendant for moving the robot, saving points, and checking telemetry:
|
|
297
299
|
|
|
298
300
|
```bash
|
|
@@ -305,10 +307,10 @@ urkit teach # reads IP from config.yaml
|
|
|
305
307
|
| Flag | Description |
|
|
306
308
|
|------|-------------|
|
|
307
309
|
| `ip` | Robot IP address (positional, overrides config) |
|
|
308
|
-
| `--gripper` | Gripper preset: `2f-85`, `2f-140`, `hand-e`, `digital`, `none` |
|
|
310
|
+
| `--gripper` | Gripper preset: `2f-85`, `2f-140`, `hand-e`, `epick-single-s`, `digital`, `none` |
|
|
309
311
|
| `--gripper-pin` | Digital gripper output pin (default: 0) |
|
|
310
|
-
| `--gripper-force` |
|
|
311
|
-
| `--gripper-speed` |
|
|
312
|
+
| `--gripper-force` | 2F grip force 0-100 (EPick: use `max_vacuum` in `gripper_config`) |
|
|
313
|
+
| `--gripper-speed` | 2F movement speed 0-100 (EPick: use `grip_timeout` in `gripper_config`) |
|
|
312
314
|
| `--gripper-close-on-high` | Digital polarity: `true` or `false` |
|
|
313
315
|
| `--points` | Path to `points.db` file (overrides config) |
|
|
314
316
|
| `--config` | Path to config file (default: `config.yaml` in project root or CWD) |
|
|
@@ -374,9 +376,10 @@ All movement and orientation keys support **hold-to-repeat**.
|
|
|
374
376
|
<tr><th>Key</th><th>Action</th></tr>
|
|
375
377
|
<tr><td><code>X</code></td><td>Open</td></tr>
|
|
376
378
|
<tr><td><code>C</code></td><td>Close</td></tr>
|
|
377
|
-
<tr><td><code>V</code></td><td>Set position (
|
|
378
|
-
<tr><td><code>6</code></td><td>Set speed (
|
|
379
|
-
<tr><td><code>7</code></td><td>Set force (
|
|
379
|
+
<tr><td><code>V</code></td><td>Set position % (2F only; hidden for the EPick)</td></tr>
|
|
380
|
+
<tr><td><code>6</code></td><td>Set speed (2F) / min vacuum (EPick)</td></tr>
|
|
381
|
+
<tr><td><code>7</code></td><td>Set force (2F) / max vacuum (EPick)</td></tr>
|
|
382
|
+
<tr><td><code>9</code></td><td>Set held payload (kg, 0 = reset to base)</td></tr>
|
|
380
383
|
</table>
|
|
381
384
|
</td>
|
|
382
385
|
<td align="center" style="width:33%">
|
|
@@ -409,10 +412,10 @@ All movement and orientation keys support **hold-to-repeat**.
|
|
|
409
412
|
The teach pendant shows live joint angles alongside TCP position and orientation:
|
|
410
413
|
|
|
411
414
|
```
|
|
412
|
-
Position
|
|
413
|
-
Orientation
|
|
414
|
-
Joints
|
|
415
|
-
|
|
415
|
+
Position (mm) X= +432.0 Y= +111.0 Z= +227.0
|
|
416
|
+
Orientation R= +131.3 P= -121.0 Y= +8.0
|
|
417
|
+
Joints J1=+150.0 J2= +20.0 J3=+160.0
|
|
418
|
+
J4= +50.0 J5= -80.0 J6=+157.0
|
|
416
419
|
```
|
|
417
420
|
|
|
418
421
|
Joint angles color-code proximity to mechanical limits:
|
|
@@ -480,13 +483,16 @@ The constructor takes a few seconds on first call: it validates the connection,
|
|
|
480
483
|
|
|
481
484
|
### Grippers
|
|
482
485
|
|
|
483
|
-
|
|
486
|
+
Built-in presets:
|
|
484
487
|
|
|
485
488
|
| Preset | Description |
|
|
486
489
|
|--------|-------------|
|
|
487
490
|
| `ROBOTIQ_HAND_E` | Robotiq Hand-E (2F-85-E) |
|
|
488
491
|
| `ROBOTIQ_2F_85` | Robotiq 2F-85 |
|
|
489
492
|
| `ROBOTIQ_2F_140` | Robotiq 2F-140 |
|
|
493
|
+
| `ROBOTIQ_EPICK_SINGLE_S/L` | EPick + 1 cup (S = Ø40, L = Ø55) |
|
|
494
|
+
| `ROBOTIQ_EPICK_DUAL_S/L` | EPick + 2-cup bracket (S = Ø40, L = Ø55) |
|
|
495
|
+
| `ROBOTIQ_EPICK_QUAD_S/L` | EPick + 4-cup bracket (S = Ø40, L = Ø55) |
|
|
490
496
|
|
|
491
497
|
```python
|
|
492
498
|
robot.gripper.activate() # required before open/close (Robotiq only)
|
|
@@ -497,7 +503,7 @@ robot.gripper.open() # fully open (blocking by default)
|
|
|
497
503
|
robot.gripper.close() # fully closed, stops on contact
|
|
498
504
|
robot.gripper.open(wait=False) # non-blocking return (waits for position)
|
|
499
505
|
robot.gripper.set_position_mm(20) # 20mm open (Robotiq only, 0 = fully closed)
|
|
500
|
-
robot.gripper.set_position_percent(50) # 50% open (
|
|
506
|
+
robot.gripper.set_position_percent(50) # 50% open (2F; repurposed on the EPick, see below)
|
|
501
507
|
robot.gripper.set_force(50) # grip force: 0-100 (Robotiq only)
|
|
502
508
|
robot.gripper.set_speed(80) # movement speed: 0-100 (Robotiq only)
|
|
503
509
|
|
|
@@ -543,6 +549,83 @@ robot.gripper.close() # turn pin 3 on
|
|
|
543
549
|
|
|
544
550
|
`set_force()` and `set_speed()` are not available for digital grippers.
|
|
545
551
|
|
|
552
|
+
#### EPick Vacuum Gripper
|
|
553
|
+
|
|
554
|
+
The EPick presets drive a Robotiq EPick vacuum gripper (e-Series only) over the same RS485 Robotiq protocol as the 2F series, using the legacy Robotiq ASCII commands. They require the **Robotiq Gripper Control** URCap installed (same setup as the 2F presets).
|
|
555
|
+
|
|
556
|
+
The semantics are inverted compared to the 2F grippers:
|
|
557
|
+
|
|
558
|
+
```python
|
|
559
|
+
robot.gripper.activate() # required before open/close
|
|
560
|
+
robot.gripper.close() # grip: pump on, wait until an object is secured
|
|
561
|
+
robot.gripper.open() # release: pump off + blow-off, wait until the object is gone
|
|
562
|
+
```
|
|
563
|
+
|
|
564
|
+
`close()` does not return until the gripper has confirmed a secured object (see Detection below), and raises `GripperError` if no object is detected within the grip timeout. A failed grip leaves the vacuum on, so call `open()` to release before moving again. `open()` waits until the vacuum is lost (the object has dropped).
|
|
565
|
+
|
|
566
|
+
Grip parameters (set at connect time, or changed between grips):
|
|
567
|
+
|
|
568
|
+
```python
|
|
569
|
+
robot.gripper.set_max_vacuum(60) # max vacuum level, 20-100% (default 60, the Robotiq URCap default)
|
|
570
|
+
robot.gripper.set_min_vacuum(40) # min vacuum level, 10% up to the max vacuum (default 40)
|
|
571
|
+
robot.gripper.set_grip_timeout(30) # grip timeout in 100 ms units, 0-100 (default 30 = 3 s)
|
|
572
|
+
```
|
|
573
|
+
|
|
574
|
+
The ranges are enforced at construction and on every setter (max 20-100, min 10 up to the current max, timeout 0-100), and a parameter of one backend passed to another raises `GripperError` instead of being ignored (`force`/`speed` on the EPick, `max_vacuum`/`grip_timeout` on the 2F). The same names work in `config.yaml`:
|
|
575
|
+
|
|
576
|
+
```yaml
|
|
577
|
+
gripper: epick-single-s
|
|
578
|
+
gripper_config:
|
|
579
|
+
max_vacuum: 70
|
|
580
|
+
grip_timeout: 40
|
|
581
|
+
```
|
|
582
|
+
|
|
583
|
+
With `set_max_vacuum(100)` the pump runs continuously and the gripper cannot confirm a grip; keep the max vacuum below 100% (60 works for typical cups and trays). The same physics applies at lower levels: if the max vacuum is higher than a leaky seal can reach, the pump keeps hunting and never enters the stable hold phase where the secured flag appears, so the grip times out (verified: a marginal-seal object gripped at 60/40 but timed out at 80/50 and 80/30). For leaky seals keep `max_vacuum` low and `min_vacuum` at or below what the seal sustains, not the other way around.
|
|
584
|
+
|
|
585
|
+
`set_position_mm()`, `get_position_mm()`, and `max_travel_mm()` are not available: the EPick has no finger travel. `set_position_percent(p)` is repurposed as a one-shot vacuum grip: `p=0` releases, `1-100` grips at that vacuum level with the normal secured-object wait (the teach pendant does not expose this; use [6]/[7] and C).
|
|
586
|
+
|
|
587
|
+
**Payload and TCP.** The bare generator body is 0.706 kg, CoG `[0, 0, 0.0515]`, TCP `[0, 0, 0.113, 0, 0, 0]` (Robotiq EPick manual, Table 6-4); cups and brackets change all three. The kits ship cups in two sizes (Ø 40 mm and Ø 55 mm), so there is one preset per bracket system + cup size (configurations without cups cannot grip and have no preset):
|
|
588
|
+
|
|
589
|
+
| Preset | Config / CLI name | Setup |
|
|
590
|
+
|--------|-------------------|-------|
|
|
591
|
+
| `ROBOTIQ_EPICK_SINGLE_S` | `epick-single-s` | 1 small (Ø40) cup on the generator port |
|
|
592
|
+
| `ROBOTIQ_EPICK_SINGLE_L` | `epick-single-l` | 1 large (Ø55) cup on the generator port |
|
|
593
|
+
| `ROBOTIQ_EPICK_DUAL_S` | `epick-dual-s` | 2-cup bracket, small cups |
|
|
594
|
+
| `ROBOTIQ_EPICK_DUAL_L` | `epick-dual-l` | 2-cup bracket, large cups |
|
|
595
|
+
| `ROBOTIQ_EPICK_QUAD_S` | `epick-quad-s` | 4-cup bracket, small cups |
|
|
596
|
+
| `ROBOTIQ_EPICK_QUAD_L` | `epick-quad-l` | 4-cup bracket, large cups |
|
|
597
|
+
|
|
598
|
+
```python
|
|
599
|
+
from urkit import URRobot, ROBOTIQ_EPICK_SINGLE_S
|
|
600
|
+
|
|
601
|
+
robot = URRobot(ip="192.168.1.50", gripper=ROBOTIQ_EPICK_SINGLE_S)
|
|
602
|
+
```
|
|
603
|
+
|
|
604
|
+
The TCP z of each preset is the bottom of the cups, the limiting point for approach moves. The presets use the manual's Table 6-4 for the body and bracket stack, and the official Festo datasheets for the cups Robotiq ships (VASB-40-1/4-PUR-B: 30 g / 32 mm, VASB-55-1/4-PUR-B: 39 g / 39 mm); all-small combinations reproduce Table 6-4 exactly:
|
|
605
|
+
|
|
606
|
+
| Preset | Mass (kg) | CoG z (m) | TCP z (m) |
|
|
607
|
+
|--------|-----------|-----------|-----------|
|
|
608
|
+
| body only (reference) | 0.706 | 0.0515 | 0.113 |
|
|
609
|
+
| `ROBOTIQ_EPICK_SINGLE_S` | 0.736 | 0.0547 | 0.145 |
|
|
610
|
+
| `ROBOTIQ_EPICK_SINGLE_L` | 0.745 | 0.0557 | 0.152 |
|
|
611
|
+
| `ROBOTIQ_EPICK_DUAL_S` | 1.116 | 0.0819 | 0.196 |
|
|
612
|
+
| `ROBOTIQ_EPICK_DUAL_L` | 1.134 | 0.0837 | 0.203 |
|
|
613
|
+
| `ROBOTIQ_EPICK_QUAD_S` | 1.341 | 0.0920 | 0.196 |
|
|
614
|
+
| `ROBOTIQ_EPICK_QUAD_L` | 1.377 | 0.0947 | 0.203 |
|
|
615
|
+
|
|
616
|
+
Bracket mass is derived (±15 g) and the Ø55 height is CAD-derived (±2 mm); if your setup is critical, measure the actual stack and pass `mass` / `center_of_gravity` / `tcp_offset` overrides, which still work:
|
|
617
|
+
|
|
618
|
+
```python
|
|
619
|
+
robot = URRobot(
|
|
620
|
+
ip="192.168.1.50",
|
|
621
|
+
gripper=ROBOTIQ_EPICK_SINGLE_S,
|
|
622
|
+
mass=0.74,
|
|
623
|
+
tcp_offset=[0.0, 0.0, 0.147, 0.0, 0.0, 0.0],
|
|
624
|
+
)
|
|
625
|
+
```
|
|
626
|
+
|
|
627
|
+
**Detection.** The EPick runs in advanced mode (rMOD=1): the pump reaches the max vacuum level, stops, and the vacuum decays back to the min level. An object is only "secured" while the vacuum is actually held there, so `close()` returns as soon as that secured state is observed on the gripper's object flag. With nothing under the suction cup the vacuum collapses and the secured state never occurs, so `close()` times out and raises `GripperError` after the grip timeout (set via `grip_timeout`). In automatic mode (rMOD=0) the EPick reports a short "seemingly constant" vacuum as an object, which false-positives with no object on the cup, so urkit does not use it.
|
|
628
|
+
|
|
546
629
|
### Points & Motion
|
|
547
630
|
|
|
548
631
|
The points database is optional. Create a robot without one and attach later:
|
|
@@ -773,7 +856,7 @@ robot.speed_slider = 0.5 # 50% velocity cap
|
|
|
773
856
|
robot.speed_slider # read current slider (0.0-1.0)
|
|
774
857
|
```
|
|
775
858
|
|
|
776
|
-
The speed slider controls the pendant's speed multiplier. It's global, persistent, and affects all motion commands.
|
|
859
|
+
The speed slider controls the pendant's speed multiplier. It's global, persistent (stored on the robot, survives restarts), and affects all motion commands. Because 0% persists as a silent freeze of all motion, the pendant's `[0]` prompt rejects 0 (1-100 only); a deliberate freeze is still possible via the API (`robot.speed_slider = 0`).
|
|
777
860
|
|
|
778
861
|
#### Changing Default Speed & Acceleration
|
|
779
862
|
|
|
@@ -909,6 +992,27 @@ robot.tcp_offset = [0, 0, 0.15, 0, 0, 0]
|
|
|
909
992
|
robot.set_payload(1.5, [0, 0, 0.05]) # mass (kg), center of gravity [x, y, z]
|
|
910
993
|
```
|
|
911
994
|
|
|
995
|
+
**Held payload.** The controller compensates gravity using the payload, so add the mass of a picked-up object before moving it, and reset after release:
|
|
996
|
+
|
|
997
|
+
```python
|
|
998
|
+
robot.gripper.close()
|
|
999
|
+
robot.set_held_payload(0.05) # holding 50 g, object CoG at the TCP
|
|
1000
|
+
robot.set_held_payload(0.05, cog=[0, 0, 0.25]) # object hangs below the flange
|
|
1001
|
+
robot.set_held_payload(0) # released: back to the base payload
|
|
1002
|
+
|
|
1003
|
+
robot.base_payload # gripper + tooling, kg (no held object)
|
|
1004
|
+
robot.held_payload # currently held mass, kg (0 = none)
|
|
1005
|
+
robot.payload # total (base + held), kg
|
|
1006
|
+
```
|
|
1007
|
+
|
|
1008
|
+
`set_held_payload(0)` resets to the base payload captured at connect (the gripper preset plus any `mass=` / `center_of_gravity` / `tcp_offset` overrides), never to a literal zero. The combined CoG is the mass-weighted average of the base CoG and the object's CoG (tool coordinates, origin at the flange). A held object that extends the tool does not need a TCP change: give its CoG the deeper z instead.
|
|
1009
|
+
|
|
1010
|
+
The base payload can be changed at runtime with `set_payload(...)`: while nothing is held, a manual `set_payload` call becomes the new base (custom fingers, a re-weighed tool). While a payload is held, `set_payload` raises, since the mass would be ambiguous: call `set_held_payload(0)` first.
|
|
1011
|
+
|
|
1012
|
+
In the teach pendant, **9** sets the held payload (prompt: `Held payload in kg (0 = reset to base)`); the Payload status row shows the held mass and hints the key, e.g. `1.427kg +0.050 held [9]`. Useful when teaching points while gripping a real part.
|
|
1013
|
+
|
|
1014
|
+
**How much to report.** There is no enforced minimum, and over-reporting is harmless. Practical guidance: below ~10 g the sag is sub-millimeter on any e-Series arm and not worth it; from ~50 g up (roughly 1% of a UR5e's rated payload) report it, since full-reach sag reaches several mm; in between, report it for slow precision work (insertion, contact moves) and skip it for coarse moves.
|
|
1015
|
+
|
|
912
1016
|
Clean shutdown:
|
|
913
1017
|
|
|
914
1018
|
```python
|
|
@@ -70,8 +70,8 @@ Requires Python 3.8+ and a Universal Robots e-Series (UR3e to UR30).
|
|
|
70
70
|
|
|
71
71
|
### Platform Support
|
|
72
72
|
|
|
73
|
-
- **Linux,
|
|
74
|
-
- **
|
|
73
|
+
- **Linux, Windows**: fully supported. The interactive CLIs (`urkit teach`, `urkit points`) are tested on both platforms
|
|
74
|
+
- **macOS**: runs the same POSIX terminal code path as Linux (termios/select); there is no macOS-specific code
|
|
75
75
|
|
|
76
76
|
### Robot Setup (one-time)
|
|
77
77
|
|
|
@@ -112,7 +112,7 @@ That's it. No `.urp` files to run, no extra programs needed.
|
|
|
112
112
|
If you have a Robotiq gripper, install the **Robotiq Gripper Control** URCap first: download from [robotiq.com/support](https://robotiq.com/support), copy the `.urcap` to a USB drive, and install via `☰` → `Settings` → `System` → `URCaps`.
|
|
113
113
|
|
|
114
114
|
```python
|
|
115
|
-
from urkit import URRobot, ROBOTIQ_HAND_E # or ROBOTIQ_2F_85, ROBOTIQ_2F_140, or gripper=None
|
|
115
|
+
from urkit import URRobot, ROBOTIQ_HAND_E # or ROBOTIQ_2F_85, ROBOTIQ_2F_140, ROBOTIQ_EPICK_SINGLE_S, or gripper=None
|
|
116
116
|
|
|
117
117
|
robot = URRobot(ip="192.168.1.50", points="points.db", gripper=ROBOTIQ_HAND_E)
|
|
118
118
|
robot.gripper.activate()
|
|
@@ -120,8 +120,10 @@ robot.gripper.activate()
|
|
|
120
120
|
robot.move_to("home")
|
|
121
121
|
robot.move_to("pick", dz=0.05) # 5cm above
|
|
122
122
|
robot.gripper.close()
|
|
123
|
+
robot.set_held_payload(0.05) # picked up 50 g: arm compensates gravity
|
|
123
124
|
robot.move_to("place")
|
|
124
125
|
robot.gripper.open()
|
|
126
|
+
robot.set_held_payload(0) # released: back to gripper-only payload
|
|
125
127
|
```
|
|
126
128
|
|
|
127
129
|
The typical workflow:
|
|
@@ -169,12 +171,14 @@ The CLI auto-loads `config.yaml` from the current working directory. Pass `--con
|
|
|
169
171
|
|-----|-------------|---------|
|
|
170
172
|
| `robot_ip` | Robot IP address | `192.168.1.50` |
|
|
171
173
|
| `points_path` | Path to SQLite points database | `points.db` |
|
|
172
|
-
| `gripper` | Gripper preset name | `hand-e`, `2f-85`, `2f-140`, `digital` |
|
|
174
|
+
| `gripper` | Gripper preset name | `hand-e`, `2f-85`, `2f-140`, `epick-single-s`, `digital` |
|
|
173
175
|
| `ik_reference` | IK reference posture (prevents elbow flipping) | `home` |
|
|
174
176
|
| `default_vel` | Default linear velocity (m/s) | `0.5` |
|
|
175
177
|
| `default_acc` | Default linear acceleration (m/s²) | `0.3` |
|
|
176
178
|
| `expert_mode` | Disable safety speed clamping | `false` |
|
|
177
179
|
|
|
180
|
+
The loader fails loudly with a reason when a config file exists but is wrong: malformed YAML (file + parse error), a document that is not a mapping, or unknown top-level keys (offending keys + the valid ones; usually a typo). The table above is the complete key set. The only silent case is a missing file, where the CLI runs on flags and built-in defaults.
|
|
181
|
+
|
|
178
182
|
### Gripper Config
|
|
179
183
|
|
|
180
184
|
Built-in preset with overrides:
|
|
@@ -265,8 +269,6 @@ urkit init --force # overwrite if exists
|
|
|
265
269
|
|
|
266
270
|
### Teach Mode
|
|
267
271
|
|
|
268
|
-
### Teach Mode
|
|
269
|
-
|
|
270
272
|
The interactive teach pendant for moving the robot, saving points, and checking telemetry:
|
|
271
273
|
|
|
272
274
|
```bash
|
|
@@ -279,10 +281,10 @@ urkit teach # reads IP from config.yaml
|
|
|
279
281
|
| Flag | Description |
|
|
280
282
|
|------|-------------|
|
|
281
283
|
| `ip` | Robot IP address (positional, overrides config) |
|
|
282
|
-
| `--gripper` | Gripper preset: `2f-85`, `2f-140`, `hand-e`, `digital`, `none` |
|
|
284
|
+
| `--gripper` | Gripper preset: `2f-85`, `2f-140`, `hand-e`, `epick-single-s`, `digital`, `none` |
|
|
283
285
|
| `--gripper-pin` | Digital gripper output pin (default: 0) |
|
|
284
|
-
| `--gripper-force` |
|
|
285
|
-
| `--gripper-speed` |
|
|
286
|
+
| `--gripper-force` | 2F grip force 0-100 (EPick: use `max_vacuum` in `gripper_config`) |
|
|
287
|
+
| `--gripper-speed` | 2F movement speed 0-100 (EPick: use `grip_timeout` in `gripper_config`) |
|
|
286
288
|
| `--gripper-close-on-high` | Digital polarity: `true` or `false` |
|
|
287
289
|
| `--points` | Path to `points.db` file (overrides config) |
|
|
288
290
|
| `--config` | Path to config file (default: `config.yaml` in project root or CWD) |
|
|
@@ -348,9 +350,10 @@ All movement and orientation keys support **hold-to-repeat**.
|
|
|
348
350
|
<tr><th>Key</th><th>Action</th></tr>
|
|
349
351
|
<tr><td><code>X</code></td><td>Open</td></tr>
|
|
350
352
|
<tr><td><code>C</code></td><td>Close</td></tr>
|
|
351
|
-
<tr><td><code>V</code></td><td>Set position (
|
|
352
|
-
<tr><td><code>6</code></td><td>Set speed (
|
|
353
|
-
<tr><td><code>7</code></td><td>Set force (
|
|
353
|
+
<tr><td><code>V</code></td><td>Set position % (2F only; hidden for the EPick)</td></tr>
|
|
354
|
+
<tr><td><code>6</code></td><td>Set speed (2F) / min vacuum (EPick)</td></tr>
|
|
355
|
+
<tr><td><code>7</code></td><td>Set force (2F) / max vacuum (EPick)</td></tr>
|
|
356
|
+
<tr><td><code>9</code></td><td>Set held payload (kg, 0 = reset to base)</td></tr>
|
|
354
357
|
</table>
|
|
355
358
|
</td>
|
|
356
359
|
<td align="center" style="width:33%">
|
|
@@ -383,10 +386,10 @@ All movement and orientation keys support **hold-to-repeat**.
|
|
|
383
386
|
The teach pendant shows live joint angles alongside TCP position and orientation:
|
|
384
387
|
|
|
385
388
|
```
|
|
386
|
-
Position
|
|
387
|
-
Orientation
|
|
388
|
-
Joints
|
|
389
|
-
|
|
389
|
+
Position (mm) X= +432.0 Y= +111.0 Z= +227.0
|
|
390
|
+
Orientation R= +131.3 P= -121.0 Y= +8.0
|
|
391
|
+
Joints J1=+150.0 J2= +20.0 J3=+160.0
|
|
392
|
+
J4= +50.0 J5= -80.0 J6=+157.0
|
|
390
393
|
```
|
|
391
394
|
|
|
392
395
|
Joint angles color-code proximity to mechanical limits:
|
|
@@ -454,13 +457,16 @@ The constructor takes a few seconds on first call: it validates the connection,
|
|
|
454
457
|
|
|
455
458
|
### Grippers
|
|
456
459
|
|
|
457
|
-
|
|
460
|
+
Built-in presets:
|
|
458
461
|
|
|
459
462
|
| Preset | Description |
|
|
460
463
|
|--------|-------------|
|
|
461
464
|
| `ROBOTIQ_HAND_E` | Robotiq Hand-E (2F-85-E) |
|
|
462
465
|
| `ROBOTIQ_2F_85` | Robotiq 2F-85 |
|
|
463
466
|
| `ROBOTIQ_2F_140` | Robotiq 2F-140 |
|
|
467
|
+
| `ROBOTIQ_EPICK_SINGLE_S/L` | EPick + 1 cup (S = Ø40, L = Ø55) |
|
|
468
|
+
| `ROBOTIQ_EPICK_DUAL_S/L` | EPick + 2-cup bracket (S = Ø40, L = Ø55) |
|
|
469
|
+
| `ROBOTIQ_EPICK_QUAD_S/L` | EPick + 4-cup bracket (S = Ø40, L = Ø55) |
|
|
464
470
|
|
|
465
471
|
```python
|
|
466
472
|
robot.gripper.activate() # required before open/close (Robotiq only)
|
|
@@ -471,7 +477,7 @@ robot.gripper.open() # fully open (blocking by default)
|
|
|
471
477
|
robot.gripper.close() # fully closed, stops on contact
|
|
472
478
|
robot.gripper.open(wait=False) # non-blocking return (waits for position)
|
|
473
479
|
robot.gripper.set_position_mm(20) # 20mm open (Robotiq only, 0 = fully closed)
|
|
474
|
-
robot.gripper.set_position_percent(50) # 50% open (
|
|
480
|
+
robot.gripper.set_position_percent(50) # 50% open (2F; repurposed on the EPick, see below)
|
|
475
481
|
robot.gripper.set_force(50) # grip force: 0-100 (Robotiq only)
|
|
476
482
|
robot.gripper.set_speed(80) # movement speed: 0-100 (Robotiq only)
|
|
477
483
|
|
|
@@ -517,6 +523,83 @@ robot.gripper.close() # turn pin 3 on
|
|
|
517
523
|
|
|
518
524
|
`set_force()` and `set_speed()` are not available for digital grippers.
|
|
519
525
|
|
|
526
|
+
#### EPick Vacuum Gripper
|
|
527
|
+
|
|
528
|
+
The EPick presets drive a Robotiq EPick vacuum gripper (e-Series only) over the same RS485 Robotiq protocol as the 2F series, using the legacy Robotiq ASCII commands. They require the **Robotiq Gripper Control** URCap installed (same setup as the 2F presets).
|
|
529
|
+
|
|
530
|
+
The semantics are inverted compared to the 2F grippers:
|
|
531
|
+
|
|
532
|
+
```python
|
|
533
|
+
robot.gripper.activate() # required before open/close
|
|
534
|
+
robot.gripper.close() # grip: pump on, wait until an object is secured
|
|
535
|
+
robot.gripper.open() # release: pump off + blow-off, wait until the object is gone
|
|
536
|
+
```
|
|
537
|
+
|
|
538
|
+
`close()` does not return until the gripper has confirmed a secured object (see Detection below), and raises `GripperError` if no object is detected within the grip timeout. A failed grip leaves the vacuum on, so call `open()` to release before moving again. `open()` waits until the vacuum is lost (the object has dropped).
|
|
539
|
+
|
|
540
|
+
Grip parameters (set at connect time, or changed between grips):
|
|
541
|
+
|
|
542
|
+
```python
|
|
543
|
+
robot.gripper.set_max_vacuum(60) # max vacuum level, 20-100% (default 60, the Robotiq URCap default)
|
|
544
|
+
robot.gripper.set_min_vacuum(40) # min vacuum level, 10% up to the max vacuum (default 40)
|
|
545
|
+
robot.gripper.set_grip_timeout(30) # grip timeout in 100 ms units, 0-100 (default 30 = 3 s)
|
|
546
|
+
```
|
|
547
|
+
|
|
548
|
+
The ranges are enforced at construction and on every setter (max 20-100, min 10 up to the current max, timeout 0-100), and a parameter of one backend passed to another raises `GripperError` instead of being ignored (`force`/`speed` on the EPick, `max_vacuum`/`grip_timeout` on the 2F). The same names work in `config.yaml`:
|
|
549
|
+
|
|
550
|
+
```yaml
|
|
551
|
+
gripper: epick-single-s
|
|
552
|
+
gripper_config:
|
|
553
|
+
max_vacuum: 70
|
|
554
|
+
grip_timeout: 40
|
|
555
|
+
```
|
|
556
|
+
|
|
557
|
+
With `set_max_vacuum(100)` the pump runs continuously and the gripper cannot confirm a grip; keep the max vacuum below 100% (60 works for typical cups and trays). The same physics applies at lower levels: if the max vacuum is higher than a leaky seal can reach, the pump keeps hunting and never enters the stable hold phase where the secured flag appears, so the grip times out (verified: a marginal-seal object gripped at 60/40 but timed out at 80/50 and 80/30). For leaky seals keep `max_vacuum` low and `min_vacuum` at or below what the seal sustains, not the other way around.
|
|
558
|
+
|
|
559
|
+
`set_position_mm()`, `get_position_mm()`, and `max_travel_mm()` are not available: the EPick has no finger travel. `set_position_percent(p)` is repurposed as a one-shot vacuum grip: `p=0` releases, `1-100` grips at that vacuum level with the normal secured-object wait (the teach pendant does not expose this; use [6]/[7] and C).
|
|
560
|
+
|
|
561
|
+
**Payload and TCP.** The bare generator body is 0.706 kg, CoG `[0, 0, 0.0515]`, TCP `[0, 0, 0.113, 0, 0, 0]` (Robotiq EPick manual, Table 6-4); cups and brackets change all three. The kits ship cups in two sizes (Ø 40 mm and Ø 55 mm), so there is one preset per bracket system + cup size (configurations without cups cannot grip and have no preset):
|
|
562
|
+
|
|
563
|
+
| Preset | Config / CLI name | Setup |
|
|
564
|
+
|--------|-------------------|-------|
|
|
565
|
+
| `ROBOTIQ_EPICK_SINGLE_S` | `epick-single-s` | 1 small (Ø40) cup on the generator port |
|
|
566
|
+
| `ROBOTIQ_EPICK_SINGLE_L` | `epick-single-l` | 1 large (Ø55) cup on the generator port |
|
|
567
|
+
| `ROBOTIQ_EPICK_DUAL_S` | `epick-dual-s` | 2-cup bracket, small cups |
|
|
568
|
+
| `ROBOTIQ_EPICK_DUAL_L` | `epick-dual-l` | 2-cup bracket, large cups |
|
|
569
|
+
| `ROBOTIQ_EPICK_QUAD_S` | `epick-quad-s` | 4-cup bracket, small cups |
|
|
570
|
+
| `ROBOTIQ_EPICK_QUAD_L` | `epick-quad-l` | 4-cup bracket, large cups |
|
|
571
|
+
|
|
572
|
+
```python
|
|
573
|
+
from urkit import URRobot, ROBOTIQ_EPICK_SINGLE_S
|
|
574
|
+
|
|
575
|
+
robot = URRobot(ip="192.168.1.50", gripper=ROBOTIQ_EPICK_SINGLE_S)
|
|
576
|
+
```
|
|
577
|
+
|
|
578
|
+
The TCP z of each preset is the bottom of the cups, the limiting point for approach moves. The presets use the manual's Table 6-4 for the body and bracket stack, and the official Festo datasheets for the cups Robotiq ships (VASB-40-1/4-PUR-B: 30 g / 32 mm, VASB-55-1/4-PUR-B: 39 g / 39 mm); all-small combinations reproduce Table 6-4 exactly:
|
|
579
|
+
|
|
580
|
+
| Preset | Mass (kg) | CoG z (m) | TCP z (m) |
|
|
581
|
+
|--------|-----------|-----------|-----------|
|
|
582
|
+
| body only (reference) | 0.706 | 0.0515 | 0.113 |
|
|
583
|
+
| `ROBOTIQ_EPICK_SINGLE_S` | 0.736 | 0.0547 | 0.145 |
|
|
584
|
+
| `ROBOTIQ_EPICK_SINGLE_L` | 0.745 | 0.0557 | 0.152 |
|
|
585
|
+
| `ROBOTIQ_EPICK_DUAL_S` | 1.116 | 0.0819 | 0.196 |
|
|
586
|
+
| `ROBOTIQ_EPICK_DUAL_L` | 1.134 | 0.0837 | 0.203 |
|
|
587
|
+
| `ROBOTIQ_EPICK_QUAD_S` | 1.341 | 0.0920 | 0.196 |
|
|
588
|
+
| `ROBOTIQ_EPICK_QUAD_L` | 1.377 | 0.0947 | 0.203 |
|
|
589
|
+
|
|
590
|
+
Bracket mass is derived (±15 g) and the Ø55 height is CAD-derived (±2 mm); if your setup is critical, measure the actual stack and pass `mass` / `center_of_gravity` / `tcp_offset` overrides, which still work:
|
|
591
|
+
|
|
592
|
+
```python
|
|
593
|
+
robot = URRobot(
|
|
594
|
+
ip="192.168.1.50",
|
|
595
|
+
gripper=ROBOTIQ_EPICK_SINGLE_S,
|
|
596
|
+
mass=0.74,
|
|
597
|
+
tcp_offset=[0.0, 0.0, 0.147, 0.0, 0.0, 0.0],
|
|
598
|
+
)
|
|
599
|
+
```
|
|
600
|
+
|
|
601
|
+
**Detection.** The EPick runs in advanced mode (rMOD=1): the pump reaches the max vacuum level, stops, and the vacuum decays back to the min level. An object is only "secured" while the vacuum is actually held there, so `close()` returns as soon as that secured state is observed on the gripper's object flag. With nothing under the suction cup the vacuum collapses and the secured state never occurs, so `close()` times out and raises `GripperError` after the grip timeout (set via `grip_timeout`). In automatic mode (rMOD=0) the EPick reports a short "seemingly constant" vacuum as an object, which false-positives with no object on the cup, so urkit does not use it.
|
|
602
|
+
|
|
520
603
|
### Points & Motion
|
|
521
604
|
|
|
522
605
|
The points database is optional. Create a robot without one and attach later:
|
|
@@ -747,7 +830,7 @@ robot.speed_slider = 0.5 # 50% velocity cap
|
|
|
747
830
|
robot.speed_slider # read current slider (0.0-1.0)
|
|
748
831
|
```
|
|
749
832
|
|
|
750
|
-
The speed slider controls the pendant's speed multiplier. It's global, persistent, and affects all motion commands.
|
|
833
|
+
The speed slider controls the pendant's speed multiplier. It's global, persistent (stored on the robot, survives restarts), and affects all motion commands. Because 0% persists as a silent freeze of all motion, the pendant's `[0]` prompt rejects 0 (1-100 only); a deliberate freeze is still possible via the API (`robot.speed_slider = 0`).
|
|
751
834
|
|
|
752
835
|
#### Changing Default Speed & Acceleration
|
|
753
836
|
|
|
@@ -883,6 +966,27 @@ robot.tcp_offset = [0, 0, 0.15, 0, 0, 0]
|
|
|
883
966
|
robot.set_payload(1.5, [0, 0, 0.05]) # mass (kg), center of gravity [x, y, z]
|
|
884
967
|
```
|
|
885
968
|
|
|
969
|
+
**Held payload.** The controller compensates gravity using the payload, so add the mass of a picked-up object before moving it, and reset after release:
|
|
970
|
+
|
|
971
|
+
```python
|
|
972
|
+
robot.gripper.close()
|
|
973
|
+
robot.set_held_payload(0.05) # holding 50 g, object CoG at the TCP
|
|
974
|
+
robot.set_held_payload(0.05, cog=[0, 0, 0.25]) # object hangs below the flange
|
|
975
|
+
robot.set_held_payload(0) # released: back to the base payload
|
|
976
|
+
|
|
977
|
+
robot.base_payload # gripper + tooling, kg (no held object)
|
|
978
|
+
robot.held_payload # currently held mass, kg (0 = none)
|
|
979
|
+
robot.payload # total (base + held), kg
|
|
980
|
+
```
|
|
981
|
+
|
|
982
|
+
`set_held_payload(0)` resets to the base payload captured at connect (the gripper preset plus any `mass=` / `center_of_gravity` / `tcp_offset` overrides), never to a literal zero. The combined CoG is the mass-weighted average of the base CoG and the object's CoG (tool coordinates, origin at the flange). A held object that extends the tool does not need a TCP change: give its CoG the deeper z instead.
|
|
983
|
+
|
|
984
|
+
The base payload can be changed at runtime with `set_payload(...)`: while nothing is held, a manual `set_payload` call becomes the new base (custom fingers, a re-weighed tool). While a payload is held, `set_payload` raises, since the mass would be ambiguous: call `set_held_payload(0)` first.
|
|
985
|
+
|
|
986
|
+
In the teach pendant, **9** sets the held payload (prompt: `Held payload in kg (0 = reset to base)`); the Payload status row shows the held mass and hints the key, e.g. `1.427kg +0.050 held [9]`. Useful when teaching points while gripping a real part.
|
|
987
|
+
|
|
988
|
+
**How much to report.** There is no enforced minimum, and over-reporting is harmless. Practical guidance: below ~10 g the sag is sub-millimeter on any e-Series arm and not worth it; from ~50 g up (roughly 1% of a UR5e's rated payload) report it, since full-reach sag reaches several mm; in between, report it for slow precision work (insertion, contact moves) and skip it for coarse moves.
|
|
989
|
+
|
|
886
990
|
Clean shutdown:
|
|
887
991
|
|
|
888
992
|
```python
|
|
@@ -24,7 +24,7 @@ Quick start::
|
|
|
24
24
|
|
|
25
25
|
from __future__ import annotations
|
|
26
26
|
|
|
27
|
-
__version__ = "0.
|
|
27
|
+
__version__ = "0.6.0"
|
|
28
28
|
|
|
29
29
|
|
|
30
30
|
from urkit.exceptions import (
|
|
@@ -55,6 +55,12 @@ from urkit.gripper.presets import (
|
|
|
55
55
|
PRESETS,
|
|
56
56
|
ROBOTIQ_2F_85,
|
|
57
57
|
ROBOTIQ_2F_140,
|
|
58
|
+
ROBOTIQ_EPICK_DUAL_L,
|
|
59
|
+
ROBOTIQ_EPICK_DUAL_S,
|
|
60
|
+
ROBOTIQ_EPICK_QUAD_L,
|
|
61
|
+
ROBOTIQ_EPICK_QUAD_S,
|
|
62
|
+
ROBOTIQ_EPICK_SINGLE_L,
|
|
63
|
+
ROBOTIQ_EPICK_SINGLE_S,
|
|
58
64
|
ROBOTIQ_HAND_E,
|
|
59
65
|
)
|
|
60
66
|
from urkit.motion import FreedriveMode
|
|
@@ -76,6 +82,12 @@ __all__ = [
|
|
|
76
82
|
"ROBOTIQ_2F_85",
|
|
77
83
|
"ROBOTIQ_2F_140",
|
|
78
84
|
"ROBOTIQ_HAND_E",
|
|
85
|
+
"ROBOTIQ_EPICK_SINGLE_S",
|
|
86
|
+
"ROBOTIQ_EPICK_SINGLE_L",
|
|
87
|
+
"ROBOTIQ_EPICK_DUAL_S",
|
|
88
|
+
"ROBOTIQ_EPICK_DUAL_L",
|
|
89
|
+
"ROBOTIQ_EPICK_QUAD_S",
|
|
90
|
+
"ROBOTIQ_EPICK_QUAD_L",
|
|
79
91
|
# Freedrive mode
|
|
80
92
|
"FreedriveMode",
|
|
81
93
|
# Move frame
|
|
@@ -61,7 +61,8 @@ def main() -> None:
|
|
|
61
61
|
type=str,
|
|
62
62
|
default=None,
|
|
63
63
|
help="Gripper preset (overrides config file). Use 'none' to disable gripper. "
|
|
64
|
-
"Accepts: 2f-85, 2f-140, hand-e, digital, none
|
|
64
|
+
"Accepts: 2f-85, 2f-140, hand-e, epick-<system>-<cup>, digital, none "
|
|
65
|
+
"(case-insensitive, _ or -)",
|
|
65
66
|
)
|
|
66
67
|
teach_parser.add_argument(
|
|
67
68
|
"--gripper-pin",
|
|
@@ -73,13 +74,15 @@ def main() -> None:
|
|
|
73
74
|
"--gripper-force",
|
|
74
75
|
type=int,
|
|
75
76
|
default=None,
|
|
76
|
-
help="
|
|
77
|
+
help="2F grip force 0-100 (EPick: use max_vacuum in the config's gripper_config) "
|
|
78
|
+
"(overrides config file)",
|
|
77
79
|
)
|
|
78
80
|
teach_parser.add_argument(
|
|
79
81
|
"--gripper-speed",
|
|
80
82
|
type=int,
|
|
81
83
|
default=None,
|
|
82
|
-
help="
|
|
84
|
+
help="2F movement speed 0-100 (EPick: use grip_timeout in the config's gripper_config) "
|
|
85
|
+
"(overrides config file)",
|
|
83
86
|
)
|
|
84
87
|
teach_parser.add_argument(
|
|
85
88
|
"--gripper-close-on-high",
|
|
@@ -29,7 +29,7 @@ robot_ip: 192.168.1.50
|
|
|
29
29
|
points_path: points.db
|
|
30
30
|
|
|
31
31
|
# Gripper preset (optional)
|
|
32
|
-
# Built-in: hand-e, 2f-85, 2f-140
|
|
32
|
+
# Built-in: hand-e, 2f-85, 2f-140, epick-<system>-<cup> (e.g. epick-quad-l)
|
|
33
33
|
# Digital I/O: digital
|
|
34
34
|
# Omit or set to none for no gripper
|
|
35
35
|
gripper: none
|
|
@@ -41,11 +41,18 @@ gripper_config:
|
|
|
41
41
|
# center_of_gravity: [0.0, 0.0, 0.0] # [x, y, z] in meters
|
|
42
42
|
# tcp_offset: [0.0, 0.0, 0.175, 0.0, 0.0, 0.0] # [x, y, z, rx, ry, rz]
|
|
43
43
|
|
|
44
|
-
#
|
|
44
|
+
# 2F grippers (hand-e, 2f-85, 2f-140)
|
|
45
45
|
# force: 100 # grip force 0-100
|
|
46
46
|
# speed: 100 # movement speed 0-100
|
|
47
47
|
# max_mm: 85 # max finger travel (e.g. 85 for 2F-85)
|
|
48
48
|
|
|
49
|
+
# EPick (vacuum): max_vacuum 20-100, min_vacuum 10 up to max_vacuum,
|
|
50
|
+
# grip_timeout 0-100 (x100 ms). A 2F param (force/speed) on an EPick
|
|
51
|
+
# preset raises an error and vice versa.
|
|
52
|
+
# max_vacuum: 60
|
|
53
|
+
# min_vacuum: 40
|
|
54
|
+
# grip_timeout: 30
|
|
55
|
+
|
|
49
56
|
# Digital gripper
|
|
50
57
|
# pin: 0 # digital output pin
|
|
51
58
|
# close_on_high: true # true=HIGH closes, false=LOW closes
|
|
@@ -19,7 +19,7 @@ from rich.table import Table
|
|
|
19
19
|
from urkit import __version__
|
|
20
20
|
from urkit.config import _load_config as load_config
|
|
21
21
|
from urkit.cli.colors import blue, cyan, dim, yellow
|
|
22
|
-
from urkit.cli.terminal import RawTerminal, read_burst, wait_input
|
|
22
|
+
from urkit.cli.terminal import RawTerminal, read_burst, wait_input
|
|
23
23
|
from urkit.points import Points
|
|
24
24
|
|
|
25
25
|
|
|
@@ -29,7 +29,6 @@ def points_command(args) -> None:
|
|
|
29
29
|
Args:
|
|
30
30
|
args: Parsed arguments from argparse (with points subcommand attributes).
|
|
31
31
|
"""
|
|
32
|
-
warn_if_windows()
|
|
33
32
|
_explore_points(args)
|
|
34
33
|
|
|
35
34
|
|