Skip to content

Commit 2022d0f

Browse files
committed
bump version to 0.3.14
- Fix freedrive: use current TCP pose as center for constrained modes (XYZ, ROTATION) - Capture ur_rtde stderr to surface robot errors in CLI - Replace Path/movePath API with individual moveL/moveJ calls in move_sequence - Add speed_x/y/z/rx/ry/rz keyword params to move_until_contact - Move inline imports to top of file (only optional/circular imports remain inline) - Add demo scripts and full config example
1 parent 9069fd0 commit 2022d0f

12 files changed

Lines changed: 502 additions & 58 deletions

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,17 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [0.3.14] — 2026-07-15
9+
10+
### Fixed
11+
- `enable_freedrive` uses current TCP pose as center for constrained modes (XYZ, ROTATION) instead of `[0,0,0,0,0,0]` — prevents IK failure when robot is far from base origin
12+
- `enable_freedrive` captures ur_rtde stderr to surface robot errors in CLI instead of generic "returned false"
13+
- `move_sequence` replaced `Path`/`movePath` API with individual `moveL`/`moveJ` calls — `blend_radius` now ignored
14+
- `move_until_contact` accepts individual `speed_x/y/z/rx/ry/rz` keyword params alongside `speed_vector`
15+
16+
### Changed
17+
- Moved inline imports to top of file (`RtdeRegisterConflictError`, `resolve_config`) — only optional/circular imports remain inline with justification
18+
819
## [0.3.13] — 2026-07-14
920

1021
### Fixed

README.md

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -421,24 +421,27 @@ robot.move_relative(delta_z=0.05, frame=MoveFrame.TOOL) # 5cm along tool Z
421421
robot.move_relative([0, 0.01, 0, 0, 0, 0])
422422
```
423423

424-
#### Sequences with Blending
424+
#### Sequences
425425

426426
```python
427+
# Chain multiple moves into one call
427428
robot.move_sequence(["a", "b", "c"])
428-
robot.move_sequence(["a", "b", "c"], blend_radius=0.02)
429429
```
430430

431431
#### Contact Detection
432432

433433
```python
434-
# Zeros FT sensor automatically, then moves until force exceeds threshold
435-
robot.move_until_contact([0, 0, -0.02, 0, 0, 0])
434+
# Move straight down until contact (zeros FT sensor automatically)
435+
robot.move_until_contact(speed_z=-0.02)
436436

437437
# Custom threshold (default: 5.0 N/Nm)
438-
robot.move_until_contact([0, 0, -0.02, 0, 0, 0], threshold=10.0)
438+
robot.move_until_contact(speed_z=-0.02, threshold=10.0)
439439

440440
# Skip zeroing if you need absolute force values
441-
robot.move_until_contact([0, 0, -0.02, 0, 0, 0], zero_first=False)
441+
robot.move_until_contact(speed_z=-0.02, zero_first=False)
442+
443+
# Full speed vector
444+
robot.move_until_contact([0, 0, -0.02, 0, 0, 0])
442445

443446
# Manual zero (e.g. before custom force-based logic)
444447
robot.zero_ft_sensor()

_demo/1_connect.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#!/usr/bin/env python3
2+
"""Demo 1: Connect and move to home — 2 lines of code."""
3+
4+
from urkit import URRobot
5+
6+
robot = URRobot.from_config("config.yaml")
7+
robot.move_to("home", linear=False)
8+
print("At home!")

