urkit 0.4.1__tar.gz → 0.4.3__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 (42) hide show
  1. {urkit-0.4.1 → urkit-0.4.3}/PKG-INFO +7 -2
  2. {urkit-0.4.1 → urkit-0.4.3}/README.md +6 -1
  3. {urkit-0.4.1 → urkit-0.4.3}/pyproject.toml +1 -1
  4. {urkit-0.4.1 → urkit-0.4.3}/src/urkit/__init__.py +1 -1
  5. {urkit-0.4.1 → urkit-0.4.3}/src/urkit/cli/connection_monitor.py +8 -1
  6. {urkit-0.4.1 → urkit-0.4.3}/src/urkit/cli/points.py +44 -41
  7. {urkit-0.4.1 → urkit-0.4.3}/src/urkit/cli/teach.py +191 -208
  8. urkit-0.4.3/src/urkit/cli/terminal.py +262 -0
  9. {urkit-0.4.1 → urkit-0.4.3}/src/urkit/points.py +8 -5
  10. {urkit-0.4.1 → urkit-0.4.3}/src/urkit/robot.py +7 -6
  11. {urkit-0.4.1 → urkit-0.4.3}/src/urkit.egg-info/PKG-INFO +7 -2
  12. {urkit-0.4.1 → urkit-0.4.3}/src/urkit.egg-info/SOURCES.txt +1 -0
  13. {urkit-0.4.1 → urkit-0.4.3}/setup.cfg +0 -0
  14. {urkit-0.4.1 → urkit-0.4.3}/src/urkit/__main__.py +0 -0
  15. {urkit-0.4.1 → urkit-0.4.3}/src/urkit/cli/__init__.py +0 -0
  16. {urkit-0.4.1 → urkit-0.4.3}/src/urkit/cli/colors.py +0 -0
  17. {urkit-0.4.1 → urkit-0.4.3}/src/urkit/cli/init.py +0 -0
  18. {urkit-0.4.1 → urkit-0.4.3}/src/urkit/config.py +0 -0
  19. {urkit-0.4.1 → urkit-0.4.3}/src/urkit/connection.py +0 -0
  20. {urkit-0.4.1 → urkit-0.4.3}/src/urkit/exceptions.py +0 -0
  21. {urkit-0.4.1 → urkit-0.4.3}/src/urkit/geometry.py +0 -0
  22. {urkit-0.4.1 → urkit-0.4.3}/src/urkit/gripper/__init__.py +0 -0
  23. {urkit-0.4.1 → urkit-0.4.3}/src/urkit/gripper/base.py +0 -0
  24. {urkit-0.4.1 → urkit-0.4.3}/src/urkit/gripper/digital.py +0 -0
  25. {urkit-0.4.1 → urkit-0.4.3}/src/urkit/gripper/presets.py +0 -0
  26. {urkit-0.4.1 → urkit-0.4.3}/src/urkit/gripper/robotiq.py +0 -0
  27. {urkit-0.4.1 → urkit-0.4.3}/src/urkit/gripper/robotiq_preamble.py +0 -0
  28. {urkit-0.4.1 → urkit-0.4.3}/src/urkit/io.py +0 -0
  29. {urkit-0.4.1 → urkit-0.4.3}/src/urkit/motion.py +0 -0
  30. {urkit-0.4.1 → urkit-0.4.3}/src/urkit/telemetry.py +0 -0
  31. {urkit-0.4.1 → urkit-0.4.3}/src/urkit.egg-info/dependency_links.txt +0 -0
  32. {urkit-0.4.1 → urkit-0.4.3}/src/urkit.egg-info/entry_points.txt +0 -0
  33. {urkit-0.4.1 → urkit-0.4.3}/src/urkit.egg-info/requires.txt +0 -0
  34. {urkit-0.4.1 → urkit-0.4.3}/src/urkit.egg-info/top_level.txt +0 -0
  35. {urkit-0.4.1 → urkit-0.4.3}/tests/test_exceptions.py +0 -0
  36. {urkit-0.4.1 → urkit-0.4.3}/tests/test_geometry.py +0 -0
  37. {urkit-0.4.1 → urkit-0.4.3}/tests/test_gripper.py +0 -0
  38. {urkit-0.4.1 → urkit-0.4.3}/tests/test_gripper_factory.py +0 -0
  39. {urkit-0.4.1 → urkit-0.4.3}/tests/test_gripper_presets.py +0 -0
  40. {urkit-0.4.1 → urkit-0.4.3}/tests/test_move_sequence.py +0 -0
  41. {urkit-0.4.1 → urkit-0.4.3}/tests/test_points.py +0 -0
  42. {urkit-0.4.1 → urkit-0.4.3}/tests/test_robot_integration.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: urkit
3
- Version: 0.4.1
3
+ Version: 0.4.3
4
4
  Summary: Universal Robots e-Series control toolkit built on ur_rtde
