hackerbot 0.2.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.
@@ -0,0 +1,219 @@
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()
@@ -0,0 +1,180 @@
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()
@@ -0,0 +1,230 @@
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()