Compare commits

...

56 Commits

Author SHA1 Message Date
firestar5683 0495453e3a Malibu 2026-02-10 20:53:35 -06:00
firestar5683 5340cc449c Blazer Pedal 2026-02-09 16:20:54 -06:00
firestar5683 89f6f7a42b User adjustable offsets 2026-02-07 23:32:46 -06:00
firestar5683 073d9ba098 Integrator Smooth On Handoff 2026-02-06 15:48:06 -06:00
firestar5683 3ad700a964 Malibu ASCM Fingerprint 2026-02-06 12:29:33 -06:00
firestar5683 c69a5080f4 Revert "merry christmas"
This reverts commit fa9234212b.
2026-02-05 22:49:40 -06:00
firestar5683 6ab4400614 Lights 2026-02-05 22:40:20 -06:00
firestar5683 8222e303a2 New Models 2026-02-05 15:06:24 -06:00
firestar5683 43da13c8b0 Limp? 2026-02-05 13:57:49 -06:00
firestar5683 1b1d60d088 Increase Fault Resilience 2026-02-05 13:35:38 -06:00
firestarsdog 9421030e2c Stats
Stats
2026-02-02 01:03:32 -05:00
firestar5683 930fa680cf Update carcontroller.py 2026-02-01 22:01:53 -06:00
firestar5683 f4fb138009 Update gmcan.py 2026-01-30 00:17:30 -06:00
firestar5683 35cee6a7f9 malibu pedal tuning 2026-01-29 00:43:38 -06:00
firestar5683 66fbf8b21f phase sync 2026-01-27 22:26:51 -06:00
firestar5683 f3306bec23 update 2026-01-27 00:12:01 -06:00
firestar5683 5338f9a5d5 malibu buttons 2026-01-26 00:08:27 -06:00
firestar5683 6a702911ab Reapply "More buttons?"
This reverts commit 4da1ddc500.
2026-01-25 23:53:44 -06:00
firestar5683 4da1ddc500 Revert "More buttons?"
This reverts commit cb0f964e60.
2026-01-22 12:02:27 -06:00
firestar5683 cb0f964e60 More buttons? 2026-01-22 01:19:59 -06:00
firestar5683 a868fc6650 Buttons 2026-01-22 00:29:40 -06:00
firestar5683 2f44ed860d Malibu Buttons 2026-01-20 23:16:35 -06:00
firestar5683 9bb133a188 Revert "Mac Update"
This reverts commit d56a8f6c23.
2026-01-19 11:41:36 -06:00
firestarsdog 251b755efd Add SASCM to vehicle settings detection/stats 2026-01-19 10:33:15 -06:00
firestar5683 d56a8f6c23 Mac Update 2026-01-18 22:22:24 -06:00
firestarsdog 894d792dbb Stats 2026-01-18 22:17:16 -06:00
firestar5683 91cb407979 Update carcontroller.py 2026-01-16 16:31:30 -06:00
firestar5683 2361ad82c9 update redneck 2026-01-15 22:49:34 -06:00
firestar5683 cea54bf498 Malibu GuessTune 2026-01-15 22:40:08 -06:00
firestar5683 bc012595ca More Malibu 2026-01-14 23:35:45 -06:00
firestar5683 c1df1eaf2a fix redneck v2 2026-01-14 13:59:17 -06:00
firestar5683 323e269a6b Remove lat smooth seconds 2026-01-14 13:50:00 -06:00
firestar5683 4c9430caf1 Malibu Phase Sync 2026-01-12 23:31:50 -06:00
firestar5683 0b193e90f0 frogpilot migration 2026-01-12 22:11:24 -06:00
firestar5683 c3d0c9c7c3 More defaults 2026-01-12 22:04:57 -06:00
firestar5683 89d871ea40 Update defaults 2026-01-12 22:00:11 -06:00
firestar5683 77956f33c2 Big Mac 2026-01-11 23:19:24 -06:00
firestar5683 3e47e95934 Malibu Checksum 2026-01-11 23:19:24 -06:00
firestar5683 3086285c72 Revert "Malibu Buttons?"
This reverts commit 22789bc95f.
2026-01-10 14:23:59 -06:00
firestar5683 5fc40a8936 Try Higher Friction 2026-01-10 14:04:39 -06:00
firestar5683 19565e7aca Malibu Pedal Tuning 2026-01-10 00:13:58 -06:00
firestar5683 22789bc95f Malibu Buttons? 2026-01-09 23:33:23 -06:00
firestar5683 22a949893d Autotune Off 2026-01-09 22:41:24 -06:00
firestar5683 7e749a73a4 pedal long flag 2026-01-09 18:05:44 -06:00
firestar5683 36c2cb5fb0 Update interface.py 2026-01-09 17:00:03 -06:00
firestar5683 fa9234212b merry christmas 2025-12-24 22:23:43 -06:00
firestar5683 fd7b50a1a6 ds2 2025-12-24 21:29:13 -06:00
firestar5683 64087ac7ea No sub? 2025-12-18 12:29:24 -06:00
firestar5683 961fc23845 Use new torque Controller 2025-12-16 22:12:50 -06:00
firestar5683 6d98e4a784 Fix Volt 2019? 2025-12-16 17:18:02 -06:00
firestar5683 cfd8c78c4c Update interface.py 2025-12-16 17:12:01 -06:00
firestar5683 1542e69a20 Try friction adjustment 2025-12-16 17:12:01 -06:00
firestar5683 ffdea13de8 Update frogpilot_tracking.py 2025-12-16 17:12:00 -06:00
firestar5683 60b000f7b5 minsteer speed 2025-12-16 17:12:00 -06:00
firestar5683 1a27190a67 Update Percentages 2025-12-16 17:12:00 -06:00
firestar5683 69703fd2ac Torque Rest of Fleet 2025-12-16 17:12:00 -06:00
71 changed files with 1141 additions and 246 deletions
+1 -1
View File
@@ -105,7 +105,7 @@ struct FrogPilotCarParams @0xf35cc4560bbf6ec2 {
isHDA2 @3 :Bool; isHDA2 @3 :Bool;
openpilotLongitudinalControlDisabled @4 :Bool; openpilotLongitudinalControlDisabled @4 :Bool;
safetyConfigs @5 :List(SafetyConfig); safetyConfigs @5 :List(SafetyConfig);
canUseSASCM @6 :Bool;
struct SafetyConfig { struct SafetyConfig {
safetyParam @0 :UInt16; safetyParam @0 :UInt16;
+51 -35
View File
@@ -642,7 +642,7 @@ const ::capnp::_::RawSchema s_aedffd8f31e7b55d = {
}; };
#endif // !CAPNP_LITE #endif // !CAPNP_LITE
CAPNP_DEFINE_ENUM(EventName_aedffd8f31e7b55d, aedffd8f31e7b55d); CAPNP_DEFINE_ENUM(EventName_aedffd8f31e7b55d, aedffd8f31e7b55d);
static const ::capnp::_::AlignedData<123> b_f35cc4560bbf6ec2 = { static const ::capnp::_::AlignedData<139> b_f35cc4560bbf6ec2 = {
{ 0, 0, 0, 0, 5, 0, 6, 0, { 0, 0, 0, 0, 5, 0, 6, 0,
194, 110, 191, 11, 86, 196, 92, 243, 194, 110, 191, 11, 86, 196, 92, 243,
13, 0, 0, 0, 1, 0, 1, 0, 13, 0, 0, 0, 1, 0, 1, 0,
@@ -652,7 +652,7 @@ static const ::capnp::_::AlignedData<123> b_f35cc4560bbf6ec2 = {
21, 0, 0, 0, 2, 1, 0, 0, 21, 0, 0, 0, 2, 1, 0, 0,
33, 0, 0, 0, 23, 0, 0, 0, 33, 0, 0, 0, 23, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
45, 0, 0, 0, 87, 1, 0, 0, 45, 0, 0, 0, 143, 1, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
99, 117, 115, 116, 111, 109, 46, 99, 99, 117, 115, 116, 111, 109, 46, 99,
@@ -664,49 +664,56 @@ static const ::capnp::_::AlignedData<123> b_f35cc4560bbf6ec2 = {
1, 0, 0, 0, 106, 0, 0, 0, 1, 0, 0, 0, 106, 0, 0, 0,
83, 97, 102, 101, 116, 121, 67, 111, 83, 97, 102, 101, 116, 121, 67, 111,
110, 102, 105, 103, 0, 0, 0, 0, 110, 102, 105, 103, 0, 0, 0, 0,
24, 0, 0, 0, 3, 0, 4, 0, 28, 0, 0, 0, 3, 0, 4, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
153, 0, 0, 0, 98, 0, 0, 0, 181, 0, 0, 0, 98, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
152, 0, 0, 0, 3, 0, 1, 0, 180, 0, 0, 0, 3, 0, 1, 0,
164, 0, 0, 0, 2, 0, 1, 0, 192, 0, 0, 0, 2, 0, 1, 0,
1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0,
0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
161, 0, 0, 0, 90, 0, 0, 0, 189, 0, 0, 0, 90, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
160, 0, 0, 0, 3, 0, 1, 0,
172, 0, 0, 0, 2, 0, 1, 0,
2, 0, 0, 0, 1, 0, 0, 0,
0, 0, 1, 0, 2, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
169, 0, 0, 0, 66, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
164, 0, 0, 0, 3, 0, 1, 0,
176, 0, 0, 0, 2, 0, 1, 0,
3, 0, 0, 0, 2, 0, 0, 0,
0, 0, 1, 0, 3, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
173, 0, 0, 0, 58, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
168, 0, 0, 0, 3, 0, 1, 0,
180, 0, 0, 0, 2, 0, 1, 0,
4, 0, 0, 0, 3, 0, 0, 0,
0, 0, 1, 0, 4, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
177, 0, 0, 0, 42, 1, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
188, 0, 0, 0, 3, 0, 1, 0, 188, 0, 0, 0, 3, 0, 1, 0,
200, 0, 0, 0, 2, 0, 1, 0, 200, 0, 0, 0, 2, 0, 1, 0,
2, 0, 0, 0, 1, 0, 0, 0,
0, 0, 1, 0, 2, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
197, 0, 0, 0, 66, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
192, 0, 0, 0, 3, 0, 1, 0,
204, 0, 0, 0, 2, 0, 1, 0,
3, 0, 0, 0, 2, 0, 0, 0,
0, 0, 1, 0, 3, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
201, 0, 0, 0, 58, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
196, 0, 0, 0, 3, 0, 1, 0,
208, 0, 0, 0, 2, 0, 1, 0,
4, 0, 0, 0, 3, 0, 0, 0,
0, 0, 1, 0, 4, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
205, 0, 0, 0, 42, 1, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
216, 0, 0, 0, 3, 0, 1, 0,
228, 0, 0, 0, 2, 0, 1, 0,
5, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1, 0, 5, 0, 0, 0, 0, 0, 1, 0, 5, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
197, 0, 0, 0, 114, 0, 0, 0, 225, 0, 0, 0, 114, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
196, 0, 0, 0, 3, 0, 1, 0, 224, 0, 0, 0, 3, 0, 1, 0,
224, 0, 0, 0, 2, 0, 1, 0, 252, 0, 0, 0, 2, 0, 1, 0,
6, 0, 0, 0, 4, 0, 0, 0,
0, 0, 1, 0, 6, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
249, 0, 0, 0, 98, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
248, 0, 0, 0, 3, 0, 1, 0,
4, 1, 0, 0, 2, 0, 1, 0,
99, 97, 110, 85, 115, 101, 80, 101, 99, 97, 110, 85, 115, 101, 80, 101,
100, 97, 108, 0, 0, 0, 0, 0, 100, 97, 108, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
@@ -764,6 +771,15 @@ static const ::capnp::_::AlignedData<123> b_f35cc4560bbf6ec2 = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
14, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
99, 97, 110, 85, 115, 101, 83, 65,
83, 67, 77, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, } 0, 0, 0, 0, 0, 0, 0, 0, }
}; };
@@ -772,11 +788,11 @@ static const ::capnp::_::AlignedData<123> b_f35cc4560bbf6ec2 = {
static const ::capnp::_::RawSchema* const d_f35cc4560bbf6ec2[] = { static const ::capnp::_::RawSchema* const d_f35cc4560bbf6ec2[] = {
&s_8d65dd40bad40951, &s_8d65dd40bad40951,
}; };
static const uint16_t m_f35cc4560bbf6ec2[] = {0, 1, 2, 3, 4, 5}; static const uint16_t m_f35cc4560bbf6ec2[] = {0, 6, 1, 2, 3, 4, 5};
static const uint16_t i_f35cc4560bbf6ec2[] = {0, 1, 2, 3, 4, 5}; static const uint16_t i_f35cc4560bbf6ec2[] = {0, 1, 2, 3, 4, 5, 6};
const ::capnp::_::RawSchema s_f35cc4560bbf6ec2 = { const ::capnp::_::RawSchema s_f35cc4560bbf6ec2 = {
0xf35cc4560bbf6ec2, b_f35cc4560bbf6ec2.words, 123, d_f35cc4560bbf6ec2, m_f35cc4560bbf6ec2, 0xf35cc4560bbf6ec2, b_f35cc4560bbf6ec2.words, 139, d_f35cc4560bbf6ec2, m_f35cc4560bbf6ec2,
1, 6, i_f35cc4560bbf6ec2, nullptr, nullptr, { &s_f35cc4560bbf6ec2, nullptr, nullptr, 0, 0, nullptr }, false 1, 7, i_f35cc4560bbf6ec2, nullptr, nullptr, { &s_f35cc4560bbf6ec2, nullptr, nullptr, 0, 0, nullptr }, false
}; };
#endif // !CAPNP_LITE #endif // !CAPNP_LITE
static const ::capnp::_::AlignedData<36> b_8d65dd40bad40951 = { static const ::capnp::_::AlignedData<36> b_8d65dd40bad40951 = {
+19
View File
@@ -669,6 +669,8 @@ public:
inline bool hasSafetyConfigs() const; inline bool hasSafetyConfigs() const;
inline ::capnp::List< ::cereal::FrogPilotCarParams::SafetyConfig, ::capnp::Kind::STRUCT>::Reader getSafetyConfigs() const; inline ::capnp::List< ::cereal::FrogPilotCarParams::SafetyConfig, ::capnp::Kind::STRUCT>::Reader getSafetyConfigs() const;
inline bool getCanUseSASCM() const;
private: private:
::capnp::_::StructReader _reader; ::capnp::_::StructReader _reader;
template <typename, ::capnp::Kind> template <typename, ::capnp::Kind>
@@ -719,6 +721,9 @@ public:
inline void adoptSafetyConfigs(::capnp::Orphan< ::capnp::List< ::cereal::FrogPilotCarParams::SafetyConfig, ::capnp::Kind::STRUCT>>&& value); inline void adoptSafetyConfigs(::capnp::Orphan< ::capnp::List< ::cereal::FrogPilotCarParams::SafetyConfig, ::capnp::Kind::STRUCT>>&& value);
inline ::capnp::Orphan< ::capnp::List< ::cereal::FrogPilotCarParams::SafetyConfig, ::capnp::Kind::STRUCT>> disownSafetyConfigs(); inline ::capnp::Orphan< ::capnp::List< ::cereal::FrogPilotCarParams::SafetyConfig, ::capnp::Kind::STRUCT>> disownSafetyConfigs();
inline bool getCanUseSASCM();
inline void setCanUseSASCM(bool value);
private: private:
::capnp::_::StructBuilder _builder; ::capnp::_::StructBuilder _builder;
template <typename, ::capnp::Kind> template <typename, ::capnp::Kind>
@@ -2220,6 +2225,20 @@ inline ::capnp::Orphan< ::capnp::List< ::cereal::FrogPilotCarParams::SafetyConfi
::capnp::bounded<0>() * ::capnp::POINTERS)); ::capnp::bounded<0>() * ::capnp::POINTERS));
} }
inline bool FrogPilotCarParams::Reader::getCanUseSASCM() const {
return _reader.getDataField<bool>(
::capnp::bounded<4>() * ::capnp::ELEMENTS);
}
inline bool FrogPilotCarParams::Builder::getCanUseSASCM() {
return _builder.getDataField<bool>(
::capnp::bounded<4>() * ::capnp::ELEMENTS);
}
inline void FrogPilotCarParams::Builder::setCanUseSASCM(bool value) {
_builder.setDataField<bool>(
::capnp::bounded<4>() * ::capnp::ELEMENTS, value);
}
inline ::uint16_t FrogPilotCarParams::SafetyConfig::Reader::getSafetyParam() const { inline ::uint16_t FrogPilotCarParams::SafetyConfig::Reader::getSafetyParam() const {
return _reader.getDataField< ::uint16_t>( return _reader.getDataField< ::uint16_t>(
::capnp::bounded<0>() * ::capnp::ELEMENTS); ::capnp::bounded<0>() * ::capnp::ELEMENTS);
Binary file not shown.
+2
View File
@@ -535,6 +535,8 @@ std::unordered_map<std::string, uint32_t> keys = {
{"SteerDelayStock", PERSISTENT}, {"SteerDelayStock", PERSISTENT},
{"SteerFriction", PERSISTENT}, {"SteerFriction", PERSISTENT},
{"SteerFrictionStock", PERSISTENT}, {"SteerFrictionStock", PERSISTENT},
{"SteerOffset", PERSISTENT},
{"SteerOffsetStock", PERSISTENT},
{"SteerLatAccel", PERSISTENT}, {"SteerLatAccel", PERSISTENT},
{"SteerLatAccelStock", PERSISTENT}, {"SteerLatAccelStock", PERSISTENT},
{"SteerKP", PERSISTENT}, {"SteerKP", PERSISTENT},
Binary file not shown.
+24 -4
View File
@@ -107,7 +107,7 @@ class ModelManager:
self.downloading_model = False self.downloading_model = False
return return
if model_version in ("v8", "v9", "v10", "v11"): if model_version in ("v8", "v9", "v10", "v11", "v12"):
# Download all PKL and metadata files for multi-file tinygrad models (v8 and v9) # Download all PKL and metadata files for multi-file tinygrad models (v8 and v9)
filenames = [ filenames = [
f"{model_to_download}_driving_policy_tinygrad.pkl", f"{model_to_download}_driving_policy_tinygrad.pkl",
@@ -115,6 +115,11 @@ class ModelManager:
f"{model_to_download}_driving_policy_metadata.pkl", f"{model_to_download}_driving_policy_metadata.pkl",
f"{model_to_download}_driving_vision_metadata.pkl", f"{model_to_download}_driving_vision_metadata.pkl",
] ]
if model_version == "v12":
filenames += [
f"{model_to_download}_driving_off_policy_tinygrad.pkl",
f"{model_to_download}_driving_off_policy_metadata.pkl",
]
for filename in filenames: for filename in filenames:
model_path = MODELS_PATH / filename model_path = MODELS_PATH / filename
model_url = f"{repo_url}/Models/{filename}" model_url = f"{repo_url}/Models/{filename}"
@@ -208,13 +213,18 @@ class ModelManager:
except Exception: except Exception:
model_version = None model_version = None
if model_version in ("v8", "v9", "v10", "v11"): if model_version in ("v8", "v9", "v10", "v11", "v12"):
v8_v9_files = [ v8_v9_files = [
f"{model}_driving_policy_tinygrad.pkl", f"{model}_driving_policy_tinygrad.pkl",
f"{model}_driving_vision_tinygrad.pkl", f"{model}_driving_vision_tinygrad.pkl",
f"{model}_driving_policy_metadata.pkl", f"{model}_driving_policy_metadata.pkl",
f"{model}_driving_vision_metadata.pkl", f"{model}_driving_vision_metadata.pkl",
] ]
if model_version == "v12":
v8_v9_files += [
f"{model}_driving_off_policy_tinygrad.pkl",
f"{model}_driving_off_policy_metadata.pkl",
]
if all((MODELS_PATH / f).is_file() for f in v8_v9_files): if all((MODELS_PATH / f).is_file() for f in v8_v9_files):
downloaded_models.add(model) downloaded_models.add(model)
elif model_version == "v7": elif model_version == "v7":
@@ -259,13 +269,18 @@ class ModelManager:
except Exception: except Exception:
model_version = None model_version = None
if model_version in ("v8", "v9", "v10", "v11"): if model_version in ("v8", "v9", "v10", "v11", "v12"):
v8_v9_files = [ v8_v9_files = [
f"{model}_driving_policy_tinygrad.pkl", f"{model}_driving_policy_tinygrad.pkl",
f"{model}_driving_vision_tinygrad.pkl", f"{model}_driving_vision_tinygrad.pkl",
f"{model}_driving_policy_metadata.pkl", f"{model}_driving_policy_metadata.pkl",
f"{model}_driving_vision_metadata.pkl", f"{model}_driving_vision_metadata.pkl",
] ]
if model_version == "v12":
v8_v9_files += [
f"{model}_driving_off_policy_tinygrad.pkl",
f"{model}_driving_off_policy_metadata.pkl",
]
for filename in v8_v9_files: for filename in v8_v9_files:
path = MODELS_PATH / filename path = MODELS_PATH / filename
expected_size = model_sizes.get(filename.rsplit(".", 1)[0]) expected_size = model_sizes.get(filename.rsplit(".", 1)[0])
@@ -378,13 +393,18 @@ class ModelManager:
handle_error(None, "Download cancelled...", "Download cancelled...", MODEL_DOWNLOAD_ALL_PARAM, DOWNLOAD_PROGRESS_PARAM, params_memory) handle_error(None, "Download cancelled...", "Download cancelled...", MODEL_DOWNLOAD_ALL_PARAM, DOWNLOAD_PROGRESS_PARAM, params_memory)
return return
if model_version in ("v8", "v9", "v10", "v11"): if model_version in ("v8", "v9", "v10", "v11", "v12"):
required_files = [ required_files = [
f"{model}_driving_policy_tinygrad.pkl", f"{model}_driving_policy_tinygrad.pkl",
f"{model}_driving_vision_tinygrad.pkl", f"{model}_driving_vision_tinygrad.pkl",
f"{model}_driving_policy_metadata.pkl", f"{model}_driving_policy_metadata.pkl",
f"{model}_driving_vision_metadata.pkl", f"{model}_driving_vision_metadata.pkl",
] ]
if model_version == "v12":
required_files += [
f"{model}_driving_off_policy_tinygrad.pkl",
f"{model}_driving_off_policy_metadata.pkl",
]
missing = [f for f in required_files if not (MODELS_PATH / f).is_file()] missing = [f for f in required_files if not (MODELS_PATH / f).is_file()]
if missing: if missing:
print(f"Tinygrad model {model} is missing files. Preparing to download...") print(f"Tinygrad model {model} is missing files. Preparing to download...")
+17 -10
View File
@@ -96,6 +96,8 @@ EXCLUDED_KEYS = {
} }
TINYGRAD_FILES = [ TINYGRAD_FILES = [
("driving_off_policy_metadata.pkl", "off-policy metadata"),
("driving_off_policy_tinygrad.pkl", "off-policy model"),
("driving_policy_metadata.pkl", "policy metadata"), ("driving_policy_metadata.pkl", "policy metadata"),
("driving_policy_tinygrad.pkl", "policy model"), ("driving_policy_tinygrad.pkl", "policy model"),
("driving_vision_metadata.pkl", "vision metadata"), ("driving_vision_metadata.pkl", "vision metadata"),
@@ -128,7 +130,7 @@ frogpilot_default_params: list[tuple[str, str | bytes, int, str]] = [
("AdjacentPath", "0", 3, "0"), ("AdjacentPath", "0", 3, "0"),
("AdjacentPathMetrics", "0", 3, "0"), ("AdjacentPathMetrics", "0", 3, "0"),
("AdvancedCustomUI", "0", 2, "0"), ("AdvancedCustomUI", "0", 2, "0"),
("AdvancedLateralTune", "0", 2, "0"), ("AdvancedLateralTune", "1", 2, "0"),
("AdvancedLongitudinalTune", "0", 3, "0"), ("AdvancedLongitudinalTune", "0", 3, "0"),
("EVTuning", "", 3, "0"), ("EVTuning", "", 3, "0"),
("AggressiveFollow", "1.25", 2, "1.25"), ("AggressiveFollow", "1.25", 2, "1.25"),
@@ -157,7 +159,7 @@ frogpilot_default_params: list[tuple[str, str | bytes, int, str]] = [
("BlacklistedModels", "", 2, ""), ("BlacklistedModels", "", 2, ""),
("BlindSpotMetrics", "1", 3, "0"), ("BlindSpotMetrics", "1", 3, "0"),
("BlindSpotPath", "1", 1, "0"), ("BlindSpotPath", "1", 1, "0"),
("BorderMetrics", "0", 3, "0"), ("BorderMetrics", "1", 3, "0"),
("CalibratedLateralAcceleration", str(DEFAULT_LATERAL_ACCELERATION), 2, str(DEFAULT_LATERAL_ACCELERATION)), ("CalibratedLateralAcceleration", str(DEFAULT_LATERAL_ACCELERATION), 2, str(DEFAULT_LATERAL_ACCELERATION)),
("CalibrationProgress", "0", 3, "0"), ("CalibrationProgress", "0", 3, "0"),
("CameraView", "3", 2, "0"), ("CameraView", "3", 2, "0"),
@@ -196,7 +198,7 @@ frogpilot_default_params: list[tuple[str, str | bytes, int, str]] = [
("CustomUI", "1", 1, "0"), ("CustomUI", "1", 1, "0"),
("DecelerationProfile", "1", 2, "0"), ("DecelerationProfile", "1", 2, "0"),
("DeveloperMetrics", "1", 3, "0"), ("DeveloperMetrics", "1", 3, "0"),
("DeveloperSidebar", "1", 3, "0"), ("DeveloperSidebar", "0", 3, "0"),
("DeveloperSidebarMetric1", "1", 3, "0"), ("DeveloperSidebarMetric1", "1", 3, "0"),
("DeveloperSidebarMetric2", "2", 3, "0"), ("DeveloperSidebarMetric2", "2", 3, "0"),
("DeveloperSidebarMetric3", "3", 3, "0"), ("DeveloperSidebarMetric3", "3", 3, "0"),
@@ -205,7 +207,7 @@ frogpilot_default_params: list[tuple[str, str | bytes, int, str]] = [
("DeveloperSidebarMetric6", "6", 3, "0"), ("DeveloperSidebarMetric6", "6", 3, "0"),
("DeveloperSidebarMetric7", "7", 3, "0"), ("DeveloperSidebarMetric7", "7", 3, "0"),
("DeveloperWidgets", "1", 3, "0"), ("DeveloperWidgets", "1", 3, "0"),
("DeveloperUI", "0", 3, "0"), ("DeveloperUI", "1", 3, "0"),
("DeviceManagement", "1", 1, "0"), ("DeviceManagement", "1", 1, "0"),
("DeviceShutdown", "9", 1, "33"), ("DeviceShutdown", "9", 1, "33"),
("DisableOnroadUploads", "0", 2, "0"), ("DisableOnroadUploads", "0", 2, "0"),
@@ -223,7 +225,7 @@ frogpilot_default_params: list[tuple[str, str | bytes, int, str]] = [
("Fahrenheit", "0", 3, "0"), ("Fahrenheit", "0", 3, "0"),
("FavoriteDestinations", "", 0, ""), ("FavoriteDestinations", "", 0, ""),
("ForceAutoTune", "0", 2, "0"), ("ForceAutoTune", "0", 2, "0"),
("ForceAutoTuneOff", "0", 2, "0"), ("ForceAutoTuneOff", "1", 2, "0"),
("ForceFingerprint", "0", 2, "0"), ("ForceFingerprint", "0", 2, "0"),
("ForceMPHDashboard", "0", 2, "0"), ("ForceMPHDashboard", "0", 2, "0"),
("ForceStops", "0", 2, "0"), ("ForceStops", "0", 2, "0"),
@@ -341,7 +343,7 @@ frogpilot_default_params: list[tuple[str, str | bytes, int, str]] = [
("RelaxedJerkSpeed", "50", 3, "50"), ("RelaxedJerkSpeed", "50", 3, "50"),
("RelaxedJerkSpeedDecrease", "50", 3, "50"), ("RelaxedJerkSpeedDecrease", "50", 3, "50"),
("RelaxedPersonalityProfile", "1", 2, "0"), ("RelaxedPersonalityProfile", "1", 2, "0"),
("ReverseCruise", "0", 1, "0"), ("ReverseCruise", "1", 1, "0"),
("RoadEdgesWidth", "2", 2, "2"), ("RoadEdgesWidth", "2", 2, "2"),
("RoadNameUI", "1", 2, "0"), ("RoadNameUI", "1", 2, "0"),
("RotatingWheel", "1", 1, "0"), ("RotatingWheel", "1", 1, "0"),
@@ -365,7 +367,7 @@ frogpilot_default_params: list[tuple[str, str | bytes, int, str]] = [
("ShownToggleDescriptions", "", 0, ""), ("ShownToggleDescriptions", "", 0, ""),
("ShowSLCOffset", "1", 0, "0"), ("ShowSLCOffset", "1", 0, "0"),
("ShowSpeedLimits", "1", 1, "0"), ("ShowSpeedLimits", "1", 1, "0"),
("ShowSteering", "0", 3, "0"), ("ShowSteering", "1", 3, "0"),
("ShowStoppingPoint", "0", 2, "0"), ("ShowStoppingPoint", "0", 2, "0"),
("ShowStoppingPointMetrics", "0", 2, "0"), ("ShowStoppingPointMetrics", "0", 2, "0"),
("ShowStorageLeft", "0", 3, "0"), ("ShowStorageLeft", "0", 3, "0"),
@@ -407,6 +409,8 @@ frogpilot_default_params: list[tuple[str, str | bytes, int, str]] = [
("SteerDelayStock", "", 3, ""), ("SteerDelayStock", "", 3, ""),
("SteerFriction", "", 3, ""), ("SteerFriction", "", 3, ""),
("SteerFrictionStock", "", 3, ""), ("SteerFrictionStock", "", 3, ""),
("SteerOffset", "", 3, ""),
("SteerOffsetStock", "", 3, ""),
("SteerKP", "", 3, ""), ("SteerKP", "", 3, ""),
("SteerKPStock", "", 3, ""), ("SteerKPStock", "", 3, ""),
("SteerLatAccel", "", 3, ""), ("SteerLatAccel", "", 3, ""),
@@ -429,8 +433,8 @@ frogpilot_default_params: list[tuple[str, str | bytes, int, str]] = [
("TrafficJerkSpeed", "50", 3, "50"), ("TrafficJerkSpeed", "50", 3, "50"),
("TrafficJerkSpeedDecrease", "50", 3, "50"), ("TrafficJerkSpeedDecrease", "50", 3, "50"),
("TrafficPersonalityProfile", "1", 2, "0"), ("TrafficPersonalityProfile", "1", 2, "0"),
("TuningLevel", "0", 0, "0"), ("TuningLevel", "3", 0, "0"),
("TuningLevelConfirmed", "0", 0, "0"), ("TuningLevelConfirmed", "1", 0, "0"),
("TurnDesires", "0", 2, "0"), ("TurnDesires", "0", 2, "0"),
("UnlimitedLength", "1", 2, "0"), ("UnlimitedLength", "1", 2, "0"),
("UnlockDoors", "1", 0, "0"), ("UnlockDoors", "1", 0, "0"),
@@ -569,6 +573,7 @@ class FrogPilotVariables:
toggle.has_pedal = CP.enableGasInterceptor toggle.has_pedal = CP.enableGasInterceptor
has_radar = not CP.radarUnavailable has_radar = not CP.radarUnavailable
toggle.has_sdsu = toggle.car_make == "toyota" and bool(CP.flags & ToyotaFlags.SMART_DSU.value) toggle.has_sdsu = toggle.car_make == "toyota" and bool(CP.flags & ToyotaFlags.SMART_DSU.value)
toggle.has_sascm = toggle.car_make == "gm" and bool(CP.flags & GMFlags.SASCM.value)
has_sng = CP.autoResumeSng has_sng = CP.autoResumeSng
toggle.has_zss = toggle.car_make == "toyota" and bool(FPCP.fpFlags & ToyotaFrogPilotFlags.ZSS.value) toggle.has_zss = toggle.car_make == "toyota" and bool(FPCP.fpFlags & ToyotaFrogPilotFlags.ZSS.value)
is_angle_car = CP.steerControlType == car.CarParams.SteerControlType.angle is_angle_car = CP.steerControlType == car.CarParams.SteerControlType.angle
@@ -612,6 +617,7 @@ class FrogPilotVariables:
toggle.steerActuatorDelay = np.clip(params.get_float("SteerDelay"), 0.01, 1.0) if advanced_lateral_tuning and tuning_level >= level["SteerDelay"] else steerActuatorDelay toggle.steerActuatorDelay = np.clip(params.get_float("SteerDelay"), 0.01, 1.0) if advanced_lateral_tuning and tuning_level >= level["SteerDelay"] else steerActuatorDelay
toggle.use_custom_steerActuatorDelay = bool(round(toggle.steerActuatorDelay, 2) != round(steerActuatorDelay, 2)) toggle.use_custom_steerActuatorDelay = bool(round(toggle.steerActuatorDelay, 2) != round(steerActuatorDelay, 2))
toggle.friction = np.clip(params.get_float("SteerFriction"), 0, 0.5) if advanced_lateral_tuning and tuning_level >= level["SteerFriction"] else friction toggle.friction = np.clip(params.get_float("SteerFriction"), 0, 0.5) if advanced_lateral_tuning and tuning_level >= level["SteerFriction"] else friction
toggle.steer_offset = np.clip(params.get_float("SteerOffset"), -0.2, 0.2) if advanced_lateral_tuning and tuning_level >= level["SteerOffset"] and toggle.car_make == "gm" else 0.0
toggle.use_custom_friction = bool(round(toggle.friction, 2) != round(friction, 2)) and is_torque_car and not toggle.force_auto_tune or toggle.force_auto_tune_off toggle.use_custom_friction = bool(round(toggle.friction, 2) != round(friction, 2)) and is_torque_car and not toggle.force_auto_tune or toggle.force_auto_tune_off
toggle.steerKp = [[0], [np.clip(params.get_float("SteerKP"), steerKp * 0.5, steerKp * 1.5) if advanced_lateral_tuning and is_torque_car and tuning_level >= level["SteerKP"] else steerKp]] toggle.steerKp = [[0], [np.clip(params.get_float("SteerKP"), steerKp * 0.5, steerKp * 1.5) if advanced_lateral_tuning and is_torque_car and tuning_level >= level["SteerKP"] else steerKp]]
toggle.latAccelFactor = np.clip(params.get_float("SteerLatAccel"), latAccelFactor * 0.75, latAccelFactor * 1.25) if advanced_lateral_tuning and tuning_level >= level["SteerLatAccel"] else latAccelFactor toggle.latAccelFactor = np.clip(params.get_float("SteerLatAccel"), latAccelFactor * 0.75, latAccelFactor * 1.25) if advanced_lateral_tuning and tuning_level >= level["SteerLatAccel"] else latAccelFactor
@@ -887,7 +893,7 @@ class FrogPilotVariables:
toggle.model_version = DEFAULT_MODEL_VERSION toggle.model_version = DEFAULT_MODEL_VERSION
toggle.classic_longitudinal = toggle.model_version in {"v1", "v2", "v3", "v4"} toggle.classic_longitudinal = toggle.model_version in {"v1", "v2", "v3", "v4"}
toggle.classic_model = toggle.model_version in {"v1", "v2", "v3", "v4"} toggle.classic_model = toggle.model_version in {"v1", "v2", "v3", "v4"}
toggle.tinygrad_model = toggle.model_version in {"v8", "v9", "v10", "v11"} toggle.tinygrad_model = toggle.model_version in {"v8", "v9", "v10", "v11", "v12"}
toggle.tomb_raider = toggle.model == "space-lab" toggle.tomb_raider = toggle.model == "space-lab"
toggle.model_ui = params.get_bool("ModelUI") if tuning_level >= level["ModelUI"] else default.get_bool("ModelUI") toggle.model_ui = params.get_bool("ModelUI") if tuning_level >= level["ModelUI"] else default.get_bool("ModelUI")
@@ -1002,6 +1008,7 @@ class FrogPilotVariables:
volt_models = { volt_models = {
"CHEVROLET_VOLT", "CHEVROLET_VOLT",
"CHEVROLET_VOLT_2019",
"CHEVROLET_VOLT_ASCM", "CHEVROLET_VOLT_ASCM",
"CHEVROLET_VOLT_CAMERA", "CHEVROLET_VOLT_CAMERA",
} }
+1 -1
View File
@@ -51,7 +51,7 @@ class FrogPilotTracking:
self.sound = FrogPilotAudibleAlert.none self.sound = FrogPilotAudibleAlert.none
self.state = State.disabled self.state = State.disabled
self.model_name = clean_model_name(dict(zip(frogpilot_toggles.available_models.split(","), frogpilot_toggles.available_model_names.split(",")))[frogpilot_toggles.model]) self.model_name = clean_model_name(frogpilot_toggles.model_name)
def update(self, now, time_validated, sm, frogpilot_toggles): def update(self, now, time_validated, sm, frogpilot_toggles):
v_cruise = min(sm["controlsState"].vCruiseCluster, V_CRUISE_MAX) * CV.KPH_TO_MS v_cruise = min(sm["controlsState"].vCruiseCluster, V_CRUISE_MAX) * CV.KPH_TO_MS
BIN
View File
Binary file not shown.
Binary file not shown.
+53 -33
View File
@@ -20,6 +20,30 @@ from openpilot.frogpilot.common.frogpilot_variables import get_frogpilot_toggles
BASE_URL = "https://nominatim.openstreetmap.org" BASE_URL = "https://nominatim.openstreetmap.org"
MINIMUM_POPULATION = 100_000 MINIMUM_POPULATION = 100_000
SEARCH_RADIUS_DEGREES = 1.45
def get_population_value(population_str):
if population_str is None:
return None
try:
return int(str(population_str).replace(",", "").split(";")[0].strip())
except Exception:
return None
def search_nearby_major_cities(lat, lon, session, state_name, country_name):
viewbox = f"{lon - SEARCH_RADIUS_DEGREES},{lat + SEARCH_RADIUS_DEGREES},{lon + SEARCH_RADIUS_DEGREES},{lat - SEARCH_RADIUS_DEGREES}"
cities = (session.get(f"{BASE_URL}/search", params={
"addressdetails": 1, "bounded": 1, "extratags": 1, "format": "jsonv2", "limit": 20, "q": "city", "viewbox": viewbox
}, timeout=10).json() or [])
qualifying = [c for c in cities if (get_population_value((c.get("extratags") or {}).get("population")) or 0) >= MINIMUM_POPULATION]
if not qualifying:
return None
nearest = min(qualifying, key=lambda c: (float(c["lat"]) - lat) ** 2 + (float(c["lon"]) - lon) ** 2)
addr = nearest.get("address") or {}
return float(nearest["lat"]), float(nearest["lon"]), addr.get("city") or addr.get("town") or nearest.get("display_name", "").split(",")[0], state_name, country_name
def get_city_center(latitude, longitude): def get_city_center(latitude, longitude):
try: try:
@@ -44,14 +68,7 @@ def get_city_center(latitude, longitude):
if data: if data:
tags = data[0] tags = data[0]
population = (tags.get("extratags") or {}).get("population") population_value = get_population_value((tags.get("extratags") or {}).get("population"))
population_value = None
if population is not None:
try:
population_value = int(str(population).replace(",", "").split(";")[0].strip())
except Exception:
population_value = None
if population_value is not None and population_value >= MINIMUM_POPULATION: if population_value is not None and population_value >= MINIMUM_POPULATION:
latitude_value = float(tags["lat"]) latitude_value = float(tags["lat"])
@@ -62,6 +79,10 @@ def get_city_center(latitude, longitude):
return latitude_value, longitude_value, city_label, state_name, country_name return latitude_value, longitude_value, city_label, state_name, country_name
nearby_result = search_nearby_major_cities(latitude, longitude, session, state_name, country_name)
if nearby_result:
return nearby_result
query = f"{state_name} state capital" if country_code == "us" else f"capital of {state_name}, {country_name}" query = f"{state_name} state capital" if country_code == "us" else f"capital of {state_name}, {country_name}"
response = session.get(f"{BASE_URL}/search", params={"addressdetails": 1, "extratags": 1, "format": "jsonv2", "limit": 5, "q": query}, timeout=10) response = session.get(f"{BASE_URL}/search", params={"addressdetails": 1, "extratags": 1, "format": "jsonv2", "limit": 5, "q": query}, timeout=10)
response.raise_for_status() response.raise_for_status()
@@ -99,14 +120,14 @@ def get_city_center(latitude, longitude):
def update_branch_commits(now): def update_branch_commits(now):
points = [] points = []
for branch in ["FrogPilot", "FrogPilot-Staging", "FrogPilot-Testing"]: branch = get_build_metadata().channel # Current running branch
try: try:
response = requests.get(f"https://api.github.com/repos/FrogAi/FrogPilot/commits/{branch}") response = requests.get(f"https://api.github.com/repos/firestar5683/StarPilot/commits/{branch}")
response.raise_for_status() response.raise_for_status()
sha = response.json()["sha"] sha = response.json()["sha"]
points.append(Point("branch_commits").field("commit", sha).tag("branch", branch).time(now)) points.append(Point("branch_commits").field("commit", sha).tag("branch", branch).time(now))
except Exception as e: except Exception as e:
print(f"Failed to fetch commit for {branch}: {e}") print(f"Failed to fetch commit for {branch}: {e}")
return points return points
@@ -129,11 +150,9 @@ def send_stats():
if frogpilot_toggles.car_make == "mock": if frogpilot_toggles.car_make == "mock":
return return
bucket = os.environ.get("STATS_BUCKET", "") bucket = "StarPilot"
org_ID = os.environ.get("STATS_ORG_ID", "") org_ID = "StarPilot"
token = os.environ.get("STATS_TOKEN", "") url = "https://stats.firestar.link"
url = os.environ.get("STATS_URL", "")
frogpilot_stats = json.loads(params.get("FrogPilotStats") or "{}") frogpilot_stats = json.loads(params.get("FrogPilotStats") or "{}")
location = json.loads(params.get("LastGPSPosition") or "{}") location = json.loads(params.get("LastGPSPosition") or "{}")
@@ -161,14 +180,19 @@ def send_stats():
user_point = ( user_point = (
Point("user_stats") Point("user_stats")
.tag("car_make", "GM" if frogpilot_toggles.car_make == "gm" else frogpilot_toggles.car_make.title())
.tag("car_model", frogpilot_toggles.car_model)
.tag("city", city)
.tag("country", country)
.tag("device", HARDWARE.get_device_type())
.tag("driving_model", clean_model_name(frogpilot_toggles.model_name))
.tag("state", state)
.tag("theme", selected_theme.title())
.tag("branch", build_metadata.channel)
.tag("dongle_id", params.get("FrogPilotDongleId", encoding="utf-8"))
.field("blocked_user", frogpilot_toggles.block_user) .field("blocked_user", frogpilot_toggles.block_user)
.field("car_make", "GM" if frogpilot_toggles.car_make == "gm" else frogpilot_toggles.car_make.title())
.field("car_model", frogpilot_toggles.car_model)
.field("city", city)
.field("country", country)
.field("current_months_kilometers", int(frogpilot_stats.get("CurrentMonthsKilometers", 0))) .field("current_months_kilometers", int(frogpilot_stats.get("CurrentMonthsKilometers", 0)))
.field("device", HARDWARE.get_device_type())
.field("driving_model", clean_model_name(frogpilot_toggles.model_name))
.field("event", 1) .field("event", 1)
.field("frogpilot_drives", int(frogpilot_stats.get("FrogPilotDrives", 0))) .field("frogpilot_drives", int(frogpilot_stats.get("FrogPilotDrives", 0)))
.field("frogpilot_hours", float(frogpilot_stats.get("FrogPilotSeconds", 0)) / (60 * 60)) .field("frogpilot_hours", float(frogpilot_stats.get("FrogPilotSeconds", 0)) / (60 * 60))
@@ -178,13 +202,12 @@ def send_stats():
.field("has_openpilot_longitudinal", frogpilot_toggles.openpilot_longitudinal) .field("has_openpilot_longitudinal", frogpilot_toggles.openpilot_longitudinal)
.field("has_pedal", frogpilot_toggles.has_pedal) .field("has_pedal", frogpilot_toggles.has_pedal)
.field("has_sdsu", frogpilot_toggles.has_sdsu) .field("has_sdsu", frogpilot_toggles.has_sdsu)
.field("has_sascm", frogpilot_toggles.has_sascm)
.field("has_zss", frogpilot_toggles.has_zss) .field("has_zss", frogpilot_toggles.has_zss)
.field("latitude", latitude) .field("latitude", latitude)
.field("longitude", longitude) .field("longitude", longitude)
.field("rainbow_path", frogpilot_toggles.rainbow_path) .field("rainbow_path", frogpilot_toggles.rainbow_path)
.field("random_events", frogpilot_toggles.random_events) .field("random_events", frogpilot_toggles.random_events)
.field("state", state)
.field("theme", selected_theme.title())
.field("total_aol_seconds", float(frogpilot_stats.get("AOLTime", 0))) .field("total_aol_seconds", float(frogpilot_stats.get("AOLTime", 0)))
.field("total_lateral_seconds", float(frogpilot_stats.get("LateralTime", 0))) .field("total_lateral_seconds", float(frogpilot_stats.get("LateralTime", 0)))
.field("total_longitudinal_seconds", float(frogpilot_stats.get("LongitudinalTime", 0))) .field("total_longitudinal_seconds", float(frogpilot_stats.get("LongitudinalTime", 0)))
@@ -193,15 +216,12 @@ def send_stats():
.field("up_to_date", is_up_to_date(build_metadata)) .field("up_to_date", is_up_to_date(build_metadata))
.field("using_stock_acc", not (frogpilot_toggles.has_cc_long or frogpilot_toggles.openpilot_longitudinal)) .field("using_stock_acc", not (frogpilot_toggles.has_cc_long or frogpilot_toggles.openpilot_longitudinal))
.tag("branch", build_metadata.channel)
.tag("dongle_id", params.get("FrogPilotDongleId", encoding="utf-8"))
.time(now) .time(now)
) )
all_points = [user_point] + update_branch_commits(now) all_points = [user_point] + update_branch_commits(now)
client = InfluxDBClient(org=org_ID, token=token, url=url) client = InfluxDBClient(org=org_ID, token=org_ID, url=url)
client.write_api(write_options=SYNCHRONOUS).write(bucket=bucket, org=org_ID, record=all_points) client.write_api(write_options=SYNCHRONOUS).write(bucket=bucket, org=org_ID, record=all_points)
print("Successfully sent FrogPilot stats!") print("Successfully sent FrogPilot stats!")
except Exception as exception: except Exception as exception:
+104 -28
View File
@@ -35,7 +35,7 @@ PROCESS_NAME = "frogpilot.tinygrad_modeld.tinygrad_modeld"
SEND_RAW_PRED = os.getenv('SEND_RAW_PRED') SEND_RAW_PRED = os.getenv('SEND_RAW_PRED')
LAT_SMOOTH_SECONDS = 0.1 LAT_SMOOTH_SECONDS = 0.0
LONG_SMOOTH_SECONDS = 0.3 LONG_SMOOTH_SECONDS = 0.3
MIN_LAT_CONTROL_SPEED = 0.3 MIN_LAT_CONTROL_SPEED = 0.3
@@ -84,6 +84,34 @@ class ModelState:
output: np.ndarray output: np.ndarray
prev_desire: np.ndarray # for tracking the rising edge of the pulse prev_desire: np.ndarray # for tracking the rising edge of the pulse
def _build_policy_inputs(self, input_shapes: dict[str, tuple[int, ...]]) -> tuple[dict[str, np.ndarray], str | None]:
numpy_inputs: dict[str, np.ndarray] = {}
# Always-supported inputs (if model expects them)
desire_key_init = next((k for k in input_shapes if k.startswith('desire')), None)
if desire_key_init:
numpy_inputs[desire_key_init] = np.zeros((1, ModelConstants.INPUT_HISTORY_BUFFER_LEN, ModelConstants.DESIRE_LEN), dtype=np.float32)
if 'traffic_convention' in input_shapes:
numpy_inputs['traffic_convention'] = np.zeros((1, ModelConstants.TRAFFIC_CONVENTION_LEN), dtype=np.float32)
if 'features_buffer' in input_shapes:
numpy_inputs['features_buffer'] = np.zeros((1, ModelConstants.INPUT_HISTORY_BUFFER_LEN, ModelConstants.FEATURE_LEN), dtype=np.float32)
# Optional inputs for non-v11 (and some v10/v9 variants)
# Lateral control params
if 'lateral_control_params' in input_shapes:
numpy_inputs['lateral_control_params'] = np.zeros((1, ModelConstants.LATERAL_CONTROL_PARAMS_LEN), dtype=np.float32)
# Previous desired curvature: handle both singular and plural key names across model versions
prev_desired_curv_key = None
if 'prev_desired_curv' in input_shapes:
prev_desired_curv_key = 'prev_desired_curv'
numpy_inputs['prev_desired_curv'] = np.zeros((1, ModelConstants.INPUT_HISTORY_BUFFER_LEN, ModelConstants.PREV_DESIRED_CURV_LEN), dtype=np.float32)
elif 'prev_desired_curvs' in input_shapes:
prev_desired_curv_key = 'prev_desired_curvs'
numpy_inputs['prev_desired_curvs'] = np.zeros((1, ModelConstants.INPUT_HISTORY_BUFFER_LEN, ModelConstants.PREV_DESIRED_CURV_LEN), dtype=np.float32)
return numpy_inputs, prev_desired_curv_key
def __init__(self, context: CLContext): def __init__(self, context: CLContext):
# Dynamically build paths based on current model ID # Dynamically build paths based on current model ID
params = Params() params = Params()
@@ -102,13 +130,17 @@ class ModelState:
models_dir = Path(__file__).parent / "models" models_dir = Path(__file__).parent / "models"
VISION_PKL_PATH = models_dir / "driving_vision_tinygrad.pkl" VISION_PKL_PATH = models_dir / "driving_vision_tinygrad.pkl"
POLICY_PKL_PATH = models_dir / "driving_policy_tinygrad.pkl" POLICY_PKL_PATH = models_dir / "driving_policy_tinygrad.pkl"
OFF_POLICY_PKL_PATH = models_dir / "driving_off_policy_tinygrad.pkl"
VISION_METADATA_PATH = models_dir / "driving_vision_metadata.pkl" VISION_METADATA_PATH = models_dir / "driving_vision_metadata.pkl"
POLICY_METADATA_PATH = models_dir / "driving_policy_metadata.pkl" POLICY_METADATA_PATH = models_dir / "driving_policy_metadata.pkl"
OFF_POLICY_METADATA_PATH = models_dir / "driving_off_policy_metadata.pkl"
else: else:
VISION_PKL_PATH = model_dir / f"{model_id}_driving_vision_tinygrad.pkl" VISION_PKL_PATH = model_dir / f"{model_id}_driving_vision_tinygrad.pkl"
POLICY_PKL_PATH = model_dir / f"{model_id}_driving_policy_tinygrad.pkl" POLICY_PKL_PATH = model_dir / f"{model_id}_driving_policy_tinygrad.pkl"
OFF_POLICY_PKL_PATH = model_dir / f"{model_id}_driving_off_policy_tinygrad.pkl"
VISION_METADATA_PATH = model_dir / f"{model_id}_driving_vision_metadata.pkl" VISION_METADATA_PATH = model_dir / f"{model_id}_driving_vision_metadata.pkl"
POLICY_METADATA_PATH = model_dir / f"{model_id}_driving_policy_metadata.pkl" POLICY_METADATA_PATH = model_dir / f"{model_id}_driving_policy_metadata.pkl"
OFF_POLICY_METADATA_PATH = model_dir / f"{model_id}_driving_off_policy_metadata.pkl"
# If ModelVersion is not set or not available, try to determine it from available model data # If ModelVersion is not set or not available, try to determine it from available model data
if not model_version: if not model_version:
@@ -160,7 +192,7 @@ class ModelState:
self.policy_generation = model_version or "v8" self.policy_generation = model_version or "v8"
self.is_v11 = (self.policy_generation == "v11") self.is_v11 = (self.policy_generation == "v11")
self.is_v9 = (self.policy_generation == "v9") self.is_v9 = (self.policy_generation == "v9")
self.mlsim = (self.policy_generation in ("v8", "v10", "v11")) self.mlsim = (self.policy_generation in ("v8", "v10", "v11", "v12"))
self.frames = {name: DrivingModelFrame(context, ModelConstants.TEMPORAL_SKIP) for name in self.vision_input_names} self.frames = {name: DrivingModelFrame(context, ModelConstants.TEMPORAL_SKIP) for name in self.vision_input_names}
self.prev_desire = np.zeros(ModelConstants.DESIRE_LEN, dtype=np.float32) self.prev_desire = np.zeros(ModelConstants.DESIRE_LEN, dtype=np.float32)
@@ -171,33 +203,50 @@ class ModelState:
# policy inputs (built dynamically to support all generations) # policy inputs (built dynamically to support all generations)
self.numpy_inputs = {} self.numpy_inputs, self.prev_desired_curv_key = self._build_policy_inputs(self.policy_input_shapes)
# Always-supported inputs (if model expects them) # Off-policy model (optional)
desire_key_init = next((k for k in self.policy_input_shapes if k.startswith('desire')), None) self.off_policy_enabled = False
if desire_key_init: self.off_policy_input_shapes: dict[str, tuple[int, ...]] = {}
self.numpy_inputs[desire_key_init] = np.zeros((1, ModelConstants.INPUT_HISTORY_BUFFER_LEN, ModelConstants.DESIRE_LEN), dtype=np.float32) self.off_policy_output_slices: dict[str, slice] = {}
if 'traffic_convention' in self.policy_input_shapes: self.off_policy_numpy_inputs: dict[str, np.ndarray] = {}
self.numpy_inputs['traffic_convention'] = np.zeros((1, ModelConstants.TRAFFIC_CONVENTION_LEN), dtype=np.float32) self.off_policy_prev_desired_curv_key: str | None = None
if 'features_buffer' in self.policy_input_shapes: self.off_policy_desire_key: str | None = None
self.numpy_inputs['features_buffer'] = np.zeros((1, ModelConstants.INPUT_HISTORY_BUFFER_LEN, ModelConstants.FEATURE_LEN), dtype=np.float32) self.off_policy_inputs: dict[str, Tensor] | None = None
self.off_policy_output: np.ndarray | None = None
# Optional inputs for non-v11 (and some v10/v9 variants) off_policy_metadata = None
# Lateral control params if self.policy_generation == "v12" or OFF_POLICY_METADATA_PATH.is_file() or OFF_POLICY_PKL_PATH.is_file():
if 'lateral_control_params' in self.policy_input_shapes: try:
self.numpy_inputs['lateral_control_params'] = np.zeros((1, ModelConstants.LATERAL_CONTROL_PARAMS_LEN), dtype=np.float32) with open(OFF_POLICY_METADATA_PATH, 'rb') as f:
off_policy_metadata = pickle.load(f)
except FileNotFoundError:
cloudlog.error(f"Missing metadata {OFF_POLICY_METADATA_PATH}, downloading...")
from openpilot.frogpilot.assets.model_manager import ModelManager
ModelManager().download_model(model_id)
try:
with open(OFF_POLICY_METADATA_PATH, 'rb') as f:
off_policy_metadata = pickle.load(f)
except FileNotFoundError:
cloudlog.warning(f"Off-policy metadata still missing: {OFF_POLICY_METADATA_PATH}")
# Previous desired curvature: handle both singular and plural key names across model versions if off_policy_metadata is not None:
self.prev_desired_curv_key = None self.off_policy_input_shapes = off_policy_metadata['input_shapes']
if 'prev_desired_curv' in self.policy_input_shapes: self.off_policy_output_slices = off_policy_metadata['output_slices']
self.prev_desired_curv_key = 'prev_desired_curv' off_policy_output_size = off_policy_metadata['output_shapes']['outputs'][1]
self.numpy_inputs['prev_desired_curv'] = np.zeros((1, ModelConstants.INPUT_HISTORY_BUFFER_LEN, ModelConstants.PREV_DESIRED_CURV_LEN), dtype=np.float32) self.off_policy_numpy_inputs, self.off_policy_prev_desired_curv_key = self._build_policy_inputs(self.off_policy_input_shapes)
elif 'prev_desired_curvs' in self.policy_input_shapes: self.off_policy_desire_key = next((k for k in self.off_policy_numpy_inputs if k.startswith('desire')), None)
self.prev_desired_curv_key = 'prev_desired_curvs' self.off_policy_inputs = {k: Tensor(v, device='NPY').realize() for k, v in self.off_policy_numpy_inputs.items()}
self.numpy_inputs['prev_desired_curvs'] = np.zeros((1, ModelConstants.INPUT_HISTORY_BUFFER_LEN, ModelConstants.PREV_DESIRED_CURV_LEN), dtype=np.float32) self.off_policy_output = np.zeros(off_policy_output_size, dtype=np.float32)
try:
with open(OFF_POLICY_PKL_PATH, "rb") as f:
self.off_policy_run = pickle.load(f)
self.off_policy_enabled = True
except FileNotFoundError:
cloudlog.warning(f"Missing off-policy model {OFF_POLICY_PKL_PATH}, skipping off-policy")
# Optional temporal buffer for previous desired curvature (allocate only if the policy expects it) # Optional temporal buffer for previous desired curvature (allocate only if any model expects it)
if getattr(self, 'prev_desired_curv_key', None) is not None: if self.prev_desired_curv_key is not None or self.off_policy_prev_desired_curv_key is not None:
self.full_prev_desired_curv = np.zeros((1, ModelConstants.FULL_HISTORY_BUFFER_LEN, ModelConstants.PREV_DESIRED_CURV_LEN), dtype=np.float32) self.full_prev_desired_curv = np.zeros((1, ModelConstants.FULL_HISTORY_BUFFER_LEN, ModelConstants.PREV_DESIRED_CURV_LEN), dtype=np.float32)
@@ -207,6 +256,7 @@ class ModelState:
self.policy_inputs = {k: Tensor(v, device='NPY').realize() for k,v in self.numpy_inputs.items()} self.policy_inputs = {k: Tensor(v, device='NPY').realize() for k,v in self.numpy_inputs.items()}
self.policy_output = np.zeros(policy_output_size, dtype=np.float32) self.policy_output = np.zeros(policy_output_size, dtype=np.float32)
self.parser = Parser() self.parser = Parser()
self.off_policy_parser = Parser(ignore_missing=True)
with open(VISION_PKL_PATH, "rb") as f: with open(VISION_PKL_PATH, "rb") as f:
self.vision_run = pickle.load(f) self.vision_run = pickle.load(f)
@@ -232,10 +282,18 @@ class ModelState:
self.full_desire[0,:-1] = self.full_desire[0,1:] self.full_desire[0,:-1] = self.full_desire[0,1:]
self.full_desire[0,-1] = new_desire self.full_desire[0,-1] = new_desire
self.numpy_inputs[self.desire_key][:] = self.full_desire.reshape((1,ModelConstants.INPUT_HISTORY_BUFFER_LEN,ModelConstants.TEMPORAL_SKIP,-1)).max(axis=2) self.numpy_inputs[self.desire_key][:] = self.full_desire.reshape((1,ModelConstants.INPUT_HISTORY_BUFFER_LEN,ModelConstants.TEMPORAL_SKIP,-1)).max(axis=2)
if self.off_policy_enabled and self.off_policy_desire_key is not None:
self.off_policy_numpy_inputs[self.off_policy_desire_key][:] = self.numpy_inputs[self.desire_key]
if 'traffic_convention' in self.numpy_inputs:
self.numpy_inputs['traffic_convention'][:] = inputs['traffic_convention']
if self.off_policy_enabled and 'traffic_convention' in self.off_policy_numpy_inputs:
self.off_policy_numpy_inputs['traffic_convention'][:] = inputs['traffic_convention']
self.numpy_inputs['traffic_convention'][:] = inputs['traffic_convention']
if 'lateral_control_params' in self.numpy_inputs: if 'lateral_control_params' in self.numpy_inputs:
self.numpy_inputs['lateral_control_params'][:] = inputs['lateral_control_params'] self.numpy_inputs['lateral_control_params'][:] = inputs['lateral_control_params']
if self.off_policy_enabled and 'lateral_control_params' in self.off_policy_numpy_inputs:
self.off_policy_numpy_inputs['lateral_control_params'][:] = inputs['lateral_control_params']
if prepare_only: if prepare_only:
return None return None
@@ -257,7 +315,10 @@ class ModelState:
self.full_features_buffer[0,:-1] = self.full_features_buffer[0,1:] self.full_features_buffer[0,:-1] = self.full_features_buffer[0,1:]
self.full_features_buffer[0,-1] = vision_outputs_dict['hidden_state'][0, :] self.full_features_buffer[0,-1] = vision_outputs_dict['hidden_state'][0, :]
self.numpy_inputs['features_buffer'][:] = self.full_features_buffer[0, self.temporal_idxs] if 'features_buffer' in self.numpy_inputs:
self.numpy_inputs['features_buffer'][:] = self.full_features_buffer[0, self.temporal_idxs]
if self.off_policy_enabled and 'features_buffer' in self.off_policy_numpy_inputs:
self.off_policy_numpy_inputs['features_buffer'][:] = self.full_features_buffer[0, self.temporal_idxs]
self.policy_output = self.policy_run(**self.policy_inputs).contiguous().realize().uop.base.buffer.numpy() self.policy_output = self.policy_run(**self.policy_inputs).contiguous().realize().uop.base.buffer.numpy()
policy_outputs_dict = self.parser.parse_policy_outputs(self.slice_outputs(self.policy_output, self.policy_output_slices)) policy_outputs_dict = self.parser.parse_policy_outputs(self.slice_outputs(self.policy_output, self.policy_output_slices))
@@ -274,9 +335,24 @@ class ModelState:
else: else:
self.numpy_inputs[self.prev_desired_curv_key][:] = self.full_prev_desired_curv[0, self.temporal_idxs] self.numpy_inputs[self.prev_desired_curv_key][:] = self.full_prev_desired_curv[0, self.temporal_idxs]
if self.off_policy_enabled and self.off_policy_prev_desired_curv_key is not None:
if self.is_v9:
self.off_policy_numpy_inputs[self.off_policy_prev_desired_curv_key][:] = 0 * self.full_prev_desired_curv[0, self.temporal_idxs]
else:
self.off_policy_numpy_inputs[self.off_policy_prev_desired_curv_key][:] = self.full_prev_desired_curv[0, self.temporal_idxs]
combined_outputs_dict = {**vision_outputs_dict, **policy_outputs_dict} combined_outputs_dict = {**vision_outputs_dict, **policy_outputs_dict}
if self.off_policy_enabled:
self.off_policy_output = self.off_policy_run(**self.off_policy_inputs).contiguous().realize().uop.base.buffer.numpy()
off_policy_outputs_dict = self.off_policy_parser.parse_policy_outputs(
self.slice_outputs(self.off_policy_output, self.off_policy_output_slices)
)
combined_outputs_dict.update(off_policy_outputs_dict)
if SEND_RAW_PRED: if SEND_RAW_PRED:
combined_outputs_dict['raw_pred'] = np.concatenate([self.vision_output.copy(), self.policy_output.copy()]) raw_pred = [self.vision_output.copy(), self.policy_output.copy()]
if self.off_policy_enabled and self.off_policy_output is not None:
raw_pred.append(self.off_policy_output.copy())
combined_outputs_dict['raw_pred'] = np.concatenate(raw_pred)
return combined_outputs_dict return combined_outputs_dict
@@ -269,6 +269,7 @@ void FrogPilotSettingsWindow::updateVariables() {
hasPedal = CP.getEnableGasInterceptor(); hasPedal = CP.getEnableGasInterceptor();
hasRadar = !CP.getRadarUnavailable(); hasRadar = !CP.getRadarUnavailable();
hasSDSU = frogpilot_toggles.value("has_sdsu").toBool(); hasSDSU = frogpilot_toggles.value("has_sdsu").toBool();
hasSASCM = frogpilot_toggles.value("has_sascm").toBool();
hasSNG = hasOpenpilotLongitudinal && CP.getAutoResumeSng(); hasSNG = hasOpenpilotLongitudinal && CP.getAutoResumeSng();
hasZSS = frogpilot_toggles.value("has_zss").toBool(); hasZSS = frogpilot_toggles.value("has_zss").toBool();
isAngleCar = CP.getSteerControlType() == cereal::CarParams::SteerControlType::ANGLE; isAngleCar = CP.getSteerControlType() == cereal::CarParams::SteerControlType::ANGLE;
@@ -285,6 +286,7 @@ void FrogPilotSettingsWindow::updateVariables() {
longitudinalActuatorDelay = CP.getLongitudinalActuatorDelay(); longitudinalActuatorDelay = CP.getLongitudinalActuatorDelay();
startAccel = CP.getStartAccel(); startAccel = CP.getStartAccel();
steerActuatorDelay = CP.getSteerActuatorDelay(); steerActuatorDelay = CP.getSteerActuatorDelay();
steerOffset = 0.0f;
steerKp = CP.getLateralTuning().which() == cereal::CarParams::LateralTuning::PID ? CP.getLateralTuning().getPid().getKpV()[0] : 0.6; steerKp = CP.getLateralTuning().which() == cereal::CarParams::LateralTuning::PID ? CP.getLateralTuning().getPid().getKpV()[0] : 0.6;
steerRatio = CP.getSteerRatio(); steerRatio = CP.getSteerRatio();
stopAccel = CP.getStopAccel(); stopAccel = CP.getStopAccel();
@@ -296,6 +298,7 @@ void FrogPilotSettingsWindow::updateVariables() {
float currentDelayStock = params.getFloat("SteerDelayStock"); float currentDelayStock = params.getFloat("SteerDelayStock");
float currentFrictionStock = params.getFloat("SteerFrictionStock"); float currentFrictionStock = params.getFloat("SteerFrictionStock");
float currentSteerOffsetStock = params.getFloat("SteerOffsetStock");
float currentKPStock = params.getFloat("SteerKPStock"); float currentKPStock = params.getFloat("SteerKPStock");
float currentLatAccelStock = params.getFloat("SteerLatAccelStock"); float currentLatAccelStock = params.getFloat("SteerLatAccelStock");
float currentLongDelayStock = params.getFloat("LongitudinalActuatorDelayStock"); float currentLongDelayStock = params.getFloat("LongitudinalActuatorDelayStock");
@@ -320,6 +323,13 @@ void FrogPilotSettingsWindow::updateVariables() {
params.putFloat("SteerFrictionStock", friction); params.putFloat("SteerFrictionStock", friction);
} }
if (currentSteerOffsetStock != steerOffset) {
if (params.getFloat("SteerOffset") == currentSteerOffsetStock) {
params.putFloat("SteerOffset", steerOffset);
}
params.putFloat("SteerOffsetStock", steerOffset);
}
if (currentKPStock != steerKp && steerKp != 0) { if (currentKPStock != steerKp && steerKp != 0) {
if (params.getFloat("SteerKP") == currentKPStock || currentKPStock == 0) { if (params.getFloat("SteerKP") == currentKPStock || currentKPStock == 0) {
params.putFloat("SteerKP", steerKp); params.putFloat("SteerKP", steerKp);
@@ -392,6 +402,7 @@ void FrogPilotSettingsWindow::updateVariables() {
canUsePedal = FPCP.getCanUsePedal(); canUsePedal = FPCP.getCanUsePedal();
canUseSDSU = FPCP.getCanUseSDSU(); canUseSDSU = FPCP.getCanUseSDSU();
canUseSASCM = FPCP.getCanUseSASCM();
openpilotLongitudinalControlDisabled = FPCP.getOpenpilotLongitudinalControlDisabled(); openpilotLongitudinalControlDisabled = FPCP.getOpenpilotLongitudinalControlDisabled();
} }
@@ -13,6 +13,7 @@ public:
bool canUsePedal = false; bool canUsePedal = false;
bool canUseSDSU = false; bool canUseSDSU = false;
bool canUseSASCM = false;
bool forceOpenDescriptions = false; bool forceOpenDescriptions = false;
bool hasAutoTune = true; bool hasAutoTune = true;
bool hasBSM = true; bool hasBSM = true;
@@ -24,6 +25,7 @@ public:
bool hasPedal = false; bool hasPedal = false;
bool hasRadar = true; bool hasRadar = true;
bool hasSDSU = false; bool hasSDSU = false;
bool hasSASCM = false;
bool hasSNG = false; bool hasSNG = false;
bool hasZSS = false; bool hasZSS = false;
bool isAngleCar = false; bool isAngleCar = false;
@@ -45,6 +47,7 @@ public:
float longitudinalActuatorDelay; float longitudinalActuatorDelay;
float startAccel; float startAccel;
float steerActuatorDelay; float steerActuatorDelay;
float steerOffset;
float steerKp; float steerKp;
float steerRatio; float steerRatio;
float stopAccel; float stopAccel;
@@ -41,6 +41,7 @@ FrogPilotLateralPanel::FrogPilotLateralPanel(FrogPilotSettingsWindow *parent) :
{"AdvancedLateralTune", tr("Advanced Lateral Tuning"), tr("<b>Advanced steering control changes to fine-tune how openpilot drives.</b>"), "../../frogpilot/assets/toggle_icons/icon_advanced_lateral_tune.png"}, {"AdvancedLateralTune", tr("Advanced Lateral Tuning"), tr("<b>Advanced steering control changes to fine-tune how openpilot drives.</b>"), "../../frogpilot/assets/toggle_icons/icon_advanced_lateral_tune.png"},
{"SteerDelay", parent->steerActuatorDelay != 0 ? QString(tr("Actuator Delay (Default: %1)")).arg(QString::number(parent->steerActuatorDelay, 'f', 2)) : tr("Actuator Delay"), tr("<b>The time between openpilot's steering command and the vehicle's response.</b> Increase if the vehicle reacts late; decrease if it feels jumpy. Auto-learned by default."), ""}, {"SteerDelay", parent->steerActuatorDelay != 0 ? QString(tr("Actuator Delay (Default: %1)")).arg(QString::number(parent->steerActuatorDelay, 'f', 2)) : tr("Actuator Delay"), tr("<b>The time between openpilot's steering command and the vehicle's response.</b> Increase if the vehicle reacts late; decrease if it feels jumpy. Auto-learned by default."), ""},
{"SteerFriction", parent->friction != 0 ? QString(tr("Friction (Default: %1)")).arg(QString::number(parent->friction, 'f', 2)) : tr("Friction"), tr("<b>Compensates for steering friction.</b> Increase if the wheel sticks near center; decrease if it jitters. Auto-learned by default."), ""}, {"SteerFriction", parent->friction != 0 ? QString(tr("Friction (Default: %1)")).arg(QString::number(parent->friction, 'f', 2)) : tr("Friction"), tr("<b>Compensates for steering friction.</b> Increase if the wheel sticks near center; decrease if it jitters. Auto-learned by default."), ""},
{"SteerOffset", parent->steerOffset != 0 ? QString(tr("Steer Offset (Default: %1)")).arg(QString::number(parent->steerOffset, 'f', 3)) : tr("Steer Offset"), tr("<b>Offsets steering torque to help compensate for alignment or tire issues.</b> More negative pulls the car right; more positive pulls it left. Most users should not need to touch this."), ""},
{"SteerKP", parent->steerKp != 0 ? QString(tr("Kp Factor (Default: %1)")).arg(QString::number(parent->steerKp, 'f', 2)) : tr("Kp Factor"), tr("<b>How strongly openpilot corrects lane position.</b> Higher is tighter but twitchier; lower is smoother but slower. Auto-learned by default."), ""}, {"SteerKP", parent->steerKp != 0 ? QString(tr("Kp Factor (Default: %1)")).arg(QString::number(parent->steerKp, 'f', 2)) : tr("Kp Factor"), tr("<b>How strongly openpilot corrects lane position.</b> Higher is tighter but twitchier; lower is smoother but slower. Auto-learned by default."), ""},
{"SteerLatAccel", parent->latAccelFactor != 0 ? QString(tr("Lateral Acceleration (Default: %1)")).arg(QString::number(parent->latAccelFactor, 'f', 2)) : tr("Lateral Acceleration"), tr("<b>Maps steering torque to turning response.</b> Increase for sharper turns; decrease for gentler steering. Auto-learned by default."), ""}, {"SteerLatAccel", parent->latAccelFactor != 0 ? QString(tr("Lateral Acceleration (Default: %1)")).arg(QString::number(parent->latAccelFactor, 'f', 2)) : tr("Lateral Acceleration"), tr("<b>Maps steering torque to turning response.</b> Increase for sharper turns; decrease for gentler steering. Auto-learned by default."), ""},
{"SteerRatio", parent->steerRatio != 0 ? QString(tr("Steer Ratio (Default: %1)")).arg(QString::number(parent->steerRatio, 'f', 2)) : tr("Steer Ratio"), tr("<b>The relationship between steering wheel rotation and road wheel angle.</b> Increase if steering feels too quick or twitchy; decrease if it feels too slow or weak. Auto-learned by default."), ""}, {"SteerRatio", parent->steerRatio != 0 ? QString(tr("Steer Ratio (Default: %1)")).arg(QString::number(parent->steerRatio, 'f', 2)) : tr("Steer Ratio"), tr("<b>The relationship between steering wheel rotation and road wheel angle.</b> Increase if steering feels too quick or twitchy; decrease if it feels too slow or weak. Auto-learned by default."), ""},
@@ -87,6 +88,9 @@ FrogPilotLateralPanel::FrogPilotLateralPanel(FrogPilotSettingsWindow *parent) :
} else if (param == "SteerFriction") { } else if (param == "SteerFriction") {
std::vector<QString> steerFrictionButton{"Reset"}; std::vector<QString> steerFrictionButton{"Reset"};
lateralToggle = new FrogPilotParamValueButtonControl(param, title, desc, icon, 0, 0.5, QString(), std::map<float, QString>(), 0.01, false, {}, steerFrictionButton, false, false); lateralToggle = new FrogPilotParamValueButtonControl(param, title, desc, icon, 0, 0.5, QString(), std::map<float, QString>(), 0.01, false, {}, steerFrictionButton, false, false);
} else if (param == "SteerOffset") {
std::vector<QString> steerOffsetButton{"Reset"};
lateralToggle = new FrogPilotParamValueButtonControl(param, title, desc, icon, -0.2, 0.2, QString(), std::map<float, QString>(), 0.005, false, {}, steerOffsetButton, false, false);
} else if (param == "SteerKP") { } else if (param == "SteerKP") {
std::vector<QString> steerKPButton{"Reset"}; std::vector<QString> steerKPButton{"Reset"};
lateralToggle = new FrogPilotParamValueButtonControl(param, title, desc, icon, parent->steerKp * 0.5, parent->steerKp * 1.5, QString(), std::map<float, QString>(), 0.01, false, {}, steerKPButton, false, false); lateralToggle = new FrogPilotParamValueButtonControl(param, title, desc, icon, parent->steerKp * 0.5, parent->steerKp * 1.5, QString(), std::map<float, QString>(), 0.01, false, {}, steerKPButton, false, false);
@@ -216,6 +220,14 @@ FrogPilotLateralPanel::FrogPilotLateralPanel(FrogPilotSettingsWindow *parent) :
} }
}); });
steerOffsetToggle = static_cast<FrogPilotParamValueButtonControl*>(toggles["SteerOffset"]);
QObject::connect(steerOffsetToggle, &FrogPilotParamValueButtonControl::buttonClicked, [parent, this]() {
if (FrogPilotConfirmationDialog::yesorno(tr("Reset <b>Steer Offset</b> to its default value?"), this)) {
params.putFloat("SteerOffset", parent->steerOffset);
steerOffsetToggle->refresh();
}
});
steerKPToggle = static_cast<FrogPilotParamValueButtonControl*>(toggles["SteerKP"]); steerKPToggle = static_cast<FrogPilotParamValueButtonControl*>(toggles["SteerKP"]);
QObject::connect(steerKPToggle, &FrogPilotParamValueButtonControl::buttonClicked, [parent, this]() { QObject::connect(steerKPToggle, &FrogPilotParamValueButtonControl::buttonClicked, [parent, this]() {
if (FrogPilotConfirmationDialog::yesorno(tr("Reset <b>Kp Factor</b> to its default value?"), this)) { if (FrogPilotConfirmationDialog::yesorno(tr("Reset <b>Kp Factor</b> to its default value?"), this)) {
@@ -255,6 +267,7 @@ void FrogPilotLateralPanel::showEvent(QShowEvent *event) {
steerDelayToggle->setTitle(QString(tr("Actuator Delay (Default: %1)")).arg(QString::number(parent->steerActuatorDelay, 'f', 2))); steerDelayToggle->setTitle(QString(tr("Actuator Delay (Default: %1)")).arg(QString::number(parent->steerActuatorDelay, 'f', 2)));
steerFrictionToggle->setTitle(QString(tr("Friction (Default: %1)")).arg(QString::number(parent->friction, 'f', 2))); steerFrictionToggle->setTitle(QString(tr("Friction (Default: %1)")).arg(QString::number(parent->friction, 'f', 2)));
steerOffsetToggle->setTitle(QString(tr("Steer Offset (Default: %1)")).arg(QString::number(parent->steerOffset, 'f', 3)));
steerKPToggle->setTitle(QString(tr("Kp Factor (Default: %1)")).arg(QString::number(parent->steerKp, 'f', 2))); steerKPToggle->setTitle(QString(tr("Kp Factor (Default: %1)")).arg(QString::number(parent->steerKp, 'f', 2)));
steerKPToggle->updateControl(parent->steerKp * 0.5, parent->steerKp * 1.5); steerKPToggle->updateControl(parent->steerKp * 0.5, parent->steerKp * 1.5);
steerLatAccelToggle->setTitle(QString(tr("Lateral Accel (Default: %1)")).arg(QString::number(parent->latAccelFactor, 'f', 2))); steerLatAccelToggle->setTitle(QString(tr("Lateral Accel (Default: %1)")).arg(QString::number(parent->latAccelFactor, 'f', 2)));
@@ -405,6 +418,12 @@ void FrogPilotLateralPanel::updateToggles() {
setVisible &= !usingNNFF; setVisible &= !usingNNFF;
} }
else if (key == "SteerOffset") {
setVisible &= parent->isGM;
setVisible &= parent->isTorqueCar || forcingTorqueController;
setVisible &= !usingNNFF;
}
else if (key == "SteerKP") { else if (key == "SteerKP") {
setVisible &= parent->steerKp != 0; setVisible &= parent->steerKp != 0;
setVisible &= !parent->isAngleCar; setVisible &= !parent->isAngleCar;
+3 -1
View File
@@ -31,6 +31,7 @@ private:
float friction; float friction;
float latAccelFactor; float latAccelFactor;
float steerActuatorDelay; float steerActuatorDelay;
float steerOffset;
float steerKp; float steerKp;
float steerRatio; float steerRatio;
@@ -38,7 +39,7 @@ private:
std::map<QString, AbstractControl*> toggles; std::map<QString, AbstractControl*> toggles;
QSet<QString> advancedLateralTuneKeys = {"ForceAutoTune", "ForceAutoTuneOff", "ForceTorqueController", "SteerDelay", "SteerFriction", "SteerLatAccel", "SteerKP", "SteerRatio"}; QSet<QString> advancedLateralTuneKeys = {"ForceAutoTune", "ForceAutoTuneOff", "ForceTorqueController", "SteerDelay", "SteerFriction", "SteerOffset", "SteerLatAccel", "SteerKP", "SteerRatio"};
QSet<QString> aolKeys = {"AlwaysOnLateralLKAS", "AlwaysOnLateralMain", "PauseAOLOnBrake"}; QSet<QString> aolKeys = {"AlwaysOnLateralLKAS", "AlwaysOnLateralMain", "PauseAOLOnBrake"};
QSet<QString> laneChangeKeys = {"LaneChangeTime", "LaneDetectionWidth", "MinimumLaneChangeSpeed", "NudgelessLaneChange", "OneLaneChange"}; QSet<QString> laneChangeKeys = {"LaneChangeTime", "LaneDetectionWidth", "MinimumLaneChangeSpeed", "NudgelessLaneChange", "OneLaneChange"};
QSet<QString> lateralTuneKeys = {"NNFF", "NNFFLite", "TurnDesires"}; QSet<QString> lateralTuneKeys = {"NNFF", "NNFFLite", "TurnDesires"};
@@ -48,6 +49,7 @@ private:
FrogPilotParamValueButtonControl *steerDelayToggle; FrogPilotParamValueButtonControl *steerDelayToggle;
FrogPilotParamValueButtonControl *steerFrictionToggle; FrogPilotParamValueButtonControl *steerFrictionToggle;
FrogPilotParamValueButtonControl *steerOffsetToggle;
FrogPilotParamValueButtonControl *steerLatAccelToggle; FrogPilotParamValueButtonControl *steerLatAccelToggle;
FrogPilotParamValueButtonControl *steerKPToggle; FrogPilotParamValueButtonControl *steerKPToggle;
FrogPilotParamValueButtonControl *steerRatioToggle; FrogPilotParamValueButtonControl *steerRatioToggle;
@@ -503,6 +503,8 @@ bool FrogPilotModelPanel::isModelInstalled(const QString &key) const {
bool has_policy_tg = false; bool has_policy_tg = false;
bool has_vision_meta = false; bool has_vision_meta = false;
bool has_vision_tg = false; bool has_vision_tg = false;
bool has_off_policy_meta = false;
bool has_off_policy_tg = false;
bool foundAny = false; bool foundAny = false;
for (const QString &file : modelDir.entryList(QDir::Files)) { for (const QString &file : modelDir.entryList(QDir::Files)) {
@@ -521,6 +523,10 @@ bool FrogPilotModelPanel::isModelInstalled(const QString &key) const {
has_policy_meta = true; has_policy_meta = true;
} else if (base.contains("_driving_policy_tinygrad")) { } else if (base.contains("_driving_policy_tinygrad")) {
has_policy_tg = true; has_policy_tg = true;
} else if (base.contains("_driving_off_policy_metadata")) {
has_off_policy_meta = true;
} else if (base.contains("_driving_off_policy_tinygrad")) {
has_off_policy_tg = true;
} else if (base.contains("_driving_vision_metadata")) { } else if (base.contains("_driving_vision_metadata")) {
has_vision_meta = true; has_vision_meta = true;
} else if (base.contains("_driving_vision_tinygrad")) { } else if (base.contains("_driving_vision_tinygrad")) {
@@ -534,6 +540,9 @@ bool FrogPilotModelPanel::isModelInstalled(const QString &key) const {
} }
if (has_policy_meta && has_policy_tg && has_vision_meta && has_vision_tg) { if (has_policy_meta && has_policy_tg && has_vision_meta && has_vision_tg) {
if (has_off_policy_meta || has_off_policy_tg) {
return has_off_policy_meta && has_off_policy_tg;
}
return true; return true;
} }
@@ -189,6 +189,7 @@ FrogPilotVehiclesPanel::FrogPilotVehiclesPanel(FrogPilotSettingsWindow *parent)
{"PedalSupport", tr("comma Pedal Support"), tr("<b>Does your vehicle support the \"comma pedal\"?</b>"), ""}, {"PedalSupport", tr("comma Pedal Support"), tr("<b>Does your vehicle support the \"comma pedal\"?</b>"), ""},
{"OpenpilotLongitudinal", tr("openpilot Longitudinal Support"), tr("<b>Can openpilot control the vehicle's acceleration and braking?</b>"), ""}, {"OpenpilotLongitudinal", tr("openpilot Longitudinal Support"), tr("<b>Can openpilot control the vehicle's acceleration and braking?</b>"), ""},
{"RadarSupport", tr("Radar Support"), tr("<b>Does openpilot use the vehicle's radar data</b> alongside the device's camera for tracking lead vehicles?"), ""}, {"RadarSupport", tr("Radar Support"), tr("<b>Does openpilot use the vehicle's radar data</b> alongside the device's camera for tracking lead vehicles?"), ""},
{"SASCMSupport", tr("SASCM Support"), tr("<b>Does your vehicle support \"SASCMs\"?</b>"), ""},
{"SDSUSupport", tr("SDSU Support"), tr("<b>Does your vehicle support \"SDSUs\"?</b>"), ""}, {"SDSUSupport", tr("SDSU Support"), tr("<b>Does your vehicle support \"SDSUs\"?</b>"), ""},
{"SNGSupport", tr("Stop-and-Go Support"), tr("<b>Does your vehicle support stop-and-go driving?</b>"), ""} {"SNGSupport", tr("Stop-and-Go Support"), tr("<b>Does your vehicle support stop-and-go driving?</b>"), ""}
}; };
@@ -342,6 +343,7 @@ void FrogPilotVehiclesPanel::showEvent(QShowEvent *event) {
QStringList detected; QStringList detected;
if (hasPedal) detected << "comma Pedal"; if (hasPedal) detected << "comma Pedal";
if (parent->hasSASCM) detected << "SASCM";
if (parent->hasSDSU) detected << "SDSU"; if (parent->hasSDSU) detected << "SDSU";
if (parent->hasZSS) detected << "ZSS"; if (parent->hasZSS) detected << "ZSS";
static_cast<LabelControl*>(toggles["HardwareDetected"])->setText(detected.isEmpty() ? tr("None") : detected.join(", ")); static_cast<LabelControl*>(toggles["HardwareDetected"])->setText(detected.isEmpty() ? tr("None") : detected.join(", "));
@@ -350,6 +352,7 @@ void FrogPilotVehiclesPanel::showEvent(QShowEvent *event) {
static_cast<LabelControl*>(toggles["OpenpilotLongitudinal"])->setText(hasOpenpilotLongitudinal ? tr("Yes") : tr("No")); static_cast<LabelControl*>(toggles["OpenpilotLongitudinal"])->setText(hasOpenpilotLongitudinal ? tr("Yes") : tr("No"));
static_cast<LabelControl*>(toggles["PedalSupport"])->setText(parent->canUsePedal ? tr("Yes") : tr("No")); static_cast<LabelControl*>(toggles["PedalSupport"])->setText(parent->canUsePedal ? tr("Yes") : tr("No"));
static_cast<LabelControl*>(toggles["RadarSupport"])->setText(parent->hasRadar ? tr("Yes") : tr("No")); static_cast<LabelControl*>(toggles["RadarSupport"])->setText(parent->hasRadar ? tr("Yes") : tr("No"));
static_cast<LabelControl*>(toggles["SASCMSupport"])->setText(parent->canUseSASCM ? tr("Yes") : tr("No"));
static_cast<LabelControl*>(toggles["SDSUSupport"])->setText(parent->canUseSDSU ? tr("Yes") : tr("No")); static_cast<LabelControl*>(toggles["SDSUSupport"])->setText(parent->canUseSDSU ? tr("Yes") : tr("No"));
static_cast<LabelControl*>(toggles["SNGSupport"])->setText(hasSNG ? tr("Yes") : tr("No")); static_cast<LabelControl*>(toggles["SNGSupport"])->setText(hasSNG ? tr("Yes") : tr("No"));
+1 -1
View File
@@ -40,7 +40,7 @@ private:
QSet<QString> hkgKeys = {"NewLongAPI", "TacoTuneHacks"}; QSet<QString> hkgKeys = {"NewLongAPI", "TacoTuneHacks"};
QSet<QString> longitudinalKeys = {"ExperimentalGMTune", "FrogsGoMoosTweak", "LongPitch", "NewLongAPI", "SNGHack", "VoltSNG"}; QSet<QString> longitudinalKeys = {"ExperimentalGMTune", "FrogsGoMoosTweak", "LongPitch", "NewLongAPI", "SNGHack", "VoltSNG"};
QSet<QString> toyotaKeys = {"ClusterOffset", "FrogsGoMoosTweak", "LockDoorsTimer", "SNGHack", "ToyotaDoors"}; QSet<QString> toyotaKeys = {"ClusterOffset", "FrogsGoMoosTweak", "LockDoorsTimer", "SNGHack", "ToyotaDoors"};
QSet<QString> vehicleInfoKeys = {"BlindSpotSupport", "HardwareDetected", "OpenpilotLongitudinal", "PedalSupport", "RadarSupport", "SDSUSupport", "SNGSupport"}; QSet<QString> vehicleInfoKeys = {"BlindSpotSupport", "HardwareDetected", "OpenpilotLongitudinal", "PedalSupport", "RadarSupport", "SASCMSupport", "SDSUSupport", "SNGSupport"};
QSet<QString> parentKeys; QSet<QString> parentKeys;
@@ -171,6 +171,7 @@ BO_ 481 ASCMSteeringButton: 7 K124_ASCM
SG_ DistanceButton : 22|1@0+ (1,0) [0|0] "" NEO SG_ DistanceButton : 22|1@0+ (1,0) [0|0] "" NEO
SG_ LKAButton : 23|1@0+ (1,0) [0|0] "" NEO SG_ LKAButton : 23|1@0+ (1,0) [0|0] "" NEO
SG_ ACCAlwaysOne : 24|1@0+ (1,0) [0|1] "" XXX SG_ ACCAlwaysOne : 24|1@0+ (1,0) [0|1] "" XXX
SG_ ACCHiddenBit : 30|1@0+ (1,0) [0|1] "" XXX
SG_ ACCButtons : 46|3@0+ (1,0) [0|0] "" NEO SG_ ACCButtons : 46|3@0+ (1,0) [0|0] "" NEO
SG_ DriveModeButton : 39|1@0+ (1,0) [0|1] "" XXX SG_ DriveModeButton : 39|1@0+ (1,0) [0|1] "" XXX
SG_ RollingCounter : 33|2@0+ (1,0) [0|3] "" NEO SG_ RollingCounter : 33|2@0+ (1,0) [0|3] "" NEO
+1
View File
@@ -165,6 +165,7 @@ BO_ 481 ASCMSteeringButton: 7 K124_ASCM
SG_ DistanceButton : 22|1@0+ (1,0) [0|0] "" NEO SG_ DistanceButton : 22|1@0+ (1,0) [0|0] "" NEO
SG_ LKAButton : 23|1@0+ (1,0) [0|0] "" NEO SG_ LKAButton : 23|1@0+ (1,0) [0|0] "" NEO
SG_ ACCAlwaysOne : 24|1@0+ (1,0) [0|1] "" XXX SG_ ACCAlwaysOne : 24|1@0+ (1,0) [0|1] "" XXX
SG_ ACCHiddenBit : 30|1@0+ (1,0) [0|1] "" XXX
SG_ ACCButtons : 46|3@0+ (1,0) [0|0] "" NEO SG_ ACCButtons : 46|3@0+ (1,0) [0|0] "" NEO
SG_ DriveModeButton : 39|1@0+ (1,0) [0|1] "" XXX SG_ DriveModeButton : 39|1@0+ (1,0) [0|1] "" XXX
SG_ RollingCounter : 33|2@0+ (1,0) [0|3] "" NEO SG_ RollingCounter : 33|2@0+ (1,0) [0|3] "" NEO
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+2 -2
View File
@@ -10,14 +10,14 @@ const SteeringLimits GM_STEERING_LIMITS = {
}; };
const LongitudinalLimits GM_ASCM_LONG_LIMITS = { const LongitudinalLimits GM_ASCM_LONG_LIMITS = {
.max_gas = 7168, .max_gas = 8191,
.min_gas = 5500, .min_gas = 5500,
.inactive_gas = 5500, .inactive_gas = 5500,
.max_brake = 400, .max_brake = 400,
}; };
const LongitudinalLimits GM_CAM_LONG_LIMITS = { const LongitudinalLimits GM_CAM_LONG_LIMITS = {
.max_gas = 7496, .max_gas = 8848,
.min_gas = 5610, .min_gas = 5610,
.inactive_gas = 5650, .inactive_gas = 5650,
.max_brake = 400, .max_brake = 400,
+19 -15
View File
@@ -805,7 +805,8 @@ class Panda:
# The panda will NAK CAN writes when there is CAN congestion. # The panda will NAK CAN writes when there is CAN congestion.
# libusb will try to send it again, with a max timeout. # libusb will try to send it again, with a max timeout.
# Timeout is in ms. If set to 0, the timeout is infinite. # Timeout is in ms. If set to 0, the timeout is infinite.
CAN_SEND_TIMEOUT_MS = 10 CAN_SEND_TIMEOUT_MS = 5
CAN_MAX_RETRIES = 3
def can_reset_communications(self): def can_reset_communications(self):
self._handle.controlWrite(Panda.REQUEST_OUT, 0xc0, 0, 0, b'') self._handle.controlWrite(Panda.REQUEST_OUT, 0xc0, 0, 0, b'')
@@ -813,18 +814,18 @@ class Panda:
@ensure_can_packet_version @ensure_can_packet_version
def can_send_many(self, arr, timeout=CAN_SEND_TIMEOUT_MS): def can_send_many(self, arr, timeout=CAN_SEND_TIMEOUT_MS):
snds = pack_can_buffer(arr) snds = pack_can_buffer(arr)
while True: for tx in snds:
try: retries = 0
for tx in snds: while len(tx) > 0:
while True: bs = self._handle.bulkWrite(3, tx, timeout=timeout)
bs = self._handle.bulkWrite(3, tx, timeout=timeout) if bs == 0:
tx = tx[bs:] retries += 1
if len(tx) == 0: if retries > self.CAN_MAX_RETRIES:
break logging.warning("CAN send: no progress after retries, dropping")
logging.error("CAN: PARTIAL SEND MANY, RETRYING") break
break else:
except (usb1.USBErrorIO, usb1.USBErrorOverflow): retries = 0
logging.error("CAN: BAD SEND MANY, RETRYING") tx = tx[bs:]
def can_send(self, addr, dat, bus, timeout=CAN_SEND_TIMEOUT_MS): def can_send(self, addr, dat, bus, timeout=CAN_SEND_TIMEOUT_MS):
self.can_send_many([[addr, None, dat, bus]], timeout=timeout) self.can_send_many([[addr, None, dat, bus]], timeout=timeout)
@@ -832,13 +833,16 @@ class Panda:
@ensure_can_packet_version @ensure_can_packet_version
def can_recv(self): def can_recv(self):
dat = bytearray() dat = bytearray()
while True: for _ in range(self.CAN_MAX_RETRIES):
try: try:
dat = self._handle.bulkRead(1, 16384) # Max receive batch size + 2 extra reserve frames dat = self._handle.bulkRead(1, 16384) # Max receive batch size + 2 extra reserve frames
break break
except (usb1.USBErrorIO, usb1.USBErrorOverflow): except (usb1.USBErrorIO, usb1.USBErrorOverflow):
logging.error("CAN: BAD RECV, RETRYING") logging.error("CAN: BAD RECV, RETRYING")
time.sleep(0.1) time.sleep(0.01)
else:
logging.error("CAN: recv failed after retries")
return []
msgs, self.can_rx_overflow_buffer = unpack_can_buffer(self.can_rx_overflow_buffer + dat) msgs, self.can_rx_overflow_buffer = unpack_can_buffer(self.can_rx_overflow_buffer + dat)
return msgs return msgs
+12 -1
View File
@@ -27,7 +27,10 @@ NACK = 0x1F
CHECKSUM_START = 0xAB CHECKSUM_START = 0xAB
MIN_ACK_TIMEOUT_MS = 100 MIN_ACK_TIMEOUT_MS = 100
MAX_ACK_TIMEOUT_MS = 500 # like C++ SPI_ACK_TIMEOUT
DEFAULT_TIMEOUT_MS = 500 # default when timeout=0
MAX_XFER_RETRY_COUNT = 5 MAX_XFER_RETRY_COUNT = 5
MAX_TIMEOUT_RETRIES = 5 # like C++
XFER_SIZE = 0x40*31 XFER_SIZE = 0x40*31
@@ -152,6 +155,8 @@ class PandaSpiHandle(BaseHandle):
return cksum return cksum
def _wait_for_ack(self, spi, ack_val: int, timeout: int, tx: int, length: int = 1) -> bytes: def _wait_for_ack(self, spi, ack_val: int, timeout: int, tx: int, length: int = 1) -> bytes:
# Original behavior preserved - timeout=0 means wait forever within this function
# The caller (_transfer) handles the overall timeout
timeout_s = max(MIN_ACK_TIMEOUT_MS, timeout) * 1e-3 timeout_s = max(MIN_ACK_TIMEOUT_MS, timeout) * 1e-3
start = time.monotonic() start = time.monotonic()
@@ -225,10 +230,15 @@ class PandaSpiHandle(BaseHandle):
logging.debug("starting transfer: endpoint=%d, max_rx_len=%d", endpoint, max_rx_len) logging.debug("starting transfer: endpoint=%d, max_rx_len=%d", endpoint, max_rx_len)
logging.debug("==============================================") logging.debug("==============================================")
# Fix timeout=0 infinite loop: default to DEFAULT_TIMEOUT_MS
if timeout == 0:
timeout = DEFAULT_TIMEOUT_MS
n = 0 n = 0
start_time = time.monotonic() start_time = time.monotonic()
exc = PandaSpiException() exc = PandaSpiException()
while (timeout == 0) or (time.monotonic() - start_time) < timeout*1e-3: # Use the timeout for the overall loop, matching original behavior but with timeout=0 fixed
while (time.monotonic() - start_time) < timeout * 1e-3:
n += 1 n += 1
logging.debug("\ntry #%d", n) logging.debug("\ntry #%d", n)
with self.dev.acquire() as spi: with self.dev.acquire() as spi:
@@ -238,6 +248,7 @@ class PandaSpiHandle(BaseHandle):
exc = e exc = e
logging.debug("SPI transfer failed, retrying", exc_info=True) logging.debug("SPI transfer failed, retrying", exc_info=True)
logging.error("SPI transfer failed after %d tries, %.2fms", n, (time.monotonic() - start_time) * 1000)
raise exc raise exc
def get_protocol_version(self) -> bytes: def get_protocol_version(self) -> bytes:
+87 -27
View File
@@ -48,14 +48,18 @@ class CarController(CarControllerBase):
self.lka_icon_status_last = (False, False) self.lka_icon_status_last = (False, False)
self.params = CarControllerParams(self.CP) self.params = CarControllerParams(self.CP)
self.is_volt = self.CP.carFingerprint in (CAR.CHEVROLET_VOLT, CAR.CHEVROLET_VOLT_ASCM, CAR.CHEVROLET_VOLT_CAMERA, CAR.CHEVROLET_VOLT_CC) self.is_volt = self.CP.carFingerprint in (CAR.CHEVROLET_VOLT, CAR.CHEVROLET_VOLT_2019, CAR.CHEVROLET_VOLT_ASCM, CAR.CHEVROLET_VOLT_CAMERA, CAR.CHEVROLET_VOLT_CC)
if self.is_volt: self.pedal_scale = 1.0
self.mass = CP.mass self.mass = CP.mass
self.tireRadius = 0.075 * CP.wheelbase + 0.1453 self.tireRadius = 0.075 * CP.wheelbase + 0.1453
self.frontalArea = 1.05 * CP.wheelbase + 0.0679 self.frontalArea = 1.05 * CP.wheelbase + 0.0679
self.coeffDrag = 0.30 self.coeffDrag = 0.30
self.airDensity = 1.225 self.airDensity = 1.225
self.params_ = Params() self.params_ = Params()
self.malibu_cancel_phase = 0
self.malibu_cancel_last_ts = 0.0
self.malibu_cancel_frame = 0
self.malibu_button_phase = 0
self.packer_pt = CANPacker(DBC[self.CP.carFingerprint]['pt']) self.packer_pt = CANPacker(DBC[self.CP.carFingerprint]['pt'])
self.packer_obj = CANPacker(DBC[self.CP.carFingerprint]['radar']) self.packer_obj = CANPacker(DBC[self.CP.carFingerprint]['radar'])
@@ -89,10 +93,18 @@ class CarController(CarControllerBase):
hud_v_cruise = hud_control.setSpeed hud_v_cruise = hud_control.setSpeed
if hud_v_cruise > 70: if hud_v_cruise > 70:
hud_v_cruise = 0 hud_v_cruise = 0
now_sec = now_nanos * 1e-9
# Send CAN commands. # Send CAN commands.
can_sends = [] can_sends = []
if self.CP.carFingerprint == CAR.CHEVROLET_MALIBU_HYBRID_CC:
phase_map = gmcan.malibu_phase_map_for_acc(CS.cruise_buttons)
if phase_map and CS.steering_button_checksum in phase_map:
phase = (phase_map[CS.steering_button_checksum] + 1) % 4
self.malibu_cancel_phase = phase
self.malibu_button_phase = phase
# Steering (Active: 50Hz, inactive: 10Hz) # Steering (Active: 50Hz, inactive: 10Hz)
steer_step = self.params.STEER_STEP if CC.latActive else self.params.INACTIVE_STEER_STEP steer_step = self.params.STEER_STEP if CC.latActive else self.params.INACTIVE_STEER_STEP
@@ -166,21 +178,46 @@ class CarController(CarControllerBase):
accel = clip(accel, self.params.ACCEL_MIN, self.params.ACCEL_MAX) accel = clip(accel, self.params.ACCEL_MIN, self.params.ACCEL_MAX)
brake_accel = clip(brake_accel, self.params.ACCEL_MIN, self.params.ACCEL_MAX) brake_accel = clip(brake_accel, self.params.ACCEL_MIN, self.params.ACCEL_MAX)
if self.CP.carFingerprint in EV_CAR: if self.CP.carFingerprint in EV_CAR:
self.params.update_ev_gas_brake_threshold(CS.out.vEgo) self.params.update_ev_gas_brake_threshold(CS.out.vEgo)
self.apply_gas = int(round(interp(accel, self.params.EV_GAS_LOOKUP_BP, self.params.GAS_LOOKUP_V))) self.apply_gas = int(round(interp(accel, self.params.EV_GAS_LOOKUP_BP, self.params.GAS_LOOKUP_V)))
self.apply_brake = int(round(interp(brake_accel, self.params.EV_BRAKE_LOOKUP_BP, self.params.BRAKE_LOOKUP_V))) self.apply_brake = int(round(interp(brake_accel, self.params.EV_BRAKE_LOOKUP_BP, self.params.BRAKE_LOOKUP_V)))
else:
self.apply_gas = int(round(interp(accel, self.params.GAS_LOOKUP_BP, self.params.GAS_LOOKUP_V)))
self.apply_brake = int(round(interp(brake_accel, self.params.BRAKE_LOOKUP_BP, self.params.BRAKE_LOOKUP_V)))
# Clamp within message-valid ranges to avoid ASCM faults from overshoot or rounding
self.apply_gas = int(round(clip(self.apply_gas, self.params.MAX_ACC_REGEN, self.params.MAX_GAS)))
self.apply_brake = int(round(clip(self.apply_brake, 0, self.params.MAX_BRAKE)))
if self.apply_brake > 0:
# Volt should never present positive torque alongside friction braking
self.apply_gas = self.params.INACTIVE_REGEN
else: else:
self.apply_gas = int(round(interp(accel, self.params.GAS_LOOKUP_BP, self.params.GAS_LOOKUP_V))) if len(CC.orientationNED) == 3 and CS.out.vEgo > self.CP.vEgoStopping:
accel_due_to_pitch = math.sin(CC.orientationNED[1]) * ACCELERATION_DUE_TO_GRAVITY
else:
accel_due_to_pitch = 0.0
gas_max = self.params.MAX_GAS
accel_max = self.params.ACCEL_MAX
accel = clip(actuators.accel + accel_due_to_pitch, self.params.ACCEL_MIN, accel_max)
torque = self.tireRadius * ((self.mass * accel) + (0.5 * self.coeffDrag * self.frontalArea * self.airDensity * CS.out.vEgo ** 2))
scaled_torque = torque + self.params.ZERO_GAS
apply_gas_torque = clip(scaled_torque, self.params.MAX_ACC_REGEN, gas_max)
BRAKE_SWITCH = int(round(interp(CS.out.vEgo, self.params.BRAKE_SWITCH_LOOKUP_BP, self.params.BRAKE_SWITCH_LOOKUP_V)))
brake_accel = min((scaled_torque - BRAKE_SWITCH) / (self.tireRadius * self.mass), 0)
self.apply_gas = int(round(apply_gas_torque))
self.apply_brake = int(round(interp(brake_accel, self.params.BRAKE_LOOKUP_BP, self.params.BRAKE_LOOKUP_V))) self.apply_brake = int(round(interp(brake_accel, self.params.BRAKE_LOOKUP_BP, self.params.BRAKE_LOOKUP_V)))
# Clamp within message-valid ranges to avoid ASCM faults from overshoot or rounding # Clamp within message-valid ranges to avoid ASCM faults from overshoot or rounding
self.apply_gas = int(round(clip(self.apply_gas, self.params.MAX_ACC_REGEN, self.params.MAX_GAS))) self.apply_gas = int(round(clip(self.apply_gas, self.params.MAX_ACC_REGEN, self.params.MAX_GAS)))
self.apply_brake = int(round(clip(self.apply_brake, 0, self.params.MAX_BRAKE))) self.apply_brake = int(round(clip(self.apply_brake, 0, self.params.MAX_BRAKE)))
if self.is_volt and self.apply_brake > 0: if self.apply_brake > 0 and self.apply_gas > self.params.INACTIVE_REGEN:
# Volt should never present positive torque alongside friction braking self.apply_gas = self.params.INACTIVE_REGEN
self.apply_gas = self.params.INACTIVE_REGEN
# Don't allow any gas above inactive regen while stopping # Don't allow any gas above inactive regen while stopping
# FIXME: brakes aren't applied immediately when enabling at a stop # FIXME: brakes aren't applied immediately when enabling at a stop
if stopping: if stopping:
@@ -188,6 +225,7 @@ class CarController(CarControllerBase):
if self.CP.carFingerprint in CC_ONLY_CAR: if self.CP.carFingerprint in CC_ONLY_CAR:
# gas interceptor only used for full long control on cars without ACC # gas interceptor only used for full long control on cars without ACC
interceptor_gas_cmd = self.calc_pedal_command(actuators.accel, CC.longActive) interceptor_gas_cmd = self.calc_pedal_command(actuators.accel, CC.longActive)
interceptor_gas_cmd = clip(interceptor_gas_cmd * self.pedal_scale, 0., 1.)
if self.CP.enableGasInterceptor and self.apply_gas > self.params.INACTIVE_REGEN and CS.out.cruiseState.standstill: if self.CP.enableGasInterceptor and self.apply_gas > self.params.INACTIVE_REGEN and CS.out.cruiseState.standstill:
# "Tap" the accelerator pedal to re-engage ACC # "Tap" the accelerator pedal to re-engage ACC
@@ -201,8 +239,15 @@ class CarController(CarControllerBase):
if CC.longActive and CS.out.vEgo > self.CP.minEnableSpeed: if CC.longActive and CS.out.vEgo > self.CP.minEnableSpeed:
# Using extend instead of append since the message is only sent intermittently # Using extend instead of append since the message is only sent intermittently
can_sends.extend(gmcan.create_gm_cc_spam_command(self.packer_pt, self, CS, actuators, frogpilot_toggles)) can_sends.extend(gmcan.create_gm_cc_spam_command(self.packer_pt, self, CS, actuators, frogpilot_toggles))
elif CC.enabled and self.frame % 52 == 0 and CS.cruise_buttons == CruiseButtons.UNPRESS and CS.out.gasPressed and CS.out.cruiseState.speed < CS.out.vEgo < hud_v_cruise: elif (CS.out.cruiseState.enabled and CC.enabled and self.frame % 52 == 0 and
can_sends.append(gmcan.create_buttons(self.packer_pt, CanBus.POWERTRAIN, (CS.buttons_counter + 1) % 4, CruiseButtons.DECEL_SET)) CS.cruise_buttons == CruiseButtons.UNPRESS and CS.out.gasPressed and CS.out.cruiseState.speed < CS.out.vEgo < hud_v_cruise):
if self.CP.carFingerprint == CAR.CHEVROLET_MALIBU_HYBRID_CC:
can_sends.append(gmcan.create_buttons_malibu(
self.packer_pt, CanBus.POWERTRAIN, CruiseButtons.DECEL_SET,
self.malibu_button_phase, CS.steering_button_prefix))
self.malibu_button_phase = (self.malibu_button_phase + 1) % 4
else:
can_sends.append(gmcan.create_buttons(self.packer_pt, CanBus.POWERTRAIN, (CS.buttons_counter + 1) % 4, CruiseButtons.DECEL_SET))
if self.CP.enableGasInterceptor: if self.CP.enableGasInterceptor:
can_sends.append(create_gas_interceptor_command(self.packer_pt, interceptor_gas_cmd, idx)) can_sends.append(create_gas_interceptor_command(self.packer_pt, interceptor_gas_cmd, idx))
if self.CP.carFingerprint not in CC_ONLY_CAR: if self.CP.carFingerprint not in CC_ONLY_CAR:
@@ -261,9 +306,17 @@ class CarController(CarControllerBase):
(self.CP.flags & GMFlags.PEDAL_LONG.value) # Always cancel stock CC when using pedal interceptor (self.CP.flags & GMFlags.PEDAL_LONG.value) # Always cancel stock CC when using pedal interceptor
or (self.CP.flags & GMFlags.CC_LONG.value and not CC.enabled) # Cancel stock CC if OP is not active or (self.CP.flags & GMFlags.CC_LONG.value and not CC.enabled) # Cancel stock CC if OP is not active
) and CS.out.cruiseState.enabled: ) and CS.out.cruiseState.enabled:
if (self.frame - self.last_button_frame) * DT_CTRL > 0.04: if self.CP.carFingerprint == CAR.CHEVROLET_MALIBU_HYBRID_CC:
self.last_button_frame = self.frame # Match 33 Hz cadence (every 3 frames) and align phase to the last seen checksum.
can_sends.append(gmcan.create_buttons(self.packer_pt, CanBus.POWERTRAIN, (CS.buttons_counter + 1) % 4, CruiseButtons.CANCEL)) if self.malibu_cancel_frame % 3 == 0:
can_sends.append(gmcan.create_buttons_malibu_cancel(
CanBus.POWERTRAIN, self.malibu_cancel_phase, CS.steering_button_prefix))
self.malibu_cancel_phase = (self.malibu_cancel_phase + 1) % 4
self.malibu_cancel_frame += 1
else:
if (self.frame - self.last_button_frame) * DT_CTRL > 0.04:
self.last_button_frame = self.frame
can_sends.append(gmcan.create_buttons(self.packer_pt, CanBus.POWERTRAIN, (CS.buttons_counter + 1) % 4, CruiseButtons.CANCEL))
else: else:
# While car is braking, cancel button causes ECM to enter a soft disable state with a fault status. # While car is braking, cancel button causes ECM to enter a soft disable state with a fault status.
@@ -271,10 +324,17 @@ class CarController(CarControllerBase):
self.cancel_counter = self.cancel_counter + 1 if CC.cruiseControl.cancel else 0 self.cancel_counter = self.cancel_counter + 1 if CC.cruiseControl.cancel else 0
# Stock longitudinal, integrated at camera # Stock longitudinal, integrated at camera
if (self.frame - self.last_button_frame) * DT_CTRL > 0.04: if self.cancel_counter > CAMERA_CANCEL_DELAY_FRAMES:
if self.cancel_counter > CAMERA_CANCEL_DELAY_FRAMES: if self.CP.carFingerprint == CAR.CHEVROLET_MALIBU_HYBRID_CC:
self.last_button_frame = self.frame if self.malibu_cancel_frame % 3 == 0:
can_sends.append(gmcan.create_buttons(self.packer_pt, CanBus.CAMERA, CS.buttons_counter, CruiseButtons.CANCEL)) can_sends.append(gmcan.create_buttons_malibu_cancel(
CanBus.POWERTRAIN, self.malibu_cancel_phase, CS.steering_button_prefix))
self.malibu_cancel_phase = (self.malibu_cancel_phase + 1) % 4
self.malibu_cancel_frame += 1
else:
if (self.frame - self.last_button_frame) * DT_CTRL > 0.04:
self.last_button_frame = self.frame
can_sends.append(gmcan.create_buttons(self.packer_pt, CanBus.CAMERA, CS.buttons_counter, CruiseButtons.CANCEL))
if self.CP.networkLocation == NetworkLocation.fwdCamera: if self.CP.networkLocation == NetworkLocation.fwdCamera:
# Silence "Take Steering" alert sent by camera, forward PSCMStatus with HandsOffSWlDetectionStatus=1 # Silence "Take Steering" alert sent by camera, forward PSCMStatus with HandsOffSWlDetectionStatus=1
+8 -2
View File
@@ -26,6 +26,8 @@ class CarState(CarStateBase):
self.pt_lka_steering_cmd_counter = 0 self.pt_lka_steering_cmd_counter = 0
self.cam_lka_steering_cmd_counter = 0 self.cam_lka_steering_cmd_counter = 0
self.buttons_counter = 0 self.buttons_counter = 0
self.steering_button_checksum = 0
self.steering_button_prefix = 0x01
self.prev_distance_button = 0 self.prev_distance_button = 0
self.distance_button = 0 self.distance_button = 0
@@ -42,6 +44,10 @@ class CarState(CarStateBase):
self.cruise_buttons = pt_cp.vl["ASCMSteeringButton"]["ACCButtons"] self.cruise_buttons = pt_cp.vl["ASCMSteeringButton"]["ACCButtons"]
self.distance_button = pt_cp.vl["ASCMSteeringButton"]["DistanceButton"] self.distance_button = pt_cp.vl["ASCMSteeringButton"]["DistanceButton"]
self.buttons_counter = pt_cp.vl["ASCMSteeringButton"]["RollingCounter"] self.buttons_counter = pt_cp.vl["ASCMSteeringButton"]["RollingCounter"]
self.steering_button_checksum = pt_cp.vl["ASCMSteeringButton"]["SteeringButtonChecksum"]
acc_always_one = pt_cp.vl["ASCMSteeringButton"]["ACCAlwaysOne"]
acc_hidden_bit = pt_cp.vl["ASCMSteeringButton"].get("ACCHiddenBit", 0)
self.steering_button_prefix = (int(acc_always_one) & 1) | ((int(acc_hidden_bit) & 1) << 6)
self.pscm_status = copy.copy(pt_cp.vl["PSCMStatus"]) self.pscm_status = copy.copy(pt_cp.vl["PSCMStatus"])
# This is to avoid a fault where you engage while still moving backwards after shifting to D. # This is to avoid a fault where you engage while still moving backwards after shifting to D.
# An Equinox has been seen with an unsupported status (3), so only check if either wheel is in reverse (2) # An Equinox has been seen with an unsupported status (3), so only check if either wheel is in reverse (2)
@@ -83,7 +89,7 @@ class CarState(CarStateBase):
# that the brake is being intermittently pressed without user interaction. # that the brake is being intermittently pressed without user interaction.
# To avoid a cruise fault we need to use a conservative brake position threshold # To avoid a cruise fault we need to use a conservative brake position threshold
# https://static.nhtsa.gov/odi/tsbs/2017/MC-10137629-9999.pdf # https://static.nhtsa.gov/odi/tsbs/2017/MC-10137629-9999.pdf
analog_thresh = 0.07 if (self.CP.flags & GMFlags.NO_ACCELERATOR_POS_MSG.value) else 8 analog_thresh = 0.10 if (self.CP.flags & GMFlags.NO_ACCELERATOR_POS_MSG.value) else 8
ret.brakePressed = ret.brake >= analog_thresh ret.brakePressed = ret.brake >= analog_thresh
# Regen braking is braking # Regen braking is braking
@@ -93,7 +99,7 @@ class CarState(CarStateBase):
if self.CP.enableGasInterceptor: if self.CP.enableGasInterceptor:
ret.gas = (pt_cp.vl["GAS_SENSOR"]["INTERCEPTOR_GAS"] + pt_cp.vl["GAS_SENSOR"]["INTERCEPTOR_GAS2"]) / 2. ret.gas = (pt_cp.vl["GAS_SENSOR"]["INTERCEPTOR_GAS"] + pt_cp.vl["GAS_SENSOR"]["INTERCEPTOR_GAS2"]) / 2.
threshold = 23 if self.CP.carFingerprint in CAMERA_ACC_CAR else 4 # Panda 595 threshold = 23.65. Set lower to avoid panda blocking messages and GasInterceptor faulting. threshold = 21 if self.CP.carFingerprint in CAMERA_ACC_CAR else 4 # Panda 595 threshold = 23.65. Set lower to avoid panda blocking messages and GasInterceptor faulting.
ret.gasPressed = ret.gas > threshold ret.gasPressed = ret.gas > threshold
else: else:
ret.gas = pt_cp.vl["AcceleratorPedal2"]["AcceleratorPedal2"] / 254. ret.gas = pt_cp.vl["AcceleratorPedal2"]["AcceleratorPedal2"] / 254.
+3
View File
@@ -66,6 +66,9 @@ FINGERPRINTS = {
CAR.CHEVROLET_MALIBU: [{ CAR.CHEVROLET_MALIBU: [{
190: 6, 193: 8, 197: 8, 199: 4, 201: 8, 209: 7, 211: 2, 241: 6, 249: 8, 288: 5, 298: 8, 304: 1, 309: 8, 311: 8, 313: 8, 320: 3, 328: 1, 352: 5, 381: 6, 384: 4, 386: 8, 388: 8, 393: 7, 398: 8, 407: 7, 413: 8, 417: 7, 419: 1, 422: 4, 426: 7, 431: 8, 442: 8, 451: 8, 452: 8, 453: 6, 455: 7, 456: 8, 479: 3, 481: 7, 485: 8, 487: 8, 489: 8, 495: 4, 497: 8, 499: 3, 500: 6, 501: 8, 508: 8, 510: 8, 528: 5, 532: 6, 554: 3, 560: 8, 562: 8, 563: 5, 564: 5, 565: 5, 567: 5, 573: 1, 577: 8, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 647: 6, 707: 8, 715: 8, 717: 5, 753: 5, 761: 7, 810: 8, 840: 5, 842: 5, 844: 8, 866: 4, 869: 4, 880: 6, 961: 8, 969: 8, 977: 8, 979: 8, 985: 5, 1001: 8, 1005: 6, 1009: 8, 1013: 3, 1017: 8, 1019: 2, 1020: 8, 1033: 7, 1034: 7, 1105: 6, 1217: 8, 1221: 5, 1223: 2, 1225: 7, 1233: 8, 1249: 8, 1257: 6, 1265: 8, 1267: 1, 1280: 4, 1296: 4, 1300: 8, 1322: 6, 1323: 4, 1328: 4, 1417: 8, 1601: 8, 1906: 7, 1907: 7, 1912: 7, 1919: 7, 1930: 7, 2016: 8, 2024: 8 190: 6, 193: 8, 197: 8, 199: 4, 201: 8, 209: 7, 211: 2, 241: 6, 249: 8, 288: 5, 298: 8, 304: 1, 309: 8, 311: 8, 313: 8, 320: 3, 328: 1, 352: 5, 381: 6, 384: 4, 386: 8, 388: 8, 393: 7, 398: 8, 407: 7, 413: 8, 417: 7, 419: 1, 422: 4, 426: 7, 431: 8, 442: 8, 451: 8, 452: 8, 453: 6, 455: 7, 456: 8, 479: 3, 481: 7, 485: 8, 487: 8, 489: 8, 495: 4, 497: 8, 499: 3, 500: 6, 501: 8, 508: 8, 510: 8, 528: 5, 532: 6, 554: 3, 560: 8, 562: 8, 563: 5, 564: 5, 565: 5, 567: 5, 573: 1, 577: 8, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 647: 6, 707: 8, 715: 8, 717: 5, 753: 5, 761: 7, 810: 8, 840: 5, 842: 5, 844: 8, 866: 4, 869: 4, 880: 6, 961: 8, 969: 8, 977: 8, 979: 8, 985: 5, 1001: 8, 1005: 6, 1009: 8, 1013: 3, 1017: 8, 1019: 2, 1020: 8, 1033: 7, 1034: 7, 1105: 6, 1217: 8, 1221: 5, 1223: 2, 1225: 7, 1233: 8, 1249: 8, 1257: 6, 1265: 8, 1267: 1, 1280: 4, 1296: 4, 1300: 8, 1322: 6, 1323: 4, 1328: 4, 1417: 8, 1601: 8, 1906: 7, 1907: 7, 1912: 7, 1919: 7, 1930: 7, 2016: 8, 2024: 8
}], }],
CAR.CHEVROLET_MALIBU_ASCM: [{
190: 6, 193: 8, 197: 8, 199: 4, 201: 8, 209: 7, 211: 2, 241: 6, 249: 8, 288: 5, 298: 8, 304: 1, 309: 8, 311: 8, 313: 8, 320: 3, 328: 1, 352: 5, 381: 6, 384: 4, 386: 8, 388: 8, 393: 7, 398: 8, 407: 7, 413: 8, 417: 7, 419: 1, 422: 4, 426: 7, 431: 8, 442: 8, 451: 8, 452: 8, 453: 6, 455: 7, 456: 8, 479: 3, 481: 7, 485: 8, 487: 8, 489: 8, 495: 4, 497: 8, 499: 3, 500: 6, 501: 8, 508: 8, 510: 8, 528: 5, 532: 6, 554: 3, 560: 8, 562: 8, 563: 5, 564: 5, 565: 5, 567: 5, 573: 1, 577: 8, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 647: 6, 707: 8, 715: 8, 717: 5, 753: 5, 761: 7, 810: 8, 840: 5, 842: 5, 844: 8, 866: 4, 869: 4, 880: 6, 961: 8, 969: 8, 977: 8, 979: 8, 985: 5, 1001: 8, 1005: 6, 1009: 8, 1013: 3, 1017: 8, 1019: 2, 1020: 8, 1033: 7, 1034: 7, 1105: 6, 1217: 8, 1221: 5, 1223: 2, 1225: 7, 1233: 8, 1249: 8, 1257: 6, 1265: 8, 1267: 1, 1280: 4, 1296: 4, 1300: 8, 1322: 6, 1323: 4, 1328: 4, 1417: 8, 1601: 8, 1906: 7, 1907: 7, 1912: 7, 1919: 7, 1930: 7, 2016: 8, 2024: 8
}],
CAR.GMC_ACADIA: [{ CAR.GMC_ACADIA: [{
190: 6, 192: 5, 193: 8, 197: 8, 199: 4, 201: 6, 208: 8, 209: 7, 211: 2, 241: 6, 249: 8, 288: 5, 289: 1, 290: 1, 298: 8, 304: 8, 309: 8, 313: 8, 320: 8, 322: 7, 328: 1, 352: 7, 368: 8, 381: 8, 384: 8, 386: 8, 388: 8, 393: 8, 398: 8, 413: 8, 417: 7, 419: 1, 422: 4, 426: 7, 431: 8, 442: 8, 451: 8, 452: 8, 453: 6, 454: 8, 455: 7, 458: 8, 460: 4, 462: 4, 463: 3, 479: 3, 481: 7, 485: 8, 489: 5, 497: 8, 499: 3, 500: 6, 501: 8, 508: 8, 510: 8, 512: 3, 530: 8, 532: 6, 534: 2, 554: 3, 560: 8, 562: 8, 563: 5, 564: 5, 567: 5, 568: 2, 573: 1, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 647: 6, 707: 8, 715: 8, 717: 5, 753: 5, 761: 7, 789: 5, 800: 6, 801: 8, 803: 8, 804: 3, 805: 8, 832: 8, 840: 5, 842: 5, 844: 8, 866: 4, 869: 4, 880: 6, 961: 8, 969: 8, 977: 8, 979: 8, 985: 5, 1001: 8, 1003: 5, 1005: 6, 1009: 8, 1017: 8, 1020: 8, 1033: 7, 1034: 7, 1105: 6, 1217: 8, 1221: 5, 1225: 8, 1233: 8, 1249: 8, 1257: 6, 1265: 8, 1267: 1, 1280: 4, 1296: 4, 1300: 8, 1322: 6, 1328: 4, 1417: 8, 1906: 7, 1907: 7, 1912: 7, 1914: 7, 1918: 7, 1919: 7, 1920: 7, 1930: 7 190: 6, 192: 5, 193: 8, 197: 8, 199: 4, 201: 6, 208: 8, 209: 7, 211: 2, 241: 6, 249: 8, 288: 5, 289: 1, 290: 1, 298: 8, 304: 8, 309: 8, 313: 8, 320: 8, 322: 7, 328: 1, 352: 7, 368: 8, 381: 8, 384: 8, 386: 8, 388: 8, 393: 8, 398: 8, 413: 8, 417: 7, 419: 1, 422: 4, 426: 7, 431: 8, 442: 8, 451: 8, 452: 8, 453: 6, 454: 8, 455: 7, 458: 8, 460: 4, 462: 4, 463: 3, 479: 3, 481: 7, 485: 8, 489: 5, 497: 8, 499: 3, 500: 6, 501: 8, 508: 8, 510: 8, 512: 3, 530: 8, 532: 6, 534: 2, 554: 3, 560: 8, 562: 8, 563: 5, 564: 5, 567: 5, 568: 2, 573: 1, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 647: 6, 707: 8, 715: 8, 717: 5, 753: 5, 761: 7, 789: 5, 800: 6, 801: 8, 803: 8, 804: 3, 805: 8, 832: 8, 840: 5, 842: 5, 844: 8, 866: 4, 869: 4, 880: 6, 961: 8, 969: 8, 977: 8, 979: 8, 985: 5, 1001: 8, 1003: 5, 1005: 6, 1009: 8, 1017: 8, 1020: 8, 1033: 7, 1034: 7, 1105: 6, 1217: 8, 1221: 5, 1225: 8, 1233: 8, 1249: 8, 1257: 6, 1265: 8, 1267: 1, 1280: 4, 1296: 4, 1300: 8, 1322: 6, 1328: 4, 1417: 8, 1906: 7, 1907: 7, 1912: 7, 1914: 7, 1918: 7, 1919: 7, 1920: 7, 1930: 7
}, },
+71
View File
@@ -7,6 +7,58 @@ from openpilot.selfdrive.car import make_can_msg
from openpilot.selfdrive.car.gm.values import CAR, CruiseButtons, CanBus from openpilot.selfdrive.car.gm.values import CAR, CruiseButtons, CanBus
MALIBU_BUTTON_TABLE = {
0: [0x2FBC, 0x25DE, 0x15EE, 0x1FCC],
1: [0x55AE, 0x5F8C, 0x6F7C, 0x659E],
4: [0x2ACD, 0x20EF, 0x1ADD, 0x10FF],
5: [0x50BF, 0x5A9D, 0x60AF, 0x6A8D],
}
MALIBU_BUTTON_MAP = {
CruiseButtons.UNPRESS: 0,
CruiseButtons.RES_ACCEL: 1,
CruiseButtons.MAIN: 4,
CruiseButtons.CANCEL: 5,
}
def malibu_phase_map_for_button(button):
key = MALIBU_BUTTON_MAP.get(button, None)
if key is None or key not in MALIBU_BUTTON_TABLE:
return None
return {v: i for i, v in enumerate(MALIBU_BUTTON_TABLE[key])}
def malibu_phase_map_for_acc(acc_value):
seq = MALIBU_BUTTON_TABLE.get(acc_value)
if not seq:
return None
return {v: i for i, v in enumerate(seq)}
def create_buttons_malibu(packer, bus, button, phase, prefix=0x41):
key = MALIBU_BUTTON_MAP.get(button, None)
if key is None or key not in MALIBU_BUTTON_TABLE:
# fallback to standard checksum for unsupported buttons
return create_buttons(packer, bus, 0, button)
values = {
"ACCButtons": button,
"RollingCounter": 0,
"ACCAlwaysOne": 1,
"DistanceButton": 0,
}
dat = packer.make_can_msg("ASCMSteeringButton", bus, values)[2]
data = bytearray(dat)
data[3] = prefix & 0xFF
seq = MALIBU_BUTTON_TABLE[key]
val = seq[phase % len(seq)]
data[5] = (val >> 8) & 0xFF
data[6] = val & 0xFF
return make_can_msg(0x1e1, bytes(data), bus)
def create_buttons(packer, bus, idx, button): def create_buttons(packer, bus, idx, button):
values = { values = {
"ACCButtons": button, "ACCButtons": button,
@@ -24,6 +76,18 @@ def create_buttons(packer, bus, idx, button):
return packer.make_can_msg("ASCMSteeringButton", bus, values) return packer.make_can_msg("ASCMSteeringButton", bus, values)
def create_buttons_malibu_cancel(bus, phase, prefix=0x41):
# Malibu Hybrid CC cancel frames use a 4-value pattern in the last 2 bytes.
data = bytearray(7)
data[3] = prefix & 0xFF
data[4] = 0x00
cancel_bytes = (0x60, 0xAF, 0x65, 0x9E, 0x6A, 0x8D, 0x6F, 0x7C)
idx = ((phase + 2) % 4) * 2
data[5] = cancel_bytes[idx]
data[6] = cancel_bytes[idx + 1]
return make_can_msg(0x1e1, bytes(data), bus)
def create_pscm_status(packer, bus, pscm_status): def create_pscm_status(packer, bus, pscm_status):
values = {s: pscm_status[s] for s in [ values = {s: pscm_status[s] for s in [
"HandsOffSWDetectionMode", "HandsOffSWDetectionMode",
@@ -215,6 +279,13 @@ def create_gm_cc_spam_command(packer, controller, CS, actuators, frogpilot_toggl
# TODO: Cleanup the timing - normal is every 30ms... # TODO: Cleanup the timing - normal is every 30ms...
if (cruiseBtn != CruiseButtons.INIT) and ((controller.frame - controller.last_button_frame) * DT_CTRL > rate): if (cruiseBtn != CruiseButtons.INIT) and ((controller.frame - controller.last_button_frame) * DT_CTRL > rate):
controller.last_button_frame = controller.frame controller.last_button_frame = controller.frame
if CS.CP.carFingerprint == CAR.CHEVROLET_MALIBU_HYBRID_CC:
phase_map = malibu_phase_map_for_button(cruiseBtn)
if phase_map:
msgs = [create_buttons_malibu(packer, CanBus.POWERTRAIN, cruiseBtn, controller.malibu_button_phase,
CS.steering_button_prefix)]
controller.malibu_button_phase = (controller.malibu_button_phase + 1) % 4
return msgs
idx = (CS.buttons_counter + 1) % 4 # Need to predict the next idx for '22-23 EUV idx = (CS.buttons_counter + 1) % 4 # Need to predict the next idx for '22-23 EUV
return [create_buttons(packer, CanBus.POWERTRAIN, idx, cruiseBtn)] return [create_buttons(packer, CanBus.POWERTRAIN, idx, cruiseBtn)]
else: else:
+42 -13
View File
@@ -35,6 +35,7 @@ VOLT_LIKE_CARS = (
CAR.CHEVROLET_VOLT_CAMERA, CAR.CHEVROLET_VOLT_CAMERA,
CAR.CHEVROLET_VOLT_ASCM, CAR.CHEVROLET_VOLT_ASCM,
CAR.CHEVROLET_MALIBU, CAR.CHEVROLET_MALIBU,
CAR.CHEVROLET_MALIBU_ASCM,
CAR.CHEVROLET_MALIBU_SDGM, CAR.CHEVROLET_MALIBU_SDGM,
CAR.CHEVROLET_MALIBU_CC, CAR.CHEVROLET_MALIBU_CC,
CAR.CHEVROLET_MALIBU_HYBRID_CC, CAR.CHEVROLET_MALIBU_HYBRID_CC,
@@ -50,6 +51,10 @@ NON_LINEAR_TORQUE_PARAMS = {
class CarInterface(CarInterfaceBase): class CarInterface(CarInterfaceBase):
def __init__(self, CP, FPCP, CarController, CarState):
super().__init__(CP, FPCP, CarController, CarState)
self.steer_offset = 0.0
@staticmethod @staticmethod
def get_pid_accel_limits(CP, current_speed, cruise_speed): def get_pid_accel_limits(CP, current_speed, cruise_speed):
return CarControllerParams.ACCEL_MIN, CarControllerParams.ACCEL_MAX return CarControllerParams.ACCEL_MIN, CarControllerParams.ACCEL_MAX
@@ -91,20 +96,28 @@ class CarInterface(CarInterfaceBase):
torque_values, lataccel_values = self.get_lataccel_torque_siglin() torque_values, lataccel_values = self.get_lataccel_torque_siglin()
def torque_from_lateral_accel_siglin(lateral_acceleration: float, torque_params: car.CarParams.LateralTorqueTuning): def torque_from_lateral_accel_siglin(lateral_acceleration: float, torque_params: car.CarParams.LateralTorqueTuning):
return np.interp(lateral_acceleration, lataccel_values, torque_values) return float(np.interp(lateral_acceleration, lataccel_values, torque_values) + self.steer_offset)
return torque_from_lateral_accel_siglin return torque_from_lateral_accel_siglin
else: else:
return self.torque_from_lateral_accel_linear def torque_from_lateral_accel_linear(lateral_acceleration: float, torque_params: car.CarParams.LateralTorqueTuning):
return self.torque_from_lateral_accel_linear(lateral_acceleration, torque_params) + self.steer_offset
return torque_from_lateral_accel_linear
def lateral_accel_from_torque(self) -> LateralAccelFromTorqueCallbackType: def lateral_accel_from_torque(self) -> LateralAccelFromTorqueCallbackType:
if self.CP.carFingerprint in NON_LINEAR_TORQUE_PARAMS: if self.CP.carFingerprint in NON_LINEAR_TORQUE_PARAMS:
torque_values, lataccel_values = self.get_lataccel_torque_siglin() torque_values, lataccel_values = self.get_lataccel_torque_siglin()
def lateral_accel_from_torque_siglin(torque: float, torque_params: car.CarParams.LateralTorqueTuning): def lateral_accel_from_torque_siglin(torque: float, torque_params: car.CarParams.LateralTorqueTuning):
return np.interp(torque, torque_values, lataccel_values) return np.interp(torque - self.steer_offset, torque_values, lataccel_values)
return lateral_accel_from_torque_siglin return lateral_accel_from_torque_siglin
else: else:
return self.lateral_accel_from_torque_linear def lateral_accel_from_torque_linear(torque: float, torque_params: car.CarParams.LateralTorqueTuning):
return self.lateral_accel_from_torque_linear(torque - self.steer_offset, torque_params)
return lateral_accel_from_torque_linear
def update(self, c: car.CarControl, can_strings: list[bytes], frogpilot_toggles) -> car.CarState:
self.steer_offset = float(getattr(frogpilot_toggles, "steer_offset", 0.0))
return super().update(c, can_strings, frogpilot_toggles)
@staticmethod @staticmethod
def _get_params(ret, candidate, fingerprint, car_fw, experimental_long, docs, frogpilot_toggles): def _get_params(ret, candidate, fingerprint, car_fw, experimental_long, docs, frogpilot_toggles):
@@ -112,6 +125,11 @@ class CarInterface(CarInterfaceBase):
ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.gm)] ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.gm)]
ret.autoResumeSng = False ret.autoResumeSng = False
ret.enableBsm = 0x142 in fingerprint[CanBus.POWERTRAIN] ret.enableBsm = 0x142 in fingerprint[CanBus.POWERTRAIN]
# Detect Beartech SASCM allows openpilot longitudinal control on SDGM and ASCM_INT vehicles
if 0x2FF in fingerprint[0]:
ret.flags |= GMFlags.SASCM.value
if PEDAL_MSG in fingerprint[0]: if PEDAL_MSG in fingerprint[0]:
ret.enableGasInterceptor = True ret.enableGasInterceptor = True
ret.safetyConfigs[0].safetyParam |= Panda.FLAG_GM_GAS_INTERCEPTOR ret.safetyConfigs[0].safetyParam |= Panda.FLAG_GM_GAS_INTERCEPTOR
@@ -148,12 +166,12 @@ class CarInterface(CarInterfaceBase):
ret.safetyConfigs[0].safetyParam |= Panda.FLAG_GM_HW_CAM ret.safetyConfigs[0].safetyParam |= Panda.FLAG_GM_HW_CAM
# Tuning for experimental long # Tuning for experimental long
ret.longitudinalTuning.kiV = [1.0, 1.0] ret.longitudinalTuning.kiV = [0.5, 0.5]
ret.stoppingDecelRate = 1.0 # reach brake quickly after enabling ret.stoppingDecelRate = 1.0 # reach brake quickly after enabling
ret.vEgoStopping = 0.25 ret.vEgoStopping = 0.25
ret.vEgoStarting = 0.25 ret.vEgoStarting = 0.25
ret.stopAccel = -0.20 ret.stopAccel = -0.25
if ret.experimentalLongitudinalAvailable and experimental_long: if ret.experimentalLongitudinalAvailable and experimental_long:
ret.pcmCruise = False ret.pcmCruise = False
@@ -199,12 +217,10 @@ class CarInterface(CarInterfaceBase):
ret.minEnableSpeed = -1 ret.minEnableSpeed = -1
if candidate in VOLT_LIKE_CARS: if candidate in VOLT_LIKE_CARS:
ret.lateralTuning.pid.kpBP = [0., 40.] CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
ret.lateralTuning.pid.kpV = [0., 0.17]
ret.lateralTuning.pid.kiBP = [0.]
ret.lateralTuning.pid.kiV = [0.]
ret.lateralTuning.pid.kf = 1. # get_steer_feedforward_volt()
ret.steerActuatorDelay = 0.2 ret.steerActuatorDelay = 0.2
if candidate == CAR.CHEVROLET_MALIBU_HYBRID_CC and ret.enableGasInterceptor:
ret.flags |= GMFlags.PEDAL_LONG.value
elif candidate == CAR.GMC_ACADIA: elif candidate == CAR.GMC_ACADIA:
ret.minEnableSpeed = -1. # engage speed is decided by pcm ret.minEnableSpeed = -1. # engage speed is decided by pcm
@@ -328,6 +344,17 @@ class CarInterface(CarInterfaceBase):
ret.vEgoStopping = 0.25 ret.vEgoStopping = 0.25
ret.vEgoStarting = 0.25 ret.vEgoStarting = 0.25
if ret.enableGasInterceptor and candidate == CAR.CHEVROLET_MALIBU_HYBRID_CC:
ret.flags |= GMFlags.PEDAL_LONG.value
ret.safetyConfigs[0].safetyParam |= Panda.FLAG_GM_PEDAL_LONG
ret.longitudinalTuning.kiBP = [0.0, 5., 35.]
ret.longitudinalTuning.kiV = [0.0, 0.18, 0.25]
ret.longitudinalTuning.kfDEPRECATED = 0.15
ret.stoppingDecelRate = 0.8
ret.minEnableSpeed = -1
ret.pcmCruise = False
ret.openpilotLongitudinalControl = not frogpilot_toggles.disable_openpilot_long
elif candidate in CC_ONLY_CAR: elif candidate in CC_ONLY_CAR:
ret.flags |= GMFlags.CC_LONG.value ret.flags |= GMFlags.CC_LONG.value
@@ -400,11 +427,13 @@ class CarInterface(CarInterfaceBase):
if ret.vEgo < self.CP.minSteerSpeed: if ret.vEgo < self.CP.minSteerSpeed:
events.add(EventName.belowSteerSpeed) events.add(EventName.belowSteerSpeed)
if (self.CP.flags & GMFlags.CC_LONG.value) and ret.vEgo < self.CP.minEnableSpeed and ret.cruiseState.enabled: if (self.CP.flags & GMFlags.CC_LONG.value) and ret.vEgo < self.CP.minEnableSpeed:
events.add(EventName.speedTooLow) if ret.cruiseState.enabled or self.CS.out.cruiseState.enabled:
events.add(EventName.speedTooLow)
if (self.CP.flags & GMFlags.PEDAL_LONG.value) and \ if (self.CP.flags & GMFlags.PEDAL_LONG.value) and \
self.CP.transmissionType == TransmissionType.direct and \ self.CP.transmissionType == TransmissionType.direct and \
self.CP.carFingerprint != CAR.CHEVROLET_MALIBU_HYBRID_CC and \
not self.CS.single_pedal_mode and \ not self.CS.single_pedal_mode and \
c.longActive: c.longActive:
events.add(FrogPilotEventName.pedalInterceptorNoBrake) events.add(FrogPilotEventName.pedalInterceptorNoBrake)
+11 -6
View File
@@ -38,12 +38,12 @@ class CarControllerParams:
def __init__(self, CP): def __init__(self, CP):
# Gas/brake lookups # Gas/brake lookups
self.ZERO_GAS = 6144 # Coasting self.ZERO_GAS = 6150 # Coasting
self.MAX_BRAKE = 400 # ~ -4.0 m/s^2 with regen self.MAX_BRAKE = 400 # ~ -4.0 m/s^2 with regen
self.BRAKE_SWITCH_MAX = self.ZERO_GAS self.BRAKE_SWITCH_MAX = self.ZERO_GAS
if CP.carFingerprint in (CAMERA_ACC_CAR | SDGM_CAR) and CP.carFingerprint not in CC_ONLY_CAR and CP.carFingerprint != CAR.CHEVROLET_BOLT_EUV: if CP.carFingerprint in (CAMERA_ACC_CAR | SDGM_CAR) and CP.carFingerprint not in CC_ONLY_CAR and CP.carFingerprint != CAR.CHEVROLET_BOLT_EUV:
self.MAX_GAS = 7496 self.MAX_GAS = 8848
self.MAX_GAS_PLUS = 8848 self.MAX_GAS_PLUS = 8848
self.MAX_ACC_REGEN = 5610 self.MAX_ACC_REGEN = 5610
self.INACTIVE_REGEN = 5650 self.INACTIVE_REGEN = 5650
@@ -52,8 +52,8 @@ class CarControllerParams:
self.max_regen_acceleration = 0. self.max_regen_acceleration = 0.
else: else:
self.MAX_GAS = 7168 # Safety limit, not ACC max. Stock ACC >8192 from standstill. self.MAX_GAS = 8191 # Safety limit, not ACC max. Stock ACC >8192 from standstill.
self.MAX_GAS_PLUS = 8191 # 8292 uses new bit, possible but not tested. Matches Twilsonco tw-main max self.MAX_GAS_PLUS = 8191
self.MAX_ACC_REGEN = 5500 # Max ACC regen is slightly less than max paddle regen self.MAX_ACC_REGEN = 5500 # Max ACC regen is slightly less than max paddle regen
self.INACTIVE_REGEN = 5500 self.INACTIVE_REGEN = 5500
# ICE has much less engine braking force compared to regen in EVs, # ICE has much less engine braking force compared to regen in EVs,
@@ -144,6 +144,10 @@ class CAR(Platforms):
[GMCarDocs("Chevrolet Malibu Premier 2017")], [GMCarDocs("Chevrolet Malibu Premier 2017")],
GMCarSpecs(mass=1496, wheelbase=2.83, steerRatio=15.8, centerToFrontRatio=0.4), GMCarSpecs(mass=1496, wheelbase=2.83, steerRatio=15.8, centerToFrontRatio=0.4),
) )
CHEVROLET_MALIBU_ASCM = GMPlatformConfig(
[GMCarDocs("Chevrolet Malibu 2017-19 ASCM Harness")],
CHEVROLET_MALIBU.specs,
)
GMC_ACADIA = GMASCMPlatformConfig( GMC_ACADIA = GMASCMPlatformConfig(
[GMCarDocs("GMC Acadia 2018", video_link="https://www.youtube.com/watch?v=0ZN6DdsBUZo")], [GMCarDocs("GMC Acadia 2018", video_link="https://www.youtube.com/watch?v=0ZN6DdsBUZo")],
GMCarSpecs(mass=1975, wheelbase=2.86, steerRatio=14.4, centerToFrontRatio=0.4), GMCarSpecs(mass=1975, wheelbase=2.86, steerRatio=14.4, centerToFrontRatio=0.4),
@@ -258,7 +262,7 @@ class CAR(Platforms):
) )
CHEVROLET_MALIBU_CC = GMPlatformConfig( CHEVROLET_MALIBU_CC = GMPlatformConfig(
[GMCarDocs("Chevrolet Malibu 2023 - No-ACC")], [GMCarDocs("Chevrolet Malibu 2023 - No-ACC")],
CarSpecs(mass=1450, wheelbase=2.8, steerRatio=15.8, centerToFrontRatio=0.4), CarSpecs(mass=1450, wheelbase=2.8, steerRatio=18.25, centerToFrontRatio=0.4, tireStiffnessFactor=0.997),
) )
CHEVROLET_MALIBU_HYBRID_CC = GMPlatformConfig( CHEVROLET_MALIBU_HYBRID_CC = GMPlatformConfig(
[GMCarDocs("Chevrolet Malibu Hybrid 2017 - No-ACC")], [GMCarDocs("Chevrolet Malibu Hybrid 2017 - No-ACC")],
@@ -306,6 +310,7 @@ class GMFlags(IntFlag):
NO_CAMERA = 4 NO_CAMERA = 4
NO_ACCELERATOR_POS_MSG = 8 NO_ACCELERATOR_POS_MSG = 8
FORCE_BRAKE_C9 = 16 FORCE_BRAKE_C9 = 16
SASCM = 32
# In a Data Module, an identifier is a string used to recognize an object, # In a Data Module, an identifier is a string used to recognize an object,
@@ -364,7 +369,7 @@ CC_ONLY_CAR = {CAR.CHEVROLET_VOLT_CC, CAR.CHEVROLET_BOLT_CC, CAR.CHEVROLET_EQUIN
# We're integrated at the Safety Data Gateway Module on these cars # We're integrated at the Safety Data Gateway Module on these cars
SDGM_CAR = {CAR.CADILLAC_XT4, CAR.CADILLAC_XT6, CAR.CHEVROLET_TRAVERSE, CAR.CHEVROLET_BLAZER, CAR.CHEVROLET_MALIBU_SDGM, CAR.BUICK_BABYENCLAVE, CAR.CHEVROLET_VOLT_2019} SDGM_CAR = {CAR.CADILLAC_XT4, CAR.CADILLAC_XT6, CAR.CHEVROLET_TRAVERSE, CAR.CHEVROLET_BLAZER, CAR.CHEVROLET_MALIBU_SDGM, CAR.BUICK_BABYENCLAVE, CAR.CHEVROLET_VOLT_2019}
ASCM_INT = {CAR.CHEVROLET_VOLT_ASCM, CAR.GMC_ACADIA_ASCM} ASCM_INT = {CAR.CHEVROLET_VOLT_ASCM, CAR.GMC_ACADIA_ASCM, CAR.CHEVROLET_MALIBU_ASCM}
# We're integrated at the camera with VOACC on these cars (instead of ASCM w/ OBD-II harness) # We're integrated at the camera with VOACC on these cars (instead of ASCM w/ OBD-II harness)
CAMERA_ACC_CAR = {CAR.CHEVROLET_BOLT_EUV, CAR.CHEVROLET_SILVERADO, CAR.CHEVROLET_EQUINOX, CAR.CHEVROLET_TRAILBLAZER, CAR.CHEVROLET_TRAX, CAR.CHEVROLET_VOLT_CAMERA, CAR.CHEVROLET_BLAZER} CAMERA_ACC_CAR = {CAR.CHEVROLET_BOLT_EUV, CAR.CHEVROLET_SILVERADO, CAR.CHEVROLET_EQUINOX, CAR.CHEVROLET_TRAILBLAZER, CAR.CHEVROLET_TRAX, CAR.CHEVROLET_VOLT_CAMERA, CAR.CHEVROLET_BLAZER}
+2 -1
View File
@@ -42,7 +42,7 @@ FRICTION_THRESHOLD = 0.09
def get_friction_threshold(v_ego): def get_friction_threshold(v_ego):
# Interpolate friction threshold from 0.09 at 50 mph to 0.15 at 75 mph # Interpolate friction threshold from 0.09 at 50 mph to 0.15 at 75 mph
from openpilot.common.numpy_fast import interp from openpilot.common.numpy_fast import interp
return interp(v_ego, [50 * CV.MPH_TO_MS, 75 * CV.MPH_TO_MS], [0.09, 0.15]) return interp(v_ego, [1 * CV.MPH_TO_MS, 75 * CV.MPH_TO_MS], [0.12, 0.25])
TORQUE_PARAMS_PATH = os.path.join(BASEDIR, 'selfdrive/car/torque_data/params.toml') TORQUE_PARAMS_PATH = os.path.join(BASEDIR, 'selfdrive/car/torque_data/params.toml')
TORQUE_OVERRIDE_PATH = os.path.join(BASEDIR, 'selfdrive/car/torque_data/override.toml') TORQUE_OVERRIDE_PATH = os.path.join(BASEDIR, 'selfdrive/car/torque_data/override.toml')
@@ -187,6 +187,7 @@ class CarInterfaceBase(ABC):
elif platform in GMCAR: elif platform in GMCAR:
fp_ret.canUsePedal = True fp_ret.canUsePedal = True
fp_ret.canUseSASCM = True
elif platform in HondaCAR: elif platform in HondaCAR:
if candidate == HondaCAR.HONDA_CLARITY: if candidate == HondaCAR.HONDA_CLARITY:
+1
View File
@@ -45,6 +45,7 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"]
"CADILLAC_XT4" = [1.45, 1.6, 0.2] "CADILLAC_XT4" = [1.45, 1.6, 0.2]
"CADILLAC_XT6" = [1.33, 1.9, 0.16] "CADILLAC_XT6" = [1.33, 1.9, 0.16]
"CHEVROLET_BOLT_EUV" = [1.0, 2.0, 0.175] "CHEVROLET_BOLT_EUV" = [1.0, 2.0, 0.175]
"CHEVROLET_MALIBU_CC" = [1.58, 1.8422651988094612, 0.205]
"CHEVROLET_SILVERADO" = [1.9, 1.9, 0.112] "CHEVROLET_SILVERADO" = [1.9, 1.9, 0.112]
"CHEVROLET_BLAZER" = [1.33, 1.33, 0.18] "CHEVROLET_BLAZER" = [1.33, 1.33, 0.18]
"CHEVROLET_TRAILBLAZER" = [1.33, 1.9, 0.16] "CHEVROLET_TRAILBLAZER" = [1.33, 1.9, 0.16]
+1
View File
@@ -5,6 +5,7 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"]
"AUDI_A3_MK3" = [1.5122414863077502, 1.7443517531719404, 0.15194151892450905] "AUDI_A3_MK3" = [1.5122414863077502, 1.7443517531719404, 0.15194151892450905]
"AUDI_Q3_MK2" = [1.4439223359448605, 1.2254955789112076, 0.1413798895978097] "AUDI_Q3_MK2" = [1.4439223359448605, 1.2254955789112076, 0.1413798895978097]
"CHEVROLET_VOLT" = [1.5961527626411784, 1.8422651988094612, 0.1572393918005158] "CHEVROLET_VOLT" = [1.5961527626411784, 1.8422651988094612, 0.1572393918005158]
"CHEVROLET_MALIBU_HYBRID_CC" = [1.5961527626411784, 1.8422651988094612, 0.1572393918005158]
"CHRYSLER_PACIFICA_2018" = [2.07140, 1.3366521181047952, 0.13776367250652022] "CHRYSLER_PACIFICA_2018" = [2.07140, 1.3366521181047952, 0.13776367250652022]
"CHRYSLER_PACIFICA_2020" = [1.86206, 1.509076559398423, 0.14328246159386085] "CHRYSLER_PACIFICA_2020" = [1.86206, 1.509076559398423, 0.14328246159386085]
"CHRYSLER_PACIFICA_2017_HYBRID" = [1.79422, 1.06831764583744, 0.116237] "CHRYSLER_PACIFICA_2017_HYBRID" = [1.79422, 1.06831764583744, 0.116237]
+1 -2
View File
@@ -56,9 +56,8 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"]
"CADILLAC_ESCALADE_ESV" = "CHEVROLET_VOLT" "CADILLAC_ESCALADE_ESV" = "CHEVROLET_VOLT"
"CADILLAC_ATS" = "CHEVROLET_VOLT" "CADILLAC_ATS" = "CHEVROLET_VOLT"
"CHEVROLET_MALIBU" = "CHEVROLET_VOLT" "CHEVROLET_MALIBU" = "CHEVROLET_VOLT"
"CHEVROLET_MALIBU_ASCM" = "CHEVROLET_VOLT"
"CHEVROLET_MALIBU_SDGM" = "CHEVROLET_VOLT" "CHEVROLET_MALIBU_SDGM" = "CHEVROLET_VOLT"
"CHEVROLET_MALIBU_CC" = "CHEVROLET_VOLT"
"CHEVROLET_MALIBU_HYBRID_CC" = "CHEVROLET_VOLT"
"HOLDEN_ASTRA" = "CHEVROLET_VOLT" "HOLDEN_ASTRA" = "CHEVROLET_VOLT"
"CHEVROLET_VOLT_CC" = "CHEVROLET_VOLT" "CHEVROLET_VOLT_CC" = "CHEVROLET_VOLT"
"CHEVROLET_VOLT_CAMERA" = "CHEVROLET_VOLT" "CHEVROLET_VOLT_CAMERA" = "CHEVROLET_VOLT"
+10 -3
View File
@@ -1,20 +1,21 @@
import math import math
from cereal import log from cereal import log
from openpilot.common.conversions import Conversions as CV from openpilot.selfdrive.controls.lib.latcontrol import LatControl, MIN_LATERAL_CONTROL_SPEED
from openpilot.selfdrive.controls.lib.latcontrol import LatControl
from openpilot.selfdrive.controls.lib.pid import PIDController from openpilot.selfdrive.controls.lib.pid import PIDController
class LatControlPID(LatControl): class LatControlPID(LatControl):
def __init__(self, CP, CI, dt): def __init__(self, CP, CI, dt):
super().__init__(CP, CI, dt) super().__init__(CP, CI, dt)
self.steer_release_i_decay = 0.8
self.prev_steering_pressed = False
self.pid = PIDController((CP.lateralTuning.pid.kpBP, CP.lateralTuning.pid.kpV), self.pid = PIDController((CP.lateralTuning.pid.kpBP, CP.lateralTuning.pid.kpV),
(CP.lateralTuning.pid.kiBP, CP.lateralTuning.pid.kiV), (CP.lateralTuning.pid.kiBP, CP.lateralTuning.pid.kiV),
pos_limit=self.steer_max, neg_limit=-self.steer_max) pos_limit=self.steer_max, neg_limit=-self.steer_max)
self.ff_factor = CP.lateralTuning.pid.kf self.ff_factor = CP.lateralTuning.pid.kf
self.get_steer_feedforward = CI.get_steer_feedforward_function() self.get_steer_feedforward = CI.get_steer_feedforward_function()
self.low_speed_reset_threshold = 7 * CV.MPH_TO_MS self.low_speed_reset_threshold = max(CP.minSteerSpeed, MIN_LATERAL_CONTROL_SPEED)
def update(self, active, CS, VM, params, steer_limited_by_safety, desired_curvature, curvature_limited, lat_delay, llk, model_data, frogpilot_toggles): def update(self, active, CS, VM, params, steer_limited_by_safety, desired_curvature, curvature_limited, lat_delay, llk, model_data, frogpilot_toggles):
pid_log = log.ControlsState.LateralPIDState.new_message() pid_log = log.ControlsState.LateralPIDState.new_message()
@@ -30,8 +31,12 @@ class LatControlPID(LatControl):
if not active: if not active:
output_torque = 0.0 output_torque = 0.0
pid_log.active = False pid_log.active = False
self.pid.reset()
else: else:
if self.prev_steering_pressed and not CS.steeringPressed:
self.pid.i *= self.steer_release_i_decay
# offset does not contribute to resistive torque # offset does not contribute to resistive torque
ff = self.ff_factor * self.get_steer_feedforward(angle_steers_des_no_offset, CS.vEgo) ff = self.ff_factor * self.get_steer_feedforward(angle_steers_des_no_offset, CS.vEgo)
if CS.vEgo < self.low_speed_reset_threshold: if CS.vEgo < self.low_speed_reset_threshold:
@@ -50,4 +55,6 @@ class LatControlPID(LatControl):
pid_log.output = float(output_torque) pid_log.output = float(output_torque)
pid_log.saturated = bool(self._check_saturation(self.steer_max - abs(output_torque) < 1e-3, CS, steer_limited_by_safety, curvature_limited)) pid_log.saturated = bool(self._check_saturation(self.steer_max - abs(output_torque) < 1e-3, CS, steer_limited_by_safety, curvature_limited))
self.prev_steering_pressed = CS.steeringPressed
return output_torque, angle_steers_des, pid_log return output_torque, angle_steers_des, pid_log
+9 -3
View File
@@ -3,11 +3,10 @@ import numpy as np
from collections import deque from collections import deque
from cereal import log from cereal import log
from openpilot.common.conversions import Conversions as CV
from openpilot.selfdrive.car.interfaces import FRICTION_THRESHOLD, get_friction_threshold from openpilot.selfdrive.car.interfaces import FRICTION_THRESHOLD, get_friction_threshold
from openpilot.selfdrive.controls.lib.drive_helpers import MIN_SPEED, get_friction from openpilot.selfdrive.controls.lib.drive_helpers import MIN_SPEED, get_friction
from openpilot.common.filter_simple import FirstOrderFilter from openpilot.common.filter_simple import FirstOrderFilter
from openpilot.selfdrive.controls.lib.latcontrol import LatControl from openpilot.selfdrive.controls.lib.latcontrol import LatControl, MIN_LATERAL_CONTROL_SPEED
from openpilot.selfdrive.controls.lib.pid import PIDController from openpilot.selfdrive.controls.lib.pid import PIDController
from openpilot.selfdrive.controls.lib.vehicle_model import ACCELERATION_DUE_TO_GRAVITY from openpilot.selfdrive.controls.lib.vehicle_model import ACCELERATION_DUE_TO_GRAVITY
@@ -41,6 +40,8 @@ VERSION = 2
class LatControlTorque(LatControl): class LatControlTorque(LatControl):
def __init__(self, CP, CI, dt): def __init__(self, CP, CI, dt):
super().__init__(CP, CI, dt) super().__init__(CP, CI, dt)
self.steer_release_i_decay = 0.8
self.prev_steering_pressed = False
self.torque_params = CP.lateralTuning.torque self.torque_params = CP.lateralTuning.torque
self.torque_from_lateral_accel = CI.torque_from_lateral_accel() self.torque_from_lateral_accel = CI.torque_from_lateral_accel()
self.lateral_accel_from_torque = CI.lateral_accel_from_torque() self.lateral_accel_from_torque = CI.lateral_accel_from_torque()
@@ -53,7 +54,7 @@ class LatControlTorque(LatControl):
self.jerk_filter = FirstOrderFilter(0.0, 1 / (2 * np.pi * LP_FILTER_CUTOFF_HZ), self.dt) self.jerk_filter = FirstOrderFilter(0.0, 1 / (2 * np.pi * LP_FILTER_CUTOFF_HZ), self.dt)
self.previous_measurement = 0.0 self.previous_measurement = 0.0
self.measurement_rate_filter = FirstOrderFilter(0.0, 1 / (2 * np.pi * (MAX_LAT_JERK_UP - 0.5)), self.dt) self.measurement_rate_filter = FirstOrderFilter(0.0, 1 / (2 * np.pi * (MAX_LAT_JERK_UP - 0.5)), self.dt)
self.low_speed_reset_threshold = 7 * CV.MPH_TO_MS self.low_speed_reset_threshold = max(CP.minSteerSpeed, MIN_LATERAL_CONTROL_SPEED)
def update_live_torque_params(self, latAccelFactor, latAccelOffset, friction): def update_live_torque_params(self, latAccelFactor, latAccelOffset, friction):
self.torque_params.latAccelFactor = latAccelFactor self.torque_params.latAccelFactor = latAccelFactor
@@ -76,6 +77,9 @@ class LatControlTorque(LatControl):
self.measurement_rate_filter.x = 0.0 self.measurement_rate_filter.x = 0.0
self.lat_accel_request_buffer = deque([0.] * self.lat_accel_request_buffer_len , maxlen=self.lat_accel_request_buffer_len) self.lat_accel_request_buffer = deque([0.] * self.lat_accel_request_buffer_len , maxlen=self.lat_accel_request_buffer_len)
else: else:
if self.prev_steering_pressed and not CS.steeringPressed:
self.pid.i *= self.steer_release_i_decay
measured_curvature = -VM.calc_curvature(math.radians(CS.steeringAngleDeg - params.angleOffsetDeg), CS.vEgo, params.roll) measured_curvature = -VM.calc_curvature(math.radians(CS.steeringAngleDeg - params.angleOffsetDeg), CS.vEgo, params.roll)
roll_compensation = params.roll * ACCELERATION_DUE_TO_GRAVITY roll_compensation = params.roll * ACCELERATION_DUE_TO_GRAVITY
curvature_deadzone = abs(VM.calc_curvature(math.radians(self.steering_angle_deadzone_deg), CS.vEgo, 0.0)) curvature_deadzone = abs(VM.calc_curvature(math.radians(self.steering_angle_deadzone_deg), CS.vEgo, 0.0))
@@ -125,5 +129,7 @@ class LatControlTorque(LatControl):
pid_log.desiredLateralJerk = float(desired_lateral_jerk) pid_log.desiredLateralJerk = float(desired_lateral_jerk)
pid_log.saturated = bool(self._check_saturation(self.steer_max - abs(output_torque) < 1e-3, CS, steer_limited_by_safety, curvature_limited)) pid_log.saturated = bool(self._check_saturation(self.steer_max - abs(output_torque) < 1e-3, CS, steer_limited_by_safety, curvature_limited))
self.prev_steering_pressed = CS.steeringPressed
# TODO left is positive in this convention # TODO left is positive in this convention
return -output_torque, 0.0, pid_log return -output_torque, 0.0, pid_log
@@ -5,7 +5,6 @@ import numpy as np
from cereal import log from cereal import log
from openpilot.common.numpy_fast import clip, interp from openpilot.common.numpy_fast import clip, interp
from openpilot.common.realtime import DT_MDL from openpilot.common.realtime import DT_MDL
from openpilot.common.swaglog import cloudlog
from openpilot.common.filter_simple import FirstOrderFilter from openpilot.common.filter_simple import FirstOrderFilter
from openpilot.common.conversions import Conversions as CV from openpilot.common.conversions import Conversions as CV
# WARNING: imports outside of constants will not trigger a rebuild # WARNING: imports outside of constants will not trigger a rebuild
@@ -422,9 +421,6 @@ class LongitudinalMpc:
scale = float(np.interp(uncertainty, [0.45, 0.60], [1.2, 1.5])) scale = float(np.interp(uncertainty, [0.45, 0.60], [1.2, 1.5]))
speed_jerk *= scale speed_jerk *= scale
if abs(filter_time_factor - prev_filter_time_factor) > 1e-3:
cloudlog.error(f"LON_FILTER; filter_time_factor={filter_time_factor:.2f}; uncertainty={uncertainty:.3f}; v_ego={v_ego:.2f} mps; lead_dist={lead_dist:.2f} m; accel_reengage={accel_reengage}")
if self.mode == 'acc': if self.mode == 'acc':
a_change_cost = acceleration_jerk if prev_accel_constraint else 0 a_change_cost = acceleration_jerk if prev_accel_constraint else 0
cost_weights = [self.current_x_ego_cost, X_EGO_COST, V_EGO_COST, A_EGO_COST, a_change_cost, speed_jerk] cost_weights = [self.current_x_ego_cost, X_EGO_COST, V_EGO_COST, A_EGO_COST, a_change_cost, speed_jerk]
@@ -627,11 +623,7 @@ class LongitudinalMpc:
self.prev_a = np.interp(T_IDXS + self.dt, T_IDXS, self.a_solution) self.prev_a = np.interp(T_IDXS + self.dt, T_IDXS, self.a_solution)
t = time.monotonic()
if self.solution_status != 0: if self.solution_status != 0:
if t > self.last_cloudlog_t + 5.0:
self.last_cloudlog_t = t
cloudlog.warning(f"Long mpc reset, solution_status: {self.solution_status}")
self.reset() self.reset()
# reset = 1 # reset = 1
# print(f"long_mpc timings: total internal {self.solve_time:.2e}, external: {(time.monotonic() - t0):.2e} qp {self.time_qp_solution:.2e}, \ # print(f"long_mpc timings: total internal {self.solve_time:.2e}, external: {(time.monotonic() - t0):.2e} qp {self.time_qp_solution:.2e}, \
+1 -17
View File
@@ -111,9 +111,6 @@ class LongitudinalPlanner:
self.a_desired_trajectory = np.zeros(CONTROL_N) self.a_desired_trajectory = np.zeros(CONTROL_N)
self.j_desired_trajectory = np.zeros(CONTROL_N) self.j_desired_trajectory = np.zeros(CONTROL_N)
self.solverExecutionTime = 0.0 self.solverExecutionTime = 0.0
# logging cadence & state
self.last_uncert_log_t = 0.0
self.prev_uncert_over = False
# ---- Rubberband mitigation state ---- # ---- Rubberband mitigation state ----
# Two uncertainty tracks (slow/fast) for asymmetric gating # Two uncertainty tracks (slow/fast) for asymmetric gating
@@ -138,7 +135,7 @@ class LongitudinalPlanner:
@property @property
def mlsim(self): def mlsim(self):
return self.generation in ("v8", "v10", "v11") return self.generation in ("v8", "v10", "v11", "v12")
def get_mpc_mode(self) -> str: def get_mpc_mode(self) -> str:
""" """
@@ -344,19 +341,6 @@ class LongitudinalPlanner:
# now_t defined earlier # now_t defined earlier
over = uncertainty > 1.0 over = uncertainty > 1.0
# Log on threshold edge or at ~1 Hz
if over != self.prev_uncert_over or (now_t - self.last_uncert_log_t) > 1.0:
try:
cloudlog.error(
f"LON_UNCERT; v_ego={v_ego:.2f} mps; desireEntropy={desire_entropy:.3f}; "
f"brakeRawMax={(raw_brake_max if 'raw_brake_max' in locals() else -1.0):.3f}; "
f"brakeDecayed={(disengage_risk if 'disengage_risk' in locals() else -1.0):.3f}; "
f"lam={(lam if 'lam' in locals() else -1.0):.2f}; uncertainty={uncertainty:.3f}; over={over}"
)
except Exception as e:
cloudlog.warning(f"LON_UNCERT log error: {e}")
self.prev_uncert_over = over
self.last_uncert_log_t = now_t
# Asymmetric accel release with hysteresis + dwell to prevent on/off pulsing # Asymmetric accel release with hysteresis + dwell to prevent on/off pulsing
rise_dwell_s, fall_dwell_s = 0.6, 0.4 rise_dwell_s, fall_dwell_s = 0.6, 0.4
+3 -3
View File
@@ -33,7 +33,7 @@ class DRIVER_MONITOR_SETTINGS:
self._SG_THRESHOLD = 0.9 self._SG_THRESHOLD = 0.9
self._BLINK_THRESHOLD = 0.865 self._BLINK_THRESHOLD = 0.865
self._EE_THRESH11 = 0.4 self._EE_THRESH11 = 0.6
self._EE_THRESH12 = 15.0 self._EE_THRESH12 = 15.0
self._EE_MAX_OFFSET1 = 0.06 self._EE_MAX_OFFSET1 = 0.06
self._EE_MIN_OFFSET1 = 0.025 self._EE_MIN_OFFSET1 = 0.025
@@ -44,9 +44,9 @@ class DRIVER_MONITOR_SETTINGS:
self._POSE_YAW_THRESHOLD = 0.4020 self._POSE_YAW_THRESHOLD = 0.4020
self._POSE_YAW_THRESHOLD_SLACK = 0.5042 self._POSE_YAW_THRESHOLD_SLACK = 0.5042
self._POSE_YAW_THRESHOLD_STRICT = self._POSE_YAW_THRESHOLD self._POSE_YAW_THRESHOLD_STRICT = self._POSE_YAW_THRESHOLD
self._PITCH_NATURAL_OFFSET = 0.029 # initial value before offset is learned self._PITCH_NATURAL_OFFSET = 0.011 # initial value before offset is learned
self._PITCH_NATURAL_THRESHOLD = 0.449 self._PITCH_NATURAL_THRESHOLD = 0.449
self._YAW_NATURAL_OFFSET = 0.097 # initial value before offset is learned self._YAW_NATURAL_OFFSET = 0.075 # initial value before offset is learned
self._PITCH_MAX_OFFSET = 0.124 self._PITCH_MAX_OFFSET = 0.124
self._PITCH_MIN_OFFSET = -0.0881 self._PITCH_MIN_OFFSET = -0.0881
self._YAW_MAX_OFFSET = 0.289 self._YAW_MAX_OFFSET = 0.289
Binary file not shown.
Binary file not shown.
+24
View File
@@ -1199,6 +1199,22 @@
<source>&lt;b&gt;Twilsonco's torque-based adjustments to smoothen out steering in curves.&lt;/b&gt;</source> <source>&lt;b&gt;Twilsonco's torque-based adjustments to smoothen out steering in curves.&lt;/b&gt;</source>
<translation type="gpt-5-generated">&lt;b&gt;تعديلات Twilsonco المعتمدة على العزم لتنعيم التوجيه في المنعطفات.&lt;/b&gt;</translation> <translation type="gpt-5-generated">&lt;b&gt;تعديلات Twilsonco المعتمدة على العزم لتنعيم التوجيه في المنعطفات.&lt;/b&gt;</translation>
</message> </message>
<message>
<source>Steer Offset (Default: %1)</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Steer Offset</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>&lt;b&gt;Offsets steering torque to help compensate for alignment or tire issues.&lt;/b&gt; More negative pulls the car right; more positive pulls it left. Most users should not need to touch this.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Reset &lt;b&gt;Steer Offset&lt;/b&gt; to its default value?</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>FrogPilotLongitudinalPanel</name> <name>FrogPilotLongitudinalPanel</name>
@@ -3798,6 +3814,14 @@ Developer - Highly customizable settings for seasoned enthusiasts</source>
<source>&lt;b&gt;Use the pedal interceptor for longitudinal control&lt;/b&gt; instead of camera ACC/Redneck when available.</source> <source>&lt;b&gt;Use the pedal interceptor for longitudinal control&lt;/b&gt; instead of camera ACC/Redneck when available.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>SASCM Support</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>&lt;b&gt;Does your vehicle support "SASCMs"?&lt;/b&gt;</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>FrogPilotVisualsPanel</name> <name>FrogPilotVisualsPanel</name>
+24
View File
@@ -1200,6 +1200,22 @@
<source>&lt;b&gt;Twilsonco's torque-based adjustments to smoothen out steering in curves.&lt;/b&gt;</source> <source>&lt;b&gt;Twilsonco's torque-based adjustments to smoothen out steering in curves.&lt;/b&gt;</source>
<translation type="gpt-5-generated">&lt;b&gt;Twilsonco make torque tweak. Steering smooth in curve.&lt;/b&gt;</translation> <translation type="gpt-5-generated">&lt;b&gt;Twilsonco make torque tweak. Steering smooth in curve.&lt;/b&gt;</translation>
</message> </message>
<message>
<source>Steer Offset (Default: %1)</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Steer Offset</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>&lt;b&gt;Offsets steering torque to help compensate for alignment or tire issues.&lt;/b&gt; More negative pulls the car right; more positive pulls it left. Most users should not need to touch this.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Reset &lt;b&gt;Steer Offset&lt;/b&gt; to its default value?</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>FrogPilotLongitudinalPanel</name> <name>FrogPilotLongitudinalPanel</name>
@@ -3802,6 +3818,14 @@ Developer - Many custom setting for seasoned enthusiast</translation>
<source>&lt;b&gt;Use the pedal interceptor for longitudinal control&lt;/b&gt; instead of camera ACC/Redneck when available.</source> <source>&lt;b&gt;Use the pedal interceptor for longitudinal control&lt;/b&gt; instead of camera ACC/Redneck when available.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>SASCM Support</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>&lt;b&gt;Does your vehicle support "SASCMs"?&lt;/b&gt;</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>FrogPilotVisualsPanel</name> <name>FrogPilotVisualsPanel</name>
+24
View File
@@ -1199,6 +1199,22 @@
<source>&lt;b&gt;Twilsonco's torque-based adjustments to smoothen out steering in curves.&lt;/b&gt;</source> <source>&lt;b&gt;Twilsonco's torque-based adjustments to smoothen out steering in curves.&lt;/b&gt;</source>
<translation type="gpt-5-generated">&lt;b&gt;Twilsoncos drehmomentbasierte Anpassungen zur Glättung der Lenkung in Kurven.&lt;/b&gt;</translation> <translation type="gpt-5-generated">&lt;b&gt;Twilsoncos drehmomentbasierte Anpassungen zur Glättung der Lenkung in Kurven.&lt;/b&gt;</translation>
</message> </message>
<message>
<source>Steer Offset (Default: %1)</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Steer Offset</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>&lt;b&gt;Offsets steering torque to help compensate for alignment or tire issues.&lt;/b&gt; More negative pulls the car right; more positive pulls it left. Most users should not need to touch this.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Reset &lt;b&gt;Steer Offset&lt;/b&gt; to its default value?</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>FrogPilotLongitudinalPanel</name> <name>FrogPilotLongitudinalPanel</name>
@@ -3798,6 +3814,14 @@ Entwickler Hochgradig anpassbare Einstellungen für versierte Enthusiasten</
<source>&lt;b&gt;Use the pedal interceptor for longitudinal control&lt;/b&gt; instead of camera ACC/Redneck when available.</source> <source>&lt;b&gt;Use the pedal interceptor for longitudinal control&lt;/b&gt; instead of camera ACC/Redneck when available.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>SASCM Support</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>&lt;b&gt;Does your vehicle support "SASCMs"?&lt;/b&gt;</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>FrogPilotVisualsPanel</name> <name>FrogPilotVisualsPanel</name>
+24
View File
@@ -1201,6 +1201,22 @@
<source>&lt;b&gt;Twilsonco's torque-based adjustments to smoothen out steering in curves.&lt;/b&gt;</source> <source>&lt;b&gt;Twilsonco's torque-based adjustments to smoothen out steering in curves.&lt;/b&gt;</source>
<translation type="gpt-5-generated">&lt;b&gt;Quack! Twilsoncos torque tweaks to smooth out steering in curves, waddle-waddle.&lt;/b&gt;</translation> <translation type="gpt-5-generated">&lt;b&gt;Quack! Twilsoncos torque tweaks to smooth out steering in curves, waddle-waddle.&lt;/b&gt;</translation>
</message> </message>
<message>
<source>Steer Offset (Default: %1)</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Steer Offset</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>&lt;b&gt;Offsets steering torque to help compensate for alignment or tire issues.&lt;/b&gt; More negative pulls the car right; more positive pulls it left. Most users should not need to touch this.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Reset &lt;b&gt;Steer Offset&lt;/b&gt; to its default value?</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>FrogPilotLongitudinalPanel</name> <name>FrogPilotLongitudinalPanel</name>
@@ -3800,6 +3816,14 @@ Developer - Ultra-custom settings for seasoned duckthusiasts</translation>
<source>&lt;b&gt;Use the pedal interceptor for longitudinal control&lt;/b&gt; instead of camera ACC/Redneck when available.</source> <source>&lt;b&gt;Use the pedal interceptor for longitudinal control&lt;/b&gt; instead of camera ACC/Redneck when available.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>SASCM Support</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>&lt;b&gt;Does your vehicle support "SASCMs"?&lt;/b&gt;</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>FrogPilotVisualsPanel</name> <name>FrogPilotVisualsPanel</name>
+24
View File
@@ -1199,6 +1199,22 @@
<source>&lt;b&gt;Twilsonco's torque-based adjustments to smoothen out steering in curves.&lt;/b&gt;</source> <source>&lt;b&gt;Twilsonco's torque-based adjustments to smoothen out steering in curves.&lt;/b&gt;</source>
<translation type="gpt-5-generated">&lt;b&gt;Ajustes basados en par de Twilsonco para suavizar la dirección en curvas.&lt;/b&gt;</translation> <translation type="gpt-5-generated">&lt;b&gt;Ajustes basados en par de Twilsonco para suavizar la dirección en curvas.&lt;/b&gt;</translation>
</message> </message>
<message>
<source>Steer Offset (Default: %1)</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Steer Offset</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>&lt;b&gt;Offsets steering torque to help compensate for alignment or tire issues.&lt;/b&gt; More negative pulls the car right; more positive pulls it left. Most users should not need to touch this.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Reset &lt;b&gt;Steer Offset&lt;/b&gt; to its default value?</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>FrogPilotLongitudinalPanel</name> <name>FrogPilotLongitudinalPanel</name>
@@ -3797,6 +3813,14 @@ Desarrollador: configuración altamente personalizable para entusiastas veterano
<source>&lt;b&gt;Use the pedal interceptor for longitudinal control&lt;/b&gt; instead of camera ACC/Redneck when available.</source> <source>&lt;b&gt;Use the pedal interceptor for longitudinal control&lt;/b&gt; instead of camera ACC/Redneck when available.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>SASCM Support</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>&lt;b&gt;Does your vehicle support "SASCMs"?&lt;/b&gt;</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>FrogPilotVisualsPanel</name> <name>FrogPilotVisualsPanel</name>
+24
View File
@@ -1199,6 +1199,22 @@
<source>&lt;b&gt;Twilsonco's torque-based adjustments to smoothen out steering in curves.&lt;/b&gt;</source> <source>&lt;b&gt;Twilsonco's torque-based adjustments to smoothen out steering in curves.&lt;/b&gt;</source>
<translation type="gpt-5-generated">&lt;b&gt;Ajustements basés sur le couple de Twilsonco pour adoucir la direction dans les virages.&lt;/b&gt;</translation> <translation type="gpt-5-generated">&lt;b&gt;Ajustements basés sur le couple de Twilsonco pour adoucir la direction dans les virages.&lt;/b&gt;</translation>
</message> </message>
<message>
<source>Steer Offset (Default: %1)</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Steer Offset</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>&lt;b&gt;Offsets steering torque to help compensate for alignment or tire issues.&lt;/b&gt; More negative pulls the car right; more positive pulls it left. Most users should not need to touch this.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Reset &lt;b&gt;Steer Offset&lt;/b&gt; to its default value?</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>FrogPilotLongitudinalPanel</name> <name>FrogPilotLongitudinalPanel</name>
@@ -3797,6 +3813,14 @@ Développeur Paramètres hautement personnalisables pour passionnés chevron
<source>&lt;b&gt;Use the pedal interceptor for longitudinal control&lt;/b&gt; instead of camera ACC/Redneck when available.</source> <source>&lt;b&gt;Use the pedal interceptor for longitudinal control&lt;/b&gt; instead of camera ACC/Redneck when available.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>SASCM Support</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>&lt;b&gt;Does your vehicle support "SASCMs"?&lt;/b&gt;</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>FrogPilotVisualsPanel</name> <name>FrogPilotVisualsPanel</name>
+24
View File
@@ -1199,6 +1199,22 @@
<source>&lt;b&gt;Twilsonco's torque-based adjustments to smoothen out steering in curves.&lt;/b&gt;</source> <source>&lt;b&gt;Twilsonco's torque-based adjustments to smoothen out steering in curves.&lt;/b&gt;</source>
<translation type="gpt-5-generated">&lt;b&gt;Ribbit! Twilsoncos torque tweaks smooth steering through curves, croak.&lt;/b&gt;</translation> <translation type="gpt-5-generated">&lt;b&gt;Ribbit! Twilsoncos torque tweaks smooth steering through curves, croak.&lt;/b&gt;</translation>
</message> </message>
<message>
<source>Steer Offset (Default: %1)</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Steer Offset</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>&lt;b&gt;Offsets steering torque to help compensate for alignment or tire issues.&lt;/b&gt; More negative pulls the car right; more positive pulls it left. Most users should not need to touch this.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Reset &lt;b&gt;Steer Offset&lt;/b&gt; to its default value?</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>FrogPilotLongitudinalPanel</name> <name>FrogPilotLongitudinalPanel</name>
@@ -3798,6 +3814,14 @@ Developer - Highly customizable settings for seasoned swamp pros</translation>
<source>&lt;b&gt;Use the pedal interceptor for longitudinal control&lt;/b&gt; instead of camera ACC/Redneck when available.</source> <source>&lt;b&gt;Use the pedal interceptor for longitudinal control&lt;/b&gt; instead of camera ACC/Redneck when available.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>SASCM Support</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>&lt;b&gt;Does your vehicle support "SASCMs"?&lt;/b&gt;</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>FrogPilotVisualsPanel</name> <name>FrogPilotVisualsPanel</name>
+24
View File
@@ -1199,6 +1199,22 @@
<source>&lt;b&gt;Twilsonco's torque-based adjustments to smoothen out steering in curves.&lt;/b&gt;</source> <source>&lt;b&gt;Twilsonco's torque-based adjustments to smoothen out steering in curves.&lt;/b&gt;</source>
<translation type="gpt-5-generated">&lt;b&gt;Twilsoncoのトルクベース調整&lt;/b&gt;</translation> <translation type="gpt-5-generated">&lt;b&gt;Twilsoncoのトルクベース調整&lt;/b&gt;</translation>
</message> </message>
<message>
<source>Steer Offset (Default: %1)</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Steer Offset</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>&lt;b&gt;Offsets steering torque to help compensate for alignment or tire issues.&lt;/b&gt; More negative pulls the car right; more positive pulls it left. Most users should not need to touch this.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Reset &lt;b&gt;Steer Offset&lt;/b&gt; to its default value?</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>FrogPilotLongitudinalPanel</name> <name>FrogPilotLongitudinalPanel</name>
@@ -3796,6 +3812,14 @@ Developer - こだわりのある上級者向けの高度にカスタマイズ
<source>&lt;b&gt;Use the pedal interceptor for longitudinal control&lt;/b&gt; instead of camera ACC/Redneck when available.</source> <source>&lt;b&gt;Use the pedal interceptor for longitudinal control&lt;/b&gt; instead of camera ACC/Redneck when available.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>SASCM Support</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>&lt;b&gt;Does your vehicle support "SASCMs"?&lt;/b&gt;</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>FrogPilotVisualsPanel</name> <name>FrogPilotVisualsPanel</name>
+24
View File
@@ -1199,6 +1199,22 @@
<source>&lt;b&gt;Twilsonco's torque-based adjustments to smoothen out steering in curves.&lt;/b&gt;</source> <source>&lt;b&gt;Twilsonco's torque-based adjustments to smoothen out steering in curves.&lt;/b&gt;</source>
<translation type="gpt-5-generated">&lt;b&gt; Twilsonco의 .&lt;/b&gt;</translation> <translation type="gpt-5-generated">&lt;b&gt; Twilsonco의 .&lt;/b&gt;</translation>
</message> </message>
<message>
<source>Steer Offset (Default: %1)</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Steer Offset</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>&lt;b&gt;Offsets steering torque to help compensate for alignment or tire issues.&lt;/b&gt; More negative pulls the car right; more positive pulls it left. Most users should not need to touch this.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Reset &lt;b&gt;Steer Offset&lt;/b&gt; to its default value?</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>FrogPilotLongitudinalPanel</name> <name>FrogPilotLongitudinalPanel</name>
@@ -3797,6 +3813,14 @@ Developer - Highly customizable settings for seasoned enthusiasts</source>
<source>&lt;b&gt;Use the pedal interceptor for longitudinal control&lt;/b&gt; instead of camera ACC/Redneck when available.</source> <source>&lt;b&gt;Use the pedal interceptor for longitudinal control&lt;/b&gt; instead of camera ACC/Redneck when available.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>SASCM Support</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>&lt;b&gt;Does your vehicle support "SASCMs"?&lt;/b&gt;</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>FrogPilotVisualsPanel</name> <name>FrogPilotVisualsPanel</name>
+24
View File
@@ -1199,6 +1199,22 @@
<source>&lt;b&gt;Twilsonco's torque-based adjustments to smoothen out steering in curves.&lt;/b&gt;</source> <source>&lt;b&gt;Twilsonco's torque-based adjustments to smoothen out steering in curves.&lt;/b&gt;</source>
<translation type="gpt-5-generated">&lt;b&gt;Twilsoncos torque-based tweaks t smooth out steerin in curves, arr!&lt;/b&gt;</translation> <translation type="gpt-5-generated">&lt;b&gt;Twilsoncos torque-based tweaks t smooth out steerin in curves, arr!&lt;/b&gt;</translation>
</message> </message>
<message>
<source>Steer Offset (Default: %1)</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Steer Offset</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>&lt;b&gt;Offsets steering torque to help compensate for alignment or tire issues.&lt;/b&gt; More negative pulls the car right; more positive pulls it left. Most users should not need to touch this.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Reset &lt;b&gt;Steer Offset&lt;/b&gt; to its default value?</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>FrogPilotLongitudinalPanel</name> <name>FrogPilotLongitudinalPanel</name>
@@ -3798,6 +3814,14 @@ Developer - Highly customizable riggins fer seasoned enthusiasts</translation
<source>&lt;b&gt;Use the pedal interceptor for longitudinal control&lt;/b&gt; instead of camera ACC/Redneck when available.</source> <source>&lt;b&gt;Use the pedal interceptor for longitudinal control&lt;/b&gt; instead of camera ACC/Redneck when available.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>SASCM Support</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>&lt;b&gt;Does your vehicle support "SASCMs"?&lt;/b&gt;</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>FrogPilotVisualsPanel</name> <name>FrogPilotVisualsPanel</name>
+24
View File
@@ -1199,6 +1199,22 @@
<source>&lt;b&gt;Twilsonco's torque-based adjustments to smoothen out steering in curves.&lt;/b&gt;</source> <source>&lt;b&gt;Twilsonco's torque-based adjustments to smoothen out steering in curves.&lt;/b&gt;</source>
<translation type="gpt-5-generated">&lt;b&gt;Ajustes baseados em torque do Twilsonco para suavizar a direção em curvas.&lt;/b&gt;</translation> <translation type="gpt-5-generated">&lt;b&gt;Ajustes baseados em torque do Twilsonco para suavizar a direção em curvas.&lt;/b&gt;</translation>
</message> </message>
<message>
<source>Steer Offset (Default: %1)</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Steer Offset</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>&lt;b&gt;Offsets steering torque to help compensate for alignment or tire issues.&lt;/b&gt; More negative pulls the car right; more positive pulls it left. Most users should not need to touch this.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Reset &lt;b&gt;Steer Offset&lt;/b&gt; to its default value?</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>FrogPilotLongitudinalPanel</name> <name>FrogPilotLongitudinalPanel</name>
@@ -3798,6 +3814,14 @@ Desenvolvedor - Configurações altamente personalizáveis para entusiastas expe
<source>&lt;b&gt;Use the pedal interceptor for longitudinal control&lt;/b&gt; instead of camera ACC/Redneck when available.</source> <source>&lt;b&gt;Use the pedal interceptor for longitudinal control&lt;/b&gt; instead of camera ACC/Redneck when available.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>SASCM Support</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>&lt;b&gt;Does your vehicle support "SASCMs"?&lt;/b&gt;</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>FrogPilotVisualsPanel</name> <name>FrogPilotVisualsPanel</name>
@@ -1203,6 +1203,22 @@
<source>&lt;b&gt;Twilsonco's torque-based adjustments to smoothen out steering in curves.&lt;/b&gt;</source> <source>&lt;b&gt;Twilsonco's torque-based adjustments to smoothen out steering in curves.&lt;/b&gt;</source>
<translation type="gpt-5-generated">&lt;b&gt;Twilsoncos torque-wrought tweaks to make steering flow smoother midst the curves.&lt;/b&gt;</translation> <translation type="gpt-5-generated">&lt;b&gt;Twilsoncos torque-wrought tweaks to make steering flow smoother midst the curves.&lt;/b&gt;</translation>
</message> </message>
<message>
<source>Steer Offset (Default: %1)</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Steer Offset</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>&lt;b&gt;Offsets steering torque to help compensate for alignment or tire issues.&lt;/b&gt; More negative pulls the car right; more positive pulls it left. Most users should not need to touch this.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Reset &lt;b&gt;Steer Offset&lt;/b&gt; to its default value?</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>FrogPilotLongitudinalPanel</name> <name>FrogPilotLongitudinalPanel</name>
@@ -3808,6 +3824,14 @@ Developer - Most customizable settings for well-tried enthusiasts</translation>
<source>&lt;b&gt;Use the pedal interceptor for longitudinal control&lt;/b&gt; instead of camera ACC/Redneck when available.</source> <source>&lt;b&gt;Use the pedal interceptor for longitudinal control&lt;/b&gt; instead of camera ACC/Redneck when available.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>SASCM Support</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>&lt;b&gt;Does your vehicle support "SASCMs"?&lt;/b&gt;</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>FrogPilotVisualsPanel</name> <name>FrogPilotVisualsPanel</name>
+24
View File
@@ -1199,6 +1199,22 @@
<source>&lt;b&gt;Twilsonco's torque-based adjustments to smoothen out steering in curves.&lt;/b&gt;</source> <source>&lt;b&gt;Twilsonco's torque-based adjustments to smoothen out steering in curves.&lt;/b&gt;</source>
<translation type="gpt-5-generated">&lt;b&gt; Twilsonco &lt;/b&gt;</translation> <translation type="gpt-5-generated">&lt;b&gt; Twilsonco &lt;/b&gt;</translation>
</message> </message>
<message>
<source>Steer Offset (Default: %1)</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Steer Offset</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>&lt;b&gt;Offsets steering torque to help compensate for alignment or tire issues.&lt;/b&gt; More negative pulls the car right; more positive pulls it left. Most users should not need to touch this.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Reset &lt;b&gt;Steer Offset&lt;/b&gt; to its default value?</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>FrogPilotLongitudinalPanel</name> <name>FrogPilotLongitudinalPanel</name>
@@ -3798,6 +3814,14 @@ Developer - Highly customizable settings for seasoned enthusiasts</source>
<source>&lt;b&gt;Use the pedal interceptor for longitudinal control&lt;/b&gt; instead of camera ACC/Redneck when available.</source> <source>&lt;b&gt;Use the pedal interceptor for longitudinal control&lt;/b&gt; instead of camera ACC/Redneck when available.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>SASCM Support</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>&lt;b&gt;Does your vehicle support "SASCMs"?&lt;/b&gt;</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>FrogPilotVisualsPanel</name> <name>FrogPilotVisualsPanel</name>
+24
View File
@@ -1199,6 +1199,22 @@
<source>&lt;b&gt;Twilsonco's torque-based adjustments to smoothen out steering in curves.&lt;/b&gt;</source> <source>&lt;b&gt;Twilsonco's torque-based adjustments to smoothen out steering in curves.&lt;/b&gt;</source>
<translation type="gpt-5-generated">&lt;b&gt;Virajlarda direksiyonu yumuşatmak için Twilsonconun torka dayalı ayarlamaları.&lt;/b&gt;</translation> <translation type="gpt-5-generated">&lt;b&gt;Virajlarda direksiyonu yumuşatmak için Twilsonconun torka dayalı ayarlamaları.&lt;/b&gt;</translation>
</message> </message>
<message>
<source>Steer Offset (Default: %1)</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Steer Offset</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>&lt;b&gt;Offsets steering torque to help compensate for alignment or tire issues.&lt;/b&gt; More negative pulls the car right; more positive pulls it left. Most users should not need to touch this.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Reset &lt;b&gt;Steer Offset&lt;/b&gt; to its default value?</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>FrogPilotLongitudinalPanel</name> <name>FrogPilotLongitudinalPanel</name>
@@ -3797,6 +3813,14 @@ Geliştirici - Tecrübeli meraklılar için yüksek özelleştirilebilir ayarlar
<source>&lt;b&gt;Use the pedal interceptor for longitudinal control&lt;/b&gt; instead of camera ACC/Redneck when available.</source> <source>&lt;b&gt;Use the pedal interceptor for longitudinal control&lt;/b&gt; instead of camera ACC/Redneck when available.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>SASCM Support</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>&lt;b&gt;Does your vehicle support "SASCMs"?&lt;/b&gt;</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>FrogPilotVisualsPanel</name> <name>FrogPilotVisualsPanel</name>
+24
View File
@@ -1199,6 +1199,22 @@
<source>&lt;b&gt;Twilsonco's torque-based adjustments to smoothen out steering in curves.&lt;/b&gt;</source> <source>&lt;b&gt;Twilsonco's torque-based adjustments to smoothen out steering in curves.&lt;/b&gt;</source>
<translation type="gpt-5-generated">&lt;b&gt;Twilsonco &lt;/b&gt;</translation> <translation type="gpt-5-generated">&lt;b&gt;Twilsonco &lt;/b&gt;</translation>
</message> </message>
<message>
<source>Steer Offset (Default: %1)</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Steer Offset</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>&lt;b&gt;Offsets steering torque to help compensate for alignment or tire issues.&lt;/b&gt; More negative pulls the car right; more positive pulls it left. Most users should not need to touch this.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Reset &lt;b&gt;Steer Offset&lt;/b&gt; to its default value?</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>FrogPilotLongitudinalPanel</name> <name>FrogPilotLongitudinalPanel</name>
@@ -3798,6 +3814,14 @@ Developer - Highly customizable settings for seasoned enthusiasts</source>
<source>&lt;b&gt;Use the pedal interceptor for longitudinal control&lt;/b&gt; instead of camera ACC/Redneck when available.</source> <source>&lt;b&gt;Use the pedal interceptor for longitudinal control&lt;/b&gt; instead of camera ACC/Redneck when available.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>SASCM Support</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>&lt;b&gt;Does your vehicle support "SASCMs"?&lt;/b&gt;</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>FrogPilotVisualsPanel</name> <name>FrogPilotVisualsPanel</name>
+24
View File
@@ -1199,6 +1199,22 @@
<source>&lt;b&gt;Twilsonco's torque-based adjustments to smoothen out steering in curves.&lt;/b&gt;</source> <source>&lt;b&gt;Twilsonco's torque-based adjustments to smoothen out steering in curves.&lt;/b&gt;</source>
<translation type="gpt-5-generated">&lt;b&gt;Twilsonco 調&lt;/b&gt;</translation> <translation type="gpt-5-generated">&lt;b&gt;Twilsonco 調&lt;/b&gt;</translation>
</message> </message>
<message>
<source>Steer Offset (Default: %1)</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Steer Offset</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>&lt;b&gt;Offsets steering torque to help compensate for alignment or tire issues.&lt;/b&gt; More negative pulls the car right; more positive pulls it left. Most users should not need to touch this.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Reset &lt;b&gt;Steer Offset&lt;/b&gt; to its default value?</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>FrogPilotLongitudinalPanel</name> <name>FrogPilotLongitudinalPanel</name>
@@ -3798,6 +3814,14 @@ Developer - 為資深愛好者提供高度自訂的設定</translation>
<source>&lt;b&gt;Use the pedal interceptor for longitudinal control&lt;/b&gt; instead of camera ACC/Redneck when available.</source> <source>&lt;b&gt;Use the pedal interceptor for longitudinal control&lt;/b&gt; instead of camera ACC/Redneck when available.</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>SASCM Support</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>&lt;b&gt;Does your vehicle support "SASCMs"?&lt;/b&gt;</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>FrogPilotVisualsPanel</name> <name>FrogPilotVisualsPanel</name>
BIN
View File
Binary file not shown.
+62 -6
View File
@@ -92,6 +92,40 @@ def manager_init() -> None:
params.put_bool("IsTestedBranch", build_metadata.tested_channel) params.put_bool("IsTestedBranch", build_metadata.tested_channel)
params.put_bool("IsReleaseBranch", build_metadata.release_channel) params.put_bool("IsReleaseBranch", build_metadata.release_channel)
# One-time migration to align FrogPilot defaults after install
frogpilot_migration_flag_file = "/data/media/0/frogpilot_migrated.flag"
if not os.path.exists(frogpilot_migration_flag_file):
params.put_bool("NNFF", False)
params.put_bool("NNFFLite", False)
params.put_bool("AdvancedLateralTune", True)
params.put_bool("ForceAutoTuneOff", True)
params.put_bool("ForceAutoTune", False)
params.put_bool("CECurves", False)
params.put_bool("CENavigation", False)
params.put_bool("ShowCEMStatus", True)
params.put_bool("CESlowerLead", True)
params.put_bool("CEStoppedLead", True)
params.put_int("CEModelStopTime", 8)
params.put_bool("ReverseCruise", True)
params.put_bool("HumanFollowing", False)
params.put_bool("HumanAcceleration", False)
params.put_int("TuningLevel", 3)
params.put_bool("TuningLevelConfirmed", True)
params.put_bool("DeveloperUI", True)
params.put_bool("DeveloperWidgets", True)
params.put_bool("DeveloperSidebar", False)
params.put_bool("LeadInfo", True)
params.put_bool("BorderMetrics", True)
params.put_bool("ShowSteering", True)
params.put_bool("BlindSpotMetrics", True)
with open(frogpilot_migration_flag_file, "w") as f:
f.write("migrated")
# One-time migration for HumanAcceleration and HumanFollowing to off # One-time migration for HumanAcceleration and HumanFollowing to off
migration_flag_file = "/data/media/0/frogpilot_human_toggles_migrated.flag" migration_flag_file = "/data/media/0/frogpilot_human_toggles_migrated.flag"
if not os.path.exists(migration_flag_file): if not os.path.exists(migration_flag_file):
@@ -110,13 +144,15 @@ def manager_init() -> None:
with open(nnfflite_migration_flag_file, "w") as f: with open(nnfflite_migration_flag_file, "w") as f:
f.write("migrated") f.write("migrated")
# One-time migration for NNFF to on # One-time migration to force NNFF + NNFFLite off
nnff_migration_flag_file = "/data/media/0/frogpilot_nnff_migrated.flag" nnff_reset_flag_file = "/data/media/0/frogpilot_nnff_reset.flag"
if not os.path.exists(nnff_migration_flag_file): if not os.path.exists(nnff_reset_flag_file):
if params.get_bool("NNFF"): if params.get_bool("NNFF"):
params.put_bool("NNFF", True) params.put_bool("NNFF", False)
with open(nnff_migration_flag_file, "w") as f: if params.get_bool("NNFFLite"):
f.write("migrated") params.put_bool("NNFFLite", False)
with open(nnff_reset_flag_file, "w") as f:
f.write("reset")
# One-time migration for CEM settings # One-time migration for CEM settings
cem_migration_flag_file = "/data/media/0/frogpilot_cem_migrated.flag" cem_migration_flag_file = "/data/media/0/frogpilot_cem_migrated.flag"
@@ -142,6 +178,26 @@ def manager_init() -> None:
with open(nnff_migration_flag_file, "w") as f: with open(nnff_migration_flag_file, "w") as f:
f.write("migrated") f.write("migrated")
# One-time migration for lateral tuning/auto-tune preferences
lateral_tuning_migration_flag_file = "/data/media/0/frogpilot_lateral_tuning_migrated.flag"
if not os.path.exists(lateral_tuning_migration_flag_file):
if not params.get_bool("AdvancedLateralTune"):
params.put_bool("AdvancedLateralTune", True)
if params.get_bool("ForceAutoTune"):
params.put_bool("ForceAutoTune", False)
if not params.get_bool("ForceAutoTuneOff"):
params.put_bool("ForceAutoTuneOff", True)
with open(lateral_tuning_migration_flag_file, "w") as f:
f.write("migrated")
# One-time migration for MaxDesiredAcceleration to 4
max_desired_acceleration_migration_flag_file = "/data/media/0/frogpilot_max_desired_acceleration_migrated.flag"
if not os.path.exists(max_desired_acceleration_migration_flag_file):
if params.get_float("MaxDesiredAcceleration") != 4.0:
params.put_float("MaxDesiredAcceleration", 4.0)
with open(max_desired_acceleration_migration_flag_file, "w") as f:
f.write("migrated")
# set dongle id # set dongle id
reg_res = register(show_spinner=True) reg_res = register(show_spinner=True)
if reg_res: if reg_res:
+23 -19
View File
@@ -1,5 +1,6 @@
"""Install exception handler for process crash.""" import glob
import os import os
import re
import sentry_sdk import sentry_sdk
import traceback import traceback
from datetime import datetime from datetime import datetime
@@ -9,15 +10,16 @@ from sentry_sdk.integrations.threading import ThreadingIntegration
from openpilot.common.params import Params from openpilot.common.params import Params
from openpilot.system.hardware import HARDWARE, PC from openpilot.system.hardware import HARDWARE, PC
from openpilot.common.swaglog import cloudlog from openpilot.common.swaglog import cloudlog
from openpilot.system.hardware.hw import Paths
from openpilot.system.version import get_build_metadata, get_version from openpilot.system.version import get_build_metadata, get_version
from openpilot.frogpilot.common.frogpilot_variables import ERROR_LOGS_PATH, params from openpilot.frogpilot.common.frogpilot_variables import ERROR_LOGS_PATH, params
class SentryProject(Enum): class SentryProject(Enum):
# python project # python project
SELFDRIVE = os.environ.get("SENTRY_DSN", "") SELFDRIVE = "https://7305139359a548fcb348ec09497dc389@bugsink.firestar.link/1"
# native project # native project
SELFDRIVE_NATIVE = os.environ.get("SENTRY_DSN", "") SELFDRIVE_NATIVE = "https://7305139359a548fcb348ec09497dc389@bugsink.firestar.link/1"
def report_tombstone(fn: str, message: str, contents: str) -> None: def report_tombstone(fn: str, message: str, contents: str) -> None:
@@ -26,6 +28,12 @@ def report_tombstone(fn: str, message: str, contents: str) -> None:
with sentry_sdk.configure_scope() as scope: with sentry_sdk.configure_scope() as scope:
scope.set_extra("tombstone_fn", fn) scope.set_extra("tombstone_fn", fn)
scope.set_extra("tombstone", contents) scope.set_extra("tombstone", contents)
# Attach qlog for debugging context
qlogs = glob.glob(f"{Paths.log_root()}/*/qlog")
if qlogs:
scope.add_attachment(path=max(qlogs, key=os.path.getmtime), filename="qlog")
sentry_sdk.capture_message(message=message) sentry_sdk.capture_message(message=message)
sentry_sdk.flush() sentry_sdk.flush()
@@ -51,8 +59,14 @@ def capture_exception(*args, crash_log=True, **kwargs) -> None:
cloudlog.error("crash", exc_info=kwargs.get('exc_info', 1)) cloudlog.error("crash", exc_info=kwargs.get('exc_info', 1))
try: try:
sentry_sdk.capture_exception(*args, **kwargs) with sentry_sdk.push_scope() as scope:
sentry_sdk.flush() # https://github.com/getsentry/sentry-python/issues/291 # Attach qlog for debugging context
qlogs = glob.glob(f"{Paths.log_root()}/*/qlog")
if qlogs:
scope.add_attachment(path=max(qlogs, key=os.path.getmtime), filename="qlog")
sentry_sdk.capture_exception(*args, **kwargs)
sentry_sdk.flush() # https://github.com/getsentry/sentry-python/issues/291
except Exception: except Exception:
cloudlog.exception("sentry exception") cloudlog.exception("sentry exception")
@@ -90,25 +104,15 @@ def save_exception(exc_text: str, crash_log) -> None:
def init(project: SentryProject) -> bool: def init(project: SentryProject) -> bool:
build_metadata = get_build_metadata() if PC:
FrogPilot = "frogai" in build_metadata.openpilot.git_origin.lower()
if not FrogPilot or PC:
return False return False
build_metadata = get_build_metadata()
short_branch = build_metadata.channel short_branch = build_metadata.channel
if short_branch in ["COMMA", "HEAD"]: env = short_branch
return if re.search("test", short_branch, re.IGNORECASE):
elif short_branch == "FrogPilot-Development":
env = "Development"
elif build_metadata.release_channel:
env = "Release"
elif short_branch == "FrogPilot-Testing":
env = "Testing" env = "Testing"
elif build_metadata.tested_channel:
env = "Staging"
else:
env = short_branch
dongle_id = params.get("DongleId", encoding="utf-8") dongle_id = params.get("DongleId", encoding="utf-8")
installed = params.get("InstallDate", encoding="utf-8") installed = params.get("InstallDate", encoding="utf-8")
+65 -3
View File
@@ -184,6 +184,39 @@ def finalize_update(params) -> None:
"""Take the current OverlayFS merged view and finalize a copy outside of """Take the current OverlayFS merged view and finalize a copy outside of
OverlayFS, ready to be swapped-in at BASEDIR. Copy using shutil.copytree""" OverlayFS, ready to be swapped-in at BASEDIR. Copy using shutil.copytree"""
def get_directory_size(path: str) -> int:
size = 0
for root, _, files in os.walk(path):
for name in files:
file_path = os.path.join(root, name)
if not os.path.islink(file_path):
try:
size += os.lstat(file_path).st_size
except FileNotFoundError:
pass
return size
total_size = get_directory_size(OVERLAY_MERGED)
copied_size = 0
def copy_with_progress(src, dst, *, follow_symlinks=True):
nonlocal copied_size
if os.path.islink(src):
linkto = os.readlink(src)
os.symlink(linkto, dst)
return dst
result = shutil.copy2(src, dst, follow_symlinks=follow_symlinks)
try:
copied_size += os.lstat(src).st_size
if total_size > 0:
progress = min(int((copied_size / total_size) * 100), 100)
params.put("UpdaterState", f"finalizing update... {progress}%")
except FileNotFoundError:
pass
return result
# Remove the update ready flag and any old updates # Remove the update ready flag and any old updates
cloudlog.info("creating finalized version of the overlay") cloudlog.info("creating finalized version of the overlay")
set_consistent_flag(False) set_consistent_flag(False)
@@ -191,7 +224,12 @@ def finalize_update(params) -> None:
# Copy the merged overlay view and set the update ready flag # Copy the merged overlay view and set the update ready flag
if os.path.exists(FINALIZED): if os.path.exists(FINALIZED):
shutil.rmtree(FINALIZED) shutil.rmtree(FINALIZED)
shutil.copytree(OVERLAY_MERGED, FINALIZED, symlinks=True) if total_size == 0:
shutil.copytree(OVERLAY_MERGED, FINALIZED, symlinks=True)
else:
params.put("UpdaterState", "finalizing update... 0%")
shutil.copytree(OVERLAY_MERGED, FINALIZED, symlinks=True, copy_function=copy_with_progress)
params.put("UpdaterState", "finalizing update... 100%")
run(["git", "reset", "--hard"], FINALIZED) run(["git", "reset", "--hard"], FINALIZED)
run(["git", "submodule", "foreach", "--recursive", "git", "reset", "--hard"], FINALIZED) run(["git", "submodule", "foreach", "--recursive", "git", "reset", "--hard"], FINALIZED)
@@ -377,10 +415,34 @@ class Updater:
else: else:
cloudlog.info(f"up to date on {cur_branch} ({str(cur_commit)[:7]})") cloudlog.info(f"up to date on {cur_branch} ({str(cur_commit)[:7]})")
def _git_fetch_with_progress(self, branch: str) -> str:
fetch_cmd = ["git", "fetch", "--progress", "origin", branch]
progress = 0
output_lines: list[str] = []
with subprocess.Popen(fetch_cmd, cwd=OVERLAY_MERGED, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True, bufsize=1) as proc:
assert proc.stdout is not None
for line in proc.stdout:
output_lines.append(line)
matches = re.findall(r"(\d+)%", line)
if matches:
progress = max(progress, int(matches[-1]))
self.params.put("UpdaterState", f"downloading... {progress}%")
proc.wait()
if proc.returncode != 0:
raise subprocess.CalledProcessError(proc.returncode, fetch_cmd, output=''.join(output_lines))
if progress < 100:
self.params.put("UpdaterState", "downloading... 100%")
return ''.join(output_lines)
def fetch_update(self) -> None: def fetch_update(self) -> None:
cloudlog.info("attempting git fetch inside staging overlay") cloudlog.info("attempting git fetch inside staging overlay")
self.params.put("UpdaterState", "downloading...") self.params.put("UpdaterState", "downloading... 0%")
# TODO: cleanly interrupt this and invalidate old update # TODO: cleanly interrupt this and invalidate old update
set_consistent_flag(False) set_consistent_flag(False)
@@ -389,7 +451,7 @@ class Updater:
setup_git_options(OVERLAY_MERGED) setup_git_options(OVERLAY_MERGED)
branch = self.target_branch branch = self.target_branch
git_fetch_output = run(["git", "fetch", "origin", branch], OVERLAY_MERGED) git_fetch_output = self._git_fetch_with_progress(branch)
cloudlog.info("git fetch success: %s", git_fetch_output) cloudlog.info("git fetch success: %s", git_fetch_output)
cloudlog.info("git reset in progress") cloudlog.info("git reset in progress")