_demo/2_pick_place.py

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Demo 2: Complete pick-and-place cycle
4+
5+
Full cycle:
6+
1. Pick object from pick location
7+
2. Place it at place location
8+
3. Return home
9+
4. Pick it back up from place location
10+
5. Bring it back to original pick location
11+
12+
Shows the proper approach pattern with Z offsets to avoid collisions.
13+
"""
14+
15+
from urkit import URRobot
16+
17+
robot = URRobot.from_config("config.yaml")
18+
robot.gripper.activate()
19+
20+
print("Moving to home...")
21+
robot.move_to("home")
22+
23+
# --- PICK ---
24+
print("\n--- PICK ---")
25+
print("Approaching pick (5cm above)...")
26+
robot.move_to("pick", offset_z=0.05)
27+
28+
print("At pick position...")
29+
robot.move_to("pick")
30+
31+
print("Closing gripper...")
32+
robot.gripper.close()
33+
34+
print("Retracting...")
35+
robot.move_to("pick", offset_z=0.05)
36+
37+
# --- PLACE ---
38+
print("\n--- PLACE ---")
39+
print("Approaching place (5cm above)...")
40+
robot.move_to("place", offset_z=0.05)
41+
42+
print("At place position...")
43+
robot.move_to("place")
44+
45+
print("Opening gripper...")
46+
robot.gripper.open()
47+
48+
print("Retracting...")
49+
robot.move_to("place", offset_z=0.05)
50+
51+
# --- RETURN HOME ---
52+
print("\nMoving to home...")
53+
robot.move_to("home")
54+
55+
# --- PICK BACK UP ---
56+
print("\n--- PICK BACK UP ---")
57+
print("Approaching place (5cm above)...")
58+
robot.move_to("place", offset_z=0.05)
59+
60+
print("At pick position...")
61+
robot.move_to("place")
62+
63+
print("Closing gripper...")
64+
robot.gripper.close()
65+
66+
print("Retracting...")
67+
robot.move_to("place", offset_z=0.05)
68+
69+
# --- BRING BACK ---
70+
print("\n--- BRING BACK ---")
71+
print("Approaching pick (5cm above)...")
72+
robot.move_to("pick", offset_z=0.05)
73+
74+
print("At place position...")
75+
robot.move_to("pick")
76+
77+
print("Opening gripper...")
78+
robot.gripper.open()
79+
80+
print("Retracting...")
81+
robot.move_to("pick", offset_z=0.05)
82+
83+
# --- DONE ---
84+
print("\nMoving to home...")
85+
robot.move_to("home")
86+
87+
print("\nDone! Full cycle complete.")

_demo/3_advanced.py

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Demo 3: Full cycle with approach points and sequences
4+
5+
Same pick-and-place as demo 2 but using:
6+
- get_pose() — resolve named points with offsets
7+
- move_sequence() — chain moves into one call
8+
- get_tcp_pose() — live telemetry
9+
"""
10+
11+
from urkit import URRobot
12+
13+
robot = URRobot.from_config("config.yaml")
14+
15+
print("Moving to home...")
16+
robot.move_to("home")
17+
18+
print("Activating gripper...")
19+
robot.gripper.activate()
20+
robot.gripper.open()
21+
22+
# --- Resolve approach points with offsets ---
23+
pick_above = robot.get_pose("pick", offset_z=0.05)
24+
place_above = robot.get_pose("place", offset_z=0.05)
25+
26+
# --- PICK ---
27+
print("\n--- PICK ---")
28+
robot.move_sequence(["home", pick_above, "pick"])
29+
30+
print("Closing gripper...")
31+
robot.gripper.close()
32+
33+
# --- PLACE ---
34+
print("\n--- PLACE ---")
35+
robot.move_sequence([pick_above, place_above, "place"])
36+
37+
tcp = robot.get_tcp_pose()
38+
print(f"TCP at place: [{tcp[0]:.3f}, {tcp[1]:.3f}, {tcp[2]:.3f}]")
39+
40+
print("Opening gripper...")
41+
robot.gripper.open()
42+
43+
# --- RETURN HOME ---
44+
print("\nMoving to home...")
45+
robot.move_sequence([place_above, "home"])
46+
47+
# --- PICK BACK UP ---
48+
print("\n--- PICK BACK UP ---")
49+
robot.move_sequence(["home", place_above, "place"])
50+
51+
print("Closing gripper...")
52+
robot.gripper.close()
53+
54+
# --- BRING BACK ---
55+
print("\n--- BRING BACK ---")
56+
robot.move_sequence([place_above, pick_above, "pick"])
57+
58+
print("Opening gripper...")
59+
robot.gripper.open()
60+
61+
# --- DONE ---
62+
print("\nMoving to home...")
63+
robot.move_sequence([pick_above, "home"])
64+
65+
print("\nDone! Full cycle complete.")

_demo/4_force_contact.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Demo 6: Force-based contact detection
4+
5+
Shows the robot approaching a surface and stopping on contact.
6+
move_until_contact zeros the FT sensor automatically.
7+
8+
Teach panel prep:
9+
- Point "home" taught — positioned above a flat surface (table, workpiece)
10+
with clear path downward to the surface.
11+
"""
12+
13+
from urkit import URRobot
14+
15+
robot = URRobot.from_config("config.yaml")
16+
17+
print("Moving to home...")
18+
robot.move_to("home")
19+
20+
start_pose = robot.get_tcp_pose()
21+
print(f"Starting Z: {start_pose[2] * 100:.1f} cm")
22+
23+
print("\nMoving down until contact (5N threshold)...")
24+
print("Watch the robot stop when it touches the surface.\n")
25+
26+
# Moves 2cm/s downward, stops when force exceeds 5N.
27+
# Zeros the FT sensor automatically before starting.
28+
robot.move_until_contact(speed_z=-0.02, threshold=5.0)
29+
30+
contact_pose = robot.get_tcp_pose()
31+
delta_cm = abs((contact_pose[2] - start_pose[2]) * 100)
32+
print(f"\nContact detected after moving {delta_cm:.1f} cm down")
33+
print(f"Table surface is at Z = {contact_pose[2] * 100:.1f} cm")
34+
35+
print("\nRetreating 5cm...")
36+
robot.move_relative(delta_z=0.05)
37+
38+
print("\nMoving to home...")
39+
robot.move_to("home")
40+
41+
print("\nDone! The robot adapted to the surface position.")

0 commit comments

Comments
 (0)