urkit 0.3.4__tar.gz → 0.3.6__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.3.4 → urkit-0.3.6}/PKG-INFO +21 -30
  2. {urkit-0.3.4 → urkit-0.3.6}/README.md +19 -28
  3. {urkit-0.3.4 → urkit-0.3.6}/pyproject.toml +3 -3
  4. {urkit-0.3.4 → urkit-0.3.6}/src/urkit/__init__.py +2 -2
  5. {urkit-0.3.4 → urkit-0.3.6}/src/urkit/__main__.py +4 -4
  6. {urkit-0.3.4 → urkit-0.3.6}/src/urkit/cli/teach.py +12 -10
  7. {urkit-0.3.4 → urkit-0.3.6}/src/urkit/gripper/__init__.py +2 -2
  8. {urkit-0.3.4 → urkit-0.3.6}/src/urkit/gripper/base.py +23 -8
  9. {urkit-0.3.4 → urkit-0.3.6}/src/urkit/gripper/digital.py +13 -2
  10. {urkit-0.3.4 → urkit-0.3.6}/src/urkit/gripper/presets.py +3 -3
  11. {urkit-0.3.4 → urkit-0.3.6}/src/urkit/gripper/robotiq.py +37 -2
  12. {urkit-0.3.4 → urkit-0.3.6}/src/urkit/robot.py +43 -7
  13. {urkit-0.3.4 → urkit-0.3.6}/src/urkit.egg-info/PKG-INFO +21 -30
  14. {urkit-0.3.4 → urkit-0.3.6}/tests/test_gripper.py +13 -13
  15. {urkit-0.3.4 → urkit-0.3.6}/tests/test_robot_integration.py +1 -1
  16. {urkit-0.3.4 → urkit-0.3.6}/setup.cfg +0 -0
  17. {urkit-0.3.4 → urkit-0.3.6}/src/urkit/cli/__init__.py +0 -0
  18. {urkit-0.3.4 → urkit-0.3.6}/src/urkit/cli/colors.py +0 -0
  19. {urkit-0.3.4 → urkit-0.3.6}/src/urkit/cli/connection_monitor.py +0 -0
  20. {urkit-0.3.4 → urkit-0.3.6}/src/urkit/cli/points.py +0 -0
  21. {urkit-0.3.4 → urkit-0.3.6}/src/urkit/config.py +0 -0
  22. {urkit-0.3.4 → urkit-0.3.6}/src/urkit/connection.py +0 -0
  23. {urkit-0.3.4 → urkit-0.3.6}/src/urkit/exceptions.py +0 -0
  24. {urkit-0.3.4 → urkit-0.3.6}/src/urkit/geometry.py +0 -0
  25. {urkit-0.3.4 → urkit-0.3.6}/src/urkit/gripper/robotiq_preamble.py +0 -0
  26. {urkit-0.3.4 → urkit-0.3.6}/src/urkit/io.py +0 -0
  27. {urkit-0.3.4 → urkit-0.3.6}/src/urkit/motion.py +0 -0
  28. {urkit-0.3.4 → urkit-0.3.6}/src/urkit/points.py +0 -0
  29. {urkit-0.3.4 → urkit-0.3.6}/src/urkit/telemetry.py +0 -0
  30. {urkit-0.3.4 → urkit-0.3.6}/src/urkit.egg-info/SOURCES.txt +0 -0
  31. {urkit-0.3.4 → urkit-0.3.6}/src/urkit.egg-info/dependency_links.txt +0 -0
  32. {urkit-0.3.4 → urkit-0.3.6}/src/urkit.egg-info/entry_points.txt +0 -0
  33. {urkit-0.3.4 → urkit-0.3.6}/src/urkit.egg-info/requires.txt +0 -0
  34. {urkit-0.3.4 → urkit-0.3.6}/src/urkit.egg-info/top_level.txt +0 -0
  35. {urkit-0.3.4 → urkit-0.3.6}/tests/test_exceptions.py +0 -0
  36. {urkit-0.3.4 → urkit-0.3.6}/tests/test_geometry.py +0 -0
  37. {urkit-0.3.4 → urkit-0.3.6}/tests/test_gripper_factory.py +0 -0
  38. {urkit-0.3.4 → urkit-0.3.6}/tests/test_gripper_presets.py +0 -0
  39. {urkit-0.3.4 → urkit-0.3.6}/tests/test_points.py +0 -0
@@ -1,11 +1,11 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: urkit
3
- Version: 0.3.4
3
+ Version: 0.3.6
4
4
  Summary: Universal Robots e-Series control toolkit built on ur_rtde
5
5
  Author: URKit Contributors
6
6
  License: MIT
7
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
8
+ Keywords: universal-robots,ur3e,ur5e,ur7e,ur8,ur10e,ur12e,ur15,ur16e,ur18,ur20,ur30,rtde,robotics,industrial-robot
9
9
  Classifier: Development Status :: 3 - Alpha
10
10
  Classifier: Intended Audience :: Developers
11
11
  Classifier: License :: OSI Approved :: MIT License
@@ -69,9 +69,9 @@ Requires Python 3.8+ and a Universal Robots e-Series (UR3e to UR30).
69
69
  ### Robot Setup (one-time)
70
70
 
71
71
  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:
72
- - **Robot**: `172.31.1.42` / Subnet `255.255.255.0`
73
- - **PC**: `172.31.1.1` / Netmask `255.255.255.0`
74
- - Verify with `ping 172.31.1.42`. Connect via direct Ethernet cable or a switch.
72
+ - **Robot**: `192.168.1.50` / Subnet `255.255.255.0`
73
+ - **PC**: `192.168.1.1` / Netmask `255.255.255.0`
74
+ - Verify with `ping 192.168.1.50`. Connect via direct Ethernet cable or a switch.
75
75
  2. **Remote Control**: `☰` → `System` → `Remote Control`: Enable. Press the remote/local button on the pendant.
76
76
  3. **Security**: `☰` → `Security` → `Services`: enable RTDE and disable EtherNet/IP, PROFINET, or MODBUS if they're claiming RTDE registers. Save and restart.
77
77
 
@@ -84,7 +84,7 @@ If you have a Robotiq gripper, install the **Robotiq Gripper Control** URCap fir
84
84
  ```python
85
85
  from urkit import URRobot, ROBOTIQ_HAND_E # or ROBOTIQ_2F_85, ROBOTIQ_2F_140, or gripper=None
86
86
 
87
- robot = URRobot(ip="172.31.1.42", points="points.db", gripper=ROBOTIQ_HAND_E)
87
+ robot = URRobot(ip="192.168.1.50", points="points.db", gripper=ROBOTIQ_HAND_E)
88
88
  robot.gripper.activate()
89
89
 
90
90
  robot.move_to("home")
@@ -111,7 +111,7 @@ URKit provides two CLI tools: **teach** for interactive robot control, and **poi
111
111
  The interactive teach pendant for moving the robot, saving points, and checking telemetry:
112
112
 
113
113
  ```bash
114
- urkit teach 172.31.1.42 # with robot IP
114
+ urkit teach 192.168.1.50 # with robot IP
115
115
  urkit teach # reads IP from config.yaml