5
5
  Author: URKit Contributors
6
6
  License: MIT
@@ -94,6 +94,11 @@ The `-U` (upgrade) flag ensures you always get the latest version. This project
94
94
 
95
95
  Requires Python 3.8+ and a Universal Robots e-Series (UR3e to UR30).
96
96
 
97
+ ### Platform Support
98
+
99
+ - **Linux, macOS**: fully supported
100
+ - **Windows**: the Python library works on Windows. The interactive CLIs (`urkit teach`, `urkit points`) run on Windows but are **not fully tested and not officially supported**. A warning is printed at startup. If you hit input or console problems, use Linux, macOS, or WSL2
101
+
97
102
  ### Robot Setup (one-time)
98
103
 
99
104
  1. **Network**: Connect your PC to the robot via Ethernet cable (direct) or a switch.
@@ -663,7 +668,7 @@ Default is `None` (controller handles IK natively). Set it globally when most of
663
668
 
664
669
  #### Point Management
665
670
 
666
- Points are stored in the active TCP frame, so they work with any tool. Swap grippers and your saved points stay valid.
671
+ Points are stored as absolute TCP poses in the robot base frame. When you move to a point, the controller moves whatever TCP is currently active to that base-frame pose, so the tool tip lands at the same physical location. Change the TCP offset (or swap grippers) and your saved points stay valid.
667
672
 
668
673
  ```python
669
674
  robot.save_point("here")
@@ -68,6 +68,11 @@ The `-U` (upgrade) flag ensures you always get the latest version. This project
68
68
 
69
69
  Requires Python 3.8+ and a Universal Robots e-Series (UR3e to UR30).
70
70
 
71
+ ### Platform Support
72
+
73
+ - **Linux, macOS**: fully supported
74
+ - **Windows**: the Python library works on Windows. The interactive CLIs (`urkit teach`, `urkit points`) run on Windows but are **not fully tested and not officially supported**. A warning is printed at startup. If you hit input or console problems, use Linux, macOS, or WSL2
75
+
71
76
  ### Robot Setup (one-time)
72
77
 
73
78
  1. **Network**: Connect your PC to the robot via Ethernet cable (direct) or a switch.
@@ -637,7 +642,7 @@ Default is `None` (controller handles IK natively). Set it globally when most of
637
642
 
638
643
  #### Point Management
639
644
 
640
- Points are stored in the active TCP frame, so they work with any tool. Swap grippers and your saved points stay valid.
645
+ Points are stored as absolute TCP poses in the robot base frame. When you move to a point, the controller moves whatever TCP is currently active to that base-frame pose, so the tool tip lands at the same physical location. Change the TCP offset (or swap grippers) and your saved points stay valid.
641
646
 
642
647
  ```python
643
648
  robot.save_point("here")
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "urkit"
7
- version = "0.4.1"
7
+ version = "0.4.3"
8
8
  description = "Universal Robots e-Series control toolkit built on ur_rtde"
9
9
  readme = "README.md"
10
10
  license = {text = "MIT"}
@@ -24,7 +24,7 @@ Quick start::
24
24
 
25
25
  from __future__ import annotations
26
26
 
27
- __version__ = "0.4.1"
27
+ __version__ = "0.4.3"
28
28
 
29
29
 
