hackerbot 0.2.0__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.
- hackerbot/head/__init__.py +21 -2
- {hackerbot-0.2.0.dist-info → hackerbot-0.3.0.dist-info}/METADATA +3 -1
- hackerbot-0.3.0.dist-info/RECORD +15 -0
- {hackerbot-0.2.0.dist-info → hackerbot-0.3.0.dist-info}/WHEEL +1 -1
- hackerbot/examples/keyboard_teleop_examples/AI_ELITE_teleop.py +0 -219
- hackerbot/examples/keyboard_teleop_examples/AI_PRO_teleop.py +0 -180
- hackerbot/examples/keyboard_teleop_examples/arm_teleop.py +0 -230
- hackerbot/examples/keyboard_teleop_examples/base_teleop.py +0 -206
- hackerbot/examples/keyboard_teleop_examples/head_teleop.py +0 -170
- hackerbot-0.2.0.dist-info/RECORD +0 -20
- {hackerbot-0.2.0.dist-info → hackerbot-0.3.0.dist-info}/licenses/LICENSE +0 -0
- {hackerbot-0.2.0.dist-info → hackerbot-0.3.0.dist-info}/top_level.txt +0 -0
hackerbot/head/__init__.py
CHANGED
@@ -6,7 +6,7 @@
|
|
6
6
|
#
|
7
7
|
# Created By: Allen Chien
|
8
8
|
# Created: April 2025
|
9
|
-
# Updated: 2025.04.
|
9
|
+
# Updated: 2025.04.20
|
10
10
|
#
|
11
11
|
# This module contains the Head component of the hackerbot
|
12
12
|
#
|
@@ -17,6 +17,9 @@
|
|
17
17
|
|
18
18
|
from hackerbot.utils.hackerbot_helper import HackerbotHelper
|
19
19
|
from .eyes import Eyes
|
20
|
+
import sounddevice as sd
|
21
|
+
from piper.voice import PiperVoice
|
22
|
+
import numpy as np
|
20
23
|
|
21
24
|
class Head():
|
22
25
|
def __init__(self, controller: HackerbotHelper):
|
@@ -58,4 +61,20 @@ class Head():
|
|
58
61
|
return True
|
59
62
|
except Exception as e:
|
60
63
|
self._controller.log_error(f"Error in head:set_idle_mode: {e}")
|
61
|
-
return False
|
64
|
+
return False
|
65
|
+
|
66
|
+
def speak(self, model_src, text, speaker_id = None):
|
67
|
+
model = model_src
|
68
|
+
voice = PiperVoice.load(model)
|
69
|
+
|
70
|
+
# Setup a sounddevice OutputStream with appropriate parameters
|
71
|
+
# The sample rate and channels should match the properties of the PCM data
|
72
|
+
stream = sd.OutputStream(samplerate=voice.config.sample_rate, channels=1, dtype='int16')
|
73
|
+
stream.start()
|
74
|
+
|
75
|
+
for audio_bytes in voice.synthesize_stream_raw(text, speaker_id = speaker_id):
|
76
|
+
int_data = np.frombuffer(audio_bytes, dtype=np.int16)
|
77
|
+
stream.write(int_data)
|
78
|
+
|
79
|
+
stream.stop()
|
80
|
+
stream.close()
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: hackerbot
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.3.0
|
4
4
|
Summary: This module contains the setup for the hackerbot python package.
|
5
5
|
Author-email: Allen Chien <allen71090@gmail.com>
|
6
6
|
License-Expression: MIT
|
@@ -10,6 +10,8 @@ Description-Content-Type: text/markdown
|
|
10
10
|
License-File: LICENSE
|
11
11
|
Requires-Dist: pyserial
|
12
12
|
Requires-Dist: pytest
|
13
|
+
Requires-Dist: piper-tts
|
14
|
+
Requires-Dist: sounddevice
|
13
15
|
Dynamic: license-file
|
14
16
|
|
15
17
|
|
@@ -0,0 +1,15 @@
|
|
1
|
+
hackerbot/__init__.py,sha256=fjzBB_VsqCuKJ3yeLdqLSvAQIz9bAMI-KXrUC6ZrscY,1248
|
2
|
+
hackerbot/core.py,sha256=oZKQEUaMn19MnaWNTDFqTZ7lziBEZeSk5CdLXLSLvr0,5521
|
3
|
+
hackerbot/arm/__init__.py,sha256=JdCmTDQ2qk3W8-Alc4mjaQYxHnmH26r0nSy0JFg6J4A,3400
|
4
|
+
hackerbot/arm/gripper.py,sha256=xZux0PZL4vvrJTTKHL7dDsRBfJr4zbmgMaA0uBR1u4s,1986
|
5
|
+
hackerbot/base/__init__.py,sha256=PG2Ykn2MLfobAWClGFnp-AZfh1xVsnbc1nQ8E6Yy6eA,8698
|
6
|
+
hackerbot/base/maps.py,sha256=I_4NdvOMnkHX6-mW43QpDPJ-eVc6npgcBXq99tU7D1g,5916
|
7
|
+
hackerbot/head/__init__.py,sha256=VvKc6Gy3hNARUbFf8HoKkc2TFWoSSswrJbqytvEKUSA,3186
|
8
|
+
hackerbot/head/eyes.py,sha256=xqeKMxL12iaa8KQzDlbgbNy3LzcmWm8aXkebztYJ4P8,1370
|
9
|
+
hackerbot/utils/hackerbot_helper.py,sha256=egQPVBBUo52ywsO6jGAGVqhyGLpMPz-b2fgLBb39WSM,4998
|
10
|
+
hackerbot/utils/serial_helper.py,sha256=l7pj32mnoVZN-7foU_FPUxdmZaE43jcMmZRBAGEX8Zc,6457
|
11
|
+
hackerbot-0.3.0.dist-info/licenses/LICENSE,sha256=SCcXH0bf35ISRu_Ks8xEKySHXiqclANLWhBUbVU8VvA,1081
|
12
|
+
hackerbot-0.3.0.dist-info/METADATA,sha256=SNyJO3uVYEOxCbfCs-JkC4ifsuNVd2HGexvpfNzmVos,1766
|
13
|
+
hackerbot-0.3.0.dist-info/WHEEL,sha256=pxyMxgL8-pra_rKaQ4drOZAegBVuX-G_4nRHjjgWbmo,91
|
14
|
+
hackerbot-0.3.0.dist-info/top_level.txt,sha256=2n_FStAr1SiI3BV67x7KJHYIOmEwxjUD59zedw2hLkU,10
|
15
|
+
hackerbot-0.3.0.dist-info/RECORD,,
|
@@ -1,219 +0,0 @@
|
|
1
|
-
################################################################################
|
2
|
-
# Copyright (c) 2025 Hackerbot Industries LLC
|
3
|
-
#
|
4
|
-
# This source code is licensed under the MIT license found in the
|
5
|
-
# LICENSE file in the root directory of this source tree.
|
6
|
-
#
|
7
|
-
# Created By: Allen Chien
|
8
|
-
# Created: April 2025
|
9
|
-
# Updated: 2025.04.01
|
10
|
-
#
|
11
|
-
# This script is an example of how to use the AI_ELITE_teleop behavior.
|
12
|
-
#
|
13
|
-
# Special thanks to the following for their code contributions to this codebase:
|
14
|
-
# Allen Chien - https://github.com/AllenChienXXX
|
15
|
-
################################################################################
|
16
|
-
|
17
|
-
|
18
|
-
from hackerbot import Hackerbot
|
19
|
-
import time
|
20
|
-
import os
|
21
|
-
|
22
|
-
import sys
|
23
|
-
from select import select
|
24
|
-
from arm_teleop import ArmTeleop
|
25
|
-
from base_teleop import BaseTeleop, KBHit
|
26
|
-
from head_teleop import HeadTeleop
|
27
|
-
|
28
|
-
class AI_ELITE_Teleop(ArmTeleop, BaseTeleop, HeadTeleop):
|
29
|
-
def __init__(self):
|
30
|
-
self.kb = KBHit()
|
31
|
-
|
32
|
-
self.robot = Hackerbot()
|
33
|
-
self.robot.base.initialize()
|
34
|
-
|
35
|
-
# Modify movement parameters
|
36
|
-
self.step_size = 0.2 # mm
|
37
|
-
self.max_l_step_size = 300.0 # mm/s
|
38
|
-
self.max_r_step_size = 90.0 # degree/s
|
39
|
-
|
40
|
-
self.joint_speed = 50
|
41
|
-
|
42
|
-
self.j_agl_1 = 0
|
43
|
-
self.j_agl_2 = 0
|
44
|
-
self.j_agl_3 = 0
|
45
|
-
self.j_agl_4 = 0
|
46
|
-
self.j_agl_5 = 0
|
47
|
-
self.j_agl_6 = 0
|
48
|
-
|
49
|
-
self.yaw = 180
|
50
|
-
self.pitch = 180
|
51
|
-
|
52
|
-
self.base_command = None
|
53
|
-
self.head_command = None
|
54
|
-
self.arm_command = None
|
55
|
-
|
56
|
-
self.stop = False
|
57
|
-
self.last_key = None # Track last keypress
|
58
|
-
|
59
|
-
# Print initial instructions to terminal
|
60
|
-
self.print_terminal_instructions()
|
61
|
-
|
62
|
-
def print_terminal_instructions(self):
|
63
|
-
"""Print instructions to the terminal"""
|
64
|
-
os.system('clear' if os.name == 'posix' else 'cls')
|
65
|
-
print("\n" + "="*10 + " Robot Teleop Controls " + "="*10 + "\r")
|
66
|
-
print("Base controls:\r")
|
67
|
-
print(" ↑ / ↓ : FWD/BCK | ← / → : L/R | space : STOP\r")
|
68
|
-
print("=" * 30 + "\r")
|
69
|
-
print("Head Controls:\r")
|
70
|
-
print(" u/i : Yaw L/R | j/k : Pitch U/D")
|
71
|
-
print("=" * 30 + "\r")
|
72
|
-
print("Arm Controls:\r")
|
73
|
-
print(" q/w : Joint 1 L/R | a/s : Joint 2 BCK/FWD | z/x : Joint 3 BCK/FWD")
|
74
|
-
print(" e/r : Joint 4 BCK/FWD | d/f : Joint 5 L/R | c/v : Joint 6 L/R")
|
75
|
-
print("\nGripper:")
|
76
|
-
print(" g/h : Open/Close gripper | b : Calibrate gripper\r")
|
77
|
-
|
78
|
-
print("\nOther:")
|
79
|
-
print(" o/p : increase/decrease step size | -/+ : decrease/increase speed\r")
|
80
|
-
print("\nCTRL-C or 0 to quit\r")
|
81
|
-
print("=" * 43 + "\r")
|
82
|
-
|
83
|
-
def update_display(self):
|
84
|
-
"""Update step size and speed in place without adding new lines"""
|
85
|
-
sys.stdout.write(f"\rCurrent step size: {self.step_size:.1f} | Current joint speed: {self.joint_speed} ")
|
86
|
-
sys.stdout.flush() # Ensure immediate update
|
87
|
-
|
88
|
-
def get_command(self):
|
89
|
-
self.base_command = False
|
90
|
-
self.head_command = False
|
91
|
-
self.arm_command = False
|
92
|
-
key = None
|
93
|
-
# Read keyboard input
|
94
|
-
if self.kb.kbhit() is not None:
|
95
|
-
key = self.kb.getch()
|
96
|
-
# print(f"key: {key}\r")
|
97
|
-
while sys.stdin in select([sys.stdin], [], [], 0)[0]:
|
98
|
-
sys.stdin.read(1)
|
99
|
-
|
100
|
-
if key == self.last_key:
|
101
|
-
self.last_key = None
|
102
|
-
return None, None
|
103
|
-
|
104
|
-
self.last_key = key # Update last key
|
105
|
-
|
106
|
-
# Check for quit conditions
|
107
|
-
if key == '0': # '0' key to quit
|
108
|
-
self.stop = True
|
109
|
-
return None, None
|
110
|
-
|
111
|
-
if key == 'o':
|
112
|
-
self.step_size += 0.1
|
113
|
-
if self.step_size > 1:
|
114
|
-
self.step_size = 1
|
115
|
-
elif key == 'p':
|
116
|
-
self.step_size -= 0.1
|
117
|
-
if self.step_size < 0.1:
|
118
|
-
self.step_size = 0.1
|
119
|
-
elif key == '-':
|
120
|
-
self.joint_speed -= 10
|
121
|
-
if self.joint_speed < 10:
|
122
|
-
self.joint_speed = 10
|
123
|
-
elif key == '+':
|
124
|
-
self.joint_speed += 10
|
125
|
-
if self.joint_speed > 100:
|
126
|
-
self.joint_speed = 100
|
127
|
-
if key in ['\x1b[A', '\x1b[B', '\x1b[D', '\x1b[C', ' ']:
|
128
|
-
l_vel, r_vel = BaseTeleop.get_base_command_from_key(self, key)
|
129
|
-
self.base_command = True
|
130
|
-
return l_vel, r_vel
|
131
|
-
elif key in ['u', 'i', 'j', 'k']:
|
132
|
-
y, p = HeadTeleop.get_head_value_from_key(self, key)
|
133
|
-
self.head_command = True
|
134
|
-
return y, p
|
135
|
-
elif key in ['q', 'w', 'a', 's', 'z', 'x', 'e', 'r', 'd', 'f', 'c', 'v', 'g', 'h', 'b']:
|
136
|
-
command, value = ArmTeleop.get_arm_value_from_key(self, key)
|
137
|
-
self.arm_command = True
|
138
|
-
return command, value
|
139
|
-
else:
|
140
|
-
return None, None
|
141
|
-
|
142
|
-
else:
|
143
|
-
self.last_key = None
|
144
|
-
return 0.0, 0.0
|
145
|
-
|
146
|
-
def run(self):
|
147
|
-
while not self.stop:
|
148
|
-
input_1, input_2 = self.get_command()
|
149
|
-
if input_1 is not None and input_2 is not None:
|
150
|
-
response = None # Initialize response
|
151
|
-
if self.base_command:
|
152
|
-
response = self.robot.base.drive(input_1, input_2, block=False)
|
153
|
-
time.sleep(0.01)
|
154
|
-
elif self.head_command:
|
155
|
-
response = self.robot.head.look(input_1, input_2, self.joint_speed)
|
156
|
-
time.sleep(0.01)
|
157
|
-
elif self.arm_command:
|
158
|
-
command = input_1
|
159
|
-
value = input_2
|
160
|
-
if isinstance(command, int): # Joint movement
|
161
|
-
# Limit joint angles based on which joint
|
162
|
-
max_angle = 175.0 if command == 6 else 165.0
|
163
|
-
if abs(value) <= max_angle:
|
164
|
-
response = self.robot.arm.move_joint(command, value, self.joint_speed)
|
165
|
-
elif command == 'gripper_open':
|
166
|
-
response = self.robot.arm.gripper.open()
|
167
|
-
elif command == 'gripper_close':
|
168
|
-
response = self.robot.arm.gripper.close()
|
169
|
-
elif command == 'gripper_calibrate':
|
170
|
-
response = self.robot.arm.gripper.calibrate()
|
171
|
-
|
172
|
-
time.sleep(0.2)
|
173
|
-
|
174
|
-
if response == False:
|
175
|
-
break
|
176
|
-
|
177
|
-
input_1 = None
|
178
|
-
input_2 = None
|
179
|
-
self.update_display()
|
180
|
-
|
181
|
-
def stow(self):
|
182
|
-
self.robot.arm.move_joints(0,0,0,0,0,0,50)
|
183
|
-
self.robot.head.look(180,180,50)
|
184
|
-
|
185
|
-
def cleanup(self):
|
186
|
-
"""Cleanup method to properly shut down the robot and restore terminal settings"""
|
187
|
-
try:
|
188
|
-
# Restore terminal settings
|
189
|
-
self.kb.set_normal_term()
|
190
|
-
# self.robot.stop_driver()
|
191
|
-
self.stow()
|
192
|
-
# Destroy the robot connection
|
193
|
-
self.robot.base.destroy(auto_dock=True)
|
194
|
-
|
195
|
-
except Exception as e:
|
196
|
-
print(f"\nError during cleanup: {e}")
|
197
|
-
# Try to restore terminal settings even if there's an error
|
198
|
-
try:
|
199
|
-
self.kb.set_normal_term()
|
200
|
-
except:
|
201
|
-
pass
|
202
|
-
|
203
|
-
def __del__(self):
|
204
|
-
"""Destructor to ensure cleanup is called"""
|
205
|
-
self.cleanup()
|
206
|
-
|
207
|
-
# Main entry point
|
208
|
-
if __name__ == '__main__':
|
209
|
-
teleop = None
|
210
|
-
try:
|
211
|
-
teleop = AI_ELITE_Teleop()
|
212
|
-
teleop.run()
|
213
|
-
except KeyboardInterrupt:
|
214
|
-
print("\nShutting down...")
|
215
|
-
except Exception as e:
|
216
|
-
print(f"\nError: {e}")
|
217
|
-
finally:
|
218
|
-
if teleop:
|
219
|
-
teleop.cleanup()
|
@@ -1,180 +0,0 @@
|
|
1
|
-
################################################################################
|
2
|
-
# Copyright (c) 2025 Hackerbot Industries LLC
|
3
|
-
#
|
4
|
-
# This source code is licensed under the MIT license found in the
|
5
|
-
# LICENSE file in the root directory of this source tree.
|
6
|
-
#
|
7
|
-
# Created By: Allen Chien
|
8
|
-
# Created: April 2025
|
9
|
-
# Updated: 2025.04.01
|
10
|
-
#
|
11
|
-
# This script is an example of how to use the AI_PRO_teleop behavior.
|
12
|
-
#
|
13
|
-
# Special thanks to the following for their code contributions to this codebase:
|
14
|
-
# Allen Chien - https://github.com/AllenChienXXX
|
15
|
-
################################################################################
|
16
|
-
|
17
|
-
|
18
|
-
from hackerbot import Hackerbot
|
19
|
-
import time
|
20
|
-
import os
|
21
|
-
|
22
|
-
import sys
|
23
|
-
from select import select
|
24
|
-
from base_teleop import BaseTeleop, KBHit
|
25
|
-
from head_teleop import HeadTeleop
|
26
|
-
|
27
|
-
class AI_PRO_Teleop():
|
28
|
-
def __init__(self):
|
29
|
-
self.kb = KBHit()
|
30
|
-
|
31
|
-
self.robot = Hackerbot()
|
32
|
-
self.robot.base.initialize()
|
33
|
-
|
34
|
-
# Modify movement parameters
|
35
|
-
self.step_size = 0.2 # mm
|
36
|
-
self.max_l_step_size = 300.0 # mm/s
|
37
|
-
self.max_r_step_size = 90.0 # degree/s
|
38
|
-
|
39
|
-
self.joint_speed = 50
|
40
|
-
|
41
|
-
self.yaw = 180
|
42
|
-
self.pitch = 180
|
43
|
-
|
44
|
-
self.base_command = None
|
45
|
-
self.head_command = None
|
46
|
-
|
47
|
-
self.stop = False
|
48
|
-
self.last_key = None # Track last keypress
|
49
|
-
|
50
|
-
# Print initial instructions to terminal
|
51
|
-
self.print_terminal_instructions()
|
52
|
-
|
53
|
-
def print_terminal_instructions(self):
|
54
|
-
"""Print instructions to the terminal"""
|
55
|
-
os.system('clear' if os.name == 'posix' else 'cls')
|
56
|
-
print("\n" + "="*10 + " Robot Teleop Controls " + "="*10 + "\r")
|
57
|
-
print("Base controls:\r")
|
58
|
-
print(" ↑ / ↓ : FWD/BCK | ← / → : L/R | space : STOP\r")
|
59
|
-
print("=" * 30 + "\r")
|
60
|
-
print("Head Controls:\r")
|
61
|
-
print(" u/i : Yaw L/R | j/k : Pitch UP/DN")
|
62
|
-
|
63
|
-
print("\nOther:")
|
64
|
-
print(" o/p : increase/decrease step size | -/+ : decrease/increase speed\r")
|
65
|
-
print("\nCTRL-C or 0 to quit\r")
|
66
|
-
print("=" * 43 + "\r")
|
67
|
-
|
68
|
-
def update_display(self):
|
69
|
-
"""Update step size and speed in place without adding new lines"""
|
70
|
-
sys.stdout.write(f"\rCurrent step size: {self.step_size:.1f} | Current joint speed: {self.joint_speed} ")
|
71
|
-
sys.stdout.flush() # Ensure immediate update
|
72
|
-
|
73
|
-
def get_command(self):
|
74
|
-
self.base_command = False
|
75
|
-
self.head_command = False
|
76
|
-
key = None
|
77
|
-
# Read keyboard input
|
78
|
-
if self.kb.kbhit() is not None:
|
79
|
-
key = self.kb.getch()
|
80
|
-
# print(f"key: {key}\r")
|
81
|
-
while sys.stdin in select([sys.stdin], [], [], 0)[0]:
|
82
|
-
sys.stdin.read(1)
|
83
|
-
|
84
|
-
if key == self.last_key:
|
85
|
-
self.last_key = None
|
86
|
-
return None, None
|
87
|
-
|
88
|
-
self.last_key = key # Update last key
|
89
|
-
|
90
|
-
# Check for quit conditions
|
91
|
-
if key == '0': # '0' key to quit
|
92
|
-
self.stop = True
|
93
|
-
return None, None
|
94
|
-
|
95
|
-
if key == 'o':
|
96
|
-
self.step_size += 0.1
|
97
|
-
if self.step_size > 1:
|
98
|
-
self.step_size = 1
|
99
|
-
elif key == 'p':
|
100
|
-
self.step_size -= 0.1
|
101
|
-
if self.step_size < 0.1:
|
102
|
-
self.step_size = 0.1
|
103
|
-
elif key == '-':
|
104
|
-
self.joint_speed -= 10
|
105
|
-
if self.joint_speed < 10:
|
106
|
-
self.joint_speed = 10
|
107
|
-
elif key == '+':
|
108
|
-
self.joint_speed += 10
|
109
|
-
if self.joint_speed > 100:
|
110
|
-
self.joint_speed = 100
|
111
|
-
if key in ['\x1b[A', '\x1b[B', '\x1b[D', '\x1b[C', ' ']:
|
112
|
-
l_vel, r_vel = BaseTeleop.get_base_command_from_key(self, key)
|
113
|
-
self.base_command = True
|
114
|
-
return l_vel, r_vel
|
115
|
-
elif key in ['u', 'i', 'j', 'k']:
|
116
|
-
y, p = HeadTeleop.get_head_value_from_key(self, key)
|
117
|
-
self.head_command = True
|
118
|
-
return y, p
|
119
|
-
else:
|
120
|
-
return None, None
|
121
|
-
|
122
|
-
else:
|
123
|
-
self.last_key = None
|
124
|
-
return 0.0, 0.0
|
125
|
-
|
126
|
-
def run(self):
|
127
|
-
while not self.stop:
|
128
|
-
input_1, input_2 = self.get_command()
|
129
|
-
if input_1 is not None and input_2 is not None:
|
130
|
-
response = None # Initialize response
|
131
|
-
if self.base_command:
|
132
|
-
response = self.robot.base.drive(input_1, input_2, block=False)
|
133
|
-
time.sleep(0.01)
|
134
|
-
elif self.head_command:
|
135
|
-
response = self.robot.head.look(input_1, input_2, self.joint_speed)
|
136
|
-
time.sleep(0.01)
|
137
|
-
if response == False:
|
138
|
-
break
|
139
|
-
|
140
|
-
input_1 = None
|
141
|
-
input_2 = None
|
142
|
-
self.update_display()
|
143
|
-
|
144
|
-
def stow(self):
|
145
|
-
self.robot.head.look(180,180,50)
|
146
|
-
|
147
|
-
def cleanup(self):
|
148
|
-
"""Cleanup method to properly shut down the robot and restore terminal settings"""
|
149
|
-
try:
|
150
|
-
# Restore terminal settings
|
151
|
-
self.kb.set_normal_term()
|
152
|
-
self.stow()
|
153
|
-
# Destroy the robot connection
|
154
|
-
self.robot.base.destroy(auto_dock=True)
|
155
|
-
|
156
|
-
except Exception as e:
|
157
|
-
print(f"\nError during cleanup: {e}")
|
158
|
-
# Try to restore terminal settings even if there's an error
|
159
|
-
try:
|
160
|
-
self.kb.set_normal_term()
|
161
|
-
except:
|
162
|
-
pass
|
163
|
-
|
164
|
-
def __del__(self):
|
165
|
-
"""Destructor to ensure cleanup is called"""
|
166
|
-
self.cleanup()
|
167
|
-
|
168
|
-
# Main entry point
|
169
|
-
if __name__ == '__main__':
|
170
|
-
teleop = None
|
171
|
-
try:
|
172
|
-
teleop = AI_PRO_Teleop()
|
173
|
-
teleop.run()
|
174
|
-
except KeyboardInterrupt:
|
175
|
-
print("\nShutting down...")
|
176
|
-
except Exception as e:
|
177
|
-
print(f"\nError: {e}")
|
178
|
-
finally:
|
179
|
-
if teleop:
|
180
|
-
teleop.cleanup()
|
@@ -1,230 +0,0 @@
|
|
1
|
-
################################################################################
|
2
|
-
# Copyright (c) 2025 Hackerbot Industries LLC
|
3
|
-
#
|
4
|
-
# This source code is licensed under the MIT license found in the
|
5
|
-
# LICENSE file in the root directory of this source tree.
|
6
|
-
#
|
7
|
-
# Created By: Allen Chien
|
8
|
-
# Created: April 2025
|
9
|
-
# Updated: 2025.04.01
|
10
|
-
#
|
11
|
-
# This script is an example of how to use the arm teleop behavior.
|
12
|
-
#
|
13
|
-
# Special thanks to the following for their code contributions to this codebase:
|
14
|
-
# Allen Chien - https://github.com/AllenChienXXX
|
15
|
-
################################################################################
|
16
|
-
|
17
|
-
|
18
|
-
from hackerbot import Hackerbot
|
19
|
-
import time
|
20
|
-
import os
|
21
|
-
|
22
|
-
import sys
|
23
|
-
from select import select
|
24
|
-
from base_teleop import KBHit
|
25
|
-
|
26
|
-
class ArmTeleop:
|
27
|
-
def __init__(self):
|
28
|
-
self.kb = KBHit()
|
29
|
-
|
30
|
-
self.robot = Hackerbot()
|
31
|
-
self.robot.base.initialize()
|
32
|
-
|
33
|
-
|
34
|
-
# Modify movement parameters
|
35
|
-
self.arm_speed = 50
|
36
|
-
self.step_size = 0.2 # mm
|
37
|
-
|
38
|
-
self.j_agl_1 = 0
|
39
|
-
self.j_agl_2 = 0
|
40
|
-
self.j_agl_3 = 0
|
41
|
-
self.j_agl_4 = 0
|
42
|
-
self.j_agl_5 = 0
|
43
|
-
self.j_agl_6 = 0
|
44
|
-
|
45
|
-
self.stop = False
|
46
|
-
self.last_key = None # Track last keypress
|
47
|
-
|
48
|
-
# Print initial instructions to terminal
|
49
|
-
self.print_terminal_instructions()
|
50
|
-
|
51
|
-
def print_terminal_instructions(self):
|
52
|
-
"""Print static instructions to the terminal"""
|
53
|
-
os.system('clear' if os.name == 'posix' else 'cls')
|
54
|
-
print("\n" + "="*10 + " Robot Arm Teleop Controls " + "="*10 + "\r")
|
55
|
-
|
56
|
-
print("\nJoint Controls (±165° for joints 1-5, ±175° for joint 6):")
|
57
|
-
print(" q/w : Joint 1 L/R")
|
58
|
-
print(" a/s : Joint 2 BCK/FWD")
|
59
|
-
print(" z/x : Joint 3 BCK/FWD")
|
60
|
-
print(" e/r : Joint 4 BCK/FWD")
|
61
|
-
print(" d/f : Joint 5 L/R")
|
62
|
-
print(" c/v : Joint 6 L/R")
|
63
|
-
|
64
|
-
print("\nGripper Controls:")
|
65
|
-
print(" g/h : Open/Close gripper")
|
66
|
-
print(" b : Calibrate gripper")
|
67
|
-
|
68
|
-
print("\nOther Controls:")
|
69
|
-
print(" o/p : increase/decrease step size")
|
70
|
-
print(" -/+ : decrease/increase speed")
|
71
|
-
print("\nCTRL-C or 0 to quit")
|
72
|
-
|
73
|
-
# Reserve space for dynamic updates
|
74
|
-
print("\n" + "=" * 43 + "\r")
|
75
|
-
|
76
|
-
def update_display(self):
|
77
|
-
"""Update step size and speed in place without adding new lines"""
|
78
|
-
sys.stdout.write(f"\rCurrent step size: {self.step_size:.1f} | Current speed: {self.arm_speed}% ")
|
79
|
-
sys.stdout.flush() # Ensure immediate update
|
80
|
-
|
81
|
-
|
82
|
-
def get_arm_command(self):
|
83
|
-
key = None
|
84
|
-
# Read keyboard input
|
85
|
-
if self.kb.kbhit() is not None:
|
86
|
-
key = self.kb.getch()
|
87
|
-
|
88
|
-
while sys.stdin in select([sys.stdin], [], [], 0)[0]:
|
89
|
-
sys.stdin.read(1)
|
90
|
-
|
91
|
-
if key == self.last_key:
|
92
|
-
self.last_key = None
|
93
|
-
return None, None
|
94
|
-
|
95
|
-
self.last_key = key
|
96
|
-
|
97
|
-
# Check for quit conditions
|
98
|
-
if key == '0': # ESC or Ctrl-C
|
99
|
-
self.stop = True
|
100
|
-
return None, None
|
101
|
-
|
102
|
-
if key == 'o':
|
103
|
-
self.step_size += 0.1
|
104
|
-
elif key == 'p':
|
105
|
-
self.step_size -= 0.1
|
106
|
-
if key == '-':
|
107
|
-
self.arm_speed -= 10
|
108
|
-
if self.arm_speed < 0:
|
109
|
-
self.arm_speed = 0
|
110
|
-
elif key == '+':
|
111
|
-
self.arm_speed += 10
|
112
|
-
if self.arm_speed > 100:
|
113
|
-
self.arm_speed = 100
|
114
|
-
|
115
|
-
command, value = self.get_arm_value_from_key(key)
|
116
|
-
return command, value
|
117
|
-
else:
|
118
|
-
self.last_key = None
|
119
|
-
return None, None
|
120
|
-
|
121
|
-
def get_arm_value_from_key(self, key):
|
122
|
-
# Joint controls
|
123
|
-
if key == 'q': # Joint 1 left
|
124
|
-
self.j_agl_1 += self.step_size*100
|
125
|
-
return 1, self.j_agl_1
|
126
|
-
elif key == 'w': # Joint 1 right
|
127
|
-
self.j_agl_1 -= self.step_size*100
|
128
|
-
return 1, self.j_agl_1
|
129
|
-
elif key == 'a': # Joint 2 left
|
130
|
-
self.j_agl_2 += self.step_size*100
|
131
|
-
return 2, self.j_agl_2
|
132
|
-
elif key == 's': # Joint 2 right
|
133
|
-
self.j_agl_2 -= self.step_size*100
|
134
|
-
return 2, self.j_agl_2
|
135
|
-
elif key == 'z': # Joint 3 left
|
136
|
-
self.j_agl_3 += self.step_size*100
|
137
|
-
return 3, self.j_agl_3
|
138
|
-
elif key == 'x': # Joint 3 right
|
139
|
-
self.j_agl_3 -= self.step_size*100
|
140
|
-
return 3, self.j_agl_3
|
141
|
-
elif key == 'e': # Joint 4 left
|
142
|
-
self.j_agl_4 += self.step_size*100
|
143
|
-
return 4, self.j_agl_4
|
144
|
-
elif key == 'r': # Joint 4 right
|
145
|
-
self.j_agl_4 -= self.step_size*100
|
146
|
-
return 4, self.j_agl_4
|
147
|
-
elif key == 'd': # Joint 5 left
|
148
|
-
self.j_agl_5 += self.step_size*100
|
149
|
-
return 5, self.j_agl_5
|
150
|
-
elif key == 'f': # Joint 5 right
|
151
|
-
self.j_agl_5 -= self.step_size*100
|
152
|
-
return 5, self.j_agl_5
|
153
|
-
elif key == 'c': # Joint 6 left
|
154
|
-
self.j_agl_6 += self.step_size*100
|
155
|
-
return 6, self.j_agl_6
|
156
|
-
elif key == 'v': # Joint 6 right
|
157
|
-
self.j_agl_6 -= self.step_size*100
|
158
|
-
return 6, self.j_agl_6
|
159
|
-
# Gripper controls
|
160
|
-
elif key == 'g': # Open gripper
|
161
|
-
return 'gripper_open', 'True'
|
162
|
-
elif key == 'h': # Close gripper
|
163
|
-
return 'gripper_close', 'True'
|
164
|
-
elif key == 'b': # Calibrate gripper
|
165
|
-
return 'gripper_calibrate', 'True'
|
166
|
-
else:
|
167
|
-
return None, None
|
168
|
-
|
169
|
-
|
170
|
-
def run(self):
|
171
|
-
while not self.stop:
|
172
|
-
response = None
|
173
|
-
command, value = self.get_arm_command()
|
174
|
-
if command is not None:
|
175
|
-
if isinstance(command, int): # Joint movement
|
176
|
-
# Limit joint angles based on which joint
|
177
|
-
max_angle = 175.0 if command == 6 else 165.0
|
178
|
-
if abs(value) <= max_angle:
|
179
|
-
response = self.robot.arm.move_joint(command, value, self.arm_speed)
|
180
|
-
|
181
|
-
elif command == 'gripper_open':
|
182
|
-
response = self.robot.arm.gripper.open()
|
183
|
-
elif command == 'gripper_close':
|
184
|
-
response = self.robot.arm.gripper.close()
|
185
|
-
elif command == 'gripper_calibrate':
|
186
|
-
response = self.robot.arm.gripper.calibrate()
|
187
|
-
|
188
|
-
if response == False:
|
189
|
-
break
|
190
|
-
time.sleep(0.2)
|
191
|
-
self.update_display()
|
192
|
-
|
193
|
-
def cleanup(self):
|
194
|
-
"""Cleanup method to properly shut down the robot and restore terminal settings"""
|
195
|
-
try:
|
196
|
-
# Restore terminal settings
|
197
|
-
self.kb.set_normal_term()
|
198
|
-
# Dock the robot
|
199
|
-
# self.robot.dock()
|
200
|
-
self.robot.arm.move_joints(0,0,0,0,0,0,50)
|
201
|
-
time.sleep(2)
|
202
|
-
# Destroy the robot connection
|
203
|
-
self.robot.destroy()
|
204
|
-
|
205
|
-
except Exception as e:
|
206
|
-
print(f"\nError during cleanup: {e}")
|
207
|
-
# Try to restore terminal settings even if there's an error
|
208
|
-
try:
|
209
|
-
self.kb.set_normal_term()
|
210
|
-
except:
|
211
|
-
pass
|
212
|
-
|
213
|
-
def __del__(self):
|
214
|
-
"""Destructor to ensure cleanup is called"""
|
215
|
-
self.cleanup()
|
216
|
-
|
217
|
-
|
218
|
-
# Main entry point
|
219
|
-
if __name__ == '__main__':
|
220
|
-
teleop = None
|
221
|
-
try:
|
222
|
-
teleop = ArmTeleop()
|
223
|
-
teleop.run()
|
224
|
-
except KeyboardInterrupt:
|
225
|
-
print("\nShutting down...")
|
226
|
-
except Exception as e:
|
227
|
-
print(f"\nError: {e}")
|
228
|
-
finally:
|
229
|
-
if teleop:
|
230
|
-
teleop.cleanup()
|
@@ -1,206 +0,0 @@
|
|
1
|
-
################################################################################
|
2
|
-
# Copyright (c) 2025 Hackerbot Industries LLC
|
3
|
-
#
|
4
|
-
# This source code is licensed under the MIT license found in the
|
5
|
-
# LICENSE file in the root directory of this source tree.
|
6
|
-
#
|
7
|
-
# Created By: Allen Chien
|
8
|
-
# Created: April 2025
|
9
|
-
# Updated: 2025.04.01
|
10
|
-
#
|
11
|
-
# This script is an example of how to use the base teleop behavior.
|
12
|
-
#
|
13
|
-
# Special thanks to the following for their code contributions to this codebase:
|
14
|
-
# Allen Chien - https://github.com/AllenChienXXX
|
15
|
-
################################################################################
|
16
|
-
|
17
|
-
|
18
|
-
from hackerbot import Hackerbot
|
19
|
-
import time
|
20
|
-
import os
|
21
|
-
|
22
|
-
import sys, termios, atexit
|
23
|
-
from select import select
|
24
|
-
|
25
|
-
class KBHit:
|
26
|
-
|
27
|
-
def __init__(self):
|
28
|
-
'''Creates a KBHit object that you can call to do various keyboard things.
|
29
|
-
'''
|
30
|
-
# Save the terminal settings
|
31
|
-
self.fd = sys.stdin.fileno()
|
32
|
-
self.new_term = termios.tcgetattr(self.fd)
|
33
|
-
self.old_term = termios.tcgetattr(self.fd)
|
34
|
-
|
35
|
-
# New terminal setting unbuffered
|
36
|
-
self.new_term[3] = (self.new_term[3] & ~termios.ICANON & ~termios.ECHO)
|
37
|
-
termios.tcsetattr(self.fd, termios.TCSAFLUSH, self.new_term)
|
38
|
-
|
39
|
-
# Support normal-terminal reset at exit
|
40
|
-
atexit.register(self.set_normal_term)
|
41
|
-
|
42
|
-
|
43
|
-
def set_normal_term(self):
|
44
|
-
''' Resets to normal terminal. On Windows this is a no-op.
|
45
|
-
'''
|
46
|
-
termios.tcsetattr(self.fd, termios.TCSAFLUSH, self.old_term)
|
47
|
-
|
48
|
-
|
49
|
-
def getch(self):
|
50
|
-
''' Returns a keyboard character after kbhit() has been called.
|
51
|
-
'''
|
52
|
-
ch1 = sys.stdin.read(1)
|
53
|
-
if ch1 == '\x1b':
|
54
|
-
# special key pressed
|
55
|
-
ch2 = sys.stdin.read(1)
|
56
|
-
ch3 = sys.stdin.read(1)
|
57
|
-
ch = ch1 + ch2 + ch3
|
58
|
-
else:
|
59
|
-
# not a special key
|
60
|
-
ch = ch1
|
61
|
-
while sys.stdin in select([sys.stdin], [], [], 0)[0]:
|
62
|
-
sys.stdin.read(1)
|
63
|
-
return ch
|
64
|
-
|
65
|
-
|
66
|
-
def kbhit(self):
|
67
|
-
''' Returns True if keyboard character was hit, False otherwise.
|
68
|
-
'''
|
69
|
-
dr,dw,de = select([sys.stdin], [], [], 0)
|
70
|
-
while sys.stdin in select([sys.stdin], [], [], 0)[0]:
|
71
|
-
sys.stdin.read(1)
|
72
|
-
return dr != []
|
73
|
-
|
74
|
-
class BaseTeleop:
|
75
|
-
def __init__(self):
|
76
|
-
self.kb = KBHit()
|
77
|
-
|
78
|
-
self.robot = Hackerbot()
|
79
|
-
self.robot.base.initialize()
|
80
|
-
|
81
|
-
# Modify movement parameters
|
82
|
-
self.step_size = 0.2 # mm
|
83
|
-
self.max_l_step_size = 300.0 # mm/s
|
84
|
-
self.max_r_step_size = 90.0 # degree/s
|
85
|
-
|
86
|
-
self.stop = False
|
87
|
-
self.last_key = None # Track last keypress
|
88
|
-
|
89
|
-
# Print initial instructions to terminal
|
90
|
-
self.print_terminal_instructions()
|
91
|
-
|
92
|
-
def print_terminal_instructions(self):
|
93
|
-
"""Print instructions to the terminal"""
|
94
|
-
os.system('clear' if os.name == 'posix' else 'cls')
|
95
|
-
print("\n" + "="*10 + " Robot Teleop Controls " + "="*10 + "\r")
|
96
|
-
print("\nMoving controls:\r")
|
97
|
-
print(" ↑ / ↓ : forward/backward | ← / → : rotate left/right | space : stop\r")
|
98
|
-
print("o/p : increase/decrease step size by 10%\r")
|
99
|
-
print("\nCTRL-C or '0' to quit\r")
|
100
|
-
print("=" * 43 + "\r")
|
101
|
-
|
102
|
-
def update_display(self):
|
103
|
-
"""Update step size in place without adding new lines"""
|
104
|
-
sys.stdout.write(f"\rCurrent step size: {self.step_size:.2f}m\r")
|
105
|
-
sys.stdout.flush() # Ensure immediate update
|
106
|
-
|
107
|
-
def get_command(self):
|
108
|
-
key = None
|
109
|
-
# Read keyboard input
|
110
|
-
if self.kb.kbhit() is not None:
|
111
|
-
key = self.kb.getch()
|
112
|
-
while sys.stdin in select([sys.stdin], [], [], 0)[0]:
|
113
|
-
sys.stdin.read(1)
|
114
|
-
|
115
|
-
if key == self.last_key:
|
116
|
-
self.last_key = None
|
117
|
-
return None, None
|
118
|
-
|
119
|
-
self.last_key = key # Update last key
|
120
|
-
|
121
|
-
# Check for quit conditions
|
122
|
-
if key == '0': # '0' key to quit
|
123
|
-
self.stop = True
|
124
|
-
return None, None
|
125
|
-
|
126
|
-
if key == 'o':
|
127
|
-
self.step_size += 0.1
|
128
|
-
elif key == 'p':
|
129
|
-
self.step_size -= 0.1
|
130
|
-
if key in ['\x1b[A', '\x1b[B', '\x1b[D', '\x1b[C', ' ']:
|
131
|
-
l_vel, r_vel = self.get_base_command_from_key(key)
|
132
|
-
else:
|
133
|
-
l_vel = None
|
134
|
-
r_vel = None
|
135
|
-
|
136
|
-
return l_vel, r_vel
|
137
|
-
else:
|
138
|
-
self.last_key = None
|
139
|
-
return 0.0, 0.0
|
140
|
-
|
141
|
-
def get_base_command_from_key(self, key):
|
142
|
-
if key == '\x1b[A': # Up arrow - Forward
|
143
|
-
l_vel = self.max_l_step_size * self.step_size
|
144
|
-
r_vel = 0.0
|
145
|
-
elif key == '\x1b[B': # Down arrow - Backward
|
146
|
-
l_vel = -self.max_l_step_size * self.step_size
|
147
|
-
r_vel = 0.0
|
148
|
-
elif key == '\x1b[D': # Left arrow - Rotate left
|
149
|
-
l_vel = 0.0
|
150
|
-
r_vel = self.max_r_step_size * self.step_size
|
151
|
-
elif key == '\x1b[C': # Right arrow - Rotate right
|
152
|
-
l_vel = 0.0
|
153
|
-
r_vel = -self.max_r_step_size * self.step_size
|
154
|
-
elif key == ' ': # Space - Stop
|
155
|
-
l_vel = 0.0
|
156
|
-
r_vel = 0.0
|
157
|
-
else:
|
158
|
-
l_vel = None
|
159
|
-
r_vel = None
|
160
|
-
return l_vel, r_vel
|
161
|
-
|
162
|
-
def run(self):
|
163
|
-
while not self.stop:
|
164
|
-
l_vel, r_vel = self.get_command()
|
165
|
-
if l_vel is not None and r_vel is not None:
|
166
|
-
respone = self.robot.base.drive(l_vel, r_vel, block=False)
|
167
|
-
if respone == False:
|
168
|
-
break
|
169
|
-
l_vel = None
|
170
|
-
r_vel = None
|
171
|
-
# time.sleep(0.01)
|
172
|
-
self.update_display()
|
173
|
-
def cleanup(self):
|
174
|
-
"""Cleanup method to properly shut down the robot and restore terminal settings"""
|
175
|
-
try:
|
176
|
-
# Restore terminal settings
|
177
|
-
self.kb.set_normal_term()
|
178
|
-
# Destroy the robot connection
|
179
|
-
self.robot.base.destroy(auto_dock=True)
|
180
|
-
|
181
|
-
except Exception as e:
|
182
|
-
print(f"\nError during cleanup: {e}")
|
183
|
-
# Try to restore terminal settings even if there's an error
|
184
|
-
try:
|
185
|
-
self.kb.set_normal_term()
|
186
|
-
except:
|
187
|
-
pass
|
188
|
-
|
189
|
-
def __del__(self):
|
190
|
-
"""Destructor to ensure cleanup is called"""
|
191
|
-
self.cleanup()
|
192
|
-
|
193
|
-
|
194
|
-
# Main entry point
|
195
|
-
if __name__ == '__main__':
|
196
|
-
teleop = None
|
197
|
-
try:
|
198
|
-
teleop = BaseTeleop()
|
199
|
-
teleop.run()
|
200
|
-
except KeyboardInterrupt:
|
201
|
-
print("\nShutting down...")
|
202
|
-
except Exception as e:
|
203
|
-
print(f"\nError: {e}")
|
204
|
-
finally:
|
205
|
-
if teleop:
|
206
|
-
teleop.cleanup()
|
@@ -1,170 +0,0 @@
|
|
1
|
-
################################################################################
|
2
|
-
# Copyright (c) 2025 Hackerbot Industries LLC
|
3
|
-
#
|
4
|
-
# This source code is licensed under the MIT license found in the
|
5
|
-
# LICENSE file in the root directory of this source tree.
|
6
|
-
#
|
7
|
-
# Created By: Allen Chien
|
8
|
-
# Created: April 2025
|
9
|
-
# Updated: 2025.04.01
|
10
|
-
#
|
11
|
-
# This script is an example of how to use the head teleop behavior.
|
12
|
-
#
|
13
|
-
# Special thanks to the following for their code contributions to this codebase:
|
14
|
-
# Allen Chien - https://github.com/AllenChienXXX
|
15
|
-
################################################################################
|
16
|
-
|
17
|
-
|
18
|
-
from hackerbot import Hackerbot
|
19
|
-
import time
|
20
|
-
import os
|
21
|
-
|
22
|
-
import sys
|
23
|
-
from select import select
|
24
|
-
from base_teleop import KBHit
|
25
|
-
|
26
|
-
class HeadTeleop:
|
27
|
-
def __init__(self):
|
28
|
-
self.kb = KBHit()
|
29
|
-
|
30
|
-
self.robot = Hackerbot()
|
31
|
-
self.robot.head.set_idle_mode(False)
|
32
|
-
|
33
|
-
# Modify movement parameters
|
34
|
-
self.joint_speed = 50
|
35
|
-
self.step_size = 0.2 # mm
|
36
|
-
|
37
|
-
self.yaw = 180
|
38
|
-
self.pitch = 180
|
39
|
-
|
40
|
-
self.stop = False
|
41
|
-
self.last_key = None # Track last keypress
|
42
|
-
|
43
|
-
# Print initial instructions to terminal
|
44
|
-
self.print_terminal_instructions()
|
45
|
-
|
46
|
-
def print_terminal_instructions(self):
|
47
|
-
"""Print static instructions to the terminal"""
|
48
|
-
os.system('clear' if os.name == 'posix' else 'cls')
|
49
|
-
print("\n" + "="*10 + " Robot Head Teleop Controls " + "="*10 + "\r")
|
50
|
-
print(" u/i : Yaw rotate L/R")
|
51
|
-
print(" j/k : Pitch rotate B/F")
|
52
|
-
|
53
|
-
print("\nOther Controls:")
|
54
|
-
print(" p/o : increase/decrease step size")
|
55
|
-
print(" -/+ : decrease/increase speed")
|
56
|
-
print("\nCTRL-C or 0 to quit")
|
57
|
-
|
58
|
-
# Reserve space for dynamic updates
|
59
|
-
print("\n" + "=" * 43 + "\r")
|
60
|
-
|
61
|
-
def update_display(self):
|
62
|
-
"""Update step size and speed in place without adding new lines"""
|
63
|
-
sys.stdout.write(f"\rCurrent step size: {self.step_size:.1f} | Current speed: {self.joint_speed}% ")
|
64
|
-
sys.stdout.flush() # Ensure immediate update
|
65
|
-
|
66
|
-
|
67
|
-
def get_head_command(self):
|
68
|
-
key = None
|
69
|
-
# Read keyboard input
|
70
|
-
if self.kb.kbhit() is not None:
|
71
|
-
key = self.kb.getch()
|
72
|
-
|
73
|
-
while sys.stdin in select([sys.stdin], [], [], 0)[0]:
|
74
|
-
sys.stdin.read(1)
|
75
|
-
|
76
|
-
if key == self.last_key:
|
77
|
-
self.last_key = None
|
78
|
-
return None, None
|
79
|
-
|
80
|
-
self.last_key = key
|
81
|
-
|
82
|
-
# Check for quit conditions
|
83
|
-
if key == '0': # ESC or Ctrl-C
|
84
|
-
self.stop = True
|
85
|
-
return None, None
|
86
|
-
|
87
|
-
if key == 'o':
|
88
|
-
self.step_size += 0.1
|
89
|
-
elif key == 'p':
|
90
|
-
self.step_size -= 0.1
|
91
|
-
if key == '-':
|
92
|
-
self.joint_speed -= 10
|
93
|
-
if self.joint_speed < 0:
|
94
|
-
self.joint_speed = 0
|
95
|
-
elif key == '+':
|
96
|
-
self.joint_speed += 10
|
97
|
-
if self.joint_speed > 100:
|
98
|
-
self.joint_speed = 100
|
99
|
-
|
100
|
-
return self.get_head_value_from_key(key)
|
101
|
-
else:
|
102
|
-
self.last_key = None
|
103
|
-
return None, None
|
104
|
-
|
105
|
-
def get_head_value_from_key(self, key):
|
106
|
-
# Joint controls
|
107
|
-
if key == 'u': # Joint 1 left
|
108
|
-
self.yaw += self.step_size*100
|
109
|
-
self.yaw = max(100, min(260, self.yaw))
|
110
|
-
elif key == 'i': # Joint 1 right
|
111
|
-
self.yaw -= self.step_size*100
|
112
|
-
self.yaw = max(100, min(260, self.yaw))
|
113
|
-
elif key == 'j': # Joint 2 left
|
114
|
-
self.pitch += self.step_size*100
|
115
|
-
self.pitch = max(150, min(250, self.pitch))
|
116
|
-
elif key == 'k': # Joint 2 right
|
117
|
-
self.pitch -= self.step_size*100
|
118
|
-
self.pitch = max(150, min(250, self.pitch))
|
119
|
-
else:
|
120
|
-
return None, None
|
121
|
-
|
122
|
-
return self.yaw, self.pitch
|
123
|
-
|
124
|
-
def run(self):
|
125
|
-
while not self.stop:
|
126
|
-
y, p = self.get_head_command()
|
127
|
-
if y is not None and p is not None:
|
128
|
-
response = self.robot.head.look(y, p, self.joint_speed)
|
129
|
-
|
130
|
-
time.sleep(0.2)
|
131
|
-
if response == False:
|
132
|
-
break
|
133
|
-
self.update_display()
|
134
|
-
|
135
|
-
def cleanup(self):
|
136
|
-
"""Cleanup method to properly shut down the robot and restore terminal settings"""
|
137
|
-
try:
|
138
|
-
# Restore terminal settings
|
139
|
-
self.kb.set_normal_term()
|
140
|
-
# Dock the robot
|
141
|
-
self.robot.head.look(180,180,50)
|
142
|
-
# Destroy the robot connection
|
143
|
-
self.robot.destroy()
|
144
|
-
|
145
|
-
except Exception as e:
|
146
|
-
print(f"\nError during cleanup: {e}")
|
147
|
-
# Try to restore terminal settings even if there's an error
|
148
|
-
try:
|
149
|
-
self.kb.set_normal_term()
|
150
|
-
except:
|
151
|
-
pass
|
152
|
-
|
153
|
-
def __del__(self):
|
154
|
-
"""Destructor to ensure cleanup is called"""
|
155
|
-
self.cleanup()
|
156
|
-
|
157
|
-
|
158
|
-
# Main entry point
|
159
|
-
if __name__ == '__main__':
|
160
|
-
teleop = None
|
161
|
-
try:
|
162
|
-
teleop = HeadTeleop()
|
163
|
-
teleop.run()
|
164
|
-
except KeyboardInterrupt:
|
165
|
-
print("\nShutting down...")
|
166
|
-
except Exception as e:
|
167
|
-
print(f"\nError: {e}")
|
168
|
-
finally:
|
169
|
-
if teleop:
|
170
|
-
teleop.cleanup()
|
hackerbot-0.2.0.dist-info/RECORD
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
hackerbot/__init__.py,sha256=fjzBB_VsqCuKJ3yeLdqLSvAQIz9bAMI-KXrUC6ZrscY,1248
|
2
|
-
hackerbot/core.py,sha256=oZKQEUaMn19MnaWNTDFqTZ7lziBEZeSk5CdLXLSLvr0,5521
|
3
|
-
hackerbot/arm/__init__.py,sha256=JdCmTDQ2qk3W8-Alc4mjaQYxHnmH26r0nSy0JFg6J4A,3400
|
4
|
-
hackerbot/arm/gripper.py,sha256=xZux0PZL4vvrJTTKHL7dDsRBfJr4zbmgMaA0uBR1u4s,1986
|
5
|
-
hackerbot/base/__init__.py,sha256=PG2Ykn2MLfobAWClGFnp-AZfh1xVsnbc1nQ8E6Yy6eA,8698
|
6
|
-
hackerbot/base/maps.py,sha256=I_4NdvOMnkHX6-mW43QpDPJ-eVc6npgcBXq99tU7D1g,5916
|
7
|
-
hackerbot/examples/keyboard_teleop_examples/AI_ELITE_teleop.py,sha256=cy9Cp4QSYafvm-5xBoq-ks8tdLJHzMvO_6pRweWLVaU,7832
|
8
|
-
hackerbot/examples/keyboard_teleop_examples/AI_PRO_teleop.py,sha256=Q99v488MncM8uZ0okPzrWihQmLKCufEgbLIIT3Od0ig,5959
|
9
|
-
hackerbot/examples/keyboard_teleop_examples/arm_teleop.py,sha256=GoyhRuqqpqwMdBKMq_pgTsbcuVNfO8sGcJKGNiD6P8k,7730
|
10
|
-
hackerbot/examples/keyboard_teleop_examples/base_teleop.py,sha256=3XpXUWtPeCcsYhffcUMWMI_upkA9VFXB0qoinWpaqvA,6545
|
11
|
-
hackerbot/examples/keyboard_teleop_examples/head_teleop.py,sha256=PfE-VzuaF4-bF0wtziyaTX2SnyKqZmDaNDbM8b-W9gQ,5328
|
12
|
-
hackerbot/head/__init__.py,sha256=fNW1u1Kb5jE7q-UGQgZ511gnHPOjeR_monSm8p9CfNI,2466
|
13
|
-
hackerbot/head/eyes.py,sha256=xqeKMxL12iaa8KQzDlbgbNy3LzcmWm8aXkebztYJ4P8,1370
|
14
|
-
hackerbot/utils/hackerbot_helper.py,sha256=egQPVBBUo52ywsO6jGAGVqhyGLpMPz-b2fgLBb39WSM,4998
|
15
|
-
hackerbot/utils/serial_helper.py,sha256=l7pj32mnoVZN-7foU_FPUxdmZaE43jcMmZRBAGEX8Zc,6457
|
16
|
-
hackerbot-0.2.0.dist-info/licenses/LICENSE,sha256=SCcXH0bf35ISRu_Ks8xEKySHXiqclANLWhBUbVU8VvA,1081
|
17
|
-
hackerbot-0.2.0.dist-info/METADATA,sha256=PvGs4X-ax2hoGDWe12HjmBS55bXcK3MMAgb6mgt8Irg,1714
|
18
|
-
hackerbot-0.2.0.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
|
19
|
-
hackerbot-0.2.0.dist-info/top_level.txt,sha256=2n_FStAr1SiI3BV67x7KJHYIOmEwxjUD59zedw2hLkU,10
|
20
|
-
hackerbot-0.2.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|