116
116
  ```
117
117
 
@@ -192,7 +192,7 @@ All movement and orientation keys support **hold-to-repeat**.
192
192
  <tr><td><code>V</code></td><td>Set position (mm)</td></tr>
193
193
  <tr><td><code>6</code></td><td>Set speed (0-100)</td></tr>
194
194
  <tr><td><code>7</code></td><td>Set force (0-100)</td></tr>
195
- <tr><td colspan="3">Gripper line shows: `Connected 50.0mm (0%) F=100 S=100`</td></tr>
195
+ <tr><td colspan="3">Gripper line shows: `Connected 25.0mm (50%) F=100 S=100`</td></tr>
196
196
  </table>
197
197
  </td>
198
198
  <td align="center" style="width:33%">
@@ -257,7 +257,7 @@ Delta movements (W/S/A/D/Q/E) use step-size-based velocities that scale with the
257
257
  To disable the slow default and use full speed, pass `--expert` or set `expert_mode: true` in your config:
258
258
 
259
259
  ```bash
260
- urkit teach 172.31.1.42 --expert
260
+ urkit teach 192.168.1.50 --expert
261
261
  ```
262
262
 
263
263
  ```yaml
@@ -274,14 +274,14 @@ expert_mode: true
274
274
  ```python
275
275
  from urkit import URRobot, ROBOTIQ_HAND_E
276
276
 
277
- robot = URRobot(ip="172.31.1.42", points="points.db", gripper=ROBOTIQ_HAND_E)
277
+ robot = URRobot(ip="192.168.1.50", points="points.db", gripper=ROBOTIQ_HAND_E)
278
278
  ```
279
279
 
280
280
  With custom motion defaults:
281
281
 
282
282
  ```python
283
283
  robot = URRobot(
284
- ip="172.31.1.42",
284
+ ip="192.168.1.50",
285
285
  points="points.db",
286
286
  gripper=ROBOTIQ_HAND_E,
287
287
  default_vel=0.5, # m/s
@@ -313,7 +313,8 @@ robot.gripper.is_activated() # check activation state
313
313
  robot.gripper.open() # fully open (blocking by default)
314
314
  robot.gripper.close() # fully closed, stops on contact
315
315
  robot.gripper.open(wait=False) # non-blocking return
316
- robot.gripper.set_position(20) # 20mm open (Robotiq only, 0 = closed)
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)
317
318
  robot.gripper.set_force(50) # grip force: 0-100 (Robotiq only)
318
319
  robot.gripper.set_speed(80) # movement speed: 0-100 (Robotiq only)
319
320
  ```
@@ -321,7 +322,7 @@ robot.gripper.set_speed(80) # movement speed: 0-100 (Robotiq only)
321
322
  Override preset values for custom fingers:
322
323
 
323
324
  ```python
324
- robot = URRobot(ip="172.31.1.42", points="points.db", gripper=ROBOTIQ_HAND_E, max_mm=120)
325
+ robot = URRobot(ip="192.168.1.50", points="points.db", gripper=ROBOTIQ_HAND_E, max_mm=120)
325
326
  ```
326
327
 
327
328
  #### Digital I/O Grippers
@@ -332,7 +333,7 @@ Robotiq grippers use a serial protocol over the robot's RS485 port. If you have
332
333
  from urkit import URRobot, DigitalGripperConfig
333
334
 
334
335
  robot = URRobot(
335
- ip="172.31.1.42",
336
+ ip="192.168.1.50",
336
337
  points="points.db",
337
338
  gripper=DigitalGripperConfig(pin=3), # pin 3 goes high = close
338
339
  )
@@ -348,7 +349,7 @@ robot.gripper.close() # turn pin 3 on
348
349
  The points database is optional. Create a robot without one and attach later:
349
350
 
350
351
  ```python
351
- robot = URRobot(ip="172.31.1.42")
352
+ robot = URRobot(ip="192.168.1.50")
352
353
  robot.points_db = "points.db"
353
354
  ```
354
355
 
@@ -552,7 +553,7 @@ URKit searches for `config.yaml` in this order:
552
553
 
553
554
  | Key | Description | Example |
554
555
  |-----|-------------|---------|
555
- | `robot_ip` | Robot IP address | `172.31.1.42` |
556
+ | `robot_ip` | Robot IP address | `192.168.1.50` |
556
557
  | `points_path` | Path to SQLite points database | `points.db` |
557
558
  | `gripper` | Gripper preset name | `hand-e`, `2f-85`, `2f-140`, `digital` |
558
559
  | `default_vel` | Default linear velocity (m/s) | `0.5` |
@@ -577,7 +578,7 @@ gripper_config:
577
578
 
578
579
  ### CLI Override Precedence
579
580
 
580
- 1. **CLI flags.** `urkit teach 172.31.1.42 --gripper none`
581
+ 1. **CLI flags.** `urkit teach 192.168.1.50 --gripper none`
581
582
  2. **Config file.** Values from `config.yaml`
582
583
  3. **Built-in defaults.** `points.db`, no gripper, 0.5 m/s velocity
583
584
 
@@ -586,7 +587,7 @@ gripper_config:
586
587
  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.
587
588
 
588
589
  ```bash
589
- urkit teach 172.31.1.42 --gripper hand-e # test, then press Y
590
+ urkit teach 192.168.1.50 --gripper hand-e # test, then press Y
590
591
  urkit teach # next time: reads from config
591
592
  ```
592
593
 
@@ -605,7 +606,7 @@ from urkit import load_config, resolve_config
605
606
  config = load_config() # auto-resolve
606
607
  config = load_config("/path/to/my.yaml") # explicit path
607
608
  path = resolve_config() # returns Path or None
608
- robot = URRobot.from_config({"robot_ip": "172.31.1.42", "gripper": "2f-85"})
609
+ robot = URRobot.from_config({"robot_ip": "192.168.1.50", "gripper": "2f-85"})
609
610
  ```
610
611
 
611
612
  ---
@@ -639,7 +640,7 @@ robot.reconnect_rtde() # reconnect after a drop
639
640
  from urkit import URKitError, MotionError, PointError
640
641
 
641
642
  try:
642
- robot = URRobot(ip="172.31.1.42", points="points.db")
643
+ robot = URRobot(ip="192.168.1.50", points="points.db")
643
644
  except RobotNotInRemoteModeError:
644
645
  print("Enable remote control on the teach pendant!")
645
646
  except RtdeRegisterConflictError:
@@ -670,13 +671,3 @@ The `URRobot` constructor takes a few seconds on first call: it validates the co
670
671
 
671
672
  See [CHANGELOG.md](CHANGELOG.md) for the full version history.
672
673
 
673
- ### Recent Changes
674
-
675
- - **v0.3.2** — Gripper speed/force keys (6/7), force/speed display
676
- - **v0.3.1** — Async motion, Space cancel, progress bar, joint display
677
- - **v0.3.0** — Safe/expert mode, speed_stop on exit, safety features
678
- - **v0.2.1** — `get_pose()` method
679
- - **v0.2.0** — README restructure
680
- - **v0.1.1** — `--gripper none`, `--config` flag, save config on demand
681
- - **v0.1.0** — Initial release
682
-
@@ -43,9 +43,9 @@ Requires Python 3.8+ and a Universal Robots e-Series (UR3e to UR30).
43
43
  ### Robot Setup (one-time)
44
44
 
45
45
  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:
46
- - **Robot**: `172.31.1.42` / Subnet `255.255.255.0`
47
- - **PC**: `172.31.1.1` / Netmask `255.255.255.0`
48
- - Verify with `ping 172.31.1.42`. Connect via direct Ethernet cable or a switch.
46
+ - **Robot**: `192.168.1.50` / Subnet `255.255.255.0`
47
+ - **PC**: `192.168.1.1` / Netmask `255.255.255.0`
48
+ - Verify with `ping 192.168.1.50`. Connect via direct Ethernet cable or a switch.
49
49
  2. **Remote Control**: `☰` → `System` → `Remote Control`: Enable. Press the remote/local button on the pendant.
50
50
  3. **Security**: `☰` → `Security` → `Services`: enable RTDE and disable EtherNet/IP, PROFINET, or MODBUS if they're claiming RTDE registers. Save and restart.
51
51
 
@@ -58,7 +58,7 @@ If you have a Robotiq gripper, install the **Robotiq Gripper Control** URCap fir
58
58
  ```python
