urkit 0.2.0__tar.gz → 0.3.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.
Files changed (39) hide show
  1. {urkit-0.2.0 → urkit-0.3.0}/PKG-INFO +109 -60
  2. {urkit-0.2.0 → urkit-0.3.0}/README.md +108 -59
  3. {urkit-0.2.0 → urkit-0.3.0}/pyproject.toml +1 -1
  4. {urkit-0.2.0 → urkit-0.3.0}/src/urkit/__init__.py +2 -4
  5. {urkit-0.2.0 → urkit-0.3.0}/src/urkit/__main__.py +8 -2
  6. {urkit-0.2.0 → urkit-0.3.0}/src/urkit/cli/points.py +69 -52
  7. {urkit-0.2.0 → urkit-0.3.0}/src/urkit/cli/teach.py +94 -20
  8. {urkit-0.2.0 → urkit-0.3.0}/src/urkit/geometry.py +1 -1
  9. {urkit-0.2.0 → urkit-0.3.0}/src/urkit/gripper/__init__.py +2 -2
  10. {urkit-0.2.0 → urkit-0.3.0}/src/urkit/gripper/presets.py +2 -2
  11. {urkit-0.2.0 → urkit-0.3.0}/src/urkit/motion.py +3 -4
  12. {urkit-0.2.0 → urkit-0.3.0}/src/urkit/points.py +1 -1
  13. {urkit-0.2.0 → urkit-0.3.0}/src/urkit/robot.py +62 -18
  14. {urkit-0.2.0 → urkit-0.3.0}/src/urkit/telemetry.py +16 -17
  15. {urkit-0.2.0 → urkit-0.3.0}/src/urkit.egg-info/PKG-INFO +109 -60
  16. {urkit-0.2.0 → urkit-0.3.0}/tests/test_robot_integration.py +1 -5
  17. {urkit-0.2.0 → urkit-0.3.0}/setup.cfg +0 -0
  18. {urkit-0.2.0 → urkit-0.3.0}/src/urkit/cli/__init__.py +0 -0
  19. {urkit-0.2.0 → urkit-0.3.0}/src/urkit/cli/colors.py +0 -0
  20. {urkit-0.2.0 → urkit-0.3.0}/src/urkit/cli/connection_monitor.py +0 -0
  21. {urkit-0.2.0 → urkit-0.3.0}/src/urkit/config.py +0 -0
  22. {urkit-0.2.0 → urkit-0.3.0}/src/urkit/connection.py +0 -0
  23. {urkit-0.2.0 → urkit-0.3.0}/src/urkit/exceptions.py +0 -0
  24. {urkit-0.2.0 → urkit-0.3.0}/src/urkit/gripper/base.py +0 -0
  25. {urkit-0.2.0 → urkit-0.3.0}/src/urkit/gripper/digital.py +0 -0
  26. {urkit-0.2.0 → urkit-0.3.0}/src/urkit/gripper/robotiq.py +0 -0
  27. {urkit-0.2.0 → urkit-0.3.0}/src/urkit/gripper/robotiq_preamble.py +0 -0
  28. {urkit-0.2.0 → urkit-0.3.0}/src/urkit/io.py +0 -0
  29. {urkit-0.2.0 → urkit-0.3.0}/src/urkit.egg-info/SOURCES.txt +0 -0
  30. {urkit-0.2.0 → urkit-0.3.0}/src/urkit.egg-info/dependency_links.txt +0 -0
  31. {urkit-0.2.0 → urkit-0.3.0}/src/urkit.egg-info/entry_points.txt +0 -0
  32. {urkit-0.2.0 → urkit-0.3.0}/src/urkit.egg-info/requires.txt +0 -0
  33. {urkit-0.2.0 → urkit-0.3.0}/src/urkit.egg-info/top_level.txt +0 -0
  34. {urkit-0.2.0 → urkit-0.3.0}/tests/test_exceptions.py +0 -0
  35. {urkit-0.2.0 → urkit-0.3.0}/tests/test_geometry.py +0 -0
  36. {urkit-0.2.0 → urkit-0.3.0}/tests/test_gripper.py +0 -0
  37. {urkit-0.2.0 → urkit-0.3.0}/tests/test_gripper_factory.py +0 -0
  38. {urkit-0.2.0 → urkit-0.3.0}/tests/test_gripper_presets.py +0 -0
  39. {urkit-0.2.0 → urkit-0.3.0}/tests/test_points.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: urkit
