urkit 0.3.7__tar.gz → 0.3.9__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {urkit-0.3.7 → urkit-0.3.9}/PKG-INFO +10 -7
- {urkit-0.3.7 → urkit-0.3.9}/README.md +9 -6
- {urkit-0.3.7 → urkit-0.3.9}/pyproject.toml +1 -1
- {urkit-0.3.7 → urkit-0.3.9}/src/urkit/__init__.py +1 -1
- {urkit-0.3.7 → urkit-0.3.9}/src/urkit/robot.py +156 -32
- {urkit-0.3.7 → urkit-0.3.9}/src/urkit.egg-info/PKG-INFO +10 -7
- {urkit-0.3.7 → urkit-0.3.9}/setup.cfg +0 -0
- {urkit-0.3.7 → urkit-0.3.9}/src/urkit/__main__.py +0 -0
- {urkit-0.3.7 → urkit-0.3.9}/src/urkit/cli/__init__.py +0 -0
- {urkit-0.3.7 → urkit-0.3.9}/src/urkit/cli/colors.py +0 -0
- {urkit-0.3.7 → urkit-0.3.9}/src/urkit/cli/connection_monitor.py +0 -0
- {urkit-0.3.7 → urkit-0.3.9}/src/urkit/cli/points.py +0 -0
- {urkit-0.3.7 → urkit-0.3.9}/src/urkit/cli/teach.py +0 -0
- {urkit-0.3.7 → urkit-0.3.9}/src/urkit/config.py +0 -0
- {urkit-0.3.7 → urkit-0.3.9}/src/urkit/connection.py +0 -0
- {urkit-0.3.7 → urkit-0.3.9}/src/urkit/exceptions.py +0 -0
- {urkit-0.3.7 → urkit-0.3.9}/src/urkit/geometry.py +0 -0
- {urkit-0.3.7 → urkit-0.3.9}/src/urkit/gripper/__init__.py +0 -0
- {urkit-0.3.7 → urkit-0.3.9}/src/urkit/gripper/base.py +0 -0
- {urkit-0.3.7 → urkit-0.3.9}/src/urkit/gripper/digital.py +0 -0
- {urkit-0.3.7 → urkit-0.3.9}/src/urkit/gripper/presets.py +0 -0
- {urkit-0.3.7 → urkit-0.3.9}/src/urkit/gripper/robotiq.py +0 -0
- {urkit-0.3.7 → urkit-0.3.9}/src/urkit/gripper/robotiq_preamble.py +0 -0
- {urkit-0.3.7 → urkit-0.3.9}/src/urkit/io.py +0 -0
- {urkit-0.3.7 → urkit-0.3.9}/src/urkit/motion.py +0 -0
- {urkit-0.3.7 → urkit-0.3.9}/src/urkit/points.py +0 -0
- {urkit-0.3.7 → urkit-0.3.9}/src/urkit/telemetry.py +0 -0
- {urkit-0.3.7 → urkit-0.3.9}/src/urkit.egg-info/SOURCES.txt +0 -0
- {urkit-0.3.7 → urkit-0.3.9}/src/urkit.egg-info/dependency_links.txt +0 -0
- {urkit-0.3.7 → urkit-0.3.9}/src/urkit.egg-info/entry_points.txt +0 -0
- {urkit-0.3.7 → urkit-0.3.9}/src/urkit.egg-info/requires.txt +0 -0
- {urkit-0.3.7 → urkit-0.3.9}/src/urkit.egg-info/top_level.txt +0 -0
- {urkit-0.3.7 → urkit-0.3.9}/tests/test_exceptions.py +0 -0
- {urkit-0.3.7 → urkit-0.3.9}/tests/test_geometry.py +0 -0
- {urkit-0.3.7 → urkit-0.3.9}/tests/test_gripper.py +0 -0
- {urkit-0.3.7 → urkit-0.3.9}/tests/test_gripper_factory.py +0 -0
- {urkit-0.3.7 → urkit-0.3.9}/tests/test_gripper_presets.py +0 -0
- {urkit-0.3.7 → urkit-0.3.9}/tests/test_points.py +0 -0
- {urkit-0.3.7 → urkit-0.3.9}/tests/test_robot_integration.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: urkit
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.9
|
|
4
4
|
Summary: Universal Robots e-Series control toolkit built on ur_rtde
|
|
5
5
|
Author: URKit Contributors
|
|
6
6
|
License: MIT
|
|
@@ -88,7 +88,7 @@ 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")
|
|
91
|
-
robot.move_to("pick",
|
|
91
|
+
robot.move_to("pick", offset_z=0.05) # 5cm above
|
|
92
92
|
robot.gripper.close()
|
|
93
93
|
robot.move_to("place")
|
|
94
94
|
robot.gripper.open()
|
|
@@ -394,10 +394,12 @@ A pose is `[x, y, z, rx, ry, rz]`: position in meters and orientation as a **rot
|
|
|
394
394
|
|
|
395
395
|
#### Offsets
|
|
396
396
|
|
|
397
|
-
Offsets
|
|
397
|
+
Offsets can use individual parameters or a full 6-element list:
|
|
398
398
|
|
|
399
399
|
```python
|
|
400
|
-
robot.move_to("pick",
|
|
400
|
+
robot.move_to("pick", offset_z=0.05) # 5cm above
|
|
401
|
+
robot.move_to("pick", offset_x=0.01, offset_z=-0.02) # combined
|
|
402
|
+
robot.move_to("pick", offset=[0, 0, 0.05, 0, 0.1, 0]) # full with rotation
|
|
401
403
|
```
|
|
402
404
|
|
|
403
405
|
#### Resolve a Pose
|
|
@@ -416,7 +418,7 @@ robot.move_to(pose) # move to the resolved pose later
|
|
|
416
418
|
from urkit import MoveFrame
|
|
417
419
|
|
|
418
420
|
robot.move_frame = MoveFrame.TOOL # default is BASE
|
|
419
|
-
robot.move_relative(
|
|
421
|
+
robot.move_relative(delta_z=0.05) # 5cm along tool Z
|
|
420
422
|
```
|
|
421
423
|
|
|
422
424
|
- **BASE** (default): delta relative to robot base
|
|
@@ -440,8 +442,9 @@ robot.import_points("backup.json")
|
|
|
440
442
|
#### Relative Moves
|
|
441
443
|
|
|
442
444
|
```python
|
|
443
|
-
robot.move_relative(
|
|
444
|
-
robot.move_relative(
|
|
445
|
+
robot.move_relative(delta_y=0.01) # 1cm along Y
|
|
446
|
+
robot.move_relative(delta_z=0.05, frame=MoveFrame.TOOL) # 5cm along tool Z
|
|
447
|
+
robot.move_relative([0, 0.01, 0, 0, 0, 0])
|
|
445
448
|
```
|
|
446
449
|
|
|
447
450
|
#### Sequences with Blending
|
|
@@ -62,7 +62,7 @@ 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")
|
|
65
|
-
robot.move_to("pick",
|
|
65
|
+
robot.move_to("pick", offset_z=0.05) # 5cm above
|
|
66
66
|
robot.gripper.close()
|
|
67
67
|
robot.move_to("place")
|
|
68
68
|
robot.gripper.open()
|
|
@@ -368,10 +368,12 @@ A pose is `[x, y, z, rx, ry, rz]`: position in meters and orientation as a **rot
|
|
|
368
368
|
|
|
369
369
|
#### Offsets
|
|
370
370
|
|
|
371
|
-
Offsets
|
|
371
|
+
Offsets can use individual parameters or a full 6-element list:
|
|
372
372
|
|
|
373
373
|
```python
|
|
374
|
-
robot.move_to("pick",
|
|
374
|
+
robot.move_to("pick", offset_z=0.05) # 5cm above
|
|
375
|
+
robot.move_to("pick", offset_x=0.01, offset_z=-0.02) # combined
|
|
376
|
+
robot.move_to("pick", offset=[0, 0, 0.05, 0, 0.1, 0]) # full with rotation
|
|
375
377
|
```
|
|
376
378
|
|
|
377
379
|
#### Resolve a Pose
|
|
@@ -390,7 +392,7 @@ robot.move_to(pose) # move to the resolved pose later
|
|
|
390
392
|
from urkit import MoveFrame
|
|
391
393
|
|
|
392
394
|
robot.move_frame = MoveFrame.TOOL # default is BASE
|
|
393
|
-
robot.move_relative(
|
|
395
|
+
robot.move_relative(delta_z=0.05) # 5cm along tool Z
|
|
394
396
|
```
|
|
395
397
|
|
|
396
398
|
- **BASE** (default): delta relative to robot base
|
|
@@ -414,8 +416,9 @@ robot.import_points("backup.json")
|
|
|
414
416
|
#### Relative Moves
|
|
415
417
|
|
|
416
418
|
```python
|
|
417
|
-
robot.move_relative(
|
|
418
|
-
robot.move_relative(
|
|
419
|
+
robot.move_relative(delta_y=0.01) # 1cm along Y
|
|
420
|
+
robot.move_relative(delta_z=0.05, frame=MoveFrame.TOOL) # 5cm along tool Z
|
|
421
|
+
robot.move_relative([0, 0.01, 0, 0, 0, 0])
|
|
419
422
|
```
|
|
420
423
|
|
|
421
424
|
#### Sequences with Blending
|
|
@@ -163,7 +163,10 @@ class URRobot:
|
|
|
163
163
|
# handles that case too.
|
|
164
164
|
self._connect_dashboard()
|
|
165
165
|
did_power_on = self.power_on()
|
|
166
|
-
|
|
166
|
+
# After power_on the robot is IDLE but brakes are still engaged —
|
|
167
|
+
# robotmode can't distinguish "IDLE braked" from "IDLE released",
|
|
168
|
+
# so force the brake release when we just powered on.
|
|
169
|
+
did_release = self.release_brakes(force=did_power_on)
|
|
167
170
|
boot_needed = did_power_on or did_release
|
|
168
171
|
|
|
169
172
|
# Settle after boot — the robot reports IDLE but the Secondary
|
|
@@ -438,7 +441,7 @@ class URRobot:
|
|
|
438
441
|
Example:
|
|
439
442
|
>>> robot.move_frame = MoveFrame.TOOL
|
|
440
443
|
>>> robot.move_relative([0.01, 0, 0, 0, 0, 0]) # +X in tool frame
|
|
441
|
-
>>> robot.move_to("pick",
|
|
444
|
+
>>> robot.move_to("pick", offset_z=0.05) # offset in tool frame
|
|
442
445
|
"""
|
|
443
446
|
return self._move_frame
|
|
444
447
|
|
|
@@ -584,9 +587,13 @@ class URRobot:
|
|
|
584
587
|
if "Powering on" in response:
|
|
585
588
|
_status("Powering on robot...", done=False)
|
|
586
589
|
logger.info("Robot powering on, waiting for ready state...")
|
|
590
|
+
# Wait until the robot reaches IDLE (brakes engaged, ready for
|
|
591
|
+
# brake release). Stopping at "not POWER_OFF" is insufficient —
|
|
592
|
+
# the robot may still be in POWER_ON or BOOTING where the
|
|
593
|
+
# dashboard rejects "brake release" with a mounting error.
|
|
587
594
|
self._poll_robotmode(
|
|
588
|
-
lambda m: "
|
|
589
|
-
timeout=
|
|
595
|
+
lambda m: "IDLE" in m.upper(),
|
|
596
|
+
timeout=15.0,
|
|
590
597
|
)
|
|
591
598
|
_status("Robot powered on", done=True)
|
|
592
599
|
return True
|
|
@@ -613,11 +620,17 @@ class URRobot:
|
|
|
613
620
|
except Exception as e:
|
|
614
621
|
raise ConnectionError(f"Power off failed: {e}")
|
|
615
622
|
|
|
616
|
-
def release_brakes(self) -> bool:
|
|
623
|
+
def release_brakes(self, *, force: bool = False) -> bool:
|
|
617
624
|
"""Release the robot brakes (enable control).
|
|
618
625
|
|
|
619
|
-
Checks the current
|
|
620
|
-
in
|
|
626
|
+
Checks the current mode first. If the robot is already
|
|
627
|
+
in RUNNING, the command is skipped silently. (IDLE cannot
|
|
628
|
+
distinguish braked from released — use *force* after power_on.)
|
|
629
|
+
|
|
630
|
+
Args:
|
|
631
|
+
force: Skip the mode check and send brake release regardless.
|
|
632
|
+
Should be True when called immediately after power_on(),
|
|
633
|
+
because robotmode reports IDLE for both braked and released.
|
|
621
634
|
|
|
622
635
|
Polls until the robot reports IDLE or RUNNING mode.
|
|
623
636
|
|
|
@@ -629,20 +642,34 @@ class URRobot:
|
|
|
629
642
|
ConnectionError: If brake release fails or times out.
|
|
630
643
|
"""
|
|
631
644
|
try:
|
|
632
|
-
# Check current mode first — skip if already
|
|
645
|
+
# Check current mode first — skip if already running.
|
|
646
|
+
# Note: IDLE is ambiguous (brakes may be engaged or released),
|
|
647
|
+
# so we only skip on RUNNING. When force=True (called after
|
|
648
|
+
# power_on), we skip the check entirely.
|
|
633
649
|
mode = self._send_dashboard("robotmode").upper()
|
|
634
|
-
if
|
|
650
|
+
if not force and "RUNNING" in mode:
|
|
635
651
|
logger.info("Brakes already released (mode: %s), skipping.", mode)
|
|
636
652
|
return False
|
|
637
653
|
|
|
638
654
|
response = self._send_dashboard("brake release")
|
|
639
655
|
logger.info("Brake release: %s", response)
|
|
656
|
+
|
|
657
|
+
# Retry once if the mounting calibration wasn't ready.
|
|
658
|
+
if "mounting is not correct" in response:
|
|
659
|
+
logger.info(
|
|
660
|
+
"Brake release rejected (mounting not ready), "
|
|
661
|
+
"retrying after 3s..."
|
|
662
|
+
)
|
|
663
|
+
time.sleep(3)
|
|
664
|
+
response = self._send_dashboard("brake release")
|
|
665
|
+
logger.info("Brake release (retry): %s", response)
|
|
666
|
+
|
|
640
667
|
if "Brake releasing" in response:
|
|
641
668
|
_status("Releasing brakes...", done=False)
|
|
642
669
|
logger.info("Brakes releasing, waiting for ready state...")
|
|
643
670
|
self._poll_robotmode(
|
|
644
671
|
lambda m: "IDLE" in m.upper() or "RUNNING" in m.upper(),
|
|
645
|
-
timeout=
|
|
672
|
+
timeout=15.0,
|
|
646
673
|
)
|
|
647
674
|
_status("Brakes released", done=True)
|
|
648
675
|
return True
|
|
@@ -821,6 +848,12 @@ class URRobot:
|
|
|
821
848
|
*,
|
|
822
849
|
offset: list[float] | None = None,
|
|
823
850
|
frame: MoveFrame | None = None,
|
|
851
|
+
offset_x: float = 0.0,
|
|
852
|
+
offset_y: float = 0.0,
|
|
853
|
+
offset_z: float = 0.0,
|
|
854
|
+
offset_rx: float = 0.0,
|
|
855
|
+
offset_ry: float = 0.0,
|
|
856
|
+
offset_rz: float = 0.0,
|
|
824
857
|
) -> list[float]:
|
|
825
858
|
"""Resolve a saved point or raw pose to a TCP pose.
|
|
826
859
|
|
|
@@ -831,9 +864,16 @@ class URRobot:
|
|
|
831
864
|
target: A saved point name (str) or a raw TCP pose
|
|
832
865
|
[x, y, z, rx, ry, rz].
|
|
833
866
|
offset: Optional offset [dx, dy, dz, drx, dry, drz]
|
|
834
|
-
applied to the target pose.
|
|
867
|
+
applied to the target pose. Mutually exclusive with
|
|
868
|
+
individual offset_* parameters.
|
|
835
869
|
frame: Coordinate frame for the offset. Falls back to the
|
|
836
870
|
current ``move_frame`` property (BASE or TOOL).
|
|
871
|
+
offset_x: X offset in meters (default 0.0).
|
|
872
|
+
offset_y: Y offset in meters (default 0.0).
|
|
873
|
+
offset_z: Z offset in meters (default 0.0).
|
|
874
|
+
offset_rx: Roll offset in radians (default 0.0).
|
|
875
|
+
offset_ry: Pitch offset in radians (default 0.0).
|
|
876
|
+
offset_rz: Yaw offset in radians (default 0.0).
|
|
837
877
|
|
|
838
878
|
Returns:
|
|
839
879
|
TCP pose as [x, y, z, rx, ry, rz].
|
|
@@ -843,18 +883,32 @@ class URRobot:
|
|
|
843
883
|
|
|
844
884
|
Example:
|
|
845
885
|
>>> pose = robot.get_pose("pick")
|
|
846
|
-
>>> pose = robot.get_pose("pick",
|
|
886
|
+
>>> pose = robot.get_pose("pick", offset_z=0.05)
|
|
847
887
|
>>> robot.move_to(pose)
|
|
848
888
|
"""
|
|
849
889
|
point = self._lookup_point(target)
|
|
850
890
|
|
|
851
|
-
|
|
852
|
-
|
|
891
|
+
# Build offset from individual params or use provided list
|
|
892
|
+
individual_offset = [offset_x, offset_y, offset_z, offset_rx, offset_ry, offset_rz]
|
|
893
|
+
has_individual = any(v != 0.0 for v in individual_offset)
|
|
894
|
+
|
|
895
|
+
if offset is not None and has_individual:
|
|
896
|
+
raise PointError(
|
|
897
|
+
"Cannot use both 'offset' list and individual offset_* parameters. "
|
|
898
|
+
"Use one or the other."
|
|
899
|
+
)
|
|
900
|
+
|
|
901
|
+
final_offset = offset if offset is not None and not has_individual else (
|
|
902
|
+
individual_offset if has_individual else None
|
|
903
|
+
)
|
|
904
|
+
|
|
905
|
+
if final_offset is not None:
|
|
906
|
+
if len(final_offset) != 6:
|
|
853
907
|
raise PointError(
|
|
854
908
|
f"Offset must have 6 values [dx, dy, dz, drx, dry, drz], "
|
|
855
|
-
f"got {len(
|
|
909
|
+
f"got {len(final_offset)}."
|
|
856
910
|
)
|
|
857
|
-
point = point.with_offset(
|
|
911
|
+
point = point.with_offset(final_offset, frame=frame or self._move_frame)
|
|
858
912
|
|
|
859
913
|
return list(point.pose)
|
|
860
914
|
|
|
@@ -868,6 +922,12 @@ class URRobot:
|
|
|
868
922
|
vel: float | None = None,
|
|
869
923
|
acc: float | None = None,
|
|
870
924
|
asynchronous: bool = False,
|
|
925
|
+
offset_x: float = 0.0,
|
|
926
|
+
offset_y: float = 0.0,
|
|
927
|
+
offset_z: float = 0.0,
|
|
928
|
+
offset_rx: float = 0.0,
|
|
929
|
+
offset_ry: float = 0.0,
|
|
930
|
+
offset_rz: float = 0.0,
|
|
871
931
|
) -> None:
|
|
872
932
|
"""Move to a saved point or raw pose.
|
|
873
933
|
|
|
@@ -877,11 +937,20 @@ class URRobot:
|
|
|
877
937
|
linear: If True (default), use Cartesian linear move (moveL).
|
|
878
938
|
If False, use joint-space move (moveJ).
|
|
879
939
|
offset: Optional offset [dx, dy, dz, drx, dry, drz]
|
|
880
|
-
applied to the target pose before moving.
|
|
940
|
+
applied to the target pose before moving. Mutually
|
|
941
|
+
exclusive with individual offset_* parameters.
|
|
881
942
|
frame: Coordinate frame for the offset. Falls back to the
|
|
882
943
|
current ``move_frame`` property (BASE or TOOL).
|
|
883
944
|
vel: Velocity override. Falls back to default_vel.
|
|
884
945
|
acc: Acceleration override. Falls back to default_acc.
|
|
946
|
+
asynchronous: If True, move runs in background and method returns
|
|
947
|
+
immediately (default False).
|
|
948
|
+
offset_x: X offset in meters (default 0.0).
|
|
949
|
+
offset_y: Y offset in meters (default 0.0).
|
|
950
|
+
offset_z: Z offset in meters (default 0.0).
|
|
951
|
+
offset_rx: Roll offset in radians (default 0.0).
|
|
952
|
+
offset_ry: Pitch offset in radians (default 0.0).
|
|
953
|
+
offset_rz: Yaw offset in radians (default 0.0).
|
|
885
954
|
|
|
886
955
|
Raises:
|
|
887
956
|
MotionError: If the move fails or IK has no solution.
|
|
@@ -890,8 +959,9 @@ class URRobot:
|
|
|
890
959
|
Example:
|
|
891
960
|
>>> robot.move_to("home")
|
|
892
961
|
>>> robot.move_to("pick", linear=False)
|
|
893
|
-
>>> robot.move_to("
|
|
894
|
-
>>> robot.move_to("
|
|
962
|
+
>>> robot.move_to("pick", offset_z=0.05) # 5cm above
|
|
963
|
+
>>> robot.move_to("pick", offset_x=0.01, offset_z=-0.02)
|
|
964
|
+
>>> robot.move_to("pick", offset=[0, 0, 0.05, 0, 0.1, 0]) # full
|
|
895
965
|
>>> robot.move_to([0.5, 0, 0.3, 0, 0, 0]) # raw pose
|
|
896
966
|
"""
|
|
897
967
|
self._check_connection()
|
|
@@ -899,14 +969,28 @@ class URRobot:
|
|
|
899
969
|
|
|
900
970
|
point = self._lookup_point(target)
|
|
901
971
|
|
|
972
|
+
# Build offset from individual params or use provided list
|
|
973
|
+
individual_offset = [offset_x, offset_y, offset_z, offset_rx, offset_ry, offset_rz]
|
|
974
|
+
has_individual = any(v != 0.0 for v in individual_offset)
|
|
975
|
+
|
|
976
|
+
if offset is not None and has_individual:
|
|
977
|
+
raise PointError(
|
|
978
|
+
"Cannot use both 'offset' list and individual offset_* parameters. "
|
|
979
|
+
"Use one or the other."
|
|
980
|
+
)
|
|
981
|
+
|
|
982
|
+
final_offset = offset if offset is not None and not has_individual else (
|
|
983
|
+
individual_offset if has_individual else None
|
|
984
|
+
)
|
|
985
|
+
|
|
902
986
|
# Apply offset if provided
|
|
903
|
-
if
|
|
904
|
-
if len(
|
|
987
|
+
if final_offset is not None:
|
|
988
|
+
if len(final_offset) != 6:
|
|
905
989
|
raise PointError(
|
|
906
990
|
f"Offset must have 6 values [dx, dy, dz, drx, dry, drz], "
|
|
907
|
-
f"got {len(
|
|
991
|
+
f"got {len(final_offset)}."
|
|
908
992
|
)
|
|
909
|
-
point = point.with_offset(
|
|
993
|
+
point = point.with_offset(final_offset, frame=frame or self._move_frame)
|
|
910
994
|
|
|
911
995
|
pose = list(point.pose)
|
|
912
996
|
|
|
@@ -978,12 +1062,19 @@ class URRobot:
|
|
|
978
1062
|
|
|
979
1063
|
def move_relative(
|
|
980
1064
|
self,
|
|
981
|
-
delta: list[float],
|
|
1065
|
+
delta: list[float] | None = None,
|
|
982
1066
|
*,
|
|
983
1067
|
linear: bool = True,
|
|
984
1068
|
frame: MoveFrame | None = None,
|
|
985
1069
|
vel: float | None = None,
|
|
986
1070
|
acc: float | None = None,
|
|
1071
|
+
asynchronous: bool = False,
|
|
1072
|
+
delta_x: float = 0.0,
|
|
1073
|
+
delta_y: float = 0.0,
|
|
1074
|
+
delta_z: float = 0.0,
|
|
1075
|
+
delta_rx: float = 0.0,
|
|
1076
|
+
delta_ry: float = 0.0,
|
|
1077
|
+
delta_rz: float = 0.0,
|
|
987
1078
|
) -> None:
|
|
988
1079
|
"""Relative Cartesian move from the current position.
|
|
989
1080
|
|
|
@@ -992,27 +1083,57 @@ class URRobot:
|
|
|
992
1083
|
|
|
993
1084
|
Args:
|
|
994
1085
|
delta: [dx, dy, dz, drx, dry, drz] in meters/radians.
|
|
1086
|
+
Mutually exclusive with individual delta_* parameters.
|
|
995
1087
|
linear: If True (default), use Cartesian linear move.
|
|
996
1088
|
If False, solve IK and use joint-space move.
|
|
997
1089
|
frame: Coordinate frame for the delta. Falls back to the
|
|
998
1090
|
current ``move_frame`` property (BASE or TOOL).
|
|
999
1091
|
vel: Velocity override. Falls back to default_vel.
|
|
1000
1092
|
acc: Acceleration override. Falls back to default_acc.
|
|
1093
|
+
asynchronous: If True, move runs in background and method returns
|
|
1094
|
+
immediately (default False).
|
|
1095
|
+
delta_x: X delta in meters (default 0.0).
|
|
1096
|
+
delta_y: Y delta in meters (default 0.0).
|
|
1097
|
+
delta_z: Z delta in meters (default 0.0).
|
|
1098
|
+
delta_rx: Roll delta in radians (default 0.0).
|
|
1099
|
+
delta_ry: Pitch delta in radians (default 0.0).
|
|
1100
|
+
delta_rz: Yaw delta in radians (default 0.0).
|
|
1001
1101
|
|
|
1002
1102
|
Raises:
|
|
1003
1103
|
MotionError: If the move fails.
|
|
1004
1104
|
|
|
1005
1105
|
Example:
|
|
1006
|
-
>>> robot.move_relative(
|
|
1007
|
-
>>> robot.move_relative(
|
|
1106
|
+
>>> robot.move_relative(delta_y=0.01) # 1cm along Y
|
|
1107
|
+
>>> robot.move_relative(delta_z=0.05, frame=MoveFrame.TOOL)
|
|
1108
|
+
>>> robot.move_relative([0, 0.01, 0, 0, 0, 0]) # full list
|
|
1008
1109
|
"""
|
|
1009
1110
|
self._check_connection()
|
|
1010
1111
|
self._disable_freedrive_guard()
|
|
1011
1112
|
|
|
1012
|
-
|
|
1113
|
+
# Build delta from individual params or use provided list
|
|
1114
|
+
individual_delta = [delta_x, delta_y, delta_z, delta_rx, delta_ry, delta_rz]
|
|
1115
|
+
has_individual = any(v != 0.0 for v in individual_delta)
|
|
1116
|
+
|
|
1117
|
+
if delta is not None and has_individual:
|
|
1118
|
+
raise MotionError(
|
|
1119
|
+
"Cannot use both 'delta' list and individual delta_* parameters. "
|
|
1120
|
+
"Use one or the other."
|
|
1121
|
+
)
|
|
1122
|
+
|
|
1123
|
+
final_delta = delta if delta is not None and not has_individual else (
|
|
1124
|
+
individual_delta if has_individual else None
|
|
1125
|
+
)
|
|
1126
|
+
|
|
1127
|
+
if final_delta is None:
|
|
1128
|
+
raise MotionError(
|
|
1129
|
+
"Relative move requires either 'delta' list or at least one "
|
|
1130
|
+
"delta_* parameter."
|
|
1131
|
+
)
|
|
1132
|
+
|
|
1133
|
+
if len(final_delta) != 6:
|
|
1013
1134
|
raise MotionError(
|
|
1014
1135
|
f"Relative move requires 6 values [dx,dy,dz,drx,dry,drz], "
|
|
1015
|
-
f"got {len(
|
|
1136
|
+
f"got {len(final_delta)}."
|
|
1016
1137
|
)
|
|
1017
1138
|
|
|
1018
1139
|
vel = vel if vel is not None else self._default_vel
|
|
@@ -1021,13 +1142,13 @@ class URRobot:
|
|
|
1021
1142
|
|
|
1022
1143
|
try:
|
|
1023
1144
|
current = list(self._rtde_r.getActualTCPPose())
|
|
1024
|
-
target = transform_pose_delta(current,
|
|
1145
|
+
target = transform_pose_delta(current, final_delta, effective_frame)
|
|
1025
1146
|
|
|
1026
1147
|
if linear:
|
|
1027
|
-
self._motion.movel(target, vel=vel, acc=acc)
|
|
1148
|
+
self._motion.movel(target, vel=vel, acc=acc, asynchronous=asynchronous)
|
|
1028
1149
|
else:
|
|
1029
1150
|
joints = self.inverse_kinematics(target)
|
|
1030
|
-
self._motion.movej(joints, vel=vel, acc=acc)
|
|
1151
|
+
self._motion.movej(joints, vel=vel, acc=acc, asynchronous=asynchronous)
|
|
1031
1152
|
except MotionError:
|
|
1032
1153
|
raise
|
|
1033
1154
|
except Exception as e:
|
|
@@ -1041,6 +1162,7 @@ class URRobot:
|
|
|
1041
1162
|
blend_radius: float = 0.0,
|
|
1042
1163
|
vel: float | None = None,
|
|
1043
1164
|
acc: float | None = None,
|
|
1165
|
+
asynchronous: bool = False,
|
|
1044
1166
|
) -> None:
|
|
1045
1167
|
"""Move through a sequence of points with optional blending.
|
|
1046
1168
|
|
|
@@ -1062,6 +1184,8 @@ class URRobot:
|
|
|
1062
1184
|
Applied to intermediate points only.
|
|
1063
1185
|
vel: Velocity override. Falls back to default_vel.
|
|
1064
1186
|
acc: Acceleration override. Falls back to default_acc.
|
|
1187
|
+
asynchronous: If True, sequence runs in background and method
|
|
1188
|
+
returns immediately (default False).
|
|
1065
1189
|
|
|
1066
1190
|
Raises:
|
|
1067
1191
|
MotionError: If the sequence fails or fewer than 2 targets.
|
|
@@ -1109,7 +1233,7 @@ class URRobot:
|
|
|
1109
1233
|
)
|
|
1110
1234
|
|
|
1111
1235
|
try:
|
|
1112
|
-
self._rtde_c.movePath(path,
|
|
1236
|
+
self._rtde_c.movePath(path, not asynchronous)
|
|
1113
1237
|
except Exception as e:
|
|
1114
1238
|
raise MotionError(f"move_sequence failed: {e}")
|
|
1115
1239
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: urkit
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.9
|
|
4
4
|
Summary: Universal Robots e-Series control toolkit built on ur_rtde
|
|
5
5
|
Author: URKit Contributors
|
|
6
6
|
License: MIT
|
|
@@ -88,7 +88,7 @@ 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")
|
|
91
|
-
robot.move_to("pick",
|
|
91
|
+
robot.move_to("pick", offset_z=0.05) # 5cm above
|
|
92
92
|
robot.gripper.close()
|
|
93
93
|
robot.move_to("place")
|
|
94
94
|
robot.gripper.open()
|
|
@@ -394,10 +394,12 @@ A pose is `[x, y, z, rx, ry, rz]`: position in meters and orientation as a **rot
|
|
|
394
394
|
|
|
395
395
|
#### Offsets
|
|
396
396
|
|
|
397
|
-
Offsets
|
|
397
|
+
Offsets can use individual parameters or a full 6-element list:
|
|
398
398
|
|
|
399
399
|
```python
|
|
400
|
-
robot.move_to("pick",
|
|
400
|
+
robot.move_to("pick", offset_z=0.05) # 5cm above
|
|
401
|
+
robot.move_to("pick", offset_x=0.01, offset_z=-0.02) # combined
|
|
402
|
+
robot.move_to("pick", offset=[0, 0, 0.05, 0, 0.1, 0]) # full with rotation
|
|
401
403
|
```
|
|
402
404
|
|
|
403
405
|
#### Resolve a Pose
|
|
@@ -416,7 +418,7 @@ robot.move_to(pose) # move to the resolved pose later
|
|
|
416
418
|
from urkit import MoveFrame
|
|
417
419
|
|
|
418
420
|
robot.move_frame = MoveFrame.TOOL # default is BASE
|
|
419
|
-
robot.move_relative(
|
|
421
|
+
robot.move_relative(delta_z=0.05) # 5cm along tool Z
|
|
420
422
|
```
|
|
421
423
|
|
|
422
424
|
- **BASE** (default): delta relative to robot base
|
|
@@ -440,8 +442,9 @@ robot.import_points("backup.json")
|
|
|
440
442
|
#### Relative Moves
|
|
441
443
|
|
|
442
444
|
```python
|
|
443
|
-
robot.move_relative(
|
|
444
|
-
robot.move_relative(
|
|
445
|
+
robot.move_relative(delta_y=0.01) # 1cm along Y
|
|
446
|
+
robot.move_relative(delta_z=0.05, frame=MoveFrame.TOOL) # 5cm along tool Z
|
|
447
|
+
robot.move_relative([0, 0.01, 0, 0, 0, 0])
|
|
445
448
|
```
|
|
446
449
|
|
|
447
450
|
#### Sequences with Blending
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|