Totally random events

Added toggle to enable a small chance of a random event occuring when certain conditions are met.
This commit is contained in:
FrogAi
2024-04-03 00:47:27 -07:00
parent 0beefa914d
commit 885dd256a8
22 changed files with 256 additions and 10 deletions
+16
View File
@@ -118,7 +118,11 @@ struct CarEvent @0x9b1657f34caf3ad3 {
paramsdPermanentError @119;
# FrogPilot events
accel30 @120;
accel35 @121;
accel40 @122;
blockUser @123;
firefoxSteerSaturated @124;
goatSteerSaturated @125;
greenLight @126;
holidayActive @127;
@@ -126,9 +130,12 @@ struct CarEvent @0x9b1657f34caf3ad3 {
leadDeparting @129;
noLaneAvailable @130;
openpilotCrashed @131;
openpilotCrashedRandomEvents @132;
pedalInterceptorNoBrake @133;
speedLimitChanged @134;
torqueNNLoad @135;
vCruise69 @138;
yourFrogTriedToKillMe @139;
radarCanErrorDEPRECATED @15;
communityFeatureDisallowedDEPRECATED @62;
@@ -420,6 +427,15 @@ struct CarControl {
promptRepeat @7;
promptDistracted @8;
# Random Events
angry @9;
doc @10;
fart @11;
firefox @12;
nessie @13;
noice @14;
uwu @15;
# Other
goat @16;
}
+2
View File
@@ -250,6 +250,7 @@ std::unordered_map<std::string, uint32_t> keys = {
{"ConditionalExperimental", PERSISTENT},
{"CrosstrekTorque", PERSISTENT},
{"CurrentHolidayTheme", PERSISTENT},
{"CurrentRandomEvent", PERSISTENT},
{"CustomAlerts", PERSISTENT},
{"CustomColors", PERSISTENT},
{"CustomCruise", PERSISTENT},
@@ -367,6 +368,7 @@ std::unordered_map<std::string, uint32_t> keys = {
{"PromptVolume", PERSISTENT},
{"QOLControls", PERSISTENT},
{"QOLVisuals", PERSISTENT},
{"RandomEvents", PERSISTENT},
{"RefuseVolume", PERSISTENT},
{"RelaxedFollow", PERSISTENT},
{"RelaxedJerk", PERSISTENT},
+67 -3
View File
@@ -191,13 +191,18 @@ class Controls:
self.always_on_lateral = self.params.get_bool("AlwaysOnLateral")
self.always_on_lateral_main = self.always_on_lateral and self.params.get_bool("AlwaysOnLateralMain")
self.fcw_random_event_triggered = False
self.holiday_theme_alerted = False
self.onroad_distance_pressed = False
self.openpilot_crashed_triggered = False
self.previously_enabled = False
self.random_event_triggered = False
self.speed_check = False
self.max_acceleration = 0
self.previous_lead_distance = 0
self.previous_speed_limit = 0
self.random_event_timer = 0
self.speed_limit_timer = 0
self.green_light_mac = MovingAverageCalculator()
@@ -418,6 +423,10 @@ class Controls:
planner_fcw = self.sm['longitudinalPlan'].fcw and self.enabled
if planner_fcw or model_fcw:
self.events.add(EventName.fcw)
self.fcw_random_event_triggered = True
elif self.fcw_random_event_triggered and self.random_events:
self.events.add(EventName.yourFrogTriedToKillMe)
self.fcw_random_event_triggered = False
for m in messaging.drain_sock(self.log_sock, wait_for_one=False):
try:
@@ -678,8 +687,13 @@ class Controls:
turning = abs(lac_log.desiredLateralAccel) > 1.0
good_speed = CS.vEgo > 5
max_torque = abs(actuators.steer) > 0.99
if undershooting and turning and good_speed and max_torque:
lac_log.active and self.events.add(EventName.goatSteerSaturated if self.goat_scream else EventName.steerSaturated)
if undershooting and turning and good_speed and max_torque and not self.random_event_triggered:
if self.sm.frame % 10000 == 0 and self.random_events:
lac_log.active and self.events.add(EventName.firefoxSteerSaturated)
self.params_memory.put_int("CurrentRandomEvent", 1)
self.random_event_triggered = True
else:
lac_log.active and self.events.add(EventName.goatSteerSaturated if self.goat_scream else EventName.steerSaturated)
elif lac_log.saturated:
# TODO probably should not use dpath_points but curvature
dpath_points = model_v2.position.y
@@ -923,6 +937,32 @@ class Controls:
self.events.add(EventName.blockUser)
return
if self.random_events:
acceleration = CS.aEgo
if not CS.gasPressed:
self.max_acceleration = max(acceleration, self.max_acceleration)
else:
self.max_acceleration = 0
if 3.5 > self.max_acceleration >= 3.0 and acceleration < 1.5:
self.events.add(EventName.accel30)
self.params_memory.put_int("CurrentRandomEvent", 2)
self.random_event_triggered = True
self.max_acceleration = 0
elif 4.0 > self.max_acceleration >= 3.5 and acceleration < 1.5:
self.events.add(EventName.accel35)
self.params_memory.put_int("CurrentRandomEvent", 3)
self.random_event_triggered = True
self.max_acceleration = 0
elif self.max_acceleration >= 4.0 and acceleration < 1.5:
self.events.add(EventName.accel40)
self.params_memory.put_int("CurrentRandomEvent", 4)
self.random_event_triggered = True
self.max_acceleration = 0
if self.green_light_alert:
green_light = not self.sm['frogpilotPlan'].redLight
green_light &= not CS.gasPressed
@@ -953,7 +993,12 @@ class Controls:
self.events.add(EventName.leadDeparting)
if os.path.isfile(os.path.join(sentry.CRASHES_DIR, 'error.txt')) and not self.openpilot_crashed_triggered:
self.events.add(EventName.openpilotCrashed)
if self.random_events:
self.events.add(EventName.openpilotCrashedRandomEvents)
else:
self.events.add(EventName.openpilotCrashed)
self.openpilot_crashed_triggered = True
if self.speed_limit_alert or self.speed_limit_confirmation:
current_speed_limit = self.sm['frogpilotPlan'].slcSpeedLimit
@@ -1005,6 +1050,17 @@ class Controls:
if self.sm.frame == 550 and self.CP.lateralTuning.which() == 'torque' and self.CI.use_nnff:
self.events.add(EventName.torqueNNLoad)
if self.random_events:
conversion = 1 if self.is_metric else CV.KPH_TO_MPH
v_cruise = max(self.v_cruise_helper.v_cruise_cluster_kph, self.v_cruise_helper.v_cruise_kph) * conversion
if 70 > v_cruise >= 69:
if not self.vCruise69_alert_played:
self.events.add(EventName.vCruise69)
self.vCruise69_alert_played = True
else:
self.vCruise69_alert_played = False
def update_frogpilot_variables(self, CS):
self.driving_gear = CS.gearShifter not in (GearShifter.neutral, GearShifter.park, GearShifter.reverse, GearShifter.unknown)
@@ -1029,6 +1085,13 @@ class Controls:
self.previously_enabled |= (self.enabled or self.FPCC.alwaysOnLateral) and CS.vEgo > CRUISING_SPEED
self.previously_enabled &= self.driving_gear
if self.random_event_triggered:
self.random_event_timer += DT_CTRL
if self.random_event_timer >= 4:
self.random_event_triggered = False
self.random_event_timer = 0
self.params_memory.remove("CurrentRandomEvent")
signal_check = CS.vEgo >= self.pause_lateral_below_speed or not (CS.leftBlinker or CS.rightBlinker) or CS.standstill
self.speed_check = CS.vEgo >= self.pause_lateral_below_speed or CS.standstill or signal_check and self.pause_lateral_below_signal
@@ -1055,6 +1118,7 @@ class Controls:
frog_sounds = custom_sounds == 1
self.goat_scream = frog_sounds and self.params.get_bool("GoatScream")
self.holiday_themes = custom_theme and self.params.get_bool("HolidayThemes")
self.random_events = custom_theme and self.params.get_bool("RandomEvents")
device_management = self.params.get_bool("DeviceManagement")
self.increase_thermal_limits = device_management and self.params.get_bool("IncreaseThermalLimits")
+57
View File
@@ -1083,6 +1083,63 @@ EVENTS: dict[int, dict[str, Alert | AlertCallbackType]] = {
EventName.torqueNNLoad: {
ET.PERMANENT: torque_nn_load_alert,
},
# Random Events
EventName.accel30: {
ET.WARNING: Alert(
"UwU u went a bit fast there!",
"( ⁄•⁄ω⁄•⁄ )",
AlertStatus.frogpilot, AlertSize.mid,
Priority.LOW, VisualAlert.none, AudibleAlert.uwu, 4.),
},
EventName.accel35: {
ET.WARNING: Alert(
"I ain't giving you no tree-fiddy",
"you damn Loch Ness monsta!",
AlertStatus.frogpilot, AlertSize.mid,
Priority.LOW, VisualAlert.none, AudibleAlert.nessie, 4.),
},
EventName.accel40: {
ET.WARNING: Alert(
"Great Scott!",
"🚗💨",
AlertStatus.frogpilot, AlertSize.mid,
Priority.LOW, VisualAlert.none, AudibleAlert.doc, 4.),
},
EventName.firefoxSteerSaturated: {
ET.WARNING: Alert(
"Turn Exceeds Steering Limit",
"IE Has Stopped Responding...",
AlertStatus.userPrompt, AlertSize.mid,
Priority.LOW, VisualAlert.steerRequired, AudibleAlert.firefox, 4.),
},
EventName.openpilotCrashedRandomEvents: {
ET.PERMANENT: Alert(
"openpilot crashed 💩",
"Please post the error log in the FrogPilot Discord!",
AlertStatus.normal, AlertSize.mid,
Priority.HIGHEST, VisualAlert.none, AudibleAlert.fart, 10.),
},
EventName.vCruise69: {
ET.PERMANENT: Alert(
"Lol 69",
"",
AlertStatus.frogpilot, AlertSize.small,
Priority.LOW, VisualAlert.none, AudibleAlert.noice, 2.),
},
EventName.yourFrogTriedToKillMe: {
ET.PERMANENT: Alert(
"Your frog tried to kill me...",
"👺",
AlertStatus.frogpilot, AlertSize.mid,
Priority.MID, VisualAlert.none, AudibleAlert.angry, 5.),
},
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 221 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

@@ -35,6 +35,7 @@ FrogPilotVisualsPanel::FrogPilotVisualsPanel(SettingsWindow *parent) : FrogPilot
{"CustomSignals", tr("Turn Signals"), tr("Add themed animation for your turn signals.\n\nWant to submit your own turn signal animation? Post it in the 'feature-request' channel in the FrogPilot Discord!"), ""},
{"CustomSounds", tr("Sound Pack"), tr("Switch out the standard openpilot sounds with a set of themed sounds.\n\nWant to submit your own sound pack? Post it in the 'feature-request' channel in the FrogPilot Discord!"), ""},
{"HolidayThemes", tr("Holiday Themes"), tr("The openpilot theme changes according to the current/upcoming holiday. Minor holidays last a day, while major holidays (Easter, Christmas, Halloween, etc.) last a week."), ""},
{"RandomEvents", tr("Random Events"), tr("Enjoy a bit of unpredictability with random events that can occur during certain driving conditions. This is purely cosmetic and has no impact on driving controls!"), ""},
{"ModelUI", tr("Model UI"), tr("Customize the model visualizations on the screen."), "../assets/offroad/icon_calibration.png"},
{"DynamicPathWidth", tr("Dynamic Path Width"), tr("Have the path width dynamically adjust based on the current engagement state of openpilot."), ""},
@@ -28,7 +28,7 @@ private:
std::set<QString> alertVolumeControlKeys = {"DisengageVolume", "EngageVolume", "PromptDistractedVolume", "PromptVolume", "RefuseVolume", "WarningImmediateVolume", "WarningSoftVolume"};
std::set<QString> customAlertsKeys = {"GreenLightAlert", "LeadDepartingAlert", "LoudBlindspotAlert"};
std::set<QString> customOnroadUIKeys = {"Compass", "CustomPaths", "DeveloperUI", "FPSCounter", "LeadInfo", "PedalsOnUI", "RoadNameUI", "WheelIcon"};
std::set<QString> customThemeKeys = {"CustomColors", "CustomIcons", "CustomSignals", "CustomSounds", "HolidayThemes"};
std::set<QString> customThemeKeys = {"CustomColors", "CustomIcons", "CustomSignals", "CustomSounds", "HolidayThemes", "RandomEvents"};
std::set<QString> modelUIKeys = {"DynamicPathWidth", "HideLeadMarker", "LaneLinesWidth", "PathEdgeWidth", "PathWidth", "RoadEdgesWidth", "UnlimitedLength"};
std::set<QString> qolKeys = {"BigMap", "CameraView", "DriverCamera", "FullMap", "HideSpeed", "MapStyle", "NumericalTemp"};
std::set<QString> screenKeys = {"HideUIElements", "ScreenBrightness", "ScreenBrightnessOnroad", "ScreenRecorder", "ScreenTimeout", "ScreenTimeoutOnroad", "StandbyMode"};
+66 -2
View File
@@ -33,6 +33,18 @@ static void drawIcon(QPainter &p, const QPoint &center, const QPixmap &img, cons
p.restore();
}
static void drawIconGif(QPainter &p, const QPoint &center, const QMovie &img, const QBrush &bg, float opacity) {
p.setRenderHint(QPainter::Antialiasing);
p.setOpacity(1.0); // bg dictates opacity of ellipse
p.setPen(Qt::NoPen);
p.setBrush(bg);
p.drawEllipse(center.x() - btn_size / 2, center.y() - btn_size / 2, btn_size, btn_size);
p.setOpacity(opacity);
QPixmap currentFrame = img.currentPixmap();
p.drawPixmap(center - QPoint(currentFrame.width() / 2, currentFrame.height() / 2), currentFrame);
p.setOpacity(1.0);
}
OnroadWindow::OnroadWindow(QWidget *parent) : QWidget(parent), scene(uiState()->scene) {
QVBoxLayout *main_layout = new QVBoxLayout(this);
main_layout->setMargin(UI_BORDER_SIZE);
@@ -410,7 +422,12 @@ ExperimentalButton::ExperimentalButton(QWidget *parent) : experimental_mode(fals
{4, loadPixmap("../frogpilot/assets/wheel_images/rocket.png", {img_size, img_size})},
{5, loadPixmap("../frogpilot/assets/wheel_images/hyundai.png", {img_size, img_size})},
{6, loadPixmap("../frogpilot/assets/wheel_images/stalin.png", {img_size, img_size})},
{7, loadPixmap("../frogpilot/assets/random_events/images/firefox.png", {img_size, img_size})},
};
wheelImagesGif[1] = new QMovie("../frogpilot/assets/random_events/images/weeb_wheel.gif", QByteArray(), this);
wheelImagesGif[2] = new QMovie("../frogpilot/assets/random_events/images/tree_fiddy.gif", QByteArray(), this);
wheelImagesGif[3] = new QMovie("../frogpilot/assets/random_events/images/great_scott.gif", QByteArray(), this);
}
void ExperimentalButton::changeMode() {
@@ -436,12 +453,41 @@ void ExperimentalButton::updateState(const UIState &s, bool leadInfo) {
}
// FrogPilot variables
int randomEvent = scene.current_random_event;
rotatingWheel = scene.rotating_wheel;
wheelIcon = scene.wheel_icon;
wheelIconGif = 0;
y_offset = leadInfo ? 10 : 0;
if (rotatingWheel && steeringAngleDeg != scene.steering_angle_deg) {
if (randomEvent == 0 && gifLabel) {
delete gifLabel;
gifLabel = nullptr;
} else if (randomEvent == 1) {
static int rotationDegree = 0;
rotationDegree = (rotationDegree + 36) % 360;
steeringAngleDeg = rotationDegree;
wheelIcon = 7;
update();
} else if (randomEvent == 2 || randomEvent == 3 || randomEvent == 4) {
if (!gifLabel) {
gifLabel = new QLabel(this);
QMovie *movie = wheelImagesGif[randomEvent - 1];
if (movie) {
gifLabel->setMovie(movie);
gifLabel->setFixedSize(img_size, img_size);
gifLabel->move((width() - gifLabel->width()) / 2, (height() - gifLabel->height()) / 2 + y_offset);
gifLabel->movie()->start();
}
}
gifLabel->show();
wheelIconGif = randomEvent - 1;
update();
} else if (rotatingWheel && steeringAngleDeg != scene.steering_angle_deg) {
steeringAngleDeg = scene.steering_angle_deg;
update();
steeringAngleDeg = scene.steering_angle_deg;
} else if (!rotatingWheel) {
@@ -457,6 +503,7 @@ void ExperimentalButton::paintEvent(QPaintEvent *event) {
QPainter p(this);
engage_img = wheelImages[wheelIcon];
QPixmap img = wheelIcon != 0 ? engage_img : (experimental_mode ? experimental_img : engage_img);
QMovie *gif = wheelImagesGif[wheelIconGif];
QColor background_color = wheelIcon != 0 && !isDown() && engageable ?
(scene.always_on_lateral_active ? QColor(10, 186, 181, 255) :
@@ -466,7 +513,11 @@ void ExperimentalButton::paintEvent(QPaintEvent *event) {
QColor(0, 0, 0, 166);
if (!(scene.map_open && scene.big_map)) {
drawIcon(p, QPoint(btn_size / 2, btn_size / 2 + y_offset), img, background_color, (isDown() || !engageable) ? 0.6 : 1.0, steeringAngleDeg);
if (wheelIconGif != 0) {
drawIconGif(p, QPoint(btn_size / 2, btn_size / 2 + y_offset), *gif, background_color, 1.0);
} else {
drawIcon(p, QPoint(btn_size / 2, btn_size / 2 + y_offset), img, background_color, (isDown() || !engageable) ? 0.6 : 1.0, steeringAngleDeg);
}
}
}
@@ -1583,11 +1634,24 @@ void AnnotatedCameraWidget::drawLeadInfo(QPainter &p) {
}
double acceleration = std::round(scene.acceleration * 100) / 100;
int randomEvent = scene.current_random_event;
if (acceleration > maxAcceleration && status == STATUS_ENGAGED) {
maxAcceleration = acceleration;
isFiveSecondsPassed = false;
timer.start();
} else if (randomEvent == 2 && maxAcceleration < 3.0) {
maxAcceleration = 3.0;
isFiveSecondsPassed = false;
timer.start();
} else if (randomEvent == 3 && maxAcceleration < 3.5) {
maxAcceleration = 3.5;
isFiveSecondsPassed = false;
timer.start();
} else if (randomEvent == 4 && maxAcceleration < 4.0) {
maxAcceleration = 4.0;
isFiveSecondsPassed = false;
timer.start();
} else {
isFiveSecondsPassed = timer.hasExpired(maxAccelDuration);
}
+11
View File
@@ -2,6 +2,8 @@
#include <memory>
#include <QMovie>
#include <QLabel>
#include <QPushButton>
#include <QStackedLayout>
#include <QWidget>
@@ -106,11 +108,20 @@ private:
UIScene &scene;
QMap<int, QPixmap> wheelImages;
QMap<int, QMovie*> wheelImagesGif;
QMovie engage_gif;
QLabel *gifLabel;
bool docRandomEventTriggered;
bool firefoxRandomEventTriggered;
bool rotatingWheel;
bool treeFiddyRandomEventTriggered;
bool weebRandomEventTriggered;
int steeringAngleDeg;
int wheelIcon;
int wheelIconGif;
int y_offset;
};
+31 -4
View File
@@ -1,5 +1,6 @@
import math
import numpy as np
import os
import time
import wave
@@ -40,6 +41,15 @@ sound_list: dict[int, tuple[str, int | None, float]] = {
AudibleAlert.warningSoft: ("warning_soft.wav", None, MAX_VOLUME),
AudibleAlert.warningImmediate: ("warning_immediate.wav", None, MAX_VOLUME),
# Random Events
AudibleAlert.angry: ("angry.wav", 1, MAX_VOLUME),
AudibleAlert.doc: ("doc.wav", 1, MAX_VOLUME),
AudibleAlert.fart: ("fart.wav", 1, MAX_VOLUME),
AudibleAlert.firefox: ("firefox.wav", 1, MAX_VOLUME),
AudibleAlert.nessie: ("nessie.wav", 1, MAX_VOLUME),
AudibleAlert.noice: ("noice.wav", 1, MAX_VOLUME),
AudibleAlert.uwu: ("uwu.wav", 1, MAX_VOLUME),
# Other
AudibleAlert.goat: ("goat.wav", None, MAX_VOLUME),
}
@@ -61,6 +71,17 @@ class Soundd:
self.params_memory = Params("/dev/shm/params")
self.previous_sound_directory = None
self.random_events_directory = BASEDIR + "/selfdrive/frogpilot/assets/random_events/sounds/"
self.random_events_map = {
AudibleAlert.angry: MAX_VOLUME,
AudibleAlert.doc: MAX_VOLUME,
AudibleAlert.fart: MAX_VOLUME,
AudibleAlert.firefox: MAX_VOLUME,
AudibleAlert.nessie: MAX_VOLUME,
AudibleAlert.noice: MAX_VOLUME,
AudibleAlert.uwu: MAX_VOLUME,
}
self.update_frogpilot_params()
@@ -82,10 +103,13 @@ class Soundd:
filename, play_count, volume = sound_list[sound]
try:
wavefile = wave.open(self.sound_directory + filename, 'r')
except FileNotFoundError:
wavefile = wave.open(BASEDIR + "/selfdrive/assets/sounds/" + filename, 'r')
if sound in self.random_events_map:
wavefile = wave.open(self.random_events_directory + filename, 'r')
else:
try:
wavefile = wave.open(self.sound_directory + filename, 'r')
except FileNotFoundError:
wavefile = wave.open(BASEDIR + "/selfdrive/assets/sounds/" + filename, 'r')
assert wavefile.getnchannels() == 1
assert wavefile.getsampwidth() == 2
@@ -168,6 +192,9 @@ class Soundd:
elif self.alert_volume_control and self.current_alert in self.volume_map:
self.current_volume = self.volume_map[self.current_alert] / 100.0
elif self.current_alert in self.random_events_map:
self.current_volume = self.random_events_map[self.current_alert]
self.get_audible_alert(sm)
rk.keep_time()
+2
View File
@@ -344,6 +344,7 @@ void ui_update_frogpilot_params(UIState *s) {
scene.custom_icons = custom_theme ? params.getInt("CustomIcons") : 0;
scene.custom_signals = custom_theme ? params.getInt("CustomSignals") : 0;
scene.holiday_themes = custom_theme && params.getBool("HolidayThemes");
scene.random_events = custom_theme && params.getBool("RandomEvents");
scene.disable_smoothing_mtsc = params.getBool("MTSCEnabled") && params.getBool("DisableMTSCSmoothing");
scene.experimental_mode_via_screen = scene.longitudinal_control && params.getBool("ExperimentalModeActivation") && params.getBool("ExperimentalModeViaTap");
@@ -467,6 +468,7 @@ void UIState::update() {
// FrogPilot live variables that need to be constantly checked
scene.conditional_status = scene.conditional_experimental ? paramsMemory.getInt("CEStatus") : 0;
scene.current_holiday_theme = scene.holiday_themes ? paramsMemory.getInt("CurrentHolidayTheme") : 0;
scene.current_random_event = scene.random_events ? paramsMemory.getInt("CurrentRandomEvent") : 0;
scene.driver_camera_timer = (scene.driver_camera && scene.reverse) ? scene.driver_camera_timer + 1 : 0;
}
+2
View File
@@ -213,6 +213,7 @@ typedef struct UIScene {
bool onroad_distance_button;
bool parked;
bool pedals_on_ui;
bool random_events;
bool reverse;
bool reverse_cruise;
bool reverse_cruise_ui;
@@ -267,6 +268,7 @@ typedef struct UIScene {
int conditional_speed_lead;
int conditional_status;
int current_holiday_theme;
int current_random_event;
int custom_colors;
int custom_icons;
int custom_signals;