3
- Version: 0.2.0
3
+ Version: 0.3.0
4
4
  Summary: Universal Robots e-Series control toolkit built on ur_rtde
5
5
  Author: URKit Contributors
6
6
  License: MIT
@@ -58,29 +58,32 @@ Built on [`ur_rtde`](https://sdurobotics.gitlab.io/ur_rtde/), it packages the op
58
58
  ## Quick Start
59
59
 
60
60
  ```bash
61
- pip install urkit
61
+ pip install -U urkit
62
62
  ```
63
63
 
64
+ The `-U` (upgrade) flag ensures you always get the latest version — this project is in early development and changes frequently.
65
+
64
66
  Requires Python 3.8+ and a Universal Robots e-Series (UR3e to UR30).
65
67
 
66
68
  ### Robot Setup (one-time)
67
69
 
68
- 1. **Network**: `☰` → `System` → `Network`: set the robot's IP and subnet.
70
+ 1. **Network**: `☰` → `System` → `System` → `Network`. Set a static IP on the robot and a matching one on your PC. Both addresses must share the same first three octets (the network), with a different last octet (the host). For example:
71
+ - **Robot**: `172.31.1.42` / Subnet `255.255.255.0`
72
+ - **PC**: `172.31.1.1` / Netmask `255.255.255.0`
73
+ - Verify with `ping 172.31.1.42`. Connect via direct Ethernet cable or a switch.
69
74
  2. **Remote Control**: `☰` → `System` → `Remote Control`: Enable. Press the remote/local button on the pendant.
70
75
  3. **Security**: `☰` → `Security` → `Services`: enable RTDE and disable EtherNet/IP, PROFINET, or MODBUS if they're claiming RTDE registers. Save and restart.
71
76
 
72
77
  That's it. No `.urp` files to run, no extra programs needed.
73
78
 
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`.
79
+ ### Example
77
80
 
78
- ### Hello World
81
+ 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`.
79
82
 
80
83
  ```python
81
- from urkit import URRobot, ROBOTIQ_HAND_E
84
+ from urkit import URRobot, ROBOTIQ_HAND_E # or ROBOTIQ_2F_85, ROBOTIQ_2F_140, or gripper=None
82
85
 
83
- robot = URRobot(ip="172.31.1.200", points="points.db", gripper=ROBOTIQ_HAND_E)
86
+ robot = URRobot(ip="172.31.1.42", points="points.db", gripper=ROBOTIQ_HAND_E)
84
87
  robot.gripper.activate()
85
88
 
86
89
  robot.move_to("home")
@@ -92,9 +95,9 @@ robot.gripper.open()
92
95
 
93
96
  The typical workflow:
94
97
 
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
+ 1. **Teach points.** Use the CLI to position the robot and save named waypoints.
99
+ 2. **Write code.** Create a robot, move to points by name, apply offsets, run sequences.
100
+ 3. **Iterate.** Add more points, tweak your code, repeat.
98
101
 
99
102
  ---
100
103
 
@@ -107,8 +110,8 @@ URKit provides two CLI tools: **teach** for interactive robot control, and **poi
107
110
  The interactive teach pendant for moving the robot, saving points, and checking telemetry:
108
111
 
109
112
  ```bash
110
- urkit teach 172.31.1.200 # with robot IP
111
- urkit teach # reads IP from config.yaml
113
+ urkit teach 172.31.1.42 # with robot IP
114
+ urkit teach # reads IP from config.yaml
112
115
  ```
113
116
 
114
117
  **Flags:**
@@ -123,25 +126,18 @@ urkit teach # reads IP from config.yaml
123
126
  | `--gripper-close-on-high` | Digital polarity: `true` or `false` |
124
127
  | `--points` | Path to `points.db` file (overrides config) |
125
128
  | `--config` | Path to config file (default: `config.yaml` in project root or CWD) |
129
+ | `-e`, `--expert` | Disable safety speed clamping (full speed for goto/tcp-down) |
126
130
  | `-v`, `--verbose` | Show verbose output (debug connection issues) |
127
131
 
128
132
  ### Points Explorer
129
133
 
130
- Browse saved waypoints with real-time search filtering no robot connection needed:
134
+ Browse saved waypoints with real-time search filtering. No robot connection needed:
131
135
 
132
136
  ```bash
133
137
  urkit points # uses default points.db
134
138
  urkit points test_points.db # use specific database
135
139
  ```
136
140
 
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
141
  ### Key Map
146
142
 
147
143
  All movement and orientation keys support **hold-to-repeat**.
@@ -219,6 +215,23 @@ All movement and orientation keys support **hold-to-repeat**.
219
215
  </tr>
220
216
  </table>
221
217
 
218
+ ### Safety
219
+
220
+ By default, **Go To** and **TCP Down** 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.
221
+
222
+ Delta movements (W/S/A/D/Q/E) use step-size-based velocities that scale with the speed slider set by the user.
223
+
224
+ To disable the slow default and use full speed, pass `--expert` or set `expert_mode: true` in your config:
225
+
226
+ ```bash
227
+ urkit teach 172.31.1.42 --expert
228
+ ```
229
+
230
+ ```yaml
231
+ # config.yaml
232
+ expert_mode: true
233
+ ```
234
+
222
235
  ---
223
236
 
224
237
  ## API Reference
@@ -228,14 +241,14 @@ All movement and orientation keys support **hold-to-repeat**.
228
241
  ```python
229
242
  from urkit import URRobot, ROBOTIQ_HAND_E
230
243
 
231
- robot = URRobot(ip="172.31.1.200", points="points.db", gripper=ROBOTIQ_HAND_E)
244
+ robot = URRobot(ip="172.31.1.42", points="points.db", gripper=ROBOTIQ_HAND_E)
232
245
  ```
233
246
 
234
247
  With custom motion defaults:
235
248
 
236
249
  ```python
237
250
  robot = URRobot(
238
- ip="172.31.1.200",
251
+ ip="172.31.1.42",
239
252
  points="points.db",
240
253
  gripper=ROBOTIQ_HAND_E,
241
254
  default_vel=0.5, # m/s
@@ -268,39 +281,41 @@ robot.gripper.open() # fully open (blocking by default)
268
281
  robot.gripper.close() # fully closed, stops on contact
269
282
  robot.gripper.open(wait=False) # non-blocking return
270
283
  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
284
+ robot.gripper.set_force(50) # grip force: 0-100 (Robotiq only)
285
+ robot.gripper.set_speed(80) # movement speed: 0-100 (Robotiq only)
273
286
  ```
274
287
 
275
288
  Override preset values for custom fingers:
276
289
 
277
290
  ```python
278
- robot = URRobot(ip="172.31.1.200", points="points.db", gripper=ROBOTIQ_HAND_E, max_mm=120)
291
+ robot = URRobot(ip="172.31.1.42", points="points.db", gripper=ROBOTIQ_HAND_E, max_mm=120)
279
292
  ```
280
293
 
281
294
  #### Digital I/O Grippers
282
295
 
283
- For suction cups, solenoids, or custom actuators:
296
+ 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).
284
297
 
285
298
  ```python
286
299
  from urkit import URRobot, DigitalGripperConfig
287
300
 
288
301
  robot = URRobot(
289
- ip="172.31.1.200",
302
+ ip="172.31.1.42",
290
303
  points="points.db",
291
- gripper=DigitalGripperConfig(pin=3),
304
+ gripper=DigitalGripperConfig(pin=3), # pin 3 goes high = close
292
305
  )
293
306
 
294
- robot.gripper.open() # turn pin off (release)
295
- robot.gripper.close() # turn pin on (grab)
307
+ robot.gripper.open() # turn pin 3 off
308
+ robot.gripper.close() # turn pin 3 on
296
309
  ```
297
310
 
311
+ `set_force()` and `set_speed()` are not available for digital grippers.
312
+
298
313
  ### Points & Motion
299
314
 
300
- The points database is optional create a robot without one and attach later:
315
+ The points database is optional. Create a robot without one and attach later:
301
316
 
302
317
  ```python
303
- robot = URRobot(ip="172.31.1.200")
318
+ robot = URRobot(ip="172.31.1.42")
304
319
  robot.points_db = "points.db"
305
320
  ```
306
321
 
@@ -312,29 +327,46 @@ robot.move_to("pick", linear=False) # joint move
312
327
  robot.move_to("pick", vel=1.0, acc=0.5) # override speed
313
328
  ```
314
329
 
315
- #### Raw Poses
330
+ - **Linear (moveL):** TCP moves in a straight line. Predictable path, slower near complex orientations.
331
+ - **Joint (moveJ):** Each joint moves simultaneously. Faster, but the TCP follows an arc.
316
332
 
317
- ```python
318
- robot.move_to([0.5, 0, 0.3, 0, 0, 0]) # [x, y, z, rx, ry, rz]
319
- ```
333
+ #### Pose Format
334
+
335
+ A pose is `[x, y, z, rx, ry, rz]`: position in meters and orientation as a **rotation vector** (axis-angle in radians). This is not RPY (roll/pitch/yaw). The teach pendant displays RPY in degrees, which is a different representation. Values you see on the pendant won't match `get_tcp_pose()` directly.
320
336
 
321
337
  #### Offsets
322
338
 
339
+ Offsets are 6-element lists `[dx, dy, dz, drx, dry, drz]`:
340
+
323
341
  ```python
324
342
  robot.move_to("pick", offset=[0, 0, 0.05, 0, 0, 0]) # 5cm above pick
325
343
  ```
326
344
 
345
+ #### Resolve a Pose
346
+
347
+ Get a pose without moving. Useful for logging, comparisons, or custom motion:
348
+
349
+ ```python
350
+ pose = robot.get_pose("pick")
351
+ pose = robot.get_pose("pick", offset=[0, 0, 0.05, 0, 0, 0]) # with offset
352
+ robot.move_to(pose) # move to the resolved pose later
353
+ ```
354
+
327
355
  #### Coordinate Frame
328
356
 
329
357
  ```python
330
358
  from urkit import MoveFrame
331
359
 
332
360
  robot.move_frame = MoveFrame.TOOL # default is BASE
333
- robot.move_to("pick", offset=[0, 0, 0.05]) # 5cm along tool Z
361
+ robot.move_relative([0, 0, 0.05, 0, 0, 0]) # 5cm along tool Z
334
362
  ```
335
363
 
336
- - **BASE** (default): offset relative to robot base
337
- - **TOOL**: offset relative to TCP orientation
364
+ - **BASE** (default): delta relative to robot base
365
+ - **TOOL**: delta relative to TCP orientation
366
+
367
+ #### Points are tool-agnostic
368
+
369
+ 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.
338
370
 
339
371
  #### Point Management
340
372
 
@@ -351,7 +383,7 @@ robot.import_points("backup.json")
351
383
 
352
384
  ```python
353
385
  robot.move_relative([0, 0.01, 0, 0, 0, 0]) # 1cm along Y
354
- robot.move_relative([0, 0, 0.05], frame=MoveFrame.TOOL)
386
+ robot.move_relative([0, 0, 0.05, 0, 0, 0], frame=MoveFrame.TOOL) # 5cm along tool Z
355
387
  ```
356
388
 
357
389
  #### Sequences with Blending
@@ -364,7 +396,7 @@ robot.move_sequence(["a", "b", "c"], blend_radius=0.02)
364
396
  #### Contact Detection
365
397
 
366
398
  ```python
367
- robot.move_until_contact([0, 0, -0.02, 0, 0, 0]) # Ctrl+C to stop
399
+ robot.move_until_contact([0, 0, -0.02, 0, 0, 0])
368
400
  ```
369
401
 
370
402
  #### Velocity Control
@@ -388,11 +420,12 @@ robot.is_freedrive_active # check state
388
420
  #### Speed Control
389
421
 
390
422
  ```python
391
- robot.speed_stop() # emergency stop
392
- robot.set_speed_slider(0.5) # 50% hardware velocity cap
423
+ robot.speed_stop() # stop velocity-controlled motion (not E-stop)
424
+ robot.set_speed_slider(0.5) # 50% velocity cap
425
+ robot.get_speed_slider() # read current slider (0.0-1.0)
393
426
  ```
394
427
 
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.
428
+ The speed slider controls the pendant's speed multiplier. It's global, persistent, and affects all motion commands.
396
429
 
397
430
  #### Inverse Kinematics
398
431
 
@@ -407,7 +440,6 @@ pose = robot.get_tcp_pose() # [x, y, z, rx, ry, rz]
407
440
  joints = robot.get_joint_positions() # [j0..j5]
408
441
  force = robot.get_tcp_force() # [fx, fy, fz, mx, my, mz]
409
442
  mode = robot.get_robot_mode() # "REMOTE_CONTROL", "SERVOING", etc.
410
- scaling = robot.get_speed_scaling() # 0.0-1.0
411
443
  payload = robot.get_payload() # kg
412
444
  robot.is_protective_stopped() # bool
413
445
  robot.is_emergency_stopped() # bool
@@ -445,11 +477,12 @@ URKit searches for `config.yaml` in this order:
445
477
 
446
478
  | Key | Description | Example |
447
479
  |-----|-------------|---------|
448
- | `robot_ip` | Robot IP address | `192.168.1.100` |
480
+ | `robot_ip` | Robot IP address | `172.31.1.42` |
449
481
  | `points_path` | Path to SQLite points database | `points.db` |
450
482
  | `gripper` | Gripper preset name | `hand-e`, `2f-85`, `2f-140`, `digital` |
451
483
  | `default_vel` | Default linear velocity (m/s) | `0.5` |
452
484
  | `default_acc` | Default linear acceleration (m/s²) | `0.3` |
485
+ | `expert_mode` | Disable safety speed clamping | `false` |
453
486
 
454
487
  ### Gripper Config
455
488
 
@@ -469,17 +502,17 @@ gripper_config:
469
502
 
470
503
  ### CLI Override Precedence
471
504
 
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
505
+ 1. **CLI flags.** `urkit teach 172.31.1.42 --gripper none`
506
+ 2. **Config file.** Values from `config.yaml`
507
+ 3. **Built-in defaults.** `points.db`, no gripper, 0.5 m/s velocity
475
508
 
476
509
  ### Saving Config
477
510
 
478
511
  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
512
 
480
513
  ```bash
481
- urkit teach 172.31.1.200 --gripper hand-e # test, then press Y
482
- urkit teach # next time: reads from config
514
+ urkit teach 172.31.1.42 --gripper hand-e # test, then press Y
515
+ urkit teach # next time: reads from config
483
516
  ```
484
517
 
485
518
  Multiple workcells:
@@ -497,7 +530,7 @@ from urkit import load_config, resolve_config
497
530
  config = load_config() # auto-resolve
498
531
  config = load_config("/path/to/my.yaml") # explicit path
499
532
  path = resolve_config() # returns Path or None
500
- robot = URRobot.from_config({"robot_ip": "172.31.1.200", "gripper": "2f-85"})
533
+ robot = URRobot.from_config({"robot_ip": "172.31.1.42", "gripper": "2f-85"})
501
534
  ```
502
535
 
503
536
  ---
@@ -509,7 +542,6 @@ robot = URRobot.from_config({"robot_ip": "172.31.1.200", "gripper": "2f-85"})
509
542
  URKit doesn't try to wrap everything. Access the raw `ur_rtde` interfaces for advanced features:
510
543
 
511
544
  ```python
512
- robot.rtde_control.moveUntilContact([0, 0, -0.02, 0, 0, 0])
513
545
  robot.rtde_control.forceMode(...)
514
546
  robot.rtde_control.servoJ(...)
515
547
  robot.rtde_receive.getActualCurrent()
@@ -517,21 +549,22 @@ robot.rtde_receive.getActualCurrent()
517
549
 
518
550
  Full `ur_rtde` documentation: <https://sdurobotics.gitlab.io/ur_rtde/>
519
551
 
520
- ### Connection Lifecycle
552
+ ### Connection Monitoring
521
553
 
522
554
  ```python
523
555
  robot.connection_lost # bool: check if RTDE dropped
524
556
  robot.reconnect_rtde() # reconnect after a drop
525
- robot.disconnect() # clean shutdown
526
557
  ```
527
558
 
559
+ `disconnect()` is called automatically when the robot object is garbage collected.
560
+
528
561
  ### Error Handling
529
562
 
530
563
  ```python
531
- from urkit import URKitError, RobotNotInRemoteModeError, RtdeRegisterConflictError
564
+ from urkit import URKitError, MotionError, PointError
532
565
 
533
566
  try:
534
- robot = URRobot(ip="172.31.1.200", points="points.db")
567
+ robot = URRobot(ip="172.31.1.42", points="points.db")
535
568
  except RobotNotInRemoteModeError:
536
569
  print("Enable remote control on the teach pendant!")
537
570
  except RtdeRegisterConflictError:
@@ -539,3 +572,19 @@ except RtdeRegisterConflictError:
539
572
  except URKitError as e:
540
573
  print(f"Error: {e}")
541
574
  ```
575
+
576
+ Common runtime errors:
577
+
578
+ | Exception | When |
579
+ |-----------|------|
580
+ | `MotionError` | Unreachable pose, bad TCP offset, freedrive failure |
581
+ | `PointError` | Point not found, no points database configured |
582
+ | `GripperError` | Gripper activation or communication failure |
583
+ | `URKitIOError` | Invalid pin number, I/O read/write failure |
584
+ | `TelemetryError` | Cannot read pose, joints, force, etc. |
585
+
586
+ 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.
587
+
588
+ ### Connection Notes
589
+
590
+ 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.