Skip to content

Commit 770dcf4

Browse files
committed
Enhancements Package
+Joystick w/ Xbox One Controller Params
1 parent a7e511b commit 770dcf4

File tree

9 files changed

+153
-10
lines changed

9 files changed

+153
-10
lines changed

selfdrive/car/interfaces.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ def __init__(self, CP, CarController, CarState):
2828
self.CP = CP
2929
self.VM = VehicleModel(CP)
3030

31+
self.hzCounter = 0
32+
3133
self.frame = 0
3234
self.steering_unpressed = 0
3335
self.low_speed_alert = False
@@ -86,7 +88,7 @@ def get_std_params(candidate, fingerprint):
8688
ret.steerRatioRear = 0. # no rear steering, at least on the listed cars aboveA
8789
ret.openpilotLongitudinalControl = False
8890
ret.stopAccel = -2.0
89-
ret.stoppingDecelRate = 0.8 # brake_travel/s while trying to stop
91+
ret.stoppingDecelRate = 0.025 # brake_travel/s while trying to stop
9092
ret.vEgoStopping = 0.5
9193
ret.vEgoStarting = 0.5 # needs to be >= vEgoStopping to avoid state transition oscillation
9294
ret.stoppingControl = True
@@ -152,8 +154,15 @@ def create_common_events(self, cs_out, extra_gears=None, pcm_enable=True):
152154
events.add(EventName.manualSteeringRequired)
153155
else:
154156
self.silent_steer_warning = False
157+
155158
if cs_out.steerError:
156-
events.add(EventName.steerUnavailable)
159+
self.hzCounter += 1
160+
if self.hzCounter > 250:
161+
events.add(EventName.steerUnavailable)
162+
self.hzCounter = 301
163+
164+
if not cs_out.steerError:
165+
self.hzCounter = 0
157166

158167
# Disable on rising edge of gas or brake. Also disable on brake when speed > 0.
159168
if (cs_out.gasPressed and not self.CS.out.gasPressed) or \

selfdrive/common/version.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
#define COMMA_VERSION "0.8.13"
1+
#define COMMA_VERSION "0.8.13-Clarity"

selfdrive/controls/lib/events.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ class StartupAlert(Alert):
184184
def __init__(self, alert_text_1: str, alert_text_2: str = "Always keep hands on wheel and eyes on road", alert_status=AlertStatus.normal):
185185
super().__init__(alert_text_1, alert_text_2,
186186
alert_status, AlertSize.mid,
187-
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 10.),
187+
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 5.),
188188

189189

190190
# ********** helper functions **********
@@ -276,12 +276,11 @@ def joystick_alert(CP: car.CarParams, sm: messaging.SubMaster, metric: bool, sof
276276
},
277277

278278
EventName.startup: {
279-
ET.PERMANENT: StartupAlert("Be ready to take over at any time")
279+
ET.PERMANENT: StartupAlert("Be ready to take over at any time"),
280280
},
281281

282282
EventName.startupMaster: {
283-
ET.PERMANENT: StartupAlert("WARNING: This branch is not tested",
284-
alert_status=AlertStatus.userPrompt),
283+
ET.PERMANENT: StartupAlert("Be ready to take over at any time"),
285284
},
286285

287286
# Car is recognized, but marked as dashcam only

selfdrive/controls/lib/longitudinal_planner.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
LON_MPC_STEP = 0.2 # first step is 0.2s
1818
AWARENESS_DECEL = -0.2 # car smoothly decel at .2m/s^2 when user is distracted
1919
A_CRUISE_MIN = -1.2
20-
A_CRUISE_MAX_VALS = [1.2, 1.2, 0.8, 0.6]
20+
A_CRUISE_MAX_VALS = [1.5, 1.2, 0.8, 0.6]
2121
A_CRUISE_MAX_BP = [0., 15., 25., 40.]
2222

2323
# Lookup table for turns

selfdrive/manager/process_config.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
PythonProcess("thermald", "selfdrive.thermald.thermald", persistent=True),
3535
PythonProcess("timezoned", "selfdrive.timezoned", enabled=TICI, persistent=True),
3636
PythonProcess("tombstoned", "selfdrive.tombstoned", enabled=not PC, persistent=True),
37-
PythonProcess("updated", "selfdrive.updated", enabled=not PC, persistent=True),
37+
#PythonProcess("updated", "selfdrive.updated", enabled=not PC, persistent=True), No Updates Allowed Here =P -wirelessnet2
3838
PythonProcess("uploader", "selfdrive.loggerd.uploader", persistent=True),
3939
PythonProcess("statsd", "selfdrive.statsd", persistent=True),
4040

