foodforthought-cli 0.2.8__py3-none-any.whl → 0.3.0__py3-none-any.whl

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 (116) hide show
  1. ate/__init__.py +6 -0
  2. ate/__main__.py +16 -0
  3. ate/auth/__init__.py +1 -0
  4. ate/auth/device_flow.py +141 -0
  5. ate/auth/token_store.py +96 -0
  6. ate/behaviors/__init__.py +12 -0
  7. ate/behaviors/approach.py +399 -0
  8. ate/cli.py +855 -4551
  9. ate/client.py +90 -0
  10. ate/commands/__init__.py +168 -0
  11. ate/commands/auth.py +389 -0
  12. ate/commands/bridge.py +448 -0
  13. ate/commands/data.py +185 -0
  14. ate/commands/deps.py +111 -0
  15. ate/commands/generate.py +384 -0
  16. ate/commands/memory.py +907 -0
  17. ate/commands/parts.py +166 -0
  18. ate/commands/primitive.py +399 -0
  19. ate/commands/protocol.py +288 -0
  20. ate/commands/recording.py +524 -0
  21. ate/commands/repo.py +154 -0
  22. ate/commands/simulation.py +291 -0
  23. ate/commands/skill.py +303 -0
  24. ate/commands/skills.py +487 -0
  25. ate/commands/team.py +147 -0
  26. ate/commands/workflow.py +271 -0
  27. ate/detection/__init__.py +38 -0
  28. ate/detection/base.py +142 -0
  29. ate/detection/color_detector.py +399 -0
  30. ate/detection/trash_detector.py +322 -0
  31. ate/drivers/__init__.py +18 -6
  32. ate/drivers/ble_transport.py +405 -0
  33. ate/drivers/mechdog.py +360 -24
  34. ate/drivers/wifi_camera.py +477 -0
  35. ate/interfaces/__init__.py +16 -0
  36. ate/interfaces/base.py +2 -0
  37. ate/interfaces/sensors.py +247 -0
  38. ate/llm_proxy.py +239 -0
  39. ate/memory/__init__.py +35 -0
  40. ate/memory/cloud.py +244 -0
  41. ate/memory/context.py +269 -0
  42. ate/memory/embeddings.py +184 -0
  43. ate/memory/export.py +26 -0
  44. ate/memory/merge.py +146 -0
  45. ate/memory/migrate/__init__.py +34 -0
  46. ate/memory/migrate/base.py +89 -0
  47. ate/memory/migrate/pipeline.py +189 -0
  48. ate/memory/migrate/sources/__init__.py +13 -0
  49. ate/memory/migrate/sources/chroma.py +170 -0
  50. ate/memory/migrate/sources/pinecone.py +120 -0
  51. ate/memory/migrate/sources/qdrant.py +110 -0
  52. ate/memory/migrate/sources/weaviate.py +160 -0
  53. ate/memory/reranker.py +353 -0
  54. ate/memory/search.py +26 -0
  55. ate/memory/store.py +548 -0
  56. ate/recording/__init__.py +42 -3
  57. ate/recording/session.py +12 -2
  58. ate/recording/visual.py +416 -0
  59. ate/robot/__init__.py +142 -0
  60. ate/robot/agentic_servo.py +856 -0
  61. ate/robot/behaviors.py +493 -0
  62. ate/robot/ble_capture.py +1000 -0
  63. ate/robot/ble_enumerate.py +506 -0
  64. ate/robot/calibration.py +88 -3
  65. ate/robot/calibration_state.py +388 -0
  66. ate/robot/commands.py +143 -11
  67. ate/robot/direction_calibration.py +554 -0
  68. ate/robot/discovery.py +104 -2
  69. ate/robot/llm_system_id.py +654 -0
  70. ate/robot/locomotion_calibration.py +508 -0
  71. ate/robot/marker_generator.py +611 -0
  72. ate/robot/perception.py +502 -0
  73. ate/robot/primitives.py +614 -0
  74. ate/robot/profiles.py +6 -0
  75. ate/robot/registry.py +5 -2
  76. ate/robot/servo_mapper.py +1153 -0
  77. ate/robot/skill_upload.py +285 -3
  78. ate/robot/target_calibration.py +500 -0
  79. ate/robot/teach.py +515 -0
  80. ate/robot/types.py +242 -0
  81. ate/robot/visual_labeler.py +9 -0
  82. ate/robot/visual_servo_loop.py +494 -0
  83. ate/robot/visual_servoing.py +570 -0
  84. ate/robot/visual_system_id.py +906 -0
  85. ate/transports/__init__.py +121 -0
  86. ate/transports/base.py +394 -0
  87. ate/transports/ble.py +405 -0
  88. ate/transports/hybrid.py +444 -0
  89. ate/transports/serial.py +345 -0
  90. ate/urdf/__init__.py +30 -0
  91. ate/urdf/capture.py +582 -0
  92. ate/urdf/cloud.py +491 -0
  93. ate/urdf/collision.py +271 -0
  94. ate/urdf/commands.py +708 -0
  95. ate/urdf/depth.py +360 -0
  96. ate/urdf/inertial.py +312 -0
  97. ate/urdf/kinematics.py +330 -0
  98. ate/urdf/lifting.py +415 -0
  99. ate/urdf/meshing.py +300 -0
  100. ate/urdf/models/__init__.py +110 -0
  101. ate/urdf/models/depth_anything.py +253 -0
  102. ate/urdf/models/sam2.py +324 -0
  103. ate/urdf/motion_analysis.py +396 -0
  104. ate/urdf/pipeline.py +468 -0
  105. ate/urdf/scale.py +256 -0
  106. ate/urdf/scan_session.py +411 -0
  107. ate/urdf/segmentation.py +299 -0
  108. ate/urdf/synthesis.py +319 -0
  109. ate/urdf/topology.py +336 -0
  110. ate/urdf/validation.py +371 -0
  111. {foodforthought_cli-0.2.8.dist-info → foodforthought_cli-0.3.0.dist-info}/METADATA +1 -1
  112. foodforthought_cli-0.3.0.dist-info/RECORD +166 -0
  113. {foodforthought_cli-0.2.8.dist-info → foodforthought_cli-0.3.0.dist-info}/WHEEL +1 -1
  114. foodforthought_cli-0.2.8.dist-info/RECORD +0 -73
  115. {foodforthought_cli-0.2.8.dist-info → foodforthought_cli-0.3.0.dist-info}/entry_points.txt +0 -0
  116. {foodforthought_cli-0.2.8.dist-info → foodforthought_cli-0.3.0.dist-info}/top_level.txt +0 -0
