-
Notifications
You must be signed in to change notification settings - Fork 57
/
Copy pathgamepad_reader.py
148 lines (120 loc) · 4.74 KB
/
gamepad_reader.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
import itertools
from absl import app
import inputs
import threading
import time
from MPC_Controller.Parameters import Parameters
from MPC_Controller.utils import GaitType, FSM_StateName
MAX_ABS_VAL = 32768
ALLOWED_MODES = [FSM_StateName.RECOVERY_STAND, FSM_StateName.LOCOMOTION]
ALLOWED_GAITS = [x for x in GaitType]
def _interpolate(raw_reading, max_raw_reading, new_scale):
return raw_reading / max_raw_reading * new_scale
class Gamepad:
"""Interface for reading commands from xbox Gamepad.
The control works as following:
1) Press LB+RB at any time for emergency stop
2) Use the left joystick for forward/backward/left/right walking.
3) Use the right joystick for rotation around the z-axis.
"""
def __init__(self,
vel_scale_x: float=.5,
vel_scale_y: float=.5,
vel_scale_rot: float=1.,
max_acc: float = .5):
"""Initialize the gamepad controller.
Args:
vel_scale_x: maximum absolute x-velocity command.
vel_scale_y: maximum absolute y-velocity command.
vel_scale_rot: maximum absolute yaw-dot command.
"""
if not inputs.devices.gamepads:
raise inputs.UnpluggedError("No gamepad found.")
self.gamepad = inputs.devices.gamepads[0]
self._vel_scale_x = float(vel_scale_x)
self._vel_scale_y = float(vel_scale_y)
self._vel_scale_rot = float(vel_scale_rot)
self._max_acc = max_acc
self._lb_pressed = False
self._rb_pressed = False
self._lj_pressed = False
self._gait_generator = itertools.cycle(ALLOWED_GAITS)
self._gait = next(self._gait_generator)
self._mode_generator = itertools.cycle(ALLOWED_MODES)
self._mode = next(self._mode_generator)#Parameters.control_mode
# Controller states
self.vx, self.vy, self.wz = 0., 0., 0.
self._FSM_switch = False
self._estop_flagged = False
self.is_running = True
self.read_thread = threading.Thread(target=self.read_loop)
self.read_thread.start()
def read_loop(self):
"""The read loop for events.
This funnction should be executed in a separate thread for continuous
event recording.
"""
while self.is_running:# and not self.estop_flagged:
try:
events = self.gamepad.read()
for event in events:
# print(event.ev_type, event.code, event.state)
self.update_command(event)
except Exception as e:
pass
def update_command(self, event):
"""Update command based on event readings."""
if event.ev_type == 'Key' and event.code == 'BTN_TL':
self._lb_pressed = bool(event.state)
if not self._estop_flagged and event.state == 0:
self._gait = next(self._gait_generator)
elif event.ev_type == 'Key' and event.code == 'BTN_TR':
self._rb_pressed = bool(event.state)
if not self._estop_flagged and event.state == 0:
self._mode = next(self._mode_generator)
elif event.ev_type == 'Key' and event.code == 'BTN_THUMBL':
self._lj_pressed = bool(event.state)
elif event.ev_type == 'Absolute' and event.code == 'ABS_X':
# Left Joystick L/R axis
self.wz = _interpolate(-event.state, MAX_ABS_VAL, self._vel_scale_rot)
elif event.ev_type == 'Absolute' and event.code == 'ABS_Y':
# Left Joystick F/B axis; need to flip sign for consistency
self.vx = _interpolate(-event.state, MAX_ABS_VAL, self._vel_scale_x)
elif event.ev_type == 'Absolute' and event.code == 'ABS_RX':
self.vy = _interpolate(-event.state, MAX_ABS_VAL, self._vel_scale_y)
if self._estop_flagged and self._lj_pressed:
print("Estop Released.")
self._estop_flagged = False
self._mode_generator = itertools.cycle(ALLOWED_MODES)
self._mode = next(self._mode_generator)#Parameters.control_mode
if self._lb_pressed and self._rb_pressed:
print("EStop Flagged, press LEFT joystick to release.")
self._estop_flagged = True
self.vx, self.vy, self.wz = 0., 0., 0.
self._mode = FSM_StateName.RECOVERY_STAND
def get_command(self):
return (self.vx, self.vy, 0), self.wz, self._estop_flagged
def get_gait(self):
return self._gait
def get_mode(self):
return self._mode
def fake_event(self, ev_type, code, value):
eventinfo = {
"ev_type": ev_type,
"state": value,
"timestamp": 0.0,
"code": code
}
event = inputs.InputEvent(self.gamepad, eventinfo)
self.update_command(event)
def stop(self):
self.is_running = False
def main(_):
gamepad = Gamepad()
while True:
print("Vx: {:.3f}, Vy: {:.3f}, Wz: {:.3f}, Estop: {}".format(gamepad.vx, gamepad.vy,
gamepad.wz,
gamepad._estop_flagged))
time.sleep(0.1)
if __name__ == "__main__":
app.run(main)