59
59
  from urkit import URRobot, ROBOTIQ_HAND_E # or ROBOTIQ_2F_85, ROBOTIQ_2F_140, or gripper=None
60
60
 
61
- robot = URRobot(ip="172.31.1.42", points="points.db", gripper=ROBOTIQ_HAND_E)
61
+ robot = URRobot(ip="192.168.1.50", points="points.db", gripper=ROBOTIQ_HAND_E)
62
62
  robot.gripper.activate()
63
63
 
64
64
  robot.move_to("home")
@@ -85,7 +85,7 @@ URKit provides two CLI tools: **teach** for interactive robot control, and **poi
85
85
  The interactive teach pendant for moving the robot, saving points, and checking telemetry:
86
86
 
87
87
  ```bash
88
- urkit teach 172.31.1.42 # with robot IP
88
+ urkit teach 192.168.1.50 # with robot IP
89
89
  urkit teach # reads IP from config.yaml
90
90
  ```
91
91
 
@@ -166,7 +166,7 @@ All movement and orientation keys support **hold-to-repeat**.
166
166
  <tr><td><code>V</code></td><td>Set position (mm)</td></tr>
167
167
  <tr><td><code>6</code></td><td>Set speed (0-100)</td></tr>
168
168
  <tr><td><code>7</code></td><td>Set force (0-100)</td></tr>
169
- <tr><td colspan="3">Gripper line shows: `Connected 50.0mm (0%) F=100 S=100`</td></tr>
169
+ <tr><td colspan="3">Gripper line shows: `Connected 25.0mm (50%) F=100 S=100`</td></tr>
170
170
  </table>
171
171
  </td>
172
172
  <td align="center" style="width:33%">
@@ -231,7 +231,7 @@ Delta movements (W/S/A/D/Q/E) use step-size-based velocities that scale with the
231
231
  To disable the slow default and use full speed, pass `--expert` or set `expert_mode: true` in your config:
232
232
 
233
233
  ```bash
234
- urkit teach 172.31.1.42 --expert
234
+ urkit teach 192.168.1.50 --expert
235
235
  ```
236
236
 
237
237
  ```yaml
@@ -248,14 +248,14 @@ expert_mode: true
248
248
  ```python
249
249
  from urkit import URRobot, ROBOTIQ_HAND_E
250
250
 
251
- robot = URRobot(ip="172.31.1.42", points="points.db", gripper=ROBOTIQ_HAND_E)
251
+ robot = URRobot(ip="192.168.1.50", points="points.db", gripper=ROBOTIQ_HAND_E)
252
252
  ```
253
253
 
254
254
  With custom motion defaults:
255
255
 
256
256
  ```python