30
30
  from urkit.exceptions import (
@@ -144,10 +144,17 @@ class ConnectionMonitor:
144
144
  logger.info("Connection monitor loop exited")
145
145
 
146
146
  def _trigger(self, reason: str) -> None:
147
- """Record fault reason and send SIGALRM to interrupt blocking calls."""
147
+ """Record fault reason and send SIGALRM to interrupt blocking calls.
148
+
149
+ On Windows there is no self-signal: the fault_detected flag is
150
+ the only interruption path, and callers poll it between and
151
+ after RTDE calls.
152
+ """
148
153
  self._reason = reason
149
154
  self._fault_event.set()
150
155
  logger.info("Fault detected: %s", reason)
156
+ if not hasattr(signal, "SIGALRM"):
157
+ return
151
158
  try:
152
159
  os.kill(os.getpid(), signal.SIGALRM)
153
160
  except OSError as e:
@@ -9,9 +9,7 @@ from __future__ import annotations
9
9
 
10
10
  import difflib
11
11
  import io
12
- import select
13
12
  import sys
14
- import termios
15
13
  import time
16
14
  from pathlib import Path
17
15
 
@@ -20,6 +18,7 @@ from rich.table import Table
20
18
 
21
19
  from urkit.config import _load_config as load_config
22
20
  from urkit.cli.colors import blue, cyan, dim, yellow
21
+ from urkit.cli.terminal import RawTerminal, read_burst, wait_input, warn_if_windows
23
22
  from urkit.points import Points
24
23
 
25
24
 
@@ -29,6 +28,7 @@ def points_command(args) -> None:
29
28
  Args:
30
29
  args: Parsed arguments from argparse (with points subcommand attributes).
31
30
  """
31
+ warn_if_windows()
32
32
  _explore_points(args)
33
33
 
34
34
 
@@ -120,12 +120,8 @@ def _interactive_points_filter(points_db: Points, all_points: list[str], points_
120
120
  refresh_error = None
121
121
 
122
122
  # Set terminal to raw mode
123
- old_settings = termios.tcgetattr(sys.stdin)
124
- new_settings = termios.tcgetattr(sys.stdin)
125
- new_settings[3] = new_settings[3] & ~(termios.ICANON | termios.ECHO)
126
- termios.tcsetattr(sys.stdin, termios.TCSADRAIN, new_settings)
127
-
128
- fd = sys.stdin.fileno()
123
+ raw = RawTerminal()
124
+ raw.enable()
129
125
 
130
126
  try:
131
127
  while True:
@@ -238,52 +234,59 @@ def _interactive_points_filter(points_db: Points, all_points: list[str], points_
238
234
  last_refresh = time.time()
239
235
 
240
236
  # Check for input (non-blocking to allow periodic refresh)
241
- rlist, _, _ = select.select([fd], [], [], 0.1)
242
- if not rlist:
237
+ if not wait_input(0.1):
243
238
  continue
244
239
 
245
- # Read input
240
+ # Read the full input burst. On Unix an arrow key arrives as
241
+ # \x1b[A in the same burst; on Windows the terminal shim
242
+ # translates arrow keys to the same byte sequence.
246
243
  try:
247
- ch = sys.stdin.read(1)
244
+ text = read_burst(0.0).decode("ascii", errors="replace")
248
245
  except Exception:
249
246
  break
247
+ if not text:
248
+ continue
250
249
 
251
- if ch == "\x1b": # ESC or arrow key or function key
252
- # Use longer timeout to reliably detect sequences
253
- rlist, _, _ = select.select([fd], [], [], 0.2)
254
- if rlist:
255
- # There's more input, likely an arrow or function key sequence
256
- try:
257
- ch2 = sys.stdin.read(1)
258
- if ch2 == "[":
259
- ch3 = sys.stdin.read(1)
260
- if ch3 == "A": # Up arrow - scroll up
261
- scroll = max(0, scroll - 1)
262
- needs_redraw = True
263
- elif ch3 == "B": # Down arrow - scroll down
264
- filtered = [p for p in all_points_sorted if filter_str == "" or filter_str.lower() in p.lower()]
265
- scroll = min(len(filtered) - 1, scroll + 1) if filtered else 0
266
- needs_redraw = True
267
- except Exception:
268
- break
250
+ if text.startswith("\x1b"): # ESC or arrow key or function key
251
+ # A bare ESC may still be the first byte of a sequence
252
+ # that arrives late; wait a bit before treating it as quit.
253
+ if text == "\x1b":
254
+ text = text + read_burst(0.2).decode("ascii", errors="replace")
255
+ if "[A" in text: # Up arrow - scroll up
256
+ scroll = max(0, scroll - 1)
257
+ needs_redraw = True
258
+ elif "[B" in text: # Down arrow - scroll down
259
+ filtered = [p for p in all_points_sorted if filter_str == "" or filter_str.lower() in p.lower()]
260
+ scroll = min(len(filtered) - 1, scroll + 1) if filtered else 0
261
+ needs_redraw = True
269
262
  else:
270
- # No more input, so this was just ESC — quit
263
+ # Just ESC (or an unrecognized sequence) — quit
264
+ break
265
+ else:
266
+ # A burst can mix printable chars and backspaces
267
+ # (fast typing), so process sequentially.
268
+ quit_requested = False
269
+ for ch in text:
270
+ if ch == "\x03": # Ctrl+C (raw byte on Windows)
271
+ quit_requested = True
272
+ break
273
+ elif ch == "\x7f" or ch == "\x08": # Backspace
274
+ if filter_str:
275
+ filter_str = filter_str[:-1]
276
+ scroll = 0
277
+ needs_redraw = True
278
+ elif ch.isprintable():
279
+ filter_str += ch
280
+ scroll = 0
281
+ needs_redraw = True
282
+ if quit_requested:
271
283
  break
272
- elif ch == "\x7f" or ch == "\x08": # Backspace
273
- if filter_str:
274
- filter_str = filter_str[:-1]
275
- scroll = 0
276
- needs_redraw = True
277
- elif ch.isprintable():
278
- filter_str += ch
279
- scroll = 0
280
- needs_redraw = True
281
284
 
282
285
  except KeyboardInterrupt:
283
286
  # Ctrl+C — exit gracefully without traceback
284
287
  pass
285
288
  finally:
286
- termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_settings)
289
+ raw.disable()
287
290
  sys.stdout.write("\n")
288
291
 
289
292