selfdrive/ui/qt/widgets/prime.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,7 @@ void SetupWidget::replyFinished(const QString &response, bool success) {
319319
} else {
320320
popup->reject();
321321

322-
if (prime_type) {
322+
if (true) {
323323
mainLayout->setCurrentWidget(primeUser);
324324
} else {
325325
mainLayout->setCurrentWidget(primeAd);

tools/joystick/README.md

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# Joystick
2+
3+
**Hardware needed**: [comma two devkit](https://comma.ai/shop/products/comma-two-devkit), laptop, joystick (optional)
4+
5+
With joystickd, you can connect your laptop to your comma device over the network and debug controls using a joystick or keyboard, however a joystick is recommended for more precise control.
6+
7+
Using a keyboard
8+
---
9+
10+
To get started, ssh into your comma device and start joystickd with the following command:
11+
12+
```shell
13+
tools/joystick/joystickd.py --keyboard
14+
```
15+
16+
The available buttons and axes will print showing their key mappings. In general, the WASD keys control gas and brakes and steering torque in 5% increments.
17+
18+
Using a joystick
19+
---
20+
21+
In order to use a joystick over the network, we need to run joystickd locally from your laptop and have it send `testJoystick` ZMQ packets over the network to the comma device. First connect a compatible joystick to your PC; joystickd uses [inputs](https://pypi.org/project/inputs) which supports many common gamepads and joysticks.
22+
23+
1. Connect your laptop to your comma device's hotspot and open a new ssh shell. Since joystickd is being run on your laptop, we need to write a parameter to let controlsd know to start in joystick debug mode:
24+
```shell
25+
# on your comma device
26+
echo -n "1" > /data/params/d/JoystickDebugMode
27+
```
28+
2. Run bridge with your laptop's IP address. This republishes the `testJoystick` packets sent from your laptop so that openpilot can receive them:
29+
```shell
30+
# on your comma device
31+
cereal/messaging/bridge {LAPTOP_IP} testJoystick
32+
```
33+
3. Finally, start joystickd on your laptop and tell it to publish ZMQ packets over the network:
34+
```shell
35+
# on your laptop
36+
export ZMQ=1
37+
tools/joystick/joystickd.py
38+
```
39+
40+
---
41+
Now start your car and openpilot should go into debug mode with an alert on startup! The status of the axes will display on the alert, while button statuses print in the shell.
42+
43+
Make sure the conditions are met in the panda to allow controls (e.g. cruise control engaged). You can also make a modification to the panda code to always allow controls.
44+
45+
![Imgur](steer.gif)

tools/joystick/joystickd.py

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
#!/usr/bin/env python
2+
import argparse
3+
4+
import cereal.messaging as messaging
5+
from common.numpy_fast import interp, clip
6+
from common.params import Params
7+
from inputs import get_gamepad
8+
from tools.lib.kbhit import KBHit
9+
10+
11+
class Keyboard:
12+
def __init__(self):
13+
self.kb = KBHit()
14+
self.axis_increment = 0.05 # 5% of full actuation each key press
15+
self.axes_map = {'w': 'gb', 's': 'gb',
16+
'a': 'steer', 'd': 'steer'}
17+
self.axes_values = {'gb': 0., 'steer': 0.}
18+
19+
def update(self):
20+
key = self.kb.getch().lower()
21+
self.cancel = False
22+
if key == 'r':
23+
self.axes_values = {ax: 0. for ax in self.axes_values}
24+
elif key == 'c':
25+
self.cancel = True
26+
elif key in self.axes_map:
27+
axis = self.axes_map[key]
28+
incr = self.axis_increment if key in ['w', 'a'] else -self.axis_increment
29+
self.axes_values[axis] = clip(self.axes_values[axis] + incr, -1, 1)
30+
else:
31+
return False
32+
return True
33+
34+
# Xbox One Controller Parameters with Halo Steering Controls -wn2
35+
class Joystick:
36+
def __init__(self):
37+
self.min_axis_value = -32767
38+
self.max_axis_value = 32767
39+
self.cancel_button = 'BTN_EAST'
40+
self.axes_values = {'ABS_Y': 0., 'ABS_RX': 0.} # gb, steer
41+
42+
def update(self):
43+
joystick_event = get_gamepad()[0]
44+
event = (joystick_event.code, joystick_event.state)
45+
self.cancel = False
46+
if event[0] == self.cancel_button and event[1] == 0: # state 0 is falling edge
47+
self.cancel = True
48+
elif event[0] in self.axes_values:
49+
self.max_axis_value = max(event[1], self.max_axis_value)
50+
self.min_axis_value = min(event[1], self.min_axis_value)
51+
52+
norm = -interp(event[1], [self.min_axis_value, self.max_axis_value], [-1., 1.])
53+
self.axes_values[event[0]] = norm if abs(norm) > 0.05 else 0. # center can be noisy, deadzone of 5%
54+
else:
55+
return False
56+
return True
57+
58+
59+
def joystick_thread(use_keyboard):
60+
Params().put_bool('JoystickDebugMode', True)
61+
joystick_sock = messaging.pub_sock('testJoystick')
62+
joystick = Keyboard() if use_keyboard else Joystick()
63+
64+
while True:
65+
ret = joystick.update() # processes joystick/key events and handles state of axes
66+
if ret:
67+
dat = messaging.new_message('testJoystick')
68+
dat.testJoystick.axes = [joystick.axes_values[a] for a in joystick.axes_values]
69+
dat.testJoystick.buttons = [joystick.cancel]
70+
joystick_sock.send(dat.to_bytes())
71+
print('\n' + ', '.join(f'{name}: {round(v, 3)}' for name, v in joystick.axes_values.items()))
72+
73+
74+
if __name__ == '__main__':
75+
parser = argparse.ArgumentParser(
76+
description='Publishes events from your joystick to control your car',
77+
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
78+
parser.add_argument('--keyboard', action='store_true', help='Use your keyboard instead of a joystick')
79+
args = parser.parse_args()
80+
81+
if args.keyboard:
82+
print('\nGas/brake control: `W` and `S` keys\n'
83+
'Steering control: `A` and `D` keys')
84+
print('Buttons:\n'
85+
'- `R`: Resets axes\n'
86+
'- `C`: Cancel cruise control')
87+
else:
88+
print('\nUsing joystick, make sure to run bridge on your device if running over the network!')
89+
90+
joystick_thread(args.keyboard)

tools/joystick/steer.gif

6.97 MB
Loading

0 commit comments

Comments
 (0)