257
257
  robot = URRobot(
258
- ip="172.31.1.42",
258
+ ip="192.168.1.50",
259
259
  points="points.db",
260
260
  gripper=ROBOTIQ_HAND_E,
261
261
  default_vel=0.5, # m/s
@@ -287,7 +287,8 @@ robot.gripper.is_activated() # check activation state
287
287
  robot.gripper.open() # fully open (blocking by default)
288
288
  robot.gripper.close() # fully closed, stops on contact
289
289
  robot.gripper.open(wait=False) # non-blocking return
290
- robot.gripper.set_position(20) # 20mm open (Robotiq only, 0 = closed)
290
+ robot.gripper.set_position_mm(20) # 20mm open (Robotiq only, 0 = closed)
291
+ robot.gripper.set_position_percent(50) # 50% open (Robotiq only, 0 = open, 100 = closed)
291
292
  robot.gripper.set_force(50) # grip force: 0-100 (Robotiq only)
292
293
  robot.gripper.set_speed(80) # movement speed: 0-100 (Robotiq only)
293
294
  ```
@@ -295,7 +296,7 @@ robot.gripper.set_speed(80) # movement speed: 0-100 (Robotiq only)
295
296
  Override preset values for custom fingers:
296
297
 
297
298
  ```python
298
- robot = URRobot(ip="172.31.1.42", points="points.db", gripper=ROBOTIQ_HAND_E, max_mm=120)
299
+ robot = URRobot(ip="192.168.1.50", points="points.db", gripper=ROBOTIQ_HAND_E, max_mm=120)
299
300
  ```
300
301
 
301
302
  #### Digital I/O Grippers
@@ -306,7 +307,7 @@ Robotiq grippers use a serial protocol over the robot's RS485 port. If you have
306
307
  from urkit import URRobot, DigitalGripperConfig
307
308
 
308
309
  robot = URRobot(
309
- ip="172.31.1.42",
310
+ ip="192.168.1.50",
310
311
  points="points.db",
311
312
  gripper=DigitalGripperConfig(pin=3), # pin 3 goes high = close
312
313
  )
@@ -322,7 +323,7 @@ robot.gripper.close() # turn pin 3 on
322
323
  The points database is optional. Create a robot without one and attach later:
323
324
 
324
325
  ```python
325
- robot = URRobot(ip="172.31.1.42")
326
+ robot = URRobot(ip="192.168.1.50")
326
327
  robot.points_db = "points.db"
327
328
  ```
328
329
 
@@ -526,7 +527,7 @@ URKit searches for `config.yaml` in this order:
526
527
 
527
528
  | Key | Description | Example |
528
529
  |-----|-------------|---------|
529
- | `robot_ip` | Robot IP address | `172.31.1.42` |
530
+ | `robot_ip` | Robot IP address | `192.168.1.50` |
530
531
  | `points_path` | Path to SQLite points database | `points.db` |
531
532
  | `gripper` | Gripper preset name | `hand-e`, `2f-85`, `2f-140`, `digital` |
532
533
  | `default_vel` | Default linear velocity (m/s) | `0.5` |
@@ -551,7 +552,7 @@ gripper_config:
551
552
 
552
553
  ### CLI Override Precedence
553
554
 
554
- 1. **CLI flags.** `urkit teach 172.31.1.42 --gripper none`
555
+ 1. **CLI flags.** `urkit teach 192.168.1.50 --gripper none`
555
556
  2. **Config file.** Values from `config.yaml`
556
557
  3. **Built-in defaults.** `points.db`, no gripper, 0.5 m/s velocity
557
558
 
@@ -560,7 +561,7 @@ gripper_config:
560
561
  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.
561
562
 
562
563
  ```bash
563
- urkit teach 172.31.1.42 --gripper hand-e # test, then press Y
564
+ urkit teach 192.168.1.50 --gripper hand-e # test, then press Y
564
565
  urkit teach # next time: reads from config
565
566
  ```
566
567
 
@@ -579,7 +580,7 @@ from urkit import load_config, resolve_config
579
580
  config = load_config() # auto-resolve
580
581
  config = load_config("/path/to/my.yaml") # explicit path
581
582
  path = resolve_config() # returns Path or None
582
- robot = URRobot.from_config({"robot_ip": "172.31.1.42", "gripper": "2f-85"})
583
+ robot = URRobot.from_config({"robot_ip": "192.168.1.50", "gripper": "2f-85"})
583
584
  ```
584
585
 
585
586
  ---
@@ -613,7 +614,7 @@ robot.reconnect_rtde() # reconnect after a drop
613
614
  from urkit import URKitError, MotionError, PointError
614
615
 
615
616
  try:
616
- robot = URRobot(ip="172.31.1.42", points="points.db")
617
+ robot = URRobot(ip="192.168.1.50", points="points.db")
617
618
  except RobotNotInRemoteModeError:
618
619
  print("Enable remote control on the teach pendant!")
619
620
  except RtdeRegisterConflictError:
@@ -644,13 +645,3 @@ The `URRobot` constructor takes a few seconds on first call: it validates the co
644
645
 
645
646
  See [CHANGELOG.md](CHANGELOG.md) for the full version history.
646
647
 
647
- ### Recent Changes
648
-
649
- - **v0.3.2** — Gripper speed/force keys (6/7), force/speed display
650
- - **v0.3.1** — Async motion, Space cancel, progress bar, joint display
651
- - **v0.3.0** — Safe/expert mode, speed_stop on exit, safety features
652
- - **v0.2.1** — `get_pose()` method
653
- - **v0.2.0** — README restructure
654
- - **v0.1.1** — `--gripper none`, `--config` flag, save config on demand
655
- - **v0.1.0** — Initial release
656
-
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "urkit"
7
- version = "0.3.4"
7
+ version = "0.3.6"
8
8
  description = "Universal Robots e-Series control toolkit built on ur_rtde"
9
9
  readme = "README.md"
10
10
  license = {text = "MIT"}
@@ -18,11 +18,11 @@ keywords = [
18
18
  "ur3e",
19
19
  "ur5e",
20
20
  "ur7e",
21
+ "ur8",
21
22
  "ur10e",
22
23
  "ur12e",
23
- "ur16e",
24
- "ur8",
25
24
  "ur15",
25
+ "ur16e",
26
26
  "ur18",
27
27
  "ur20",
28
28
  "ur30",
@@ -10,7 +10,7 @@ Quick start::
10
10
  from urkit import URRobot, ROBOTIQ_HAND_E
11
11
 
12
12
  robot = URRobot(
13
- ip="172.31.1.42",
13
+ ip="192.168.1.50",
14
14
  points="points.db",
15
15
  gripper=ROBOTIQ_HAND_E,
16
16
  )
@@ -24,7 +24,7 @@ Quick start::
24
24
 
25
25
  from __future__ import annotations
26
26
 
27
- __version__ = "0.3.4"
27
+ __version__ = "0.3.6"
28
28
 
29
29
  from urkit.config import load_config, resolve_config
30
30
  from urkit.exceptions import (
@@ -1,8 +1,8 @@
1
1
  """urkit CLI entry point.
2
2
 
3
3
  Usage:
4
- urkit teach 172.31.1.42
5
- urkit teach 172.31.1.42 --gripper=hand-e
4
+ urkit teach 192.168.1.50
5
+ urkit teach 192.168.1.50 --gripper=hand-e
6
6
  urkit points list
7
7
  urkit points list --filter "pick*"
8
8
  """
@@ -41,8 +41,8 @@ def main() -> None:
41
41
  "--gripper",
42
42
  type=str,
43
43
  default=None,
44
- choices=["2f-85", "2f-140", "hand-e", "digital", "none"],
45
- help="Gripper preset (overrides config file). Use 'none' to disable gripper",
44
+ help="Gripper preset (overrides config file). Use 'none' to disable gripper. "
45
+ "Accepts: 2f-85, 2f-140, hand-e, digital, none (case-insensitive, _ or -)",
46
46
  )
47
47
  teach_parser.add_argument(
48
48
  "--gripper-pin",
@@ -4,9 +4,9 @@ A single terminal-based UI for manual robot control, point management,
4
4
  and freedrive — matching the pattern from robot_mover's point_saver.cpp.
5
5
 
6
6
  Usage:
7
- urkit 172.31.1.42 # connect with IP
7
+ urkit 192.168.1.50 # connect with IP
8
8
  urkit # reads robot_ip from config
9
- urkit -v 172.31.1.42 # verbose (debug boot commands)
9
+ urkit -v 192.168.1.50 # verbose (debug boot commands)
10
10
  """
11
11
 
12
12
  from __future__ import annotations
@@ -351,7 +351,7 @@ def _draw_screen(
351
351
  if payload == 0:
352
352
  tcp_label = f"{dim('0.0kg (no payload)')}"
353
353
  else:
354
- tcp_label = green(f"{payload:.1f}kg")
354
+ tcp_label = green(f"{payload:.3f}kg")
355
355
  lines.append(f" {blue('Payload:'.ljust(lw))} {tcp_label}")
356
356
  except Exception:
357
357
  pass
@@ -1229,13 +1229,12 @@ def _teach_pendant(
1229
1229
 
1230
1230
  elif key == "v":
1231
1231
  if robot.gripper:
1232
- max_mm = getattr(robot.gripper, '_max_mm', None)
1233
- prompt = f" Gripper position (0-{max_mm} mm): " if max_mm is not None else " Gripper position (mm): "
1232
+ prompt = " Gripper position (0-100%): "
1234
1233
  val = _read_input(prompt)
1235
1234
  try:
1236
- mm = float(val) # type: ignore
1237
- robot.gripper.set_position(mm) # type: ignore
1238
- messages.append(f"Gripper set to {mm:.1f} mm")
1235
+ percent = float(val) # type: ignore
1236
+ robot.gripper.set_position_percent(int(percent)) # type: ignore
1237
+ messages.append(f"Gripper set to {int(percent)}%")
1239
1238
  except (ValueError, TypeError):
1240
1239
  messages.append("Invalid position value")
1241
1240
  except Exception as e:
@@ -1369,6 +1368,9 @@ def teach_command(args) -> None:
1369
1368
  # "none" is an explicit CLI override — don't fall through to config
1370
1369
  if gripper_name and gripper_name.lower() == "none": # type: ignore
1371
1370
  gripper_name = None
1371
+ # Normalize: lowercase, replace _ with - (e.g. "2F_140" → "2f-140")
1372
+ if gripper_name and isinstance(gripper_name, str):
1373
+ gripper_name = gripper_name.lower().replace("_", "-")
1372
1374
  points_path = args.points or config.get("points_path") or "points.db"
1373
1375
 
1374
1376
  # Resolve gripper constructor params from config.yaml gripper_config section
@@ -1406,7 +1408,7 @@ def teach_command(args) -> None:
1406
1408
 
1407
1409
  if not ip:
1408
1410
  print("Error: No robot IP specified.")
1409
- print(" Usage: urkit 172.31.1.42")
1411
+ print(" Usage: urkit 192.168.1.50")
1410
1412
  print(" Or: urkit (uses last-used IP from config)")
1411
1413
  print(f" Config: {_resolve_default_config_path()}")
1412
1414
  sys.exit(1)
@@ -1414,7 +1416,7 @@ def teach_command(args) -> None:
1414
1416
  # Validate IP format before any connection attempt
1415
1417
  if not _validate_ip(ip): # type: ignore
1416
1418
  print(f"Error: \"{ip}\" is not a valid IPv4 address.")
1417
- print(" Usage: urkit 172.31.1.42")
1419
+ print(" Usage: urkit 192.168.1.50")
1418
1420
  sys.exit(1)
1419
1421
 
1420
1422
  # Quick ping check to verify reachability
@@ -7,10 +7,10 @@ Usage::
7
7
  from urkit import URRobot, ROBOTIQ_2F_85, DigitalGripperConfig
8
8
 
9
9
  # Robotiq preset — one arg does everything
10
- robot = URRobot(ip="172.31.1.42", gripper=ROBOTIQ_2F_85)
10
+ robot = URRobot(ip="192.168.1.50", gripper=ROBOTIQ_2F_85)
11
11
 
12
12
  # Digital I/O gripper
13
- robot = URRobot(ip="172.31.1.42", gripper=DigitalGripperConfig(pin=3))
13
+ robot = URRobot(ip="192.168.1.50", gripper=DigitalGripperConfig(pin=3))
14
14
  """
15
15
 
16
16
  from urkit.gripper.base import Gripper
@@ -1,7 +1,7 @@
1
1
  """Abstract gripper plugin interface.
2
2
 
3
3
  All gripper backends must implement this interface so that
4
- ``robot.gripper.open()``, ``close()``, and ``set_position()`` work
4
+ ``robot.gripper.open()``, ``close()``, ``set_position_mm()``, and ``set_position_percent()`` work
5
5
  uniformly regardless of the underlying hardware.
6
6
  """
7
7
 
@@ -13,7 +13,7 @@ from abc import ABC, abstractmethod
13
13
  class Gripper(ABC):
14
14
  """Abstract base class for gripper backends.
15
15
 
16
- Subclasses must implement ``open()``, ``close()``, and ``set_position()``.
16
+ Subclasses must implement ``open()``, ``close()``, ``set_position_mm()``, and ``set_position_percent()``.
17
17
  The ``activate()`` method is a no-op by default and should be overridden
18
18
  by backends that require explicit activation (e.g., Robotiq). The factory
19
19
  method ``Gripper.create()`` returns the appropriate backend.
@@ -36,15 +36,15 @@ class Gripper(ABC):
36
36
  """
37
37
 
38
38
  @abstractmethod
39
- def set_position(self, position: int) -> None:
40
- """Set the gripper to a specific position.
39
+ def set_position_mm(self, mm: float) -> None:
40
+ """Set the gripper to a specific position in millimeters.
41
41
 
42
- For Robotiq 2F grippers, position is 0-100 (0 = fully open,
43
- 100 = fully closed). Digital grippers don't support this and
44
- raise GripperError.
42
+ For Robotiq 2F grippers, mm is 0 (fully closed) to max_mm
43
+ (fully open). Digital grippers don't support this and raise
44
+ GripperError.
45
45
 
46
46
  Args:
47
- position: Gripper position.
47
+ mm: Opening in millimeters.
48
48
 
49
49
  Raises:
50
50
  GripperError: If the operation fails.
@@ -77,6 +77,21 @@ class Gripper(ABC):
77
77
  sockets or release resources (e.g., Robotiq grippers).
78
78
  """
79
79
 
80
+ def set_position_percent(self, percent: int, *, wait: bool = True) -> None:
81
+ """Set the gripper to a specific percentage opening.
82
+
83
+ 0 = fully open, 100 = fully closed.
84
+
85
+ Args:
86
+ percent: Percentage opening (0-100).
87
+ wait: If True, block until the gripper reaches the target
88
+ position (default True).
89
+
90
+ Raises:
91
+ GripperError: If percent is out of range or the operation
92
+ fails.
93
+ """
94
+
80
95
  def get_position_mm(self) -> float | None:
81
96
  """Return the last commanded position in mm, or None if unknown.
82
97
 
@@ -98,14 +98,25 @@ class DigitalGripper(Gripper):
98
98
  "ON" if self._closed_when_high else "OFF",
99
99
  )
100
100
 
101
- def set_position(self, position: int) -> None:
101
+ def set_position_mm(self, mm: float) -> None:
102
102
  """Set the gripper position.
103
103
 
104
104
  Raises:
105
105
  GripperError: Always — digital grippers don't support position control.
106
106
  """
107
107
  raise GripperError(
108
- "Digital grippers do not support set_position. "
108
+ "Digital grippers do not support set_position_mm. "
109
+ "Use open() or close() instead."
110
+ )
111
+
112
+ def set_position_percent(self, percent: int, *, wait: bool = True) -> None:
113
+ """Set the gripper position as a percentage.
114
+
115
+ Raises:
116
+ GripperError: Always — digital grippers don't support position control.
117
+ """
118
+ raise GripperError(
119
+ "Digital grippers do not support set_position_percent. "
109
120
  "Use open() or close() instead."
110
121
  )
111
122
 
@@ -10,12 +10,12 @@ Usage::
10
10
  from urkit.gripper.presets import ROBOTIQ_2F_85
11
11
 
12
12
  # One arg — specs + backend
13
- robot = URRobot(ip="172.31.1.42", gripper=ROBOTIQ_2F_85)
13
+ robot = URRobot(ip="192.168.1.50", gripper=ROBOTIQ_2F_85)
14
14
 
15
15
  # Digital I/O gripper
16
16
  from urkit.gripper.presets import DigitalGripperConfig
17
17
 
18
- robot = URRobot(ip="172.31.1.42", gripper=DigitalGripperConfig(pin=3))
18
+ robot = URRobot(ip="192.168.1.50", gripper=DigitalGripperConfig(pin=3))
19
19
  """
20
20
 
21
21
  from __future__ import annotations
@@ -33,7 +33,7 @@ class GripperPreset:
33
33
  center_of_gravity: Center of gravity in tool coordinates [x, y, z], meters.
34
34
  tcp_offset: TCP offset [x, y, z, rx, ry, rz], meters/radians.
35
35
  backend: Gripper backend name (e.g. ``"robotiq"``).
36
- max_mm: Maximum finger travel in mm (for ``set_position()``).
36
+ max_mm: Maximum finger travel in mm (for ``set_position_mm()``).
37
37
  force: Gripper force 0-100 (default 100).
38
38
  speed: Gripper speed 0-100 (default 100).
39
39
  """
@@ -94,7 +94,7 @@ class RobotiqGripper(Gripper):
94
94
  if not self._activated:
95
95
  raise GripperError(
96
96
  "Gripper is not activated. Call activate() before "
97
- "using open(), close(), or set_position()."
97
+ "using open(), close(), or set_position_mm()."
98
98
  )
99
99
 
100
100
  def _build_script(self, function_call: str) -> str:
@@ -259,7 +259,7 @@ class RobotiqGripper(Gripper):
259
259
  self._last_position_mm = 0.0
260
260
  logger.debug("Robotiq gripper closed (wait=%s)", wait)
261
261
 
262
- def set_position(self, mm: float, *, wait: bool = True) -> None:
262
+ def set_position_mm(self, mm: float, *, wait: bool = True) -> None:
263
263
  """Set the gripper to a specific opening in millimeters.
264
264
 
265
265
  Args:
@@ -285,6 +285,41 @@ class RobotiqGripper(Gripper):
285
285
  self._last_position_mm = mm
286
286
  logger.debug("Robotiq gripper set to %.1f mm (wait=%s)", mm, wait)
287
287
 
288
+ def set_position_percent(self, percent: int, *, wait: bool = True) -> None:
289
+ """Set the gripper to a specific percentage opening.
290
+
291
+ 0 = fully open, 100 = fully closed. Delegates to the preamble's
292
+ normalized functions (``rq_move_norm`` / ``rq_move_and_wait_norm``)
293
+ which handle the 0-100 → 0-255 gripper protocol conversion.
294
+
295
+ Args:
296
+ percent: Percentage opening (0-100).
297
+ wait: If True, block until the gripper reaches the target
298
+ position (default True).
299
+
300
+ Raises:
301
+ GripperError: If percent is out of range or the gripper
302
+ has not been activated.
303
+ """
304
+ if not 0 <= percent <= 100:
305
+ raise GripperError(
306
+ f"Robotiq gripper percent must be 0-100, got {percent}."
307
+ )
308
+ self._require_activated()
309
+ func = (
310
+ f"rq_move_and_wait_norm({percent})"
311
+ if wait
312
+ else f"rq_move_norm({percent})"
313
+ )
314
+ self._send_script(self._build_script(func))
315
+ # Track last position in mm for consistency with get_position_mm()
316
+ mm = self._max_mm * (1 - percent / 100.0)
317
+ self._last_position_mm = mm
318
+ logger.debug(
319
+ "Robotiq gripper set to %d%% (%.1f mm) (wait=%s)",
320
+ percent, mm, wait,
321
+ )
322
+
288
323
  def set_force(self, force: int) -> None:
289
324
  """Set gripper force for subsequent movements.
290
325
 
@@ -87,7 +87,7 @@ class URRobot:
87
87
 
88
88
  Example:
89
89
  >>> from urkit import URRobot, ROBOTIQ_2F_85
90
- >>> robot = URRobot(ip="172.31.1.42", gripper=ROBOTIQ_2F_85)
90
+ >>> robot = URRobot(ip="192.168.1.50", gripper=ROBOTIQ_2F_85)
91
91
  >>> robot.move_relative([0.01, 0, 0, 0, 0, 0]) # works without points
92
92
  >>> robot.points_db = "points.db" # set lazily
93
93
  >>> robot.save_point("home")
@@ -118,6 +118,7 @@ class URRobot:
118
118
  resolved_cog: list[float] = [0.0, 0.0, 0.0]
119
119
  resolved_tcp: list[float] | None = None
120
120
  gripper_backend: str | None = None
121
+ self._payload: float = 0.0
121
122
  if isinstance(gripper, GripperPreset):
122
123
  resolved_payload = gripper.mass
123
124
  resolved_cog = list(gripper.center_of_gravity)
@@ -246,10 +247,14 @@ class URRobot:
246
247
  self.set_tcp_offset(resolved_tcp)
247
248
  if resolved_payload > 0:
248
249
  self.set_payload(resolved_payload, resolved_cog)
250
+ else:
251
+ # No payload configured — explicitly zero it on the robot
252
+ # to clear any stale value from a previous session.
253
+ self.set_payload(0.0)
249
254
 
250
255
  logger.info("URRobot initialized at %s", ip)
251
256
 
252
- def activate_gripper(self, *, timeout: float = 5.0) -> bool:
257
+ def activate_gripper(self, *, timeout: float = 10.0) -> bool:
253
258
  """Activate the gripper with a timeout.
254
259
 
255
260
  Tries to activate the configured gripper. If activation fails
@@ -322,7 +327,7 @@ class URRobot:
322
327
 
323
328
  Config file keys::
324
329
 
325
- robot_ip: 172.31.1.42
330
+ robot_ip: 192.168.1.50
326
331
  points_path: points.db
327
332
  gripper: hand-e
328
333
  gripper_config:
@@ -335,7 +340,7 @@ class URRobot:
335
340
  Example:
336
341
  >>> robot = URRobot.from_config("config.yaml")
337
342
  >>> robot = URRobot.from_config("config.yaml", ip="10.0.0.50")
338
- >>> robot = URRobot.from_config({"robot_ip": "172.31.1.42", "points_path": "points.db", "gripper": "2f-85"})
343
+ >>> robot = URRobot.from_config({"robot_ip": "192.168.1.50", "points_path": "points.db", "gripper": "2f-85"})
339
344
  """
340
345
  from urkit.config import resolve_config
341
346
 
@@ -740,9 +745,25 @@ class URRobot:
740
745
  cog = center_of_gravity if center_of_gravity is not None else [0.0, 0.0, 0.0]
741
746
  if len(cog) != 3:
742
747
  raise MotionError(f"Center of gravity must have 3 values, got {len(cog)}.")
748
+ # Try newer setTargetPayload first (PolyScope 5.11.0+), fall back to setPayload
743
749
  try:
744
- self._rtde_c.setPayload(mass, cog)
745
- logger.info("Payload set to %.2f kg, CoG=%s", mass, cog)
750
+ inertia = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
751
+ self._rtde_c.setTargetPayload(mass, cog, inertia)
752
+ self._payload = mass
753
+ logger.info("Payload set to %.2f kg, CoG=%s (setTargetPayload)", mass, cog)
754
+ except AttributeError:
755
+ # setTargetPayload not available — older PolyScope
756
+ try:
757
+ self._rtde_c.setPayload(mass, cog)
758
+ self._payload = mass
759
+ logger.warning(
760
+ "Payload set to %.2f kg, CoG=%s (setPayload fallback — "
761
+ "setTargetPayload unavailable, likely PolyScope < 5.11.0)",
762
+ mass,
763
+ cog,
764
+ )
765
+ except Exception as e2:
766
+ raise MotionError(f"Failed to set payload: {e2}")
746
767
  except Exception as e:
747
768
  raise MotionError(f"Failed to set payload: {e}")
748
769
 
@@ -1264,7 +1285,22 @@ class URRobot:
1264
1285
 
1265
1286
  def get_payload(self) -> float:
1266
1287
  """Get the currently configured payload mass (kg)."""
1267
- return self._telemetry.get_payload()
1288
+ return self._payload
1289
+
1290
+ def get_polyscope_version(self) -> str | None:
1291
+ """Get the PolyScope version string via Dashboard (e.g. '5.25.0').
1292
+
1293
+ Returns:
1294
+ Version string, or None if Dashboard is unavailable.
1295
+ """
1296
+ try:
1297
+ if self._dashboard is None:
1298
+ self._connect_dashboard()
1299
+ if self._dashboard is None:
1300
+ return None
1301
+ return _dashboard_command(self._dashboard, "version") # type: ignore
1302
+ except Exception:
1303
+ return None
1268
1304
 
1269
1305
  def is_protective_stopped(self) -> bool:
1270
1306
  """Check if the robot is in protective stop."""
@@ -1,11 +1,11 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: urkit
3
- Version: 0.3.4
3
+ Version: 0.3.6
4
4
  Summary: Universal Robots e-Series control toolkit built on ur_rtde
5
5
  Author: URKit Contributors
6
6
  License: MIT
7
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
8
+ Keywords: universal-robots,ur3e,ur5e,ur7e,ur8,ur10e,ur12e,ur15,ur16e,ur18,ur20,ur30,rtde,robotics,industrial-robot
9
9
  Classifier: Development Status :: 3 - Alpha
10
10
  Classifier: Intended Audience :: Developers
11
11
  Classifier: License :: OSI Approved :: MIT License
@@ -69,9 +69,9 @@ Requires Python 3.8+ and a Universal Robots e-Series (UR3e to UR30).
69
69
  ### Robot Setup (one-time)
70
70
 
71
71
  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:
72
- - **Robot**: `172.31.1.42` / Subnet `255.255.255.0`
73
- - **PC**: `172.31.1.1` / Netmask `255.255.255.0`
74
- - Verify with `ping 172.31.1.42`. Connect via direct Ethernet cable or a switch.
72
+ - **Robot**: `192.168.1.50` / Subnet `255.255.255.0`
73
+ - **PC**: `192.168.1.1` / Netmask `255.255.255.0`
74
+ - Verify with `ping 192.168.1.50`. Connect via direct Ethernet cable or a switch.
75
75
  2. **Remote Control**: `☰` → `System` → `Remote Control`: Enable. Press the remote/local button on the pendant.
76
76
  3. **Security**: `☰` → `Security` → `Services`: enable RTDE and disable EtherNet/IP, PROFINET, or MODBUS if they're claiming RTDE registers. Save and restart.
77
77
 
@@ -84,7 +84,7 @@ If you have a Robotiq gripper, install the **Robotiq Gripper Control** URCap fir
84
84
  ```python
85
85
  from urkit import URRobot, ROBOTIQ_HAND_E # or ROBOTIQ_2F_85, ROBOTIQ_2F_140, or gripper=None
86
86
 
87
- robot = URRobot(ip="172.31.1.42", points="points.db", gripper=ROBOTIQ_HAND_E)
87
+ robot = URRobot(ip="192.168.1.50", points="points.db", gripper=ROBOTIQ_HAND_E)
88
88
  robot.gripper.activate()
89
89
 
90
90
  robot.move_to("home")
@@ -111,7 +111,7 @@ URKit provides two CLI tools: **teach** for interactive robot control, and **poi
111
111
  The interactive teach pendant for moving the robot, saving points, and checking telemetry:
112
112
 
113
113
  ```bash
114
- urkit teach 172.31.1.42 # with robot IP
114
+ urkit teach 192.168.1.50 # with robot IP
115
115
  urkit teach # reads IP from config.yaml
116
116
  ```
117
117
 
@@ -192,7 +192,7 @@ All movement and orientation keys support **hold-to-repeat**.
192
192
  <tr><td><code>V</code></td><td>Set position (mm)</td></tr>
193
193
  <tr><td><code>6</code></td><td>Set speed (0-100)</td></tr>
194
194
  <tr><td><code>7</code></td><td>Set force (0-100)</td></tr>
195
- <tr><td colspan="3">Gripper line shows: `Connected 50.0mm (0%) F=100 S=100`</td></tr>
195
+ <tr><td colspan="3">Gripper line shows: `Connected 25.0mm (50%) F=100 S=100`</td></tr>
196
196
  </table>
197
197
  </td>
198
198
  <td align="center" style="width:33%">
@@ -257,7 +257,7 @@ Delta movements (W/S/A/D/Q/E) use step-size-based velocities that scale with the
257
257
  To disable the slow default and use full speed, pass `--expert` or set `expert_mode: true` in your config:
258
258
 
259
259
  ```bash
260
- urkit teach 172.31.1.42 --expert
260
+ urkit teach 192.168.1.50 --expert
261
261
  ```
262
262
 
263
263
  ```yaml
@@ -274,14 +274,14 @@ expert_mode: true
274
274
  ```python
275
275
  from urkit import URRobot, ROBOTIQ_HAND_E
276
276
 
277
- robot = URRobot(ip="172.31.1.42", points="points.db", gripper=ROBOTIQ_HAND_E)
277
+ robot = URRobot(ip="192.168.1.50", points="points.db", gripper=ROBOTIQ_HAND_E)
278
278
  ```
279
279
 
280
280
  With custom motion defaults:
281
281
 
282
282
  ```python
283
283
  robot = URRobot(
284
- ip="172.31.1.42",
284
+ ip="192.168.1.50",
285
285
  points="points.db",
286
286
  gripper=ROBOTIQ_HAND_E,
287
287
  default_vel=0.5, # m/s
@@ -313,7 +313,8 @@ robot.gripper.is_activated() # check activation state
313
313
  robot.gripper.open() # fully open (blocking by default)
314
314
  robot.gripper.close() # fully closed, stops on contact
315
315
  robot.gripper.open(wait=False) # non-blocking return
316
- robot.gripper.set_position(20) # 20mm open (Robotiq only, 0 = closed)
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)
317
318
  robot.gripper.set_force(50) # grip force: 0-100 (Robotiq only)
318
319
  robot.gripper.set_speed(80) # movement speed: 0-100 (Robotiq only)
319
320
  ```
@@ -321,7 +322,7 @@ robot.gripper.set_speed(80) # movement speed: 0-100 (Robotiq only)
321
322
  Override preset values for custom fingers:
322
323
 
323
324
  ```python
324
- robot = URRobot(ip="172.31.1.42", points="points.db", gripper=ROBOTIQ_HAND_E, max_mm=120)
325
+ robot = URRobot(ip="192.168.1.50", points="points.db", gripper=ROBOTIQ_HAND_E, max_mm=120)
325
326
  ```
326
327
 
327
328
  #### Digital I/O Grippers
@@ -332,7 +333,7 @@ Robotiq grippers use a serial protocol over the robot's RS485 port. If you have
332
333
  from urkit import URRobot, DigitalGripperConfig
333
334
 
334
335
  robot = URRobot(
335
- ip="172.31.1.42",
336
+ ip="192.168.1.50",
336
337
  points="points.db",
337
338
  gripper=DigitalGripperConfig(pin=3), # pin 3 goes high = close
338
339
  )
@@ -348,7 +349,7 @@ robot.gripper.close() # turn pin 3 on
348
349
  The points database is optional. Create a robot without one and attach later:
349
350
 
350
351
  ```python
351
- robot = URRobot(ip="172.31.1.42")
352
+ robot = URRobot(ip="192.168.1.50")
352
353
  robot.points_db = "points.db"
353
354
  ```
354
355
 
@@ -552,7 +553,7 @@ URKit searches for `config.yaml` in this order:
552
553
 
553
554
  | Key | Description | Example |
554
555
  |-----|-------------|---------|
555
- | `robot_ip` | Robot IP address | `172.31.1.42` |
556
+ | `robot_ip` | Robot IP address | `192.168.1.50` |
556
557
  | `points_path` | Path to SQLite points database | `points.db` |
557
558
  | `gripper` | Gripper preset name | `hand-e`, `2f-85`, `2f-140`, `digital` |
558
559
  | `default_vel` | Default linear velocity (m/s) | `0.5` |
@@ -577,7 +578,7 @@ gripper_config:
577
578
 
578
579
  ### CLI Override Precedence
579
580
 
580
- 1. **CLI flags.** `urkit teach 172.31.1.42 --gripper none`
581
+ 1. **CLI flags.** `urkit teach 192.168.1.50 --gripper none`
581
582
  2. **Config file.** Values from `config.yaml`
582
583
  3. **Built-in defaults.** `points.db`, no gripper, 0.5 m/s velocity
583
584
 
@@ -586,7 +587,7 @@ gripper_config:
586
587
  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.
587
588
 
588
589
  ```bash
589
- urkit teach 172.31.1.42 --gripper hand-e # test, then press Y
590
+ urkit teach 192.168.1.50 --gripper hand-e # test, then press Y
590
591
  urkit teach # next time: reads from config
591
592
  ```
592
593
 
@@ -605,7 +606,7 @@ from urkit import load_config, resolve_config
605
606
  config = load_config() # auto-resolve
606
607
  config = load_config("/path/to/my.yaml") # explicit path
607
608
  path = resolve_config() # returns Path or None
608
- robot = URRobot.from_config({"robot_ip": "172.31.1.42", "gripper": "2f-85"})
609
+ robot = URRobot.from_config({"robot_ip": "192.168.1.50", "gripper": "2f-85"})
609
610
  ```
610
611
 
611
612
  ---
@@ -639,7 +640,7 @@ robot.reconnect_rtde() # reconnect after a drop
639
640
  from urkit import URKitError, MotionError, PointError
640
641
 
641
642
  try:
642
- robot = URRobot(ip="172.31.1.42", points="points.db")
643
+ robot = URRobot(ip="192.168.1.50", points="points.db")
643
644
  except RobotNotInRemoteModeError:
644
645
  print("Enable remote control on the teach pendant!")
645
646
  except RtdeRegisterConflictError:
@@ -670,13 +671,3 @@ The `URRobot` constructor takes a few seconds on first call: it validates the co
670
671
 
671
672
  See [CHANGELOG.md](CHANGELOG.md) for the full version history.
672
673
 
673
- ### Recent Changes
674
-
675
- - **v0.3.2** — Gripper speed/force keys (6/7), force/speed display
676
- - **v0.3.1** — Async motion, Space cancel, progress bar, joint display
677
- - **v0.3.0** — Safe/expert mode, speed_stop on exit, safety features
678
- - **v0.2.1** — `get_pose()` method
679
- - **v0.2.0** — README restructure
680
- - **v0.1.1** — `--gripper none`, `--config` flag, save config on demand
681
- - **v0.1.0** — Initial release
682
-
@@ -49,10 +49,10 @@ class TestRobotiqActivation:
49
49
  with pytest.raises(GripperError, match="not activated"):
50
50
  self.gripper.close()
51
51
 
52
- def test_set_position_without_activate_raises(self):
53
- """set_position() raises if gripper is not activated."""
52
+ def test_set_position_mm_without_activate_raises(self):
53
+ """set_position_mm() raises if gripper is not activated."""
54
54
  with pytest.raises(GripperError, match="not activated"):
55
- self.gripper.set_position(50)
55
+ self.gripper.set_position_mm(50)
56
56
 
57
57
  def test_activate_sends_script_and_sets_flag(self):
58
58
  """activate() sends the preamble+activation script and sets _activated."""
@@ -86,11 +86,11 @@ class TestRobotiqActivation:
86
86
  # activate (combined check+activate+open) + close = 2 calls
87
87
  assert self.rtde.sendCustomScriptFunction.call_count == 2
88
88
 
89
- def test_set_position_after_activate(self):
90
- """set_position() works after activate()."""
89
+ def test_set_position_mm_after_activate(self):
90
+ """set_position_mm() works after activate()."""
91
91
  self.gripper.activate()
92
- self.gripper.set_position(25)
93
- # activate (combined check+activate+open) + set_position = 2 calls
92
+ self.gripper.set_position_mm(25)
93
+ # activate (combined check+activate+open) + set_position_mm = 2 calls
94
94
  assert self.rtde.sendCustomScriptFunction.call_count == 2
95
95
 
96
96
  def test_requires_rtde_control(self):
@@ -137,16 +137,16 @@ class TestRobotiqActivation:
137
137
  self.gripper.close()
138
138
  assert self.gripper.get_position_mm() == 0.0
139
139
 
140
- def test_get_position_mm_after_set_position(self):
140
+ def test_get_position_mm_after_set_position_mm(self):
141
141
  """get_position_mm() returns the commanded position."""
142
142
  self.gripper.activate()
143
- self.gripper.set_position(25)
143
+ self.gripper.set_position_mm(25)
144
144
  assert self.gripper.get_position_mm() == 25.0
145
145
 
146
146
  def test_get_position_mm_after_disconnect(self):
147
147
  """get_position_mm() returns None after disconnect."""
148
148
  self.gripper.activate()
149
- self.gripper.set_position(30)
149
+ self.gripper.set_position_mm(30)
150
150
  self.gripper.disconnect()
151
151
  assert self.gripper.get_position_mm() is None
152
152
 
@@ -189,10 +189,10 @@ class TestDigitalActivation:
189
189
  gripper.close()
190
190
  mock_rtde.setStandardDigitalOut.assert_called_with(1, False)
191
191
 
192
- def test_set_position_raises(self, mock_rtde, mock_rtde_r):
192
+ def test_set_position_mm_raises(self, mock_rtde, mock_rtde_r):
193
193
  gripper = DigitalGripper(mock_rtde, mock_rtde_r, pin=0)
194
- with pytest.raises(GripperError, match="do not support set_position"):
195
- gripper.set_position(0)
194
+ with pytest.raises(GripperError, match="do not support set_position_mm"):
195
+ gripper.set_position_mm(0)
196
196
 
197
197
  def test_set_force_raises(self, mock_rtde, mock_rtde_r):
198
198
  gripper = DigitalGripper(mock_rtde, mock_rtde_r, pin=0)
@@ -1,7 +1,7 @@
1
1
  """Integration tests against a real Universal Robot.
2
2
 
3
3
  Set ROBOT_IP environment variable to run:
4
- ROBOT_IP=172.31.1.42 PYTHONPATH= .venv/bin/python -m pytest tests/test_robot_integration.py -v
4
+ ROBOT_IP=192.168.1.50 PYTHONPATH= .venv/bin/python -m pytest tests/test_robot_integration.py -v
5
5
 
6
6
  Tests are skipped automatically if ROBOT_IP is not set or the robot
7
7
  is unreachable. All tests are designed to be safe — read-only telemetry
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes