urkit 0.4.6__tar.gz → 0.5.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {urkit-0.4.6 → urkit-0.5.0}/PKG-INFO +47 -23
- {urkit-0.4.6 → urkit-0.5.0}/README.md +46 -22
- {urkit-0.4.6 → urkit-0.5.0}/pyproject.toml +1 -1
- {urkit-0.4.6 → urkit-0.5.0}/src/urkit/__init__.py +4 -2
- {urkit-0.4.6 → urkit-0.5.0}/src/urkit/__main__.py +8 -0
- {urkit-0.4.6 → urkit-0.5.0}/src/urkit/cli/teach.py +161 -62
- {urkit-0.4.6 → urkit-0.5.0}/src/urkit/cli/terminal.py +188 -33
- {urkit-0.4.6 → urkit-0.5.0}/src/urkit/geometry.py +2 -1
- {urkit-0.4.6 → urkit-0.5.0}/src/urkit/motion.py +82 -30
- {urkit-0.4.6 → urkit-0.5.0}/src/urkit/points.py +9 -9
- {urkit-0.4.6 → urkit-0.5.0}/src/urkit/robot.py +268 -224
- {urkit-0.4.6 → urkit-0.5.0}/src/urkit.egg-info/PKG-INFO +47 -23
- {urkit-0.4.6 → urkit-0.5.0}/src/urkit.egg-info/SOURCES.txt +6 -1
- urkit-0.5.0/tests/test_connection_gate.py +104 -0
- urkit-0.5.0/tests/test_freedrive_cycle.py +96 -0
- urkit-0.5.0/tests/test_ik_reference.py +236 -0
- urkit-0.5.0/tests/test_message_line.py +93 -0
- {urkit-0.4.6 → urkit-0.5.0}/tests/test_move_sequence.py +5 -4
- {urkit-0.4.6 → urkit-0.5.0}/tests/test_points.py +5 -5
- {urkit-0.4.6 → urkit-0.5.0}/tests/test_robot_integration.py +2 -2
- urkit-0.5.0/tests/test_terminal_input.py +247 -0
- {urkit-0.4.6 → urkit-0.5.0}/setup.cfg +0 -0
- {urkit-0.4.6 → urkit-0.5.0}/src/urkit/cli/__init__.py +0 -0
- {urkit-0.4.6 → urkit-0.5.0}/src/urkit/cli/colors.py +0 -0
- {urkit-0.4.6 → urkit-0.5.0}/src/urkit/cli/connection_monitor.py +0 -0
- {urkit-0.4.6 → urkit-0.5.0}/src/urkit/cli/init.py +0 -0
- {urkit-0.4.6 → urkit-0.5.0}/src/urkit/cli/points.py +0 -0
- {urkit-0.4.6 → urkit-0.5.0}/src/urkit/config.py +0 -0
- {urkit-0.4.6 → urkit-0.5.0}/src/urkit/connection.py +0 -0
- {urkit-0.4.6 → urkit-0.5.0}/src/urkit/exceptions.py +0 -0
- {urkit-0.4.6 → urkit-0.5.0}/src/urkit/gripper/__init__.py +0 -0
- {urkit-0.4.6 → urkit-0.5.0}/src/urkit/gripper/base.py +0 -0
- {urkit-0.4.6 → urkit-0.5.0}/src/urkit/gripper/digital.py +0 -0
- {urkit-0.4.6 → urkit-0.5.0}/src/urkit/gripper/presets.py +0 -0
- {urkit-0.4.6 → urkit-0.5.0}/src/urkit/gripper/robotiq.py +0 -0
- {urkit-0.4.6 → urkit-0.5.0}/src/urkit/gripper/robotiq_preamble.py +0 -0
- {urkit-0.4.6 → urkit-0.5.0}/src/urkit/io.py +0 -0
- {urkit-0.4.6 → urkit-0.5.0}/src/urkit/telemetry.py +0 -0
- {urkit-0.4.6 → urkit-0.5.0}/src/urkit.egg-info/dependency_links.txt +0 -0
- {urkit-0.4.6 → urkit-0.5.0}/src/urkit.egg-info/entry_points.txt +0 -0
- {urkit-0.4.6 → urkit-0.5.0}/src/urkit.egg-info/requires.txt +0 -0
- {urkit-0.4.6 → urkit-0.5.0}/src/urkit.egg-info/top_level.txt +0 -0
- {urkit-0.4.6 → urkit-0.5.0}/tests/test_exceptions.py +0 -0
- {urkit-0.4.6 → urkit-0.5.0}/tests/test_geometry.py +0 -0
- {urkit-0.4.6 → urkit-0.5.0}/tests/test_gripper.py +0 -0
- {urkit-0.4.6 → urkit-0.5.0}/tests/test_gripper_factory.py +0 -0
- {urkit-0.4.6 → urkit-0.5.0}/tests/test_gripper_presets.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: urkit
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
4
4
|
Summary: Universal Robots e-Series control toolkit built on ur_rtde
|
|
5
5
|
Author: URKit Contributors
|
|
6
6
|
License: MIT
|
|
@@ -46,7 +46,7 @@ Built for labs and research setups where you need to get the robot moving fast a
|
|
|
46
46
|
|
|
47
47
|
## How it works
|
|
48
48
|
|
|
49
|
-
Use the CLI to position the robot and save named waypoints. Then reference them by name in your code: move to points, apply
|
|
49
|
+
Use the CLI to position the robot and save named waypoints. Then reference them by name in your code: move to points, apply deltas, run sequences. Points are stored in a local SQLite database, no robot-side setup needed.
|
|
50
50
|
|
|
51
51
|
The typical workflow: teach points with the pendant, write a few lines of Python to string them together, run it. Add vision, add sensors, add logic. The robot is just one component in your pipeline.
|
|
52
52
|
|
|
@@ -144,7 +144,7 @@ robot = URRobot(ip="192.168.1.50", points="points.db", gripper=ROBOTIQ_HAND_E)
|
|
|
144
144
|
robot.gripper.activate()
|
|
145
145
|
|
|
146
146
|
robot.move_to("home")
|
|
147
|
-
robot.move_to("pick",
|
|
147
|
+
robot.move_to("pick", dz=0.05) # 5cm above
|
|
148
148
|
robot.gripper.close()
|
|
149
149
|
robot.move_to("place")
|
|
150
150
|
robot.gripper.open()
|
|
@@ -162,7 +162,7 @@ from urkit import URRobot
|
|
|
162
162
|
|
|
163
163
|
robot = URRobot.from_config("config.yaml")
|
|
164
164
|
robot.move_to("home")
|
|
165
|
-
robot.move_to("pick",
|
|
165
|
+
robot.move_to("pick", dz=0.05)
|
|
166
166
|
```
|
|
167
167
|
|
|
168
168
|
5. **Iterate.** Add more points, tweak your code, repeat.
|
|
@@ -592,14 +592,14 @@ while robot.is_moving():
|
|
|
592
592
|
|
|
593
593
|
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_current_point()` directly.
|
|
594
594
|
|
|
595
|
-
####
|
|
595
|
+
#### Deltas
|
|
596
596
|
|
|
597
|
-
|
|
597
|
+
Deltas can use individual parameters or a full 6-element list:
|
|
598
598
|
|
|
599
599
|
```python
|
|
600
|
-
robot.move_to("pick",
|
|
601
|
-
robot.move_to("pick",
|
|
602
|
-
robot.move_to("pick",
|
|
600
|
+
robot.move_to("pick", dz=0.05) # 5cm above
|
|
601
|
+
robot.move_to("pick", dx=0.01, dz=-0.02) # combined
|
|
602
|
+
robot.move_to("pick", delta=[0, 0, 0.05, 0, 0.1, 0]) # full with rotation
|
|
603
603
|
```
|
|
604
604
|
|
|
605
605
|
#### Resolve a Pose
|
|
@@ -608,7 +608,7 @@ Get a pose without moving. Useful for logging, comparisons, or custom motion:
|
|
|
608
608
|
|
|
609
609
|
```python
|
|
610
610
|
point = robot.get_point("pick")
|
|
611
|
-
point = robot.get_point("pick",
|
|
611
|
+
point = robot.get_point("pick", delta=[0, 0, 0.05, 0, 0, 0]) # with delta
|
|
612
612
|
robot.move_to(pose) # move to the resolved pose later
|
|
613
613
|
```
|
|
614
614
|
|
|
@@ -618,7 +618,7 @@ robot.move_to(pose) # move to the resolved pose later
|
|
|
618
618
|
from urkit import MoveFrame
|
|
619
619
|
|
|
620
620
|
robot.move_frame = MoveFrame.TOOL # default is BASE
|
|
621
|
-
robot.move_relative(
|
|
621
|
+
robot.move_relative(dz=0.05) # 5cm along tool Z
|
|
622
622
|
```
|
|
623
623
|
|
|
624
624
|
- **BASE** (default): delta relative to robot base
|
|
@@ -639,7 +639,7 @@ robot.ik_reference = "home"
|
|
|
639
639
|
# Now all moves stay close to that posture, no elbow flipping
|
|
640
640
|
robot.move_to("pick")
|
|
641
641
|
robot.move_to("place")
|
|
642
|
-
robot.move_relative(
|
|
642
|
+
robot.move_relative(dz=-0.05)
|
|
643
643
|
```
|
|
644
644
|
|
|
645
645
|
**In config.yaml** (recommended for permanent setup):
|
|
@@ -682,12 +682,12 @@ robot.import_points("backup.json")
|
|
|
682
682
|
#### Relative Moves
|
|
683
683
|
|
|
684
684
|
```python
|
|
685
|
-
robot.move_relative(
|
|
686
|
-
robot.move_relative(
|
|
685
|
+
robot.move_relative(dy=0.01) # 1cm along Y
|
|
686
|
+
robot.move_relative(dz=0.05, frame=MoveFrame.TOOL) # 5cm along tool Z
|
|
687
687
|
robot.move_relative([0, 0.01, 0, 0, 0, 0]) # full 6-element delta
|
|
688
688
|
```
|
|
689
689
|
|
|
690
|
-
Individual delta parameters (`
|
|
690
|
+
Individual delta parameters (`dx`, `dy`, `dz`, `drx`, `dry`, `drz`) are mutually exclusive with the `delta` list. Use one or the other.
|
|
691
691
|
|
|
692
692
|
#### Sequences
|
|
693
693
|
|
|
@@ -718,26 +718,26 @@ Before sending any move, it checks that each pose has a valid IK solution. Unrea
|
|
|
718
718
|
|
|
719
719
|
```python
|
|
720
720
|
# Move straight down until contact (zeros FT sensor automatically)
|
|
721
|
-
robot.move_until_contact(
|
|
721
|
+
robot.move_until_contact(vz=-0.02)
|
|
722
722
|
|
|
723
723
|
# Custom threshold (default: 5.0 N/Nm)
|
|
724
|
-
robot.move_until_contact(
|
|
724
|
+
robot.move_until_contact(vz=-0.02, threshold=10.0)
|
|
725
725
|
|
|
726
726
|
# Skip zeroing if you need absolute force values
|
|
727
|
-
robot.move_until_contact(
|
|
727
|
+
robot.move_until_contact(vz=-0.02, zero_first=False)
|
|
728
728
|
|
|
729
729
|
# Full speed vector
|
|
730
730
|
robot.move_until_contact([0, 0, -0.02, 0, 0, 0])
|
|
731
731
|
|
|
732
732
|
# Abort after 10s or 200mm of travel, whichever comes first
|
|
733
|
-
robot.move_until_contact(
|
|
733
|
+
robot.move_until_contact(vz=-0.02, timeout=10.0, max_distance=0.2)
|
|
734
734
|
|
|
735
735
|
# Returns True if contact detected, False if timeout/max_distance hit
|
|
736
736
|
for _ in range(3):
|
|
737
|
-
if robot.move_until_contact(
|
|
737
|
+
if robot.move_until_contact(vz=-0.02, timeout=10.0, max_distance=0.2):
|
|
738
738
|
break # contact detected
|
|
739
739
|
# No contact, back off and retry
|
|
740
|
-
robot.move_relative(
|
|
740
|
+
robot.move_relative(dz=0.01)
|
|
741
741
|
|
|
742
742
|
# Manual zero (e.g. before custom force-based logic)
|
|
743
743
|
robot.zero_ft_sensor()
|
|
@@ -800,7 +800,7 @@ joints = robot.inverse_kinematics([0.5, 0, 0.3, 0, 0, 0])
|
|
|
800
800
|
|
|
801
801
|
```python
|
|
802
802
|
pose = robot.get_current_point() # [x, y, z, rx, ry, rz]
|
|
803
|
-
pose = robot.get_current_point(
|
|
803
|
+
pose = robot.get_current_point(dz=0.05) # with delta
|
|
804
804
|
joints = robot.get_joint_positions() # [j0..j5]
|
|
805
805
|
force = robot.get_tcp_force() # [fx, fy, fz, mx, my, mz]
|
|
806
806
|
mode = robot.get_robot_mode() # "REMOTE_CONTROL", "SERVOING", etc.
|
|
@@ -937,9 +937,33 @@ Full `ur_rtde` documentation: <https://sdurobotics.gitlab.io/ur_rtde/>
|
|
|
937
937
|
|
|
938
938
|
```python
|
|
939
939
|
robot.connection_lost # bool: check if RTDE dropped
|
|
940
|
-
robot.reconnect_rtde() # reconnect after a drop
|
|
941
940
|
```
|
|
942
941
|
|
|
942
|
+
An RTDE drop is fatal for the session: urkit raises and the CLI exits.
|
|
943
|
+
Restart `urkit` (or create a new `URRobot`) to reconnect. urkit
|
|
944
|
+
deliberately does not auto-reconnect mid-session: a silent reconnect
|
|
945
|
+
hides what happened to the link and lets the native layer resynchronize
|
|
946
|
+
state behind your back.
|
|
947
|
+
|
|
948
|
+
**What happens when the link drops mid-session** (verified by
|
|
949
|
+
force-dropping the network with Windows firewall rules):
|
|
950
|
+
|
|
951
|
+
- **Before a motion call**: every motion command checks the link first
|
|
952
|
+
and raises `URKitConnectionError` immediately. This matters because a
|
|
953
|
+
call into the native layer on a dead link would not return an error:
|
|
954
|
+
the vendored `ur_rtde` library enters its own internal reconnect
|
|
955
|
+
loop and blocks indefinitely (measured: 45 s+ and still hanging
|
|
956
|
+
under a firewall block).
|
|
957
|
+
- **While a motion is running**: the CLI's connection monitor detects
|
|
958
|
+
the drop within ~0.1 s and exits cleanly (interrupt watcher on
|
|
959
|
+
Windows, SIGALRM on Unix). In library code, an in-flight call can
|
|
960
|
+
block inside the native reconnect loop; kill the process and restart.
|
|
961
|
+
- **After a hard drop**: the robot can keep the RTDE registers locked
|
|
962
|
+
until the dead connection times out. If a fresh connect fails with
|
|
963
|
+
`RtdeRegisterConflictError`, power cycle the controller (dashboard
|
|
964
|
+
`power off` / `power on` works remotely; or Settings -> System ->
|
|
965
|
+
Shutdown on the pendant), then reconnect.
|
|
966
|
+
|
|
943
967
|
### Error Handling
|
|
944
968
|
|
|
945
969
|
```python
|
|
@@ -20,7 +20,7 @@ Built for labs and research setups where you need to get the robot moving fast a
|
|
|
20
20
|
|
|
21
21
|
## How it works
|
|
22
22
|
|
|
23
|
-
Use the CLI to position the robot and save named waypoints. Then reference them by name in your code: move to points, apply
|
|
23
|
+
Use the CLI to position the robot and save named waypoints. Then reference them by name in your code: move to points, apply deltas, run sequences. Points are stored in a local SQLite database, no robot-side setup needed.
|
|
24
24
|
|
|
25
25
|
The typical workflow: teach points with the pendant, write a few lines of Python to string them together, run it. Add vision, add sensors, add logic. The robot is just one component in your pipeline.
|
|
26
26
|
|
|
@@ -118,7 +118,7 @@ robot = URRobot(ip="192.168.1.50", points="points.db", gripper=ROBOTIQ_HAND_E)
|
|
|
118
118
|
robot.gripper.activate()
|
|
119
119
|
|
|
120
120
|
robot.move_to("home")
|
|
121
|
-
robot.move_to("pick",
|
|
121
|
+
robot.move_to("pick", dz=0.05) # 5cm above
|
|
122
122
|
robot.gripper.close()
|
|
123
123
|
robot.move_to("place")
|
|
124
124
|
robot.gripper.open()
|
|
@@ -136,7 +136,7 @@ from urkit import URRobot
|
|
|
136
136
|
|
|
137
137
|
robot = URRobot.from_config("config.yaml")
|
|
138
138
|
robot.move_to("home")
|
|
139
|
-
robot.move_to("pick",
|
|
139
|
+
robot.move_to("pick", dz=0.05)
|
|
140
140
|
```
|
|
141
141
|
|
|
142
142
|
5. **Iterate.** Add more points, tweak your code, repeat.
|
|
@@ -566,14 +566,14 @@ while robot.is_moving():
|
|
|
566
566
|
|
|
567
567
|
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_current_point()` directly.
|
|
568
568
|
|
|
569
|
-
####
|
|
569
|
+
#### Deltas
|
|
570
570
|
|
|
571
|
-
|
|
571
|
+
Deltas can use individual parameters or a full 6-element list:
|
|
572
572
|
|
|
573
573
|
```python
|
|
574
|
-
robot.move_to("pick",
|
|
575
|
-
robot.move_to("pick",
|
|
576
|
-
robot.move_to("pick",
|
|
574
|
+
robot.move_to("pick", dz=0.05) # 5cm above
|
|
575
|
+
robot.move_to("pick", dx=0.01, dz=-0.02) # combined
|
|
576
|
+
robot.move_to("pick", delta=[0, 0, 0.05, 0, 0.1, 0]) # full with rotation
|
|
577
577
|
```
|
|
578
578
|
|
|
579
579
|
#### Resolve a Pose
|
|
@@ -582,7 +582,7 @@ Get a pose without moving. Useful for logging, comparisons, or custom motion:
|
|
|
582
582
|
|
|
583
583
|
```python
|
|
584
584
|
point = robot.get_point("pick")
|
|
585
|
-
point = robot.get_point("pick",
|
|
585
|
+
point = robot.get_point("pick", delta=[0, 0, 0.05, 0, 0, 0]) # with delta
|
|
586
586
|
robot.move_to(pose) # move to the resolved pose later
|
|
587
587
|
```
|
|
588
588
|
|
|
@@ -592,7 +592,7 @@ robot.move_to(pose) # move to the resolved pose later
|
|
|
592
592
|
from urkit import MoveFrame
|
|
593
593
|
|
|
594
594
|
robot.move_frame = MoveFrame.TOOL # default is BASE
|
|
595
|
-
robot.move_relative(
|
|
595
|
+
robot.move_relative(dz=0.05) # 5cm along tool Z
|
|
596
596
|
```
|
|
597
597
|
|
|
598
598
|
- **BASE** (default): delta relative to robot base
|
|
@@ -613,7 +613,7 @@ robot.ik_reference = "home"
|
|
|
613
613
|
# Now all moves stay close to that posture, no elbow flipping
|
|
614
614
|
robot.move_to("pick")
|
|
615
615
|
robot.move_to("place")
|
|
616
|
-
robot.move_relative(
|
|
616
|
+
robot.move_relative(dz=-0.05)
|
|
617
617
|
```
|
|
618
618
|
|
|
619
619
|
**In config.yaml** (recommended for permanent setup):
|
|
@@ -656,12 +656,12 @@ robot.import_points("backup.json")
|
|
|
656
656
|
#### Relative Moves
|
|
657
657
|
|
|
658
658
|
```python
|
|
659
|
-
robot.move_relative(
|
|
660
|
-
robot.move_relative(
|
|
659
|
+
robot.move_relative(dy=0.01) # 1cm along Y
|
|
660
|
+
robot.move_relative(dz=0.05, frame=MoveFrame.TOOL) # 5cm along tool Z
|
|
661
661
|
robot.move_relative([0, 0.01, 0, 0, 0, 0]) # full 6-element delta
|
|
662
662
|
```
|
|
663
663
|
|
|
664
|
-
Individual delta parameters (`
|
|
664
|
+
Individual delta parameters (`dx`, `dy`, `dz`, `drx`, `dry`, `drz`) are mutually exclusive with the `delta` list. Use one or the other.
|
|
665
665
|
|
|
666
666
|
#### Sequences
|
|
667
667
|
|
|
@@ -692,26 +692,26 @@ Before sending any move, it checks that each pose has a valid IK solution. Unrea
|
|
|
692
692
|
|
|
693
693
|
```python
|
|
694
694
|
# Move straight down until contact (zeros FT sensor automatically)
|
|
695
|
-
robot.move_until_contact(
|
|
695
|
+
robot.move_until_contact(vz=-0.02)
|
|
696
696
|
|
|
697
697
|
# Custom threshold (default: 5.0 N/Nm)
|
|
698
|
-
robot.move_until_contact(
|
|
698
|
+
robot.move_until_contact(vz=-0.02, threshold=10.0)
|
|
699
699
|
|
|
700
700
|
# Skip zeroing if you need absolute force values
|
|
701
|
-
robot.move_until_contact(
|
|
701
|
+
robot.move_until_contact(vz=-0.02, zero_first=False)
|
|
702
702
|
|
|
703
703
|
# Full speed vector
|
|
704
704
|
robot.move_until_contact([0, 0, -0.02, 0, 0, 0])
|
|
705
705
|
|
|
706
706
|
# Abort after 10s or 200mm of travel, whichever comes first
|
|
707
|
-
robot.move_until_contact(
|
|
707
|
+
robot.move_until_contact(vz=-0.02, timeout=10.0, max_distance=0.2)
|
|
708
708
|
|
|
709
709
|
# Returns True if contact detected, False if timeout/max_distance hit
|
|
710
710
|
for _ in range(3):
|
|
711
|
-
if robot.move_until_contact(
|
|
711
|
+
if robot.move_until_contact(vz=-0.02, timeout=10.0, max_distance=0.2):
|
|
712
712
|
break # contact detected
|
|
713
713
|
# No contact, back off and retry
|
|
714
|
-
robot.move_relative(
|
|
714
|
+
robot.move_relative(dz=0.01)
|
|
715
715
|
|
|
716
716
|
# Manual zero (e.g. before custom force-based logic)
|
|
717
717
|
robot.zero_ft_sensor()
|
|
@@ -774,7 +774,7 @@ joints = robot.inverse_kinematics([0.5, 0, 0.3, 0, 0, 0])
|
|
|
774
774
|
|
|
775
775
|
```python
|
|
776
776
|
pose = robot.get_current_point() # [x, y, z, rx, ry, rz]
|
|
777
|
-
pose = robot.get_current_point(
|
|
777
|
+
pose = robot.get_current_point(dz=0.05) # with delta
|
|
778
778
|
joints = robot.get_joint_positions() # [j0..j5]
|
|
779
779
|
force = robot.get_tcp_force() # [fx, fy, fz, mx, my, mz]
|
|
780
780
|
mode = robot.get_robot_mode() # "REMOTE_CONTROL", "SERVOING", etc.
|
|
@@ -911,9 +911,33 @@ Full `ur_rtde` documentation: <https://sdurobotics.gitlab.io/ur_rtde/>
|
|
|
911
911
|
|
|
912
912
|
```python
|
|
913
913
|
robot.connection_lost # bool: check if RTDE dropped
|
|
914
|
-
robot.reconnect_rtde() # reconnect after a drop
|
|
915
914
|
```
|
|
916
915
|
|
|
916
|
+
An RTDE drop is fatal for the session: urkit raises and the CLI exits.
|
|
917
|
+
Restart `urkit` (or create a new `URRobot`) to reconnect. urkit
|
|
918
|
+
deliberately does not auto-reconnect mid-session: a silent reconnect
|
|
919
|
+
hides what happened to the link and lets the native layer resynchronize
|
|
920
|
+
state behind your back.
|
|
921
|
+
|
|
922
|
+
**What happens when the link drops mid-session** (verified by
|
|
923
|
+
force-dropping the network with Windows firewall rules):
|
|
924
|
+
|
|
925
|
+
- **Before a motion call**: every motion command checks the link first
|
|
926
|
+
and raises `URKitConnectionError` immediately. This matters because a
|
|
927
|
+
call into the native layer on a dead link would not return an error:
|
|
928
|
+
the vendored `ur_rtde` library enters its own internal reconnect
|
|
929
|
+
loop and blocks indefinitely (measured: 45 s+ and still hanging
|
|
930
|
+
under a firewall block).
|
|
931
|
+
- **While a motion is running**: the CLI's connection monitor detects
|
|
932
|
+
the drop within ~0.1 s and exits cleanly (interrupt watcher on
|
|
933
|
+
Windows, SIGALRM on Unix). In library code, an in-flight call can
|
|
934
|
+
block inside the native reconnect loop; kill the process and restart.
|
|
935
|
+
- **After a hard drop**: the robot can keep the RTDE registers locked
|
|
936
|
+
until the dead connection times out. If a fresh connect fails with
|
|
937
|
+
`RtdeRegisterConflictError`, power cycle the controller (dashboard
|
|
938
|
+
`power off` / `power on` works remotely; or Settings -> System ->
|
|
939
|
+
Shutdown on the pendant), then reconnect.
|
|
940
|
+
|
|
917
941
|
### Error Handling
|
|
918
942
|
|
|
919
943
|
```python
|
|
@@ -24,7 +24,7 @@ Quick start::
|
|
|
24
24
|
|
|
25
25
|
from __future__ import annotations
|
|
26
26
|
|
|
27
|
-
__version__ = "0.
|
|
27
|
+
__version__ = "0.5.0"
|
|
28
28
|
|
|
29
29
|
|
|
30
30
|
from urkit.exceptions import (
|
|
@@ -58,7 +58,7 @@ from urkit.gripper.presets import (
|
|
|
58
58
|
ROBOTIQ_HAND_E,
|
|
59
59
|
)
|
|
60
60
|
from urkit.motion import FreedriveMode
|
|
61
|
-
from urkit.robot import URRobot
|
|
61
|
+
from urkit.robot import GLOBAL, URRobot
|
|
62
62
|
|
|
63
63
|
__all__ = [
|
|
64
64
|
# Version
|
|
@@ -66,6 +66,8 @@ __all__ = [
|
|
|
66
66
|
|
|
67
67
|
# Core class
|
|
68
68
|
"URRobot",
|
|
69
|
+
# IK reference sentinel (per-call ik_reference=GLOBAL)
|
|
70
|
+
"GLOBAL",
|
|
69
71
|
# Gripper
|
|
70
72
|
"Gripper",
|
|
71
73
|
"GripperPreset",
|
|
@@ -142,6 +142,14 @@ def main() -> None:
|
|
|
142
142
|
|
|
143
143
|
def main_entry() -> None:
|
|
144
144
|
"""Entry point for console script."""
|
|
145
|
+
# A redirected Windows console uses the ANSI code page (cp1252):
|
|
146
|
+
# unencodable characters (status symbols, log text) must degrade
|
|
147
|
+
# to '?' instead of crashing the session. TTY consoles are
|
|
148
|
+
# Unicode-native and unaffected.
|
|
149
|
+
for stream in (sys.stdout, sys.stderr):
|
|
150
|
+
reconfigure = getattr(stream, "reconfigure", None)
|
|
151
|
+
if reconfigure is not None:
|
|
152
|
+
reconfigure(errors="replace")
|
|
145
153
|
main()
|
|
146
154
|
|
|
147
155
|
|