ate/robot/types.py ADDED
@@ -0,0 +1,242 @@
1
+ """
2
+ Unified type definitions for robot joints and servos.
3
+
4
+ This module provides a single source of truth for joint-related enums,
5
+ avoiding inconsistencies across different modules.
6
+
7
+ Two distinct concepts:
8
+ - JointType: How the joint moves mechanically (URDF standard)
9
+ - JointRole: What function the joint serves on the robot body
10
+ """
11
+
12
+ from enum import Enum
13
+ from typing import Optional, List
14
+
15
+
16
+ class JointType(Enum):
17
+ """
18
+ Mechanical joint type following URDF conventions.
19
+
20
+ Describes HOW the joint moves, not what it's used for.
21
+ Compatible with standard robotics formats (URDF, SDF, MJCF).
22
+ """
23
+ UNKNOWN = "unknown"
24
+ REVOLUTE = "revolute" # Rotation around an axis with limits
25
+ PRISMATIC = "prismatic" # Linear translation along an axis
26
+ CONTINUOUS = "continuous" # Rotation without limits (wheels)
27
+ FIXED = "fixed" # No relative motion
28
+ FLOATING = "floating" # 6DOF free motion (rare)
29
+ PLANAR = "planar" # 2D motion in a plane (rare)
30
+
31
+ @classmethod
32
+ def from_string(cls, value: str) -> "JointType":
33
+ """
34
+ Parse joint type from string, with helpful error messages.
35
+
36
+ Accepts common variations and provides suggestions on failure.
37
+ """
38
+ if not value:
39
+ return cls.UNKNOWN
40
+
41
+ normalized = value.lower().strip()
42
+
43
+ # Direct match
44
+ for member in cls:
45
+ if member.value == normalized:
46
+ return member
47
+
48
+ # Common aliases
49
+ aliases = {
50
+ "rotary": cls.REVOLUTE,
51
+ "rotation": cls.REVOLUTE,
52
+ "rotate": cls.REVOLUTE,
53
+ "linear": cls.PRISMATIC,
54
+ "sliding": cls.PRISMATIC,
55
+ "slide": cls.PRISMATIC,
56
+ "wheel": cls.CONTINUOUS,
57
+ "static": cls.FIXED,
58
+ "rigid": cls.FIXED,
59
+ "free": cls.FLOATING,
60
+ }
61
+
62
+ if normalized in aliases:
63
+ return aliases[normalized]
64
+
65
+ # Fuzzy match - check if value contains any known type
66
+ for member in cls:
67
+ if member.value in normalized or normalized in member.value:
68
+ return member
69
+
70
+ # No match - return UNKNOWN but could raise with suggestions
71
+ return cls.UNKNOWN
72
+
73
+ @classmethod
74
+ def valid_values(cls) -> List[str]:
75
+ """Return list of valid values for error messages."""
76
+ return [m.value for m in cls if m != cls.UNKNOWN]
77
+
78
+
79
+ class JointRole(Enum):
80
+ """
81
+ Semantic role/function of a joint on the robot body.
82
+
83
+ Describes WHAT the joint does, not how it moves mechanically.
84
+ Used for semantic skill development and pose mapping.
85
+ """
86
+ UNKNOWN = "unknown"
87
+
88
+ # Locomotion - Legs
89
+ HIP_ROLL = "hip_roll"
90
+ HIP_PITCH = "hip_pitch"
91
+ HIP_YAW = "hip_yaw"
92
+ KNEE = "knee"
93
+ ANKLE = "ankle"
94
+ ANKLE_ROLL = "ankle_roll"
95
+
96
+ # Arm - Shoulder
97
+ SHOULDER_PAN = "shoulder_pan"
98
+ SHOULDER_LIFT = "shoulder_lift"
99
+ SHOULDER_ROLL = "shoulder_roll"
100
+
101
+ # Arm - Elbow/Wrist
102
+ ELBOW = "elbow"
103
+ ELBOW_ROLL = "elbow_roll"
104
+ WRIST_ROLL = "wrist_roll"
105
+ WRIST_PITCH = "wrist_pitch"
106
+ WRIST_YAW = "wrist_yaw"
107
+
108
+ # End Effector
109
+ GRIPPER = "gripper"
110
+ FINGER = "finger"
111
+
112
+ # Body/Head
113
+ HEAD_PAN = "head_pan"
114
+ HEAD_TILT = "head_tilt"
115
+ BODY_PITCH = "body_pitch"
116
+ BODY_ROLL = "body_roll"
117
+ TORSO = "torso"
118
+
119
+ # Wheels/Tracks
120
+ WHEEL = "wheel"
121
+ TRACK = "track"
122
+
123
+ @classmethod
124
+ def from_string(cls, value: str) -> "JointRole":
125
+ """
126
+ Parse joint role from string, with intelligent fallbacks.
127
+
128
+ Handles common variations and provides best-effort matching.
129
+ """
130
+ if not value:
131
+ return cls.UNKNOWN
132
+
133
+ normalized = value.lower().strip().replace("-", "_").replace(" ", "_")
134
+
135
+ # Direct match
136
+ for member in cls:
137
+ if member.value == normalized:
138
+ return member
139
+
140
+ # Common aliases and partial matches
141
+ aliases = {
142
+ # Arm shortcuts
143
+ "shoulder": cls.SHOULDER_LIFT,
144
+ "arm_shoulder": cls.SHOULDER_LIFT,
145
+ "arm_elbow": cls.ELBOW,
146
+ "arm_wrist": cls.WRIST_ROLL,
147
+
148
+ # Leg shortcuts
149
+ "hip": cls.HIP_PITCH,
150
+ "thigh": cls.HIP_PITCH,
151
+ "calf": cls.KNEE,
152
+ "shin": cls.KNEE,
153
+ "foot": cls.ANKLE,
154
+
155
+ # Generic URDF types -> infer role from context
156
+ "revolute": cls.UNKNOWN, # Could be anything
157
+ "prismatic": cls.UNKNOWN,
158
+ "continuous": cls.WHEEL,
159
+
160
+ # End effector
161
+ "claw": cls.GRIPPER,
162
+ "hand": cls.GRIPPER,
163
+ "pincer": cls.GRIPPER,
164
+ }
165
+
166
+ if normalized in aliases:
167
+ return aliases[normalized]
168
+
169
+ # Fuzzy match - check if value contains any known role
170
+ for member in cls:
171
+ if member.value in normalized:
172
+ return member
173
+ if normalized in member.value:
174
+ return member
175
+
176
+ return cls.UNKNOWN
177
+
178
+ @classmethod
179
+ def valid_values(cls) -> List[str]:
180
+ """Return list of valid values for error messages."""
181
+ return [m.value for m in cls if m != cls.UNKNOWN]
182
+
183
+ @classmethod
184
+ def suggest_similar(cls, value: str, max_suggestions: int = 3) -> List[str]:
185
+ """
186
+ Suggest similar valid values for a given invalid input.
187
+
188
+ Uses simple substring matching for suggestions.
189
+ """
190
+ if not value:
191
+ return []
192
+
193
+ normalized = value.lower().strip()
194
+ suggestions = []
195
+
196
+ for member in cls:
197
+ if member == cls.UNKNOWN:
198
+ continue
199
+ # Check for partial matches
200
+ if normalized in member.value or member.value in normalized:
201
+ suggestions.append(member.value)
202
+ # Check for word overlap
203
+ elif any(word in member.value for word in normalized.split("_")):
204
+ suggestions.append(member.value)
205
+
206
+ return suggestions[:max_suggestions]
207
+
208
+
209
+ def infer_joint_type_from_role(role: JointRole) -> JointType:
210
+ """
211
+ Infer the most likely mechanical joint type from a semantic role.
212
+
213
+ Most robot joints are revolute, with some exceptions.
214
+ """
215
+ prismatic_roles = {
216
+ JointRole.GRIPPER, # Many grippers are linear
217
+ JointRole.FINGER,
218
+ }
219
+
220
+ continuous_roles = {
221
+ JointRole.WHEEL,
222
+ JointRole.TRACK,
223
+ }
224
+
225
+ if role in prismatic_roles:
226
+ return JointType.REVOLUTE # Actually most grippers are revolute too
227
+ elif role in continuous_roles:
228
+ return JointType.CONTINUOUS
229
+ elif role == JointRole.UNKNOWN:
230
+ return JointType.UNKNOWN
231
+ else:
232
+ return JointType.REVOLUTE # Default for most robot joints
233
+
234
+
235
+ def format_valid_options(enum_class, prefix: str = "Valid options") -> str:
236
+ """Format valid enum options for error messages."""
237
+ values = [m.value for m in enum_class if m.value != "unknown"]
238
+ return f"{prefix}: {', '.join(values)}"
239
+
240
+
241
+ # Type aliases for backwards compatibility
242
+ ServoType = JointRole # Alias for semantic clarity in servo contexts
@@ -1037,3 +1037,12 @@ def list_skill_libraries() -> List[str]:
1037
1037
  if not lib_dir.exists():
1038
1038
  return []
1039
1039
  return [p.stem for p in lib_dir.glob("*.json")]
1040
+
1041
+
1042
+ def save_skill_library(library: SkillLibrary) -> Path:
1043
+ """Save a skill library to disk."""
1044
+ lib_dir = Path.home() / ".ate" / "skill_libraries"
1045
+ lib_dir.mkdir(parents=True, exist_ok=True)
1046
+ lib_path = lib_dir / f"{library.robot_name}.json"
1047
+ library.save(lib_path)
1048
+ return lib_path