mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-08-26 18:53:44 +08:00
Compare commits
92 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0d22009343 | |||
| efa430bf4d | |||
| d90b2a6342 | |||
| d7839b2d08 | |||
| f590e27735 | |||
| 66d56cae79 | |||
| ac91a5762d | |||
| 4138d33a14 | |||
| fd8ff076b7 | |||
| fe3aaa017a | |||
| 7021e377a2 | |||
| 0c5a7b58f8 | |||
| ecaf1e278a | |||
| 0364574b0a | |||
| 0ecfebfcdb | |||
| 93af0e0450 | |||
| 0e7b41f5ac | |||
| 3ed579f39e | |||
| 27803113e9 | |||
| 7c3a5599ee | |||
| ba7df481de | |||
| 23b415ca73 | |||
| 7616edc8e2 | |||
| 745673879c | |||
| 7198e296b4 | |||
| 2583f7e014 | |||
| e8e2bf5580 | |||
| 9cfbfacf34 | |||
| 9164e75bf8 | |||
| 4c125d40d5 | |||
| 833bea5bcd | |||
| 2c76c2ff6e | |||
| 652c7e9cf7 | |||
| 27dfba30d6 | |||
| 060cc825cb | |||
| 37e26c57da | |||
| e74c0dfe46 | |||
| 8efc228063 | |||
| 11774e1961 | |||
| c1ccb837c1 | |||
| 28f9c6c917 | |||
| 3d7ce5237b | |||
| 750638ac6a | |||
| 125746589a | |||
| 4b65a4dd4d | |||
| d08cdc7cfe | |||
| ee4d07fd61 | |||
| 29e7fb3cef | |||
| 31e50774a5 | |||
| aef9f61240 | |||
| 50a3d544d4 | |||
| b07d455a77 | |||
| faa01306ce | |||
| a4ab9d7d59 | |||
| c862021fbb | |||
| 1d65b32500 | |||
| 0f3b1c4ed1 | |||
| 0642960c0c | |||
| da473770b1 | |||
| 4a2379714c | |||
| 390717786a | |||
| 4c8e81470c | |||
| 70aaa9a1b8 | |||
| 434c283eb3 | |||
| be37e0443b | |||
| 92183fc007 | |||
| bff349c9d0 | |||
| 051029ee93 | |||
| c921013474 | |||
| 901d0c7fa9 | |||
| 7956d4f702 | |||
| e5b32259d8 | |||
| be0a836307 | |||
| fa8b5c3656 | |||
| 32d021bef3 | |||
| eb902a609f | |||
| 717d94048b | |||
| e0b78a9b64 | |||
| 9292b81de0 | |||
| bf67329ae0 | |||
| 790daa8505 | |||
| 0d352b3e36 | |||
| 4f817a555e | |||
| 0fd2c9441b | |||
| 9951cbf587 | |||
| 40084af0c1 | |||
| 5e568fffb4 | |||
| 754ff86b50 | |||
| 9ff058110e | |||
| 91ec00b71e | |||
| 690e5c3a9d | |||
| 1aee027d2f |
+3
-2
@@ -532,11 +532,12 @@ struct CarParams {
|
||||
useSteeringAngle @0 :Bool;
|
||||
kp @1 :Float32;
|
||||
ki @2 :Float32;
|
||||
kd @8 : Float32;
|
||||
friction @3 :Float32;
|
||||
kf @4 :Float32;
|
||||
steeringAngleDeadzoneDeg @5 :Float32;
|
||||
latAccelFactor @6 :Float32;
|
||||
latAccelOffset @7 :Float32;
|
||||
kfDEPRECATED @4 :Float32;
|
||||
}
|
||||
|
||||
struct LongitudinalPIDTuning {
|
||||
@@ -544,7 +545,7 @@ struct CarParams {
|
||||
kpV @1 :List(Float32);
|
||||
kiBP @2 :List(Float32);
|
||||
kiV @3 :List(Float32);
|
||||
kf @6 :Float32;
|
||||
kfDEPRECATED @6 :Float32;
|
||||
deadzoneBP @4 :List(Float32);
|
||||
deadzoneV @5 :List(Float32);
|
||||
}
|
||||
|
||||
+30
-33
@@ -105,11 +105,7 @@ struct FrogPilotCarParams @0xf35cc4560bbf6ec2 {
|
||||
isHDA2 @3 :Bool;
|
||||
openpilotLongitudinalControlDisabled @4 :Bool;
|
||||
safetyConfigs @5 :List(SafetyConfig);
|
||||
|
||||
lateralTuning :union {
|
||||
pid @6 :Car.CarParams.LateralPIDTuning;
|
||||
torque @7 :Car.CarParams.LateralTorqueTuning;
|
||||
}
|
||||
canUseSASCM @6 :Bool;
|
||||
|
||||
struct SafetyConfig {
|
||||
safetyParam @0 :UInt16;
|
||||
@@ -193,34 +189,35 @@ struct FrogPilotPlan @0xa1680744031fdb2d {
|
||||
cscTraining @4 :Bool;
|
||||
dangerJerk @5 :Float32;
|
||||
desiredFollowDistance @6 :Int64;
|
||||
experimentalMode @7 :Bool;
|
||||
forcingStop @8 :Bool;
|
||||
forcingStopLength @9 :Float32;
|
||||
frogpilotEvents @10 :List(FrogPilotCarEvent);
|
||||
increasedStoppedDistance @11 :Float32;
|
||||
lateralCheck @12 :Bool;
|
||||
laneWidthLeft @13 :Float32;
|
||||
laneWidthRight @14 :Float32;
|
||||
maxAcceleration @15 :Float32;
|
||||
minAcceleration @16 :Float32;
|
||||
redLight @17 :Bool;
|
||||
roadCurvature @18 :Float32;
|
||||
slcMapSpeedLimit @19 :Float32;
|
||||
slcMapboxSpeedLimit @20 :Float32;
|
||||
slcNextSpeedLimit @21 :Float32;
|
||||
slcOverriddenSpeed @22 :Float32;
|
||||
slcSpeedLimit @23 :Float32;
|
||||
slcSpeedLimitOffset @24 :Float32;
|
||||
slcSpeedLimitSource @25 :Text;
|
||||
speedJerk @26 :Float32;
|
||||
speedJerkStock @27 :Float32;
|
||||
speedLimitChanged @28 :Bool;
|
||||
tFollow @29 :Float32;
|
||||
themeUpdated @30 :Bool;
|
||||
togglesUpdated @31 :Bool;
|
||||
trackingLead @32 :Bool;
|
||||
unconfirmedSlcSpeedLimit @33 :Float32;
|
||||
vCruise @34 :Float32;
|
||||
disableThrottle @7 :Bool;
|
||||
experimentalMode @8 :Bool;
|
||||
forcingStop @9 :Bool;
|
||||
forcingStopLength @10 :Float32;
|
||||
frogpilotEvents @11 :List(FrogPilotCarEvent);
|
||||
increasedStoppedDistance @12 :Float32;
|
||||
lateralCheck @13 :Bool;
|
||||
laneWidthLeft @14 :Float32;
|
||||
laneWidthRight @15 :Float32;
|
||||
maxAcceleration @16 :Float32;
|
||||
minAcceleration @17 :Float32;
|
||||
redLight @18 :Bool;
|
||||
roadCurvature @19 :Float32;
|
||||
slcMapSpeedLimit @20 :Float32;
|
||||
slcMapboxSpeedLimit @21 :Float32;
|
||||
slcNextSpeedLimit @22 :Float32;
|
||||
slcOverriddenSpeed @23 :Float32;
|
||||
slcSpeedLimit @24 :Float32;
|
||||
slcSpeedLimitOffset @25 :Float32;
|
||||
slcSpeedLimitSource @26 :Text;
|
||||
speedJerk @27 :Float32;
|
||||
speedJerkStock @28 :Float32;
|
||||
speedLimitChanged @29 :Bool;
|
||||
tFollow @30 :Float32;
|
||||
themeUpdated @31 :Bool;
|
||||
togglesUpdated @32 :Bool;
|
||||
trackingLead @33 :Bool;
|
||||
unconfirmedSlcSpeedLimit @34 :Float32;
|
||||
vCruise @35 :Float32;
|
||||
}
|
||||
|
||||
struct FrogPilotRadarState @0xcb9fd56c7057593a {
|
||||
|
||||
@@ -5262,17 +5262,17 @@ const ::capnp::_::RawSchema s_9622723fcbd14c2e = {
|
||||
0, 5, i_9622723fcbd14c2e, nullptr, nullptr, { &s_9622723fcbd14c2e, nullptr, nullptr, 0, 0, nullptr }, false
|
||||
};
|
||||
#endif // !CAPNP_LITE
|
||||
static const ::capnp::_::AlignedData<147> b_80366e0e804ecc1d = {
|
||||
static const ::capnp::_::AlignedData<163> b_80366e0e804ecc1d = {
|
||||
{ 0, 0, 0, 0, 5, 0, 6, 0,
|
||||
29, 204, 78, 128, 14, 110, 54, 128,
|
||||
20, 0, 0, 0, 1, 0, 4, 0,
|
||||
20, 0, 0, 0, 1, 0, 5, 0,
|
||||
218, 169, 170, 144, 36, 55, 105, 140,
|
||||
0, 0, 7, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
21, 0, 0, 0, 66, 1, 0, 0,
|
||||
37, 0, 0, 0, 7, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
33, 0, 0, 0, 199, 1, 0, 0,
|
||||
33, 0, 0, 0, 255, 1, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
99, 97, 114, 46, 99, 97, 112, 110,
|
||||
@@ -5281,63 +5281,70 @@ static const ::capnp::_::AlignedData<147> b_80366e0e804ecc1d = {
|
||||
114, 97, 108, 84, 111, 114, 113, 117,
|
||||
101, 84, 117, 110, 105, 110, 103, 0,
|
||||
0, 0, 0, 0, 1, 0, 1, 0,
|
||||
32, 0, 0, 0, 3, 0, 4, 0,
|
||||
36, 0, 0, 0, 3, 0, 4, 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,
|
||||
209, 0, 0, 0, 138, 0, 0, 0,
|
||||
237, 0, 0, 0, 138, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
212, 0, 0, 0, 3, 0, 1, 0,
|
||||
224, 0, 0, 0, 2, 0, 1, 0,
|
||||
240, 0, 0, 0, 3, 0, 1, 0,
|
||||
252, 0, 0, 0, 2, 0, 1, 0,
|
||||
1, 0, 0, 0, 1, 0, 0, 0,
|
||||
0, 0, 1, 0, 1, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
221, 0, 0, 0, 26, 0, 0, 0,
|
||||
249, 0, 0, 0, 26, 0, 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,
|
||||
244, 0, 0, 0, 3, 0, 1, 0,
|
||||
0, 1, 0, 0, 2, 0, 1, 0,
|
||||
2, 0, 0, 0, 2, 0, 0, 0,
|
||||
0, 0, 1, 0, 2, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
225, 0, 0, 0, 26, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
220, 0, 0, 0, 3, 0, 1, 0,
|
||||
232, 0, 0, 0, 2, 0, 1, 0,
|
||||
3, 0, 0, 0, 3, 0, 0, 0,
|
||||
0, 0, 1, 0, 3, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
229, 0, 0, 0, 74, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
228, 0, 0, 0, 3, 0, 1, 0,
|
||||
240, 0, 0, 0, 2, 0, 1, 0,
|
||||
4, 0, 0, 0, 4, 0, 0, 0,
|
||||
0, 0, 1, 0, 4, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
237, 0, 0, 0, 26, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
232, 0, 0, 0, 3, 0, 1, 0,
|
||||
244, 0, 0, 0, 2, 0, 1, 0,
|
||||
5, 0, 0, 0, 5, 0, 0, 0,
|
||||
0, 0, 1, 0, 5, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
241, 0, 0, 0, 202, 0, 0, 0,
|
||||
253, 0, 0, 0, 26, 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,
|
||||
6, 0, 0, 0, 6, 0, 0, 0,
|
||||
0, 0, 1, 0, 6, 0, 0, 0,
|
||||
4, 0, 0, 0, 3, 0, 0, 0,
|
||||
0, 0, 1, 0, 3, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 1, 0, 0, 122, 0, 0, 0,
|
||||
1, 1, 0, 0, 74, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 1, 0, 0, 3, 0, 1, 0,
|
||||
12, 1, 0, 0, 2, 0, 1, 0,
|
||||
7, 0, 0, 0, 7, 0, 0, 0,
|
||||
0, 0, 1, 0, 7, 0, 0, 0,
|
||||
8, 0, 0, 0, 4, 0, 0, 0,
|
||||
0, 0, 1, 0, 4, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
9, 1, 0, 0, 122, 0, 0, 0,
|
||||
9, 1, 0, 0, 106, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
8, 1, 0, 0, 3, 0, 1, 0,
|
||||
20, 1, 0, 0, 2, 0, 1, 0,
|
||||
5, 0, 0, 0, 5, 0, 0, 0,
|
||||
0, 0, 1, 0, 5, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
17, 1, 0, 0, 202, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
24, 1, 0, 0, 3, 0, 1, 0,
|
||||
36, 1, 0, 0, 2, 0, 1, 0,
|
||||
6, 0, 0, 0, 6, 0, 0, 0,
|
||||
0, 0, 1, 0, 6, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
33, 1, 0, 0, 122, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
32, 1, 0, 0, 3, 0, 1, 0,
|
||||
44, 1, 0, 0, 2, 0, 1, 0,
|
||||
7, 0, 0, 0, 7, 0, 0, 0,
|
||||
0, 0, 1, 0, 7, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
41, 1, 0, 0, 122, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
40, 1, 0, 0, 3, 0, 1, 0,
|
||||
52, 1, 0, 0, 2, 0, 1, 0,
|
||||
3, 0, 0, 0, 8, 0, 0, 0,
|
||||
0, 0, 1, 0, 8, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
49, 1, 0, 0, 26, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
44, 1, 0, 0, 3, 0, 1, 0,
|
||||
56, 1, 0, 0, 2, 0, 1, 0,
|
||||
117, 115, 101, 83, 116, 101, 101, 114,
|
||||
105, 110, 103, 65, 110, 103, 108, 101,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
@@ -5373,7 +5380,8 @@ static const ::capnp::_::AlignedData<147> b_80366e0e804ecc1d = {
|
||||
10, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
107, 102, 0, 0, 0, 0, 0, 0,
|
||||
107, 102, 68, 69, 80, 82, 69, 67,
|
||||
65, 84, 69, 68, 0, 0, 0, 0,
|
||||
10, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
@@ -5403,6 +5411,14 @@ static const ::capnp::_::AlignedData<147> b_80366e0e804ecc1d = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
108, 97, 116, 65, 99, 99, 101, 108,
|
||||
79, 102, 102, 115, 101, 116, 0, 0,
|
||||
10, 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,
|
||||
10, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
107, 100, 0, 0, 0, 0, 0, 0,
|
||||
10, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
@@ -5413,14 +5429,14 @@ static const ::capnp::_::AlignedData<147> b_80366e0e804ecc1d = {
|
||||
};
|
||||
::capnp::word const* const bp_80366e0e804ecc1d = b_80366e0e804ecc1d.words;
|
||||
#if !CAPNP_LITE
|
||||
static const uint16_t m_80366e0e804ecc1d[] = {3, 4, 2, 1, 6, 7, 5, 0};
|
||||
static const uint16_t i_80366e0e804ecc1d[] = {0, 1, 2, 3, 4, 5, 6, 7};
|
||||
static const uint16_t m_80366e0e804ecc1d[] = {3, 8, 4, 2, 1, 6, 7, 5, 0};
|
||||
static const uint16_t i_80366e0e804ecc1d[] = {0, 1, 2, 3, 4, 5, 6, 7, 8};
|
||||
const ::capnp::_::RawSchema s_80366e0e804ecc1d = {
|
||||
0x80366e0e804ecc1d, b_80366e0e804ecc1d.words, 147, nullptr, m_80366e0e804ecc1d,
|
||||
0, 8, i_80366e0e804ecc1d, nullptr, nullptr, { &s_80366e0e804ecc1d, nullptr, nullptr, 0, 0, nullptr }, false
|
||||
0x80366e0e804ecc1d, b_80366e0e804ecc1d.words, 163, nullptr, m_80366e0e804ecc1d,
|
||||
0, 9, i_80366e0e804ecc1d, nullptr, nullptr, { &s_80366e0e804ecc1d, nullptr, nullptr, 0, 0, nullptr }, false
|
||||
};
|
||||
#endif // !CAPNP_LITE
|
||||
static const ::capnp::_::AlignedData<151> b_c342cefc303e9b8e = {
|
||||
static const ::capnp::_::AlignedData<152> b_c342cefc303e9b8e = {
|
||||
{ 0, 0, 0, 0, 5, 0, 6, 0,
|
||||
142, 155, 62, 48, 252, 206, 66, 195,
|
||||
20, 0, 0, 0, 1, 0, 1, 0,
|
||||
@@ -5486,10 +5502,10 @@ static const ::capnp::_::AlignedData<151> b_c342cefc303e9b8e = {
|
||||
4, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 1, 0, 6, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
53, 1, 0, 0, 26, 0, 0, 0,
|
||||
53, 1, 0, 0, 106, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
48, 1, 0, 0, 3, 0, 1, 0,
|
||||
60, 1, 0, 0, 2, 0, 1, 0,
|
||||
52, 1, 0, 0, 3, 0, 1, 0,
|
||||
64, 1, 0, 0, 2, 0, 1, 0,
|
||||
107, 112, 66, 80, 0, 0, 0, 0,
|
||||
14, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
@@ -5564,7 +5580,8 @@ static const ::capnp::_::AlignedData<151> b_c342cefc303e9b8e = {
|
||||
14, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
107, 102, 0, 0, 0, 0, 0, 0,
|
||||
107, 102, 68, 69, 80, 82, 69, 67,
|
||||
65, 84, 69, 68, 0, 0, 0, 0,
|
||||
10, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
@@ -5578,7 +5595,7 @@ static const ::capnp::_::AlignedData<151> b_c342cefc303e9b8e = {
|
||||
static const uint16_t m_c342cefc303e9b8e[] = {4, 5, 6, 2, 3, 0, 1};
|
||||
static const uint16_t i_c342cefc303e9b8e[] = {0, 1, 2, 3, 4, 5, 6};
|
||||
const ::capnp::_::RawSchema s_c342cefc303e9b8e = {
|
||||
0xc342cefc303e9b8e, b_c342cefc303e9b8e.words, 151, nullptr, m_c342cefc303e9b8e,
|
||||
0xc342cefc303e9b8e, b_c342cefc303e9b8e.words, 152, nullptr, m_c342cefc303e9b8e,
|
||||
0, 7, i_c342cefc303e9b8e, nullptr, nullptr, { &s_c342cefc303e9b8e, nullptr, nullptr, 0, 0, nullptr }, false
|
||||
};
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
+32
-13
@@ -626,7 +626,7 @@ struct CarParams::LateralTorqueTuning {
|
||||
class Pipeline;
|
||||
|
||||
struct _capnpPrivate {
|
||||
CAPNP_DECLARE_STRUCT_HEADER(80366e0e804ecc1d, 4, 0)
|
||||
CAPNP_DECLARE_STRUCT_HEADER(80366e0e804ecc1d, 5, 0)
|
||||
#if !CAPNP_LITE
|
||||
static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; }
|
||||
#endif // !CAPNP_LITE
|
||||
@@ -3140,7 +3140,7 @@ public:
|
||||
|
||||
inline float getFriction() const;
|
||||
|
||||
inline float getKf() const;
|
||||
inline float getKfDEPRECATED() const;
|
||||
|
||||
inline float getSteeringAngleDeadzoneDeg() const;
|
||||
|
||||
@@ -3148,6 +3148,8 @@ public:
|
||||
|
||||
inline float getLatAccelOffset() const;
|
||||
|
||||
inline float getKd() const;
|
||||
|
||||
private:
|
||||
::capnp::_::StructReader _reader;
|
||||
template <typename, ::capnp::Kind>
|
||||
@@ -3188,8 +3190,8 @@ public:
|
||||
inline float getFriction();
|
||||
inline void setFriction(float value);
|
||||
|
||||
inline float getKf();
|
||||
inline void setKf(float value);
|
||||
inline float getKfDEPRECATED();
|
||||
inline void setKfDEPRECATED(float value);
|
||||
|
||||
inline float getSteeringAngleDeadzoneDeg();
|
||||
inline void setSteeringAngleDeadzoneDeg(float value);
|
||||
@@ -3200,6 +3202,9 @@ public:
|
||||
inline float getLatAccelOffset();
|
||||
inline void setLatAccelOffset(float value);
|
||||
|
||||
inline float getKd();
|
||||
inline void setKd(float value);
|
||||
|
||||
private:
|
||||
::capnp::_::StructBuilder _builder;
|
||||
template <typename, ::capnp::Kind>
|
||||
@@ -3261,7 +3266,7 @@ public:
|
||||
inline bool hasDeadzoneV() const;
|
||||
inline ::capnp::List<float, ::capnp::Kind::PRIMITIVE>::Reader getDeadzoneV() const;
|
||||
|
||||
inline float getKf() const;
|
||||
inline float getKfDEPRECATED() const;
|
||||
|
||||
private:
|
||||
::capnp::_::StructReader _reader;
|
||||
@@ -3339,8 +3344,8 @@ public:
|
||||
inline void adoptDeadzoneV(::capnp::Orphan< ::capnp::List<float, ::capnp::Kind::PRIMITIVE>>&& value);
|
||||
inline ::capnp::Orphan< ::capnp::List<float, ::capnp::Kind::PRIMITIVE>> disownDeadzoneV();
|
||||
|
||||
inline float getKf();
|
||||
inline void setKf(float value);
|
||||
inline float getKfDEPRECATED();
|
||||
inline void setKfDEPRECATED(float value);
|
||||
|
||||
private:
|
||||
::capnp::_::StructBuilder _builder;
|
||||
@@ -7791,16 +7796,16 @@ inline void CarParams::LateralTorqueTuning::Builder::setFriction(float value) {
|
||||
::capnp::bounded<3>() * ::capnp::ELEMENTS, value);
|
||||
}
|
||||
|
||||
inline float CarParams::LateralTorqueTuning::Reader::getKf() const {
|
||||
inline float CarParams::LateralTorqueTuning::Reader::getKfDEPRECATED() const {
|
||||
return _reader.getDataField<float>(
|
||||
::capnp::bounded<4>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
|
||||
inline float CarParams::LateralTorqueTuning::Builder::getKf() {
|
||||
inline float CarParams::LateralTorqueTuning::Builder::getKfDEPRECATED() {
|
||||
return _builder.getDataField<float>(
|
||||
::capnp::bounded<4>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
inline void CarParams::LateralTorqueTuning::Builder::setKf(float value) {
|
||||
inline void CarParams::LateralTorqueTuning::Builder::setKfDEPRECATED(float value) {
|
||||
_builder.setDataField<float>(
|
||||
::capnp::bounded<4>() * ::capnp::ELEMENTS, value);
|
||||
}
|
||||
@@ -7847,6 +7852,20 @@ inline void CarParams::LateralTorqueTuning::Builder::setLatAccelOffset(float val
|
||||
::capnp::bounded<7>() * ::capnp::ELEMENTS, value);
|
||||
}
|
||||
|
||||
inline float CarParams::LateralTorqueTuning::Reader::getKd() const {
|
||||
return _reader.getDataField<float>(
|
||||
::capnp::bounded<8>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
|
||||
inline float CarParams::LateralTorqueTuning::Builder::getKd() {
|
||||
return _builder.getDataField<float>(
|
||||
::capnp::bounded<8>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
inline void CarParams::LateralTorqueTuning::Builder::setKd(float value) {
|
||||
_builder.setDataField<float>(
|
||||
::capnp::bounded<8>() * ::capnp::ELEMENTS, value);
|
||||
}
|
||||
|
||||
inline bool CarParams::LongitudinalPIDTuning::Reader::hasKpBP() const {
|
||||
return !_reader.getPointerField(
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS).isNull();
|
||||
@@ -8075,16 +8094,16 @@ inline ::capnp::Orphan< ::capnp::List<float, ::capnp::Kind::PRIMITIVE>> CarPara
|
||||
::capnp::bounded<5>() * ::capnp::POINTERS));
|
||||
}
|
||||
|
||||
inline float CarParams::LongitudinalPIDTuning::Reader::getKf() const {
|
||||
inline float CarParams::LongitudinalPIDTuning::Reader::getKfDEPRECATED() const {
|
||||
return _reader.getDataField<float>(
|
||||
::capnp::bounded<0>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
|
||||
inline float CarParams::LongitudinalPIDTuning::Builder::getKf() {
|
||||
inline float CarParams::LongitudinalPIDTuning::Builder::getKfDEPRECATED() {
|
||||
return _builder.getDataField<float>(
|
||||
::capnp::bounded<0>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
inline void CarParams::LongitudinalPIDTuning::Builder::setKf(float value) {
|
||||
inline void CarParams::LongitudinalPIDTuning::Builder::setKfDEPRECATED(float value) {
|
||||
_builder.setDataField<float>(
|
||||
::capnp::bounded<0>() * ::capnp::ELEMENTS, value);
|
||||
}
|
||||
|
||||
+197
-252
@@ -642,12 +642,12 @@ const ::capnp::_::RawSchema s_aedffd8f31e7b55d = {
|
||||
};
|
||||
#endif // !CAPNP_LITE
|
||||
CAPNP_DEFINE_ENUM(EventName_aedffd8f31e7b55d, aedffd8f31e7b55d);
|
||||
static const ::capnp::_::AlignedData<132> b_f35cc4560bbf6ec2 = {
|
||||
static const ::capnp::_::AlignedData<139> b_f35cc4560bbf6ec2 = {
|
||||
{ 0, 0, 0, 0, 5, 0, 6, 0,
|
||||
194, 110, 191, 11, 86, 196, 92, 243,
|
||||
13, 0, 0, 0, 1, 0, 1, 0,
|
||||
89, 10, 85, 29, 102, 186, 38, 181,
|
||||
2, 0, 7, 0, 0, 0, 0, 0,
|
||||
1, 0, 7, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
21, 0, 0, 0, 2, 1, 0, 0,
|
||||
33, 0, 0, 0, 23, 0, 0, 0,
|
||||
@@ -707,13 +707,13 @@ static const ::capnp::_::AlignedData<132> b_f35cc4560bbf6ec2 = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
224, 0, 0, 0, 3, 0, 1, 0,
|
||||
252, 0, 0, 0, 2, 0, 1, 0,
|
||||
6, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 0,
|
||||
73, 118, 234, 203, 210, 73, 201, 252,
|
||||
249, 0, 0, 0, 114, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 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,
|
||||
100, 97, 108, 0, 0, 0, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 0,
|
||||
@@ -773,20 +773,26 @@ static const ::capnp::_::AlignedData<132> b_f35cc4560bbf6ec2 = {
|
||||
14, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
108, 97, 116, 101, 114, 97, 108, 84,
|
||||
117, 110, 105, 110, 103, 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, }
|
||||
};
|
||||
::capnp::word const* const bp_f35cc4560bbf6ec2 = b_f35cc4560bbf6ec2.words;
|
||||
#if !CAPNP_LITE
|
||||
static const ::capnp::_::RawSchema* const d_f35cc4560bbf6ec2[] = {
|
||||
&s_8d65dd40bad40951,
|
||||
&s_fcc949d2cbea7649,
|
||||
};
|
||||
static const uint16_t m_f35cc4560bbf6ec2[] = {0, 1, 2, 3, 6, 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, 6};
|
||||
const ::capnp::_::RawSchema s_f35cc4560bbf6ec2 = {
|
||||
0xf35cc4560bbf6ec2, b_f35cc4560bbf6ec2.words, 132, d_f35cc4560bbf6ec2, m_f35cc4560bbf6ec2,
|
||||
2, 7, i_f35cc4560bbf6ec2, nullptr, nullptr, { &s_f35cc4560bbf6ec2, nullptr, nullptr, 0, 0, nullptr }, false
|
||||
0xf35cc4560bbf6ec2, b_f35cc4560bbf6ec2.words, 139, d_f35cc4560bbf6ec2, m_f35cc4560bbf6ec2,
|
||||
1, 7, i_f35cc4560bbf6ec2, nullptr, nullptr, { &s_f35cc4560bbf6ec2, nullptr, nullptr, 0, 0, nullptr }, false
|
||||
};
|
||||
#endif // !CAPNP_LITE
|
||||
static const ::capnp::_::AlignedData<36> b_8d65dd40bad40951 = {
|
||||
@@ -836,71 +842,6 @@ const ::capnp::_::RawSchema s_8d65dd40bad40951 = {
|
||||
0, 1, i_8d65dd40bad40951, nullptr, nullptr, { &s_8d65dd40bad40951, nullptr, nullptr, 0, 0, nullptr }, false
|
||||
};
|
||||
#endif // !CAPNP_LITE
|
||||
static const ::capnp::_::AlignedData<49> b_fcc949d2cbea7649 = {
|
||||
{ 0, 0, 0, 0, 5, 0, 6, 0,
|
||||
73, 118, 234, 203, 210, 73, 201, 252,
|
||||
32, 0, 0, 0, 1, 0, 1, 0,
|
||||
194, 110, 191, 11, 86, 196, 92, 243,
|
||||
2, 0, 7, 0, 1, 0, 2, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 0,
|
||||
21, 0, 0, 0, 114, 1, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
33, 0, 0, 0, 119, 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,
|
||||
97, 112, 110, 112, 58, 70, 114, 111,
|
||||
103, 80, 105, 108, 111, 116, 67, 97,
|
||||
114, 80, 97, 114, 97, 109, 115, 46,
|
||||
108, 97, 116, 101, 114, 97, 108, 84,
|
||||
117, 110, 105, 110, 103, 0, 0, 0,
|
||||
8, 0, 0, 0, 3, 0, 4, 0,
|
||||
0, 0, 255, 255, 1, 0, 0, 0,
|
||||
0, 0, 1, 0, 6, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
41, 0, 0, 0, 34, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
36, 0, 0, 0, 3, 0, 1, 0,
|
||||
48, 0, 0, 0, 2, 0, 1, 0,
|
||||
1, 0, 254, 255, 1, 0, 0, 0,
|
||||
0, 0, 1, 0, 7, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
45, 0, 0, 0, 58, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
40, 0, 0, 0, 3, 0, 1, 0,
|
||||
52, 0, 0, 0, 2, 0, 1, 0,
|
||||
112, 105, 100, 0, 0, 0, 0, 0,
|
||||
16, 0, 0, 0, 0, 0, 0, 0,
|
||||
46, 76, 209, 203, 63, 114, 34, 150,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
16, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
116, 111, 114, 113, 117, 101, 0, 0,
|
||||
16, 0, 0, 0, 0, 0, 0, 0,
|
||||
29, 204, 78, 128, 14, 110, 54, 128,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
16, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, }
|
||||
};
|
||||
::capnp::word const* const bp_fcc949d2cbea7649 = b_fcc949d2cbea7649.words;
|
||||
#if !CAPNP_LITE
|
||||
static const ::capnp::_::RawSchema* const d_fcc949d2cbea7649[] = {
|
||||
&s_80366e0e804ecc1d,
|
||||
&s_9622723fcbd14c2e,
|
||||
&s_f35cc4560bbf6ec2,
|
||||
};
|
||||
static const uint16_t m_fcc949d2cbea7649[] = {0, 1};
|
||||
static const uint16_t i_fcc949d2cbea7649[] = {0, 1};
|
||||
const ::capnp::_::RawSchema s_fcc949d2cbea7649 = {
|
||||
0xfcc949d2cbea7649, b_fcc949d2cbea7649.words, 49, d_fcc949d2cbea7649, m_fcc949d2cbea7649,
|
||||
3, 2, i_fcc949d2cbea7649, nullptr, nullptr, { &s_fcc949d2cbea7649, nullptr, nullptr, 0, 0, nullptr }, false
|
||||
};
|
||||
#endif // !CAPNP_LITE
|
||||
static const ::capnp::_::AlignedData<268> b_da96579883444c35 = {
|
||||
{ 0, 0, 0, 0, 5, 0, 6, 0,
|
||||
53, 76, 68, 131, 152, 87, 150, 218,
|
||||
@@ -1739,7 +1680,7 @@ const ::capnp::_::RawSchema s_f416ec09499d9d19 = {
|
||||
0, 3, i_f416ec09499d9d19, nullptr, nullptr, { &s_f416ec09499d9d19, nullptr, nullptr, 0, 0, nullptr }, false
|
||||
};
|
||||
#endif // !CAPNP_LITE
|
||||
static const ::capnp::_::AlignedData<597> b_a1680744031fdb2d = {
|
||||
static const ::capnp::_::AlignedData<613> b_a1680744031fdb2d = {
|
||||
{ 0, 0, 0, 0, 5, 0, 6, 0,
|
||||
45, 219, 31, 3, 68, 7, 104, 161,
|
||||
13, 0, 0, 0, 1, 0, 13, 0,
|
||||
@@ -1749,7 +1690,7 @@ static const ::capnp::_::AlignedData<597> b_a1680744031fdb2d = {
|
||||
21, 0, 0, 0, 218, 0, 0, 0,
|
||||
33, 0, 0, 0, 7, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
29, 0, 0, 0, 175, 7, 0, 0,
|
||||
29, 0, 0, 0, 231, 7, 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,
|
||||
@@ -1757,252 +1698,259 @@ static const ::capnp::_::AlignedData<597> b_a1680744031fdb2d = {
|
||||
103, 80, 105, 108, 111, 116, 80, 108,
|
||||
97, 110, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 1, 0, 1, 0,
|
||||
140, 0, 0, 0, 3, 0, 4, 0,
|
||||
144, 0, 0, 0, 3, 0, 4, 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,
|
||||
197, 3, 0, 0, 138, 0, 0, 0,
|
||||
225, 3, 0, 0, 138, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
200, 3, 0, 0, 3, 0, 1, 0,
|
||||
212, 3, 0, 0, 2, 0, 1, 0,
|
||||
228, 3, 0, 0, 3, 0, 1, 0,
|
||||
240, 3, 0, 0, 2, 0, 1, 0,
|
||||
1, 0, 0, 0, 1, 0, 0, 0,
|
||||
0, 0, 1, 0, 1, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
209, 3, 0, 0, 178, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
212, 3, 0, 0, 3, 0, 1, 0,
|
||||
224, 3, 0, 0, 2, 0, 1, 0,
|
||||
2, 0, 0, 0, 64, 0, 0, 0,
|
||||
0, 0, 1, 0, 2, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
221, 3, 0, 0, 162, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
224, 3, 0, 0, 3, 0, 1, 0,
|
||||
236, 3, 0, 0, 2, 0, 1, 0,
|
||||
3, 0, 0, 0, 3, 0, 0, 0,
|
||||
0, 0, 1, 0, 3, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
233, 3, 0, 0, 74, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
232, 3, 0, 0, 3, 0, 1, 0,
|
||||
244, 3, 0, 0, 2, 0, 1, 0,
|
||||
4, 0, 0, 0, 65, 0, 0, 0,
|
||||
0, 0, 1, 0, 4, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
241, 3, 0, 0, 98, 0, 0, 0,
|
||||
237, 3, 0, 0, 178, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
240, 3, 0, 0, 3, 0, 1, 0,
|
||||
252, 3, 0, 0, 2, 0, 1, 0,
|
||||
5, 0, 0, 0, 4, 0, 0, 0,
|
||||
0, 0, 1, 0, 5, 0, 0, 0,
|
||||
2, 0, 0, 0, 64, 0, 0, 0,
|
||||
0, 0, 1, 0, 2, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
249, 3, 0, 0, 90, 0, 0, 0,
|
||||
249, 3, 0, 0, 162, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
248, 3, 0, 0, 3, 0, 1, 0,
|
||||
4, 4, 0, 0, 2, 0, 1, 0,
|
||||
6, 0, 0, 0, 3, 0, 0, 0,
|
||||
0, 0, 1, 0, 6, 0, 0, 0,
|
||||
252, 3, 0, 0, 3, 0, 1, 0,
|
||||
8, 4, 0, 0, 2, 0, 1, 0,
|
||||
3, 0, 0, 0, 3, 0, 0, 0,
|
||||
0, 0, 1, 0, 3, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 4, 0, 0, 178, 0, 0, 0,
|
||||
5, 4, 0, 0, 74, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
4, 4, 0, 0, 3, 0, 1, 0,
|
||||
16, 4, 0, 0, 2, 0, 1, 0,
|
||||
4, 0, 0, 0, 65, 0, 0, 0,
|
||||
0, 0, 1, 0, 4, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
13, 4, 0, 0, 98, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
12, 4, 0, 0, 3, 0, 1, 0,
|
||||
24, 4, 0, 0, 2, 0, 1, 0,
|
||||
5, 0, 0, 0, 4, 0, 0, 0,
|
||||
0, 0, 1, 0, 5, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
21, 4, 0, 0, 90, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
20, 4, 0, 0, 3, 0, 1, 0,
|
||||
32, 4, 0, 0, 2, 0, 1, 0,
|
||||
6, 0, 0, 0, 3, 0, 0, 0,
|
||||
0, 0, 1, 0, 6, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
29, 4, 0, 0, 178, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
32, 4, 0, 0, 3, 0, 1, 0,
|
||||
44, 4, 0, 0, 2, 0, 1, 0,
|
||||
7, 0, 0, 0, 66, 0, 0, 0,
|
||||
0, 0, 1, 0, 7, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
13, 4, 0, 0, 138, 0, 0, 0,
|
||||
41, 4, 0, 0, 130, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
16, 4, 0, 0, 3, 0, 1, 0,
|
||||
28, 4, 0, 0, 2, 0, 1, 0,
|
||||
40, 4, 0, 0, 3, 0, 1, 0,
|
||||
52, 4, 0, 0, 2, 0, 1, 0,
|
||||
8, 0, 0, 0, 67, 0, 0, 0,
|
||||
0, 0, 1, 0, 8, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
25, 4, 0, 0, 98, 0, 0, 0,
|
||||
49, 4, 0, 0, 138, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
24, 4, 0, 0, 3, 0, 1, 0,
|
||||
36, 4, 0, 0, 2, 0, 1, 0,
|
||||
9, 0, 0, 0, 5, 0, 0, 0,
|
||||
52, 4, 0, 0, 3, 0, 1, 0,
|
||||
64, 4, 0, 0, 2, 0, 1, 0,
|
||||
9, 0, 0, 0, 68, 0, 0, 0,
|
||||
0, 0, 1, 0, 9, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
33, 4, 0, 0, 146, 0, 0, 0,
|
||||
61, 4, 0, 0, 98, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
36, 4, 0, 0, 3, 0, 1, 0,
|
||||
48, 4, 0, 0, 2, 0, 1, 0,
|
||||
10, 0, 0, 0, 0, 0, 0, 0,
|
||||
60, 4, 0, 0, 3, 0, 1, 0,
|
||||
72, 4, 0, 0, 2, 0, 1, 0,
|
||||
10, 0, 0, 0, 5, 0, 0, 0,
|
||||
0, 0, 1, 0, 10, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
45, 4, 0, 0, 130, 0, 0, 0,
|
||||
69, 4, 0, 0, 146, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
44, 4, 0, 0, 3, 0, 1, 0,
|
||||
72, 4, 0, 0, 2, 0, 1, 0,
|
||||
11, 0, 0, 0, 8, 0, 0, 0,
|
||||
72, 4, 0, 0, 3, 0, 1, 0,
|
||||
84, 4, 0, 0, 2, 0, 1, 0,
|
||||
11, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 1, 0, 11, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
69, 4, 0, 0, 202, 0, 0, 0,
|
||||
81, 4, 0, 0, 130, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
76, 4, 0, 0, 3, 0, 1, 0,
|
||||
88, 4, 0, 0, 2, 0, 1, 0,
|
||||
12, 0, 0, 0, 68, 0, 0, 0,
|
||||
80, 4, 0, 0, 3, 0, 1, 0,
|
||||
108, 4, 0, 0, 2, 0, 1, 0,
|
||||
12, 0, 0, 0, 8, 0, 0, 0,
|
||||
0, 0, 1, 0, 12, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
85, 4, 0, 0, 106, 0, 0, 0,
|
||||
105, 4, 0, 0, 202, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
84, 4, 0, 0, 3, 0, 1, 0,
|
||||
96, 4, 0, 0, 2, 0, 1, 0,
|
||||
13, 0, 0, 0, 9, 0, 0, 0,
|
||||
112, 4, 0, 0, 3, 0, 1, 0,
|
||||
124, 4, 0, 0, 2, 0, 1, 0,
|
||||
13, 0, 0, 0, 69, 0, 0, 0,
|
||||
0, 0, 1, 0, 13, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
93, 4, 0, 0, 114, 0, 0, 0,
|
||||
121, 4, 0, 0, 106, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
92, 4, 0, 0, 3, 0, 1, 0,
|
||||
104, 4, 0, 0, 2, 0, 1, 0,
|
||||
14, 0, 0, 0, 10, 0, 0, 0,
|
||||
120, 4, 0, 0, 3, 0, 1, 0,
|
||||
132, 4, 0, 0, 2, 0, 1, 0,
|
||||
14, 0, 0, 0, 9, 0, 0, 0,
|
||||
0, 0, 1, 0, 14, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
101, 4, 0, 0, 122, 0, 0, 0,
|
||||
129, 4, 0, 0, 114, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
100, 4, 0, 0, 3, 0, 1, 0,
|
||||
112, 4, 0, 0, 2, 0, 1, 0,
|
||||
15, 0, 0, 0, 11, 0, 0, 0,
|
||||
128, 4, 0, 0, 3, 0, 1, 0,
|
||||
140, 4, 0, 0, 2, 0, 1, 0,
|
||||
15, 0, 0, 0, 10, 0, 0, 0,
|
||||
0, 0, 1, 0, 15, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
109, 4, 0, 0, 130, 0, 0, 0,
|
||||
137, 4, 0, 0, 122, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
108, 4, 0, 0, 3, 0, 1, 0,
|
||||
120, 4, 0, 0, 2, 0, 1, 0,
|
||||
16, 0, 0, 0, 12, 0, 0, 0,
|
||||
136, 4, 0, 0, 3, 0, 1, 0,
|
||||
148, 4, 0, 0, 2, 0, 1, 0,
|
||||
16, 0, 0, 0, 11, 0, 0, 0,
|
||||
0, 0, 1, 0, 16, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
117, 4, 0, 0, 130, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
116, 4, 0, 0, 3, 0, 1, 0,
|
||||
128, 4, 0, 0, 2, 0, 1, 0,
|
||||
17, 0, 0, 0, 69, 0, 0, 0,
|
||||
0, 0, 1, 0, 17, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
125, 4, 0, 0, 74, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
124, 4, 0, 0, 3, 0, 1, 0,
|
||||
136, 4, 0, 0, 2, 0, 1, 0,
|
||||
18, 0, 0, 0, 13, 0, 0, 0,
|
||||
0, 0, 1, 0, 18, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
133, 4, 0, 0, 114, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
132, 4, 0, 0, 3, 0, 1, 0,
|
||||
144, 4, 0, 0, 2, 0, 1, 0,
|
||||
19, 0, 0, 0, 14, 0, 0, 0,
|
||||
0, 0, 1, 0, 19, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
141, 4, 0, 0, 138, 0, 0, 0,
|
||||
145, 4, 0, 0, 130, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
144, 4, 0, 0, 3, 0, 1, 0,
|
||||
156, 4, 0, 0, 2, 0, 1, 0,
|
||||
20, 0, 0, 0, 15, 0, 0, 0,
|
||||
0, 0, 1, 0, 20, 0, 0, 0,
|
||||
17, 0, 0, 0, 12, 0, 0, 0,
|
||||
0, 0, 1, 0, 17, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
153, 4, 0, 0, 162, 0, 0, 0,
|
||||
153, 4, 0, 0, 130, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
156, 4, 0, 0, 3, 0, 1, 0,
|
||||
168, 4, 0, 0, 2, 0, 1, 0,
|
||||
21, 0, 0, 0, 16, 0, 0, 0,
|
||||
0, 0, 1, 0, 21, 0, 0, 0,
|
||||
152, 4, 0, 0, 3, 0, 1, 0,
|
||||
164, 4, 0, 0, 2, 0, 1, 0,
|
||||
18, 0, 0, 0, 70, 0, 0, 0,
|
||||
0, 0, 1, 0, 18, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
165, 4, 0, 0, 146, 0, 0, 0,
|
||||
161, 4, 0, 0, 74, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
160, 4, 0, 0, 3, 0, 1, 0,
|
||||
172, 4, 0, 0, 2, 0, 1, 0,
|
||||
19, 0, 0, 0, 13, 0, 0, 0,
|
||||
0, 0, 1, 0, 19, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
169, 4, 0, 0, 114, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
168, 4, 0, 0, 3, 0, 1, 0,
|
||||
180, 4, 0, 0, 2, 0, 1, 0,
|
||||
22, 0, 0, 0, 17, 0, 0, 0,
|
||||
0, 0, 1, 0, 22, 0, 0, 0,
|
||||
20, 0, 0, 0, 14, 0, 0, 0,
|
||||
0, 0, 1, 0, 20, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
177, 4, 0, 0, 154, 0, 0, 0,
|
||||
177, 4, 0, 0, 138, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
180, 4, 0, 0, 3, 0, 1, 0,
|
||||
192, 4, 0, 0, 2, 0, 1, 0,
|
||||
23, 0, 0, 0, 18, 0, 0, 0,
|
||||
21, 0, 0, 0, 15, 0, 0, 0,
|
||||
0, 0, 1, 0, 21, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
189, 4, 0, 0, 162, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
192, 4, 0, 0, 3, 0, 1, 0,
|
||||
204, 4, 0, 0, 2, 0, 1, 0,
|
||||
22, 0, 0, 0, 16, 0, 0, 0,
|
||||
0, 0, 1, 0, 22, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
201, 4, 0, 0, 146, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
204, 4, 0, 0, 3, 0, 1, 0,
|
||||
216, 4, 0, 0, 2, 0, 1, 0,
|
||||
23, 0, 0, 0, 17, 0, 0, 0,
|
||||
0, 0, 1, 0, 23, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
189, 4, 0, 0, 114, 0, 0, 0,
|
||||
213, 4, 0, 0, 154, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
188, 4, 0, 0, 3, 0, 1, 0,
|
||||
200, 4, 0, 0, 2, 0, 1, 0,
|
||||
24, 0, 0, 0, 19, 0, 0, 0,
|
||||
216, 4, 0, 0, 3, 0, 1, 0,
|
||||
228, 4, 0, 0, 2, 0, 1, 0,
|
||||
24, 0, 0, 0, 18, 0, 0, 0,
|
||||
0, 0, 1, 0, 24, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
197, 4, 0, 0, 162, 0, 0, 0,
|
||||
225, 4, 0, 0, 114, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
200, 4, 0, 0, 3, 0, 1, 0,
|
||||
212, 4, 0, 0, 2, 0, 1, 0,
|
||||
25, 0, 0, 0, 1, 0, 0, 0,
|
||||
224, 4, 0, 0, 3, 0, 1, 0,
|
||||
236, 4, 0, 0, 2, 0, 1, 0,
|
||||
25, 0, 0, 0, 19, 0, 0, 0,
|
||||
0, 0, 1, 0, 25, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
209, 4, 0, 0, 162, 0, 0, 0,
|
||||
233, 4, 0, 0, 162, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
212, 4, 0, 0, 3, 0, 1, 0,
|
||||
224, 4, 0, 0, 2, 0, 1, 0,
|
||||
26, 0, 0, 0, 20, 0, 0, 0,
|
||||
236, 4, 0, 0, 3, 0, 1, 0,
|
||||
248, 4, 0, 0, 2, 0, 1, 0,
|
||||
26, 0, 0, 0, 1, 0, 0, 0,
|
||||
0, 0, 1, 0, 26, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
221, 4, 0, 0, 82, 0, 0, 0,
|
||||
245, 4, 0, 0, 162, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
220, 4, 0, 0, 3, 0, 1, 0,
|
||||
232, 4, 0, 0, 2, 0, 1, 0,
|
||||
27, 0, 0, 0, 21, 0, 0, 0,
|
||||
248, 4, 0, 0, 3, 0, 1, 0,
|
||||
4, 5, 0, 0, 2, 0, 1, 0,
|
||||
27, 0, 0, 0, 20, 0, 0, 0,
|
||||
0, 0, 1, 0, 27, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
229, 4, 0, 0, 122, 0, 0, 0,
|
||||
1, 5, 0, 0, 82, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
228, 4, 0, 0, 3, 0, 1, 0,
|
||||
240, 4, 0, 0, 2, 0, 1, 0,
|
||||
28, 0, 0, 0, 70, 0, 0, 0,
|
||||
0, 5, 0, 0, 3, 0, 1, 0,
|
||||
12, 5, 0, 0, 2, 0, 1, 0,
|
||||
28, 0, 0, 0, 21, 0, 0, 0,
|
||||
0, 0, 1, 0, 28, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
237, 4, 0, 0, 146, 0, 0, 0,
|
||||
9, 5, 0, 0, 122, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
240, 4, 0, 0, 3, 0, 1, 0,
|
||||
252, 4, 0, 0, 2, 0, 1, 0,
|
||||
29, 0, 0, 0, 22, 0, 0, 0,
|
||||
8, 5, 0, 0, 3, 0, 1, 0,
|
||||
20, 5, 0, 0, 2, 0, 1, 0,
|
||||
29, 0, 0, 0, 71, 0, 0, 0,
|
||||
0, 0, 1, 0, 29, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
249, 4, 0, 0, 66, 0, 0, 0,
|
||||
17, 5, 0, 0, 146, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
244, 4, 0, 0, 3, 0, 1, 0,
|
||||
0, 5, 0, 0, 2, 0, 1, 0,
|
||||
30, 0, 0, 0, 71, 0, 0, 0,
|
||||
20, 5, 0, 0, 3, 0, 1, 0,
|
||||
32, 5, 0, 0, 2, 0, 1, 0,
|
||||
30, 0, 0, 0, 22, 0, 0, 0,
|
||||
0, 0, 1, 0, 30, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
253, 4, 0, 0, 106, 0, 0, 0,
|
||||
29, 5, 0, 0, 66, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
252, 4, 0, 0, 3, 0, 1, 0,
|
||||
8, 5, 0, 0, 2, 0, 1, 0,
|
||||
24, 5, 0, 0, 3, 0, 1, 0,
|
||||
36, 5, 0, 0, 2, 0, 1, 0,
|
||||
31, 0, 0, 0, 72, 0, 0, 0,
|
||||
0, 0, 1, 0, 31, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
5, 5, 0, 0, 122, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
4, 5, 0, 0, 3, 0, 1, 0,
|
||||
16, 5, 0, 0, 2, 0, 1, 0,
|
||||
32, 0, 0, 0, 73, 0, 0, 0,
|
||||
0, 0, 1, 0, 32, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
13, 5, 0, 0, 106, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
12, 5, 0, 0, 3, 0, 1, 0,
|
||||
24, 5, 0, 0, 2, 0, 1, 0,
|
||||
33, 0, 0, 0, 23, 0, 0, 0,
|
||||
0, 0, 1, 0, 33, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
21, 5, 0, 0, 202, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
28, 5, 0, 0, 3, 0, 1, 0,
|
||||
40, 5, 0, 0, 2, 0, 1, 0,
|
||||
34, 0, 0, 0, 24, 0, 0, 0,
|
||||
0, 0, 1, 0, 34, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
37, 5, 0, 0, 66, 0, 0, 0,
|
||||
33, 5, 0, 0, 106, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
32, 5, 0, 0, 3, 0, 1, 0,
|
||||
44, 5, 0, 0, 2, 0, 1, 0,
|
||||
32, 0, 0, 0, 73, 0, 0, 0,
|
||||
0, 0, 1, 0, 32, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
41, 5, 0, 0, 122, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
40, 5, 0, 0, 3, 0, 1, 0,
|
||||
52, 5, 0, 0, 2, 0, 1, 0,
|
||||
33, 0, 0, 0, 74, 0, 0, 0,
|
||||
0, 0, 1, 0, 33, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
49, 5, 0, 0, 106, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
48, 5, 0, 0, 3, 0, 1, 0,
|
||||
60, 5, 0, 0, 2, 0, 1, 0,
|
||||
34, 0, 0, 0, 23, 0, 0, 0,
|
||||
0, 0, 1, 0, 34, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
57, 5, 0, 0, 202, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
64, 5, 0, 0, 3, 0, 1, 0,
|
||||
76, 5, 0, 0, 2, 0, 1, 0,
|
||||
35, 0, 0, 0, 24, 0, 0, 0,
|
||||
0, 0, 1, 0, 35, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
73, 5, 0, 0, 66, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
68, 5, 0, 0, 3, 0, 1, 0,
|
||||
80, 5, 0, 0, 2, 0, 1, 0,
|
||||
97, 99, 99, 101, 108, 101, 114, 97,
|
||||
116, 105, 111, 110, 74, 101, 114, 107,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
@@ -2070,6 +2018,15 @@ static const ::capnp::_::AlignedData<597> b_a1680744031fdb2d = {
|
||||
5, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
100, 105, 115, 97, 98, 108, 101, 84,
|
||||
104, 114, 111, 116, 116, 108, 101, 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,
|
||||
101, 120, 112, 101, 114, 105, 109, 101,
|
||||
110, 116, 97, 108, 77, 111, 100, 101,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
@@ -2343,11 +2300,11 @@ static const ::capnp::_::AlignedData<597> b_a1680744031fdb2d = {
|
||||
static const ::capnp::_::RawSchema* const d_a1680744031fdb2d[] = {
|
||||
&s_81c2f05a394cf4af,
|
||||
};
|
||||
static const uint16_t m_a1680744031fdb2d[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14, 12, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34};
|
||||
static const uint16_t i_a1680744031fdb2d[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34};
|
||||
static const uint16_t m_a1680744031fdb2d[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 15, 13, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35};
|
||||
static const uint16_t i_a1680744031fdb2d[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35};
|
||||
const ::capnp::_::RawSchema s_a1680744031fdb2d = {
|
||||
0xa1680744031fdb2d, b_a1680744031fdb2d.words, 597, d_a1680744031fdb2d, m_a1680744031fdb2d,
|
||||
1, 35, i_a1680744031fdb2d, nullptr, nullptr, { &s_a1680744031fdb2d, nullptr, nullptr, 0, 0, nullptr }, false
|
||||
0xa1680744031fdb2d, b_a1680744031fdb2d.words, 613, d_a1680744031fdb2d, m_a1680744031fdb2d,
|
||||
1, 36, i_a1680744031fdb2d, nullptr, nullptr, { &s_a1680744031fdb2d, nullptr, nullptr, 0, 0, nullptr }, false
|
||||
};
|
||||
#endif // !CAPNP_LITE
|
||||
static const ::capnp::_::AlignedData<55> b_cb9fd56c7057593a = {
|
||||
@@ -2761,18 +2718,6 @@ constexpr ::capnp::_::RawSchema const* FrogPilotCarParams::SafetyConfig::_capnpP
|
||||
#endif // !CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
// FrogPilotCarParams::LateralTuning
|
||||
#if CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
constexpr uint16_t FrogPilotCarParams::LateralTuning::_capnpPrivate::dataWordSize;
|
||||
constexpr uint16_t FrogPilotCarParams::LateralTuning::_capnpPrivate::pointerCount;
|
||||
#endif // !CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
#if !CAPNP_LITE
|
||||
#if CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
constexpr ::capnp::Kind FrogPilotCarParams::LateralTuning::_capnpPrivate::kind;
|
||||
constexpr ::capnp::_::RawSchema const* FrogPilotCarParams::LateralTuning::_capnpPrivate::schema;
|
||||
#endif // !CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
// FrogPilotCarState
|
||||
#if CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
constexpr uint16_t FrogPilotCarState::_capnpPrivate::dataWordSize;
|
||||
|
||||
+68
-287
@@ -84,7 +84,6 @@ enum class EventName_aedffd8f31e7b55d: uint16_t {
|
||||
CAPNP_DECLARE_ENUM(EventName, aedffd8f31e7b55d);
|
||||
CAPNP_DECLARE_SCHEMA(f35cc4560bbf6ec2);
|
||||
CAPNP_DECLARE_SCHEMA(8d65dd40bad40951);
|
||||
CAPNP_DECLARE_SCHEMA(fcc949d2cbea7649);
|
||||
CAPNP_DECLARE_SCHEMA(da96579883444c35);
|
||||
CAPNP_DECLARE_SCHEMA(ccb4d6b0dc102d40);
|
||||
CAPNP_DECLARE_SCHEMA(8033e8e60d6a0edb);
|
||||
@@ -185,10 +184,9 @@ struct FrogPilotCarParams {
|
||||
class Builder;
|
||||
class Pipeline;
|
||||
struct SafetyConfig;
|
||||
struct LateralTuning;
|
||||
|
||||
struct _capnpPrivate {
|
||||
CAPNP_DECLARE_STRUCT_HEADER(f35cc4560bbf6ec2, 1, 2)
|
||||
CAPNP_DECLARE_STRUCT_HEADER(f35cc4560bbf6ec2, 1, 1)
|
||||
#if !CAPNP_LITE
|
||||
static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; }
|
||||
#endif // !CAPNP_LITE
|
||||
@@ -210,25 +208,6 @@ struct FrogPilotCarParams::SafetyConfig {
|
||||
};
|
||||
};
|
||||
|
||||
struct FrogPilotCarParams::LateralTuning {
|
||||
LateralTuning() = delete;
|
||||
|
||||
class Reader;
|
||||
class Builder;
|
||||
class Pipeline;
|
||||
enum Which: uint16_t {
|
||||
PID,
|
||||
TORQUE,
|
||||
};
|
||||
|
||||
struct _capnpPrivate {
|
||||
CAPNP_DECLARE_STRUCT_HEADER(fcc949d2cbea7649, 1, 2)
|
||||
#if !CAPNP_LITE
|
||||
static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; }
|
||||
#endif // !CAPNP_LITE
|
||||
};
|
||||
};
|
||||
|
||||
struct FrogPilotCarState {
|
||||
FrogPilotCarState() = delete;
|
||||
|
||||
@@ -690,7 +669,7 @@ public:
|
||||
inline bool hasSafetyConfigs() const;
|
||||
inline ::capnp::List< ::cereal::FrogPilotCarParams::SafetyConfig, ::capnp::Kind::STRUCT>::Reader getSafetyConfigs() const;
|
||||
|
||||
inline typename LateralTuning::Reader getLateralTuning() const;
|
||||
inline bool getCanUseSASCM() const;
|
||||
|
||||
private:
|
||||
::capnp::_::StructReader _reader;
|
||||
@@ -742,8 +721,8 @@ public:
|
||||
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 typename LateralTuning::Builder getLateralTuning();
|
||||
inline typename LateralTuning::Builder initLateralTuning();
|
||||
inline bool getCanUseSASCM();
|
||||
inline void setCanUseSASCM(bool value);
|
||||
|
||||
private:
|
||||
::capnp::_::StructBuilder _builder;
|
||||
@@ -763,7 +742,6 @@ public:
|
||||
inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless)
|
||||
: _typeless(kj::mv(typeless)) {}
|
||||
|
||||
inline typename LateralTuning::Pipeline getLateralTuning();
|
||||
private:
|
||||
::capnp::AnyPointer::Pipeline _typeless;
|
||||
friend class ::capnp::PipelineHook;
|
||||
@@ -848,103 +826,6 @@ private:
|
||||
};
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
class FrogPilotCarParams::LateralTuning::Reader {
|
||||
public:
|
||||
typedef LateralTuning Reads;
|
||||
|
||||
Reader() = default;
|
||||
inline explicit Reader(::capnp::_::StructReader base): _reader(base) {}
|
||||
|
||||
inline ::capnp::MessageSize totalSize() const {
|
||||
return _reader.totalSize().asPublic();
|
||||
}
|
||||
|
||||
#if !CAPNP_LITE
|
||||
inline ::kj::StringTree toString() const {
|
||||
return ::capnp::_::structString(_reader, *_capnpPrivate::brand());
|
||||
}
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
inline Which which() const;
|
||||
inline bool isPid() const;
|
||||
inline bool hasPid() const;
|
||||
inline ::cereal::CarParams::LateralPIDTuning::Reader getPid() const;
|
||||
|
||||
inline bool isTorque() const;
|
||||
inline bool hasTorque() const;
|
||||
inline ::cereal::CarParams::LateralTorqueTuning::Reader getTorque() const;
|
||||
|
||||
private:
|
||||
::capnp::_::StructReader _reader;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::ToDynamic_;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::_::PointerHelpers;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::List;
|
||||
friend class ::capnp::MessageBuilder;
|
||||
friend class ::capnp::Orphanage;
|
||||
};
|
||||
|
||||
class FrogPilotCarParams::LateralTuning::Builder {
|
||||
public:
|
||||
typedef LateralTuning Builds;
|
||||
|
||||
Builder() = delete; // Deleted to discourage incorrect usage.
|
||||
// You can explicitly initialize to nullptr instead.
|
||||
inline Builder(decltype(nullptr)) {}
|
||||
inline explicit Builder(::capnp::_::StructBuilder base): _builder(base) {}
|
||||
inline operator Reader() const { return Reader(_builder.asReader()); }
|
||||
inline Reader asReader() const { return *this; }
|
||||
|
||||
inline ::capnp::MessageSize totalSize() const { return asReader().totalSize(); }
|
||||
#if !CAPNP_LITE
|
||||
inline ::kj::StringTree toString() const { return asReader().toString(); }
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
inline Which which();
|
||||
inline bool isPid();
|
||||
inline bool hasPid();
|
||||
inline ::cereal::CarParams::LateralPIDTuning::Builder getPid();
|
||||
inline void setPid( ::cereal::CarParams::LateralPIDTuning::Reader value);
|
||||
inline ::cereal::CarParams::LateralPIDTuning::Builder initPid();
|
||||
inline void adoptPid(::capnp::Orphan< ::cereal::CarParams::LateralPIDTuning>&& value);
|
||||
inline ::capnp::Orphan< ::cereal::CarParams::LateralPIDTuning> disownPid();
|
||||
|
||||
inline bool isTorque();
|
||||
inline bool hasTorque();
|
||||
inline ::cereal::CarParams::LateralTorqueTuning::Builder getTorque();
|
||||
inline void setTorque( ::cereal::CarParams::LateralTorqueTuning::Reader value);
|
||||
inline ::cereal::CarParams::LateralTorqueTuning::Builder initTorque();
|
||||
inline void adoptTorque(::capnp::Orphan< ::cereal::CarParams::LateralTorqueTuning>&& value);
|
||||
inline ::capnp::Orphan< ::cereal::CarParams::LateralTorqueTuning> disownTorque();
|
||||
|
||||
private:
|
||||
::capnp::_::StructBuilder _builder;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::ToDynamic_;
|
||||
friend class ::capnp::Orphanage;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::_::PointerHelpers;
|
||||
};
|
||||
|
||||
#if !CAPNP_LITE
|
||||
class FrogPilotCarParams::LateralTuning::Pipeline {
|
||||
public:
|
||||
typedef LateralTuning Pipelines;
|
||||
|
||||
inline Pipeline(decltype(nullptr)): _typeless(nullptr) {}
|
||||
inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless)
|
||||
: _typeless(kj::mv(typeless)) {}
|
||||
|
||||
private:
|
||||
::capnp::AnyPointer::Pipeline _typeless;
|
||||
friend class ::capnp::PipelineHook;
|
||||
template <typename, ::capnp::Kind>
|
||||
friend struct ::capnp::ToDynamic_;
|
||||
};
|
||||
#endif // !CAPNP_LITE
|
||||
|
||||
class FrogPilotCarState::Reader {
|
||||
public:
|
||||
typedef FrogPilotCarState Reads;
|
||||
@@ -1557,6 +1438,8 @@ public:
|
||||
|
||||
inline ::int64_t getDesiredFollowDistance() const;
|
||||
|
||||
inline bool getDisableThrottle() const;
|
||||
|
||||
inline bool getExperimentalMode() const;
|
||||
|
||||
inline bool getForcingStop() const;
|
||||
@@ -1664,6 +1547,9 @@ public:
|
||||
inline ::int64_t getDesiredFollowDistance();
|
||||
inline void setDesiredFollowDistance( ::int64_t value);
|
||||
|
||||
inline bool getDisableThrottle();
|
||||
inline void setDisableThrottle(bool value);
|
||||
|
||||
inline bool getExperimentalMode();
|
||||
inline void setExperimentalMode(bool value);
|
||||
|
||||
@@ -2339,22 +2225,20 @@ inline ::capnp::Orphan< ::capnp::List< ::cereal::FrogPilotCarParams::SafetyConfi
|
||||
::capnp::bounded<0>() * ::capnp::POINTERS));
|
||||
}
|
||||
|
||||
inline typename FrogPilotCarParams::LateralTuning::Reader FrogPilotCarParams::Reader::getLateralTuning() const {
|
||||
return typename FrogPilotCarParams::LateralTuning::Reader(_reader);
|
||||
inline bool FrogPilotCarParams::Reader::getCanUseSASCM() const {
|
||||
return _reader.getDataField<bool>(
|
||||
::capnp::bounded<4>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
inline typename FrogPilotCarParams::LateralTuning::Builder FrogPilotCarParams::Builder::getLateralTuning() {
|
||||
return typename FrogPilotCarParams::LateralTuning::Builder(_builder);
|
||||
|
||||
inline bool FrogPilotCarParams::Builder::getCanUseSASCM() {
|
||||
return _builder.getDataField<bool>(
|
||||
::capnp::bounded<4>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
#if !CAPNP_LITE
|
||||
inline typename FrogPilotCarParams::LateralTuning::Pipeline FrogPilotCarParams::Pipeline::getLateralTuning() {
|
||||
return typename FrogPilotCarParams::LateralTuning::Pipeline(_typeless.noop());
|
||||
}
|
||||
#endif // !CAPNP_LITE
|
||||
inline typename FrogPilotCarParams::LateralTuning::Builder FrogPilotCarParams::Builder::initLateralTuning() {
|
||||
_builder.setDataField< ::uint16_t>(::capnp::bounded<1>() * ::capnp::ELEMENTS, 0);
|
||||
_builder.getPointerField(::capnp::bounded<1>() * ::capnp::POINTERS).clear();
|
||||
return typename FrogPilotCarParams::LateralTuning::Builder(_builder);
|
||||
inline void FrogPilotCarParams::Builder::setCanUseSASCM(bool value) {
|
||||
_builder.setDataField<bool>(
|
||||
::capnp::bounded<4>() * ::capnp::ELEMENTS, value);
|
||||
}
|
||||
|
||||
inline ::uint16_t FrogPilotCarParams::SafetyConfig::Reader::getSafetyParam() const {
|
||||
return _reader.getDataField< ::uint16_t>(
|
||||
::capnp::bounded<0>() * ::capnp::ELEMENTS);
|
||||
@@ -2369,123 +2253,6 @@ inline void FrogPilotCarParams::SafetyConfig::Builder::setSafetyParam( ::uint16_
|
||||
::capnp::bounded<0>() * ::capnp::ELEMENTS, value);
|
||||
}
|
||||
|
||||
inline ::cereal::FrogPilotCarParams::LateralTuning::Which FrogPilotCarParams::LateralTuning::Reader::which() const {
|
||||
return _reader.getDataField<Which>(
|
||||
::capnp::bounded<1>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
inline ::cereal::FrogPilotCarParams::LateralTuning::Which FrogPilotCarParams::LateralTuning::Builder::which() {
|
||||
return _builder.getDataField<Which>(
|
||||
::capnp::bounded<1>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
|
||||
inline bool FrogPilotCarParams::LateralTuning::Reader::isPid() const {
|
||||
return which() == FrogPilotCarParams::LateralTuning::PID;
|
||||
}
|
||||
inline bool FrogPilotCarParams::LateralTuning::Builder::isPid() {
|
||||
return which() == FrogPilotCarParams::LateralTuning::PID;
|
||||
}
|
||||
inline bool FrogPilotCarParams::LateralTuning::Reader::hasPid() const {
|
||||
if (which() != FrogPilotCarParams::LateralTuning::PID) return false;
|
||||
return !_reader.getPointerField(
|
||||
::capnp::bounded<1>() * ::capnp::POINTERS).isNull();
|
||||
}
|
||||
inline bool FrogPilotCarParams::LateralTuning::Builder::hasPid() {
|
||||
if (which() != FrogPilotCarParams::LateralTuning::PID) return false;
|
||||
return !_builder.getPointerField(
|
||||
::capnp::bounded<1>() * ::capnp::POINTERS).isNull();
|
||||
}
|
||||
inline ::cereal::CarParams::LateralPIDTuning::Reader FrogPilotCarParams::LateralTuning::Reader::getPid() const {
|
||||
KJ_IREQUIRE((which() == FrogPilotCarParams::LateralTuning::PID),
|
||||
"Must check which() before get()ing a union member.");
|
||||
return ::capnp::_::PointerHelpers< ::cereal::CarParams::LateralPIDTuning>::get(_reader.getPointerField(
|
||||
::capnp::bounded<1>() * ::capnp::POINTERS));
|
||||
}
|
||||
inline ::cereal::CarParams::LateralPIDTuning::Builder FrogPilotCarParams::LateralTuning::Builder::getPid() {
|
||||
KJ_IREQUIRE((which() == FrogPilotCarParams::LateralTuning::PID),
|
||||
"Must check which() before get()ing a union member.");
|
||||
return ::capnp::_::PointerHelpers< ::cereal::CarParams::LateralPIDTuning>::get(_builder.getPointerField(
|
||||
::capnp::bounded<1>() * ::capnp::POINTERS));
|
||||
}
|
||||
inline void FrogPilotCarParams::LateralTuning::Builder::setPid( ::cereal::CarParams::LateralPIDTuning::Reader value) {
|
||||
_builder.setDataField<FrogPilotCarParams::LateralTuning::Which>(
|
||||
::capnp::bounded<1>() * ::capnp::ELEMENTS, FrogPilotCarParams::LateralTuning::PID);
|
||||
::capnp::_::PointerHelpers< ::cereal::CarParams::LateralPIDTuning>::set(_builder.getPointerField(
|
||||
::capnp::bounded<1>() * ::capnp::POINTERS), value);
|
||||
}
|
||||
inline ::cereal::CarParams::LateralPIDTuning::Builder FrogPilotCarParams::LateralTuning::Builder::initPid() {
|
||||
_builder.setDataField<FrogPilotCarParams::LateralTuning::Which>(
|
||||
::capnp::bounded<1>() * ::capnp::ELEMENTS, FrogPilotCarParams::LateralTuning::PID);
|
||||
return ::capnp::_::PointerHelpers< ::cereal::CarParams::LateralPIDTuning>::init(_builder.getPointerField(
|
||||
::capnp::bounded<1>() * ::capnp::POINTERS));
|
||||
}
|
||||
inline void FrogPilotCarParams::LateralTuning::Builder::adoptPid(
|
||||
::capnp::Orphan< ::cereal::CarParams::LateralPIDTuning>&& value) {
|
||||
_builder.setDataField<FrogPilotCarParams::LateralTuning::Which>(
|
||||
::capnp::bounded<1>() * ::capnp::ELEMENTS, FrogPilotCarParams::LateralTuning::PID);
|
||||
::capnp::_::PointerHelpers< ::cereal::CarParams::LateralPIDTuning>::adopt(_builder.getPointerField(
|
||||
::capnp::bounded<1>() * ::capnp::POINTERS), kj::mv(value));
|
||||
}
|
||||
inline ::capnp::Orphan< ::cereal::CarParams::LateralPIDTuning> FrogPilotCarParams::LateralTuning::Builder::disownPid() {
|
||||
KJ_IREQUIRE((which() == FrogPilotCarParams::LateralTuning::PID),
|
||||
"Must check which() before get()ing a union member.");
|
||||
return ::capnp::_::PointerHelpers< ::cereal::CarParams::LateralPIDTuning>::disown(_builder.getPointerField(
|
||||
::capnp::bounded<1>() * ::capnp::POINTERS));
|
||||
}
|
||||
|
||||
inline bool FrogPilotCarParams::LateralTuning::Reader::isTorque() const {
|
||||
return which() == FrogPilotCarParams::LateralTuning::TORQUE;
|
||||
}
|
||||
inline bool FrogPilotCarParams::LateralTuning::Builder::isTorque() {
|
||||
return which() == FrogPilotCarParams::LateralTuning::TORQUE;
|
||||
}
|
||||
inline bool FrogPilotCarParams::LateralTuning::Reader::hasTorque() const {
|
||||
if (which() != FrogPilotCarParams::LateralTuning::TORQUE) return false;
|
||||
return !_reader.getPointerField(
|
||||
::capnp::bounded<1>() * ::capnp::POINTERS).isNull();
|
||||
}
|
||||
inline bool FrogPilotCarParams::LateralTuning::Builder::hasTorque() {
|
||||
if (which() != FrogPilotCarParams::LateralTuning::TORQUE) return false;
|
||||
return !_builder.getPointerField(
|
||||
::capnp::bounded<1>() * ::capnp::POINTERS).isNull();
|
||||
}
|
||||
inline ::cereal::CarParams::LateralTorqueTuning::Reader FrogPilotCarParams::LateralTuning::Reader::getTorque() const {
|
||||
KJ_IREQUIRE((which() == FrogPilotCarParams::LateralTuning::TORQUE),
|
||||
"Must check which() before get()ing a union member.");
|
||||
return ::capnp::_::PointerHelpers< ::cereal::CarParams::LateralTorqueTuning>::get(_reader.getPointerField(
|
||||
::capnp::bounded<1>() * ::capnp::POINTERS));
|
||||
}
|
||||
inline ::cereal::CarParams::LateralTorqueTuning::Builder FrogPilotCarParams::LateralTuning::Builder::getTorque() {
|
||||
KJ_IREQUIRE((which() == FrogPilotCarParams::LateralTuning::TORQUE),
|
||||
"Must check which() before get()ing a union member.");
|
||||
return ::capnp::_::PointerHelpers< ::cereal::CarParams::LateralTorqueTuning>::get(_builder.getPointerField(
|
||||
::capnp::bounded<1>() * ::capnp::POINTERS));
|
||||
}
|
||||
inline void FrogPilotCarParams::LateralTuning::Builder::setTorque( ::cereal::CarParams::LateralTorqueTuning::Reader value) {
|
||||
_builder.setDataField<FrogPilotCarParams::LateralTuning::Which>(
|
||||
::capnp::bounded<1>() * ::capnp::ELEMENTS, FrogPilotCarParams::LateralTuning::TORQUE);
|
||||
::capnp::_::PointerHelpers< ::cereal::CarParams::LateralTorqueTuning>::set(_builder.getPointerField(
|
||||
::capnp::bounded<1>() * ::capnp::POINTERS), value);
|
||||
}
|
||||
inline ::cereal::CarParams::LateralTorqueTuning::Builder FrogPilotCarParams::LateralTuning::Builder::initTorque() {
|
||||
_builder.setDataField<FrogPilotCarParams::LateralTuning::Which>(
|
||||
::capnp::bounded<1>() * ::capnp::ELEMENTS, FrogPilotCarParams::LateralTuning::TORQUE);
|
||||
return ::capnp::_::PointerHelpers< ::cereal::CarParams::LateralTorqueTuning>::init(_builder.getPointerField(
|
||||
::capnp::bounded<1>() * ::capnp::POINTERS));
|
||||
}
|
||||
inline void FrogPilotCarParams::LateralTuning::Builder::adoptTorque(
|
||||
::capnp::Orphan< ::cereal::CarParams::LateralTorqueTuning>&& value) {
|
||||
_builder.setDataField<FrogPilotCarParams::LateralTuning::Which>(
|
||||
::capnp::bounded<1>() * ::capnp::ELEMENTS, FrogPilotCarParams::LateralTuning::TORQUE);
|
||||
::capnp::_::PointerHelpers< ::cereal::CarParams::LateralTorqueTuning>::adopt(_builder.getPointerField(
|
||||
::capnp::bounded<1>() * ::capnp::POINTERS), kj::mv(value));
|
||||
}
|
||||
inline ::capnp::Orphan< ::cereal::CarParams::LateralTorqueTuning> FrogPilotCarParams::LateralTuning::Builder::disownTorque() {
|
||||
KJ_IREQUIRE((which() == FrogPilotCarParams::LateralTuning::TORQUE),
|
||||
"Must check which() before get()ing a union member.");
|
||||
return ::capnp::_::PointerHelpers< ::cereal::CarParams::LateralTorqueTuning>::disown(_builder.getPointerField(
|
||||
::capnp::bounded<1>() * ::capnp::POINTERS));
|
||||
}
|
||||
|
||||
inline bool FrogPilotCarState::Reader::getAccelPressed() const {
|
||||
return _reader.getDataField<bool>(
|
||||
::capnp::bounded<0>() * ::capnp::ELEMENTS);
|
||||
@@ -3036,34 +2803,48 @@ inline void FrogPilotPlan::Builder::setDesiredFollowDistance( ::int64_t value) {
|
||||
::capnp::bounded<3>() * ::capnp::ELEMENTS, value);
|
||||
}
|
||||
|
||||
inline bool FrogPilotPlan::Reader::getExperimentalMode() const {
|
||||
inline bool FrogPilotPlan::Reader::getDisableThrottle() const {
|
||||
return _reader.getDataField<bool>(
|
||||
::capnp::bounded<66>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
|
||||
inline bool FrogPilotPlan::Builder::getExperimentalMode() {
|
||||
inline bool FrogPilotPlan::Builder::getDisableThrottle() {
|
||||
return _builder.getDataField<bool>(
|
||||
::capnp::bounded<66>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
inline void FrogPilotPlan::Builder::setExperimentalMode(bool value) {
|
||||
inline void FrogPilotPlan::Builder::setDisableThrottle(bool value) {
|
||||
_builder.setDataField<bool>(
|
||||
::capnp::bounded<66>() * ::capnp::ELEMENTS, value);
|
||||
}
|
||||
|
||||
inline bool FrogPilotPlan::Reader::getForcingStop() const {
|
||||
inline bool FrogPilotPlan::Reader::getExperimentalMode() const {
|
||||
return _reader.getDataField<bool>(
|
||||
::capnp::bounded<67>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
|
||||
inline bool FrogPilotPlan::Builder::getForcingStop() {
|
||||
inline bool FrogPilotPlan::Builder::getExperimentalMode() {
|
||||
return _builder.getDataField<bool>(
|
||||
::capnp::bounded<67>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
inline void FrogPilotPlan::Builder::setForcingStop(bool value) {
|
||||
inline void FrogPilotPlan::Builder::setExperimentalMode(bool value) {
|
||||
_builder.setDataField<bool>(
|
||||
::capnp::bounded<67>() * ::capnp::ELEMENTS, value);
|
||||
}
|
||||
|
||||
inline bool FrogPilotPlan::Reader::getForcingStop() const {
|
||||
return _reader.getDataField<bool>(
|
||||
::capnp::bounded<68>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
|
||||
inline bool FrogPilotPlan::Builder::getForcingStop() {
|
||||
return _builder.getDataField<bool>(
|
||||
::capnp::bounded<68>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
inline void FrogPilotPlan::Builder::setForcingStop(bool value) {
|
||||
_builder.setDataField<bool>(
|
||||
::capnp::bounded<68>() * ::capnp::ELEMENTS, value);
|
||||
}
|
||||
|
||||
inline float FrogPilotPlan::Reader::getForcingStopLength() const {
|
||||
return _reader.getDataField<float>(
|
||||
::capnp::bounded<5>() * ::capnp::ELEMENTS);
|
||||
@@ -3128,16 +2909,16 @@ inline void FrogPilotPlan::Builder::setIncreasedStoppedDistance(float value) {
|
||||
|
||||
inline bool FrogPilotPlan::Reader::getLateralCheck() const {
|
||||
return _reader.getDataField<bool>(
|
||||
::capnp::bounded<68>() * ::capnp::ELEMENTS);
|
||||
::capnp::bounded<69>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
|
||||
inline bool FrogPilotPlan::Builder::getLateralCheck() {
|
||||
return _builder.getDataField<bool>(
|
||||
::capnp::bounded<68>() * ::capnp::ELEMENTS);
|
||||
::capnp::bounded<69>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
inline void FrogPilotPlan::Builder::setLateralCheck(bool value) {
|
||||
_builder.setDataField<bool>(
|
||||
::capnp::bounded<68>() * ::capnp::ELEMENTS, value);
|
||||
::capnp::bounded<69>() * ::capnp::ELEMENTS, value);
|
||||
}
|
||||
|
||||
inline float FrogPilotPlan::Reader::getLaneWidthLeft() const {
|
||||
@@ -3198,16 +2979,16 @@ inline void FrogPilotPlan::Builder::setMinAcceleration(float value) {
|
||||
|
||||
inline bool FrogPilotPlan::Reader::getRedLight() const {
|
||||
return _reader.getDataField<bool>(
|
||||
::capnp::bounded<69>() * ::capnp::ELEMENTS);
|
||||
::capnp::bounded<70>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
|
||||
inline bool FrogPilotPlan::Builder::getRedLight() {
|
||||
return _builder.getDataField<bool>(
|
||||
::capnp::bounded<69>() * ::capnp::ELEMENTS);
|
||||
::capnp::bounded<70>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
inline void FrogPilotPlan::Builder::setRedLight(bool value) {
|
||||
_builder.setDataField<bool>(
|
||||
::capnp::bounded<69>() * ::capnp::ELEMENTS, value);
|
||||
::capnp::bounded<70>() * ::capnp::ELEMENTS, value);
|
||||
}
|
||||
|
||||
inline float FrogPilotPlan::Reader::getRoadCurvature() const {
|
||||
@@ -3372,16 +3153,16 @@ inline void FrogPilotPlan::Builder::setSpeedJerkStock(float value) {
|
||||
|
||||
inline bool FrogPilotPlan::Reader::getSpeedLimitChanged() const {
|
||||
return _reader.getDataField<bool>(
|
||||
::capnp::bounded<70>() * ::capnp::ELEMENTS);
|
||||
::capnp::bounded<71>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
|
||||
inline bool FrogPilotPlan::Builder::getSpeedLimitChanged() {
|
||||
return _builder.getDataField<bool>(
|
||||
::capnp::bounded<70>() * ::capnp::ELEMENTS);
|
||||
::capnp::bounded<71>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
inline void FrogPilotPlan::Builder::setSpeedLimitChanged(bool value) {
|
||||
_builder.setDataField<bool>(
|
||||
::capnp::bounded<70>() * ::capnp::ELEMENTS, value);
|
||||
::capnp::bounded<71>() * ::capnp::ELEMENTS, value);
|
||||
}
|
||||
|
||||
inline float FrogPilotPlan::Reader::getTFollow() const {
|
||||
@@ -3400,46 +3181,46 @@ inline void FrogPilotPlan::Builder::setTFollow(float value) {
|
||||
|
||||
inline bool FrogPilotPlan::Reader::getThemeUpdated() const {
|
||||
return _reader.getDataField<bool>(
|
||||
::capnp::bounded<71>() * ::capnp::ELEMENTS);
|
||||
::capnp::bounded<72>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
|
||||
inline bool FrogPilotPlan::Builder::getThemeUpdated() {
|
||||
return _builder.getDataField<bool>(
|
||||
::capnp::bounded<71>() * ::capnp::ELEMENTS);
|
||||
::capnp::bounded<72>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
inline void FrogPilotPlan::Builder::setThemeUpdated(bool value) {
|
||||
_builder.setDataField<bool>(
|
||||
::capnp::bounded<71>() * ::capnp::ELEMENTS, value);
|
||||
}
|
||||
|
||||
inline bool FrogPilotPlan::Reader::getTogglesUpdated() const {
|
||||
return _reader.getDataField<bool>(
|
||||
::capnp::bounded<72>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
|
||||
inline bool FrogPilotPlan::Builder::getTogglesUpdated() {
|
||||
return _builder.getDataField<bool>(
|
||||
::capnp::bounded<72>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
inline void FrogPilotPlan::Builder::setTogglesUpdated(bool value) {
|
||||
_builder.setDataField<bool>(
|
||||
::capnp::bounded<72>() * ::capnp::ELEMENTS, value);
|
||||
}
|
||||
|
||||
inline bool FrogPilotPlan::Reader::getTrackingLead() const {
|
||||
inline bool FrogPilotPlan::Reader::getTogglesUpdated() const {
|
||||
return _reader.getDataField<bool>(
|
||||
::capnp::bounded<73>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
|
||||
inline bool FrogPilotPlan::Builder::getTrackingLead() {
|
||||
inline bool FrogPilotPlan::Builder::getTogglesUpdated() {
|
||||
return _builder.getDataField<bool>(
|
||||
::capnp::bounded<73>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
inline void FrogPilotPlan::Builder::setTrackingLead(bool value) {
|
||||
inline void FrogPilotPlan::Builder::setTogglesUpdated(bool value) {
|
||||
_builder.setDataField<bool>(
|
||||
::capnp::bounded<73>() * ::capnp::ELEMENTS, value);
|
||||
}
|
||||
|
||||
inline bool FrogPilotPlan::Reader::getTrackingLead() const {
|
||||
return _reader.getDataField<bool>(
|
||||
::capnp::bounded<74>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
|
||||
inline bool FrogPilotPlan::Builder::getTrackingLead() {
|
||||
return _builder.getDataField<bool>(
|
||||
::capnp::bounded<74>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
inline void FrogPilotPlan::Builder::setTrackingLead(bool value) {
|
||||
_builder.setDataField<bool>(
|
||||
::capnp::bounded<74>() * ::capnp::ELEMENTS, value);
|
||||
}
|
||||
|
||||
inline float FrogPilotPlan::Reader::getUnconfirmedSlcSpeedLimit() const {
|
||||
return _reader.getDataField<float>(
|
||||
::capnp::bounded<23>() * ::capnp::ELEMENTS);
|
||||
|
||||
+103
-71
@@ -9336,17 +9336,17 @@ const ::capnp::_::RawSchema s_f28c5dc9e09375e3 = {
|
||||
0, 10, i_f28c5dc9e09375e3, nullptr, nullptr, { &s_f28c5dc9e09375e3, nullptr, nullptr, 0, 0, nullptr }, false
|
||||
};
|
||||
#endif // !CAPNP_LITE
|
||||
static const ::capnp::_::AlignedData<191> b_e774a050cbf689a4 = {
|
||||
static const ::capnp::_::AlignedData<223> b_e774a050cbf689a4 = {
|
||||
{ 0, 0, 0, 0, 5, 0, 6, 0,
|
||||
164, 137, 246, 203, 80, 160, 116, 231,
|
||||
24, 0, 0, 0, 1, 0, 5, 0,
|
||||
24, 0, 0, 0, 1, 0, 6, 0,
|
||||
241, 171, 1, 54, 197, 105, 255, 151,
|
||||
0, 0, 7, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
21, 0, 0, 0, 90, 1, 0, 0,
|
||||
41, 0, 0, 0, 7, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
37, 0, 0, 0, 111, 2, 0, 0,
|
||||
37, 0, 0, 0, 223, 2, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
108, 111, 103, 46, 99, 97, 112, 110,
|
||||
@@ -9356,84 +9356,98 @@ static const ::capnp::_::AlignedData<191> b_e774a050cbf689a4 = {
|
||||
111, 114, 113, 117, 101, 83, 116, 97,
|
||||
116, 101, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 1, 0, 1, 0,
|
||||
44, 0, 0, 0, 3, 0, 4, 0,
|
||||
52, 0, 0, 0, 3, 0, 4, 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,
|
||||
37, 1, 0, 0, 58, 0, 0, 0,
|
||||
93, 1, 0, 0, 58, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
32, 1, 0, 0, 3, 0, 1, 0,
|
||||
44, 1, 0, 0, 2, 0, 1, 0,
|
||||
88, 1, 0, 0, 3, 0, 1, 0,
|
||||
100, 1, 0, 0, 2, 0, 1, 0,
|
||||
1, 0, 0, 0, 1, 0, 0, 0,
|
||||
0, 0, 1, 0, 1, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
41, 1, 0, 0, 50, 0, 0, 0,
|
||||
97, 1, 0, 0, 50, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
36, 1, 0, 0, 3, 0, 1, 0,
|
||||
48, 1, 0, 0, 2, 0, 1, 0,
|
||||
92, 1, 0, 0, 3, 0, 1, 0,
|
||||
104, 1, 0, 0, 2, 0, 1, 0,
|
||||
3, 0, 0, 0, 2, 0, 0, 0,
|
||||
0, 0, 1, 0, 2, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
45, 1, 0, 0, 18, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
40, 1, 0, 0, 3, 0, 1, 0,
|
||||
52, 1, 0, 0, 2, 0, 1, 0,
|
||||
4, 0, 0, 0, 3, 0, 0, 0,
|
||||
0, 0, 1, 0, 3, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
49, 1, 0, 0, 18, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
44, 1, 0, 0, 3, 0, 1, 0,
|
||||
56, 1, 0, 0, 2, 0, 1, 0,
|
||||
5, 0, 0, 0, 4, 0, 0, 0,
|
||||
0, 0, 1, 0, 4, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
53, 1, 0, 0, 18, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
48, 1, 0, 0, 3, 0, 1, 0,
|
||||
60, 1, 0, 0, 2, 0, 1, 0,
|
||||
6, 0, 0, 0, 5, 0, 0, 0,
|
||||
0, 0, 1, 0, 5, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
57, 1, 0, 0, 18, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
52, 1, 0, 0, 3, 0, 1, 0,
|
||||
64, 1, 0, 0, 2, 0, 1, 0,
|
||||
7, 0, 0, 0, 6, 0, 0, 0,
|
||||
0, 0, 1, 0, 6, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
61, 1, 0, 0, 58, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
56, 1, 0, 0, 3, 0, 1, 0,
|
||||
68, 1, 0, 0, 2, 0, 1, 0,
|
||||
8, 0, 0, 0, 1, 0, 0, 0,
|
||||
0, 0, 1, 0, 7, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
65, 1, 0, 0, 82, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
64, 1, 0, 0, 3, 0, 1, 0,
|
||||
76, 1, 0, 0, 2, 0, 1, 0,
|
||||
2, 0, 0, 0, 7, 0, 0, 0,
|
||||
0, 0, 1, 0, 8, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
73, 1, 0, 0, 82, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
72, 1, 0, 0, 3, 0, 1, 0,
|
||||
84, 1, 0, 0, 2, 0, 1, 0,
|
||||
9, 0, 0, 0, 8, 0, 0, 0,
|
||||
0, 0, 1, 0, 9, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
81, 1, 0, 0, 154, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
84, 1, 0, 0, 3, 0, 1, 0,
|
||||
96, 1, 0, 0, 2, 0, 1, 0,
|
||||
10, 0, 0, 0, 9, 0, 0, 0,
|
||||
0, 0, 1, 0, 10, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
93, 1, 0, 0, 162, 0, 0, 0,
|
||||
101, 1, 0, 0, 18, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
96, 1, 0, 0, 3, 0, 1, 0,
|
||||
108, 1, 0, 0, 2, 0, 1, 0,
|
||||
4, 0, 0, 0, 3, 0, 0, 0,
|
||||
0, 0, 1, 0, 3, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
105, 1, 0, 0, 18, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
100, 1, 0, 0, 3, 0, 1, 0,
|
||||
112, 1, 0, 0, 2, 0, 1, 0,
|
||||
5, 0, 0, 0, 4, 0, 0, 0,
|
||||
0, 0, 1, 0, 4, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
109, 1, 0, 0, 18, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
104, 1, 0, 0, 3, 0, 1, 0,
|
||||
116, 1, 0, 0, 2, 0, 1, 0,
|
||||
6, 0, 0, 0, 5, 0, 0, 0,
|
||||
0, 0, 1, 0, 5, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
113, 1, 0, 0, 18, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
108, 1, 0, 0, 3, 0, 1, 0,
|
||||
120, 1, 0, 0, 2, 0, 1, 0,
|
||||
7, 0, 0, 0, 6, 0, 0, 0,
|
||||
0, 0, 1, 0, 6, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
117, 1, 0, 0, 58, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
112, 1, 0, 0, 3, 0, 1, 0,
|
||||
124, 1, 0, 0, 2, 0, 1, 0,
|
||||
8, 0, 0, 0, 1, 0, 0, 0,
|
||||
0, 0, 1, 0, 7, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
121, 1, 0, 0, 82, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
120, 1, 0, 0, 3, 0, 1, 0,
|
||||
132, 1, 0, 0, 2, 0, 1, 0,
|
||||
2, 0, 0, 0, 7, 0, 0, 0,
|
||||
0, 0, 1, 0, 8, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
129, 1, 0, 0, 82, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
128, 1, 0, 0, 3, 0, 1, 0,
|
||||
140, 1, 0, 0, 2, 0, 1, 0,
|
||||
9, 0, 0, 0, 8, 0, 0, 0,
|
||||
0, 0, 1, 0, 9, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
137, 1, 0, 0, 154, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
140, 1, 0, 0, 3, 0, 1, 0,
|
||||
152, 1, 0, 0, 2, 0, 1, 0,
|
||||
10, 0, 0, 0, 9, 0, 0, 0,
|
||||
0, 0, 1, 0, 10, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
149, 1, 0, 0, 162, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
152, 1, 0, 0, 3, 0, 1, 0,
|
||||
164, 1, 0, 0, 2, 0, 1, 0,
|
||||
11, 0, 0, 0, 10, 0, 0, 0,
|
||||
0, 0, 1, 0, 11, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
161, 1, 0, 0, 154, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
164, 1, 0, 0, 3, 0, 1, 0,
|
||||
176, 1, 0, 0, 2, 0, 1, 0,
|
||||
12, 0, 0, 0, 11, 0, 0, 0,
|
||||
0, 0, 1, 0, 12, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
173, 1, 0, 0, 66, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
168, 1, 0, 0, 3, 0, 1, 0,
|
||||
180, 1, 0, 0, 2, 0, 1, 0,
|
||||
97, 99, 116, 105, 118, 101, 0, 0,
|
||||
1, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
@@ -9526,16 +9540,34 @@ static const ::capnp::_::AlignedData<191> b_e774a050cbf689a4 = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
10, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
100, 101, 115, 105, 114, 101, 100, 76,
|
||||
97, 116, 101, 114, 97, 108, 74, 101,
|
||||
114, 107, 0, 0, 0, 0, 0, 0,
|
||||
10, 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,
|
||||
10, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
118, 101, 114, 115, 105, 111, 110, 0,
|
||||
4, 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,
|
||||
4, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, }
|
||||
};
|
||||
::capnp::word const* const bp_e774a050cbf689a4 = b_e774a050cbf689a4.words;
|
||||
#if !CAPNP_LITE
|
||||
static const uint16_t m_e774a050cbf689a4[] = {0, 9, 4, 10, 1, 8, 5, 3, 6, 2, 7};
|
||||
static const uint16_t i_e774a050cbf689a4[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
|
||||
static const uint16_t m_e774a050cbf689a4[] = {0, 9, 4, 10, 11, 1, 8, 5, 3, 6, 2, 7, 12};
|
||||
static const uint16_t i_e774a050cbf689a4[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
|
||||
const ::capnp::_::RawSchema s_e774a050cbf689a4 = {
|
||||
0xe774a050cbf689a4, b_e774a050cbf689a4.words, 191, nullptr, m_e774a050cbf689a4,
|
||||
0, 11, i_e774a050cbf689a4, nullptr, nullptr, { &s_e774a050cbf689a4, nullptr, nullptr, 0, 0, nullptr }, false
|
||||
0xe774a050cbf689a4, b_e774a050cbf689a4.words, 223, nullptr, m_e774a050cbf689a4,
|
||||
0, 13, i_e774a050cbf689a4, nullptr, nullptr, { &s_e774a050cbf689a4, nullptr, nullptr, 0, 0, nullptr }, false
|
||||
};
|
||||
#endif // !CAPNP_LITE
|
||||
static const ::capnp::_::AlignedData<130> b_9024e2d790c82ade = {
|
||||
|
||||
@@ -1076,7 +1076,7 @@ struct ControlsState::LateralTorqueState {
|
||||
class Pipeline;
|
||||
|
||||
struct _capnpPrivate {
|
||||
CAPNP_DECLARE_STRUCT_HEADER(e774a050cbf689a4, 5, 0)
|
||||
CAPNP_DECLARE_STRUCT_HEADER(e774a050cbf689a4, 6, 0)
|
||||
#if !CAPNP_LITE
|
||||
static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; }
|
||||
#endif // !CAPNP_LITE
|
||||
@@ -7531,6 +7531,10 @@ public:
|
||||
|
||||
inline float getDesiredLateralAccel() const;
|
||||
|
||||
inline float getDesiredLateralJerk() const;
|
||||
|
||||
inline ::int32_t getVersion() const;
|
||||
|
||||
private:
|
||||
::capnp::_::StructReader _reader;
|
||||
template <typename, ::capnp::Kind>
|
||||
@@ -7592,6 +7596,12 @@ public:
|
||||
inline float getDesiredLateralAccel();
|
||||
inline void setDesiredLateralAccel(float value);
|
||||
|
||||
inline float getDesiredLateralJerk();
|
||||
inline void setDesiredLateralJerk(float value);
|
||||
|
||||
inline ::int32_t getVersion();
|
||||
inline void setVersion( ::int32_t value);
|
||||
|
||||
private:
|
||||
::capnp::_::StructBuilder _builder;
|
||||
template <typename, ::capnp::Kind>
|
||||
@@ -30064,6 +30074,34 @@ inline void ControlsState::LateralTorqueState::Builder::setDesiredLateralAccel(f
|
||||
::capnp::bounded<9>() * ::capnp::ELEMENTS, value);
|
||||
}
|
||||
|
||||
inline float ControlsState::LateralTorqueState::Reader::getDesiredLateralJerk() const {
|
||||
return _reader.getDataField<float>(
|
||||
::capnp::bounded<10>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
|
||||
inline float ControlsState::LateralTorqueState::Builder::getDesiredLateralJerk() {
|
||||
return _builder.getDataField<float>(
|
||||
::capnp::bounded<10>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
inline void ControlsState::LateralTorqueState::Builder::setDesiredLateralJerk(float value) {
|
||||
_builder.setDataField<float>(
|
||||
::capnp::bounded<10>() * ::capnp::ELEMENTS, value);
|
||||
}
|
||||
|
||||
inline ::int32_t ControlsState::LateralTorqueState::Reader::getVersion() const {
|
||||
return _reader.getDataField< ::int32_t>(
|
||||
::capnp::bounded<11>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
|
||||
inline ::int32_t ControlsState::LateralTorqueState::Builder::getVersion() {
|
||||
return _builder.getDataField< ::int32_t>(
|
||||
::capnp::bounded<11>() * ::capnp::ELEMENTS);
|
||||
}
|
||||
inline void ControlsState::LateralTorqueState::Builder::setVersion( ::int32_t value) {
|
||||
_builder.setDataField< ::int32_t>(
|
||||
::capnp::bounded<11>() * ::capnp::ELEMENTS, value);
|
||||
}
|
||||
|
||||
inline bool ControlsState::LateralLQRState::Reader::getActive() const {
|
||||
return _reader.getDataField<bool>(
|
||||
::capnp::bounded<0>() * ::capnp::ELEMENTS);
|
||||
|
||||
Binary file not shown.
@@ -795,6 +795,8 @@ struct ControlsState @0x97ff69c53601abf1 {
|
||||
saturated @7 :Bool;
|
||||
actualLateralAccel @9 :Float32;
|
||||
desiredLateralAccel @10 :Float32;
|
||||
desiredLateralJerk @11 :Float32;
|
||||
version @12 :Int32;
|
||||
}
|
||||
|
||||
struct LateralLQRState {
|
||||
|
||||
@@ -224,6 +224,7 @@ std::unordered_map<std::string, uint32_t> keys = {
|
||||
{"AdvancedLateralTune", PERSISTENT},
|
||||
{"AdvancedLongitudinalTune", PERSISTENT},
|
||||
{"AggressiveFollow", PERSISTENT},
|
||||
{"AggressiveFollowHigh", PERSISTENT},
|
||||
{"AggressiveJerkAcceleration", PERSISTENT},
|
||||
{"AggressiveJerkDanger", PERSISTENT},
|
||||
{"AggressiveJerkDeceleration", PERSISTENT},
|
||||
@@ -321,6 +322,7 @@ std::unordered_map<std::string, uint32_t> keys = {
|
||||
{"DynamicPedalsOnUI", PERSISTENT},
|
||||
{"EngageVolume", PERSISTENT},
|
||||
{"ExperimentalGMTune", PERSISTENT},
|
||||
{"EVTuning", PERSISTENT},
|
||||
{"Fahrenheit", PERSISTENT},
|
||||
{"FavoriteDestinations", PERSISTENT | DONT_LOG},
|
||||
{"FlashPanda", CLEAR_ON_MANAGER_START},
|
||||
@@ -346,6 +348,7 @@ std::unordered_map<std::string, uint32_t> keys = {
|
||||
{"FrogsGoMoosTweak", PERSISTENT},
|
||||
{"FullMap", PERSISTENT},
|
||||
{"GasRegenCmd", PERSISTENT},
|
||||
{"GMPedalLongitudinal", PERSISTENT},
|
||||
{"GoatScream", PERSISTENT},
|
||||
{"GreenLightAlert", PERSISTENT},
|
||||
{"HideAlerts", PERSISTENT},
|
||||
@@ -406,6 +409,10 @@ std::unordered_map<std::string, uint32_t> keys = {
|
||||
{"ModelToDownload", CLEAR_ON_MANAGER_START},
|
||||
{"ModelUI", PERSISTENT},
|
||||
{"ModelVersions", PERSISTENT},
|
||||
{"ModelReleasedDates", PERSISTENT},
|
||||
{"CommunityFavorites", PERSISTENT},
|
||||
{"UserFavorites", PERSISTENT},
|
||||
{"SortModelsByDate", PERSISTENT},
|
||||
{"NavigationUI", PERSISTENT},
|
||||
{"NextMapSpeedLimit", CLEAR_ON_MANAGER_START},
|
||||
{"NewLongAPI", PERSISTENT},
|
||||
@@ -451,6 +458,7 @@ std::unordered_map<std::string, uint32_t> keys = {
|
||||
{"RandomThemes", PERSISTENT},
|
||||
{"RefuseVolume", PERSISTENT},
|
||||
{"RelaxedFollow", PERSISTENT},
|
||||
{"RelaxedFollowHigh", PERSISTENT},
|
||||
{"RelaxedJerkAcceleration", PERSISTENT},
|
||||
{"RelaxedJerkDanger", PERSISTENT},
|
||||
{"RelaxedJerkDeceleration", PERSISTENT},
|
||||
@@ -510,6 +518,7 @@ std::unordered_map<std::string, uint32_t> keys = {
|
||||
{"SpeedLimitsFiltered", PERSISTENT | DONT_LOG},
|
||||
{"SpeedLimitSources", PERSISTENT},
|
||||
{"StandardFollow", PERSISTENT},
|
||||
{"StandardFollowHigh", PERSISTENT},
|
||||
{"StandardJerkAcceleration", PERSISTENT},
|
||||
{"StandardJerkDanger", PERSISTENT},
|
||||
{"StandardJerkDeceleration", PERSISTENT},
|
||||
@@ -526,6 +535,8 @@ std::unordered_map<std::string, uint32_t> keys = {
|
||||
{"SteerDelayStock", PERSISTENT},
|
||||
{"SteerFriction", PERSISTENT},
|
||||
{"SteerFrictionStock", PERSISTENT},
|
||||
{"SteerOffset", PERSISTENT},
|
||||
{"SteerOffsetStock", PERSISTENT},
|
||||
{"SteerLatAccel", PERSISTENT},
|
||||
{"SteerLatAccelStock", PERSISTENT},
|
||||
{"SteerKP", PERSISTENT},
|
||||
@@ -540,6 +551,7 @@ std::unordered_map<std::string, uint32_t> keys = {
|
||||
{"StoppedTimer", PERSISTENT},
|
||||
{"TacoTune", PERSISTENT},
|
||||
{"TacoTuneHacks", PERSISTENT},
|
||||
{"TrailerLoad", PERSISTENT},
|
||||
{"TestAlert", CLEAR_ON_MANAGER_START},
|
||||
{"TetheringEnabled", PERSISTENT},
|
||||
{"ThemeDownloadProgress", CLEAR_ON_MANAGER_START},
|
||||
@@ -579,6 +591,7 @@ std::unordered_map<std::string, uint32_t> keys = {
|
||||
{"WheelIcon", PERSISTENT},
|
||||
{"WheelSpeed", PERSISTENT},
|
||||
{"StopDistance", PERSISTENT},
|
||||
{"RecoveryPower", PERSISTENT},
|
||||
{"WheelToDownload", CLEAR_ON_MANAGER_START},
|
||||
};
|
||||
|
||||
|
||||
Binary file not shown.
+12
-1
@@ -6,6 +6,7 @@ from collections import deque
|
||||
|
||||
from setproctitle import getproctitle
|
||||
|
||||
from openpilot.common.swaglog import cloudlog
|
||||
from openpilot.system.hardware import PC
|
||||
|
||||
|
||||
@@ -34,7 +35,17 @@ def set_realtime_priority(level: int) -> None:
|
||||
|
||||
def set_core_affinity(cores: list[int]) -> None:
|
||||
if not PC:
|
||||
os.sched_setaffinity(0, cores)
|
||||
for attempt in range(3): # Retry up to 3 times
|
||||
try:
|
||||
os.sched_setaffinity(0, cores)
|
||||
return
|
||||
except OSError as e:
|
||||
if e.errno == 22: # EINVAL
|
||||
time.sleep(0.1) # Brief delay before retry
|
||||
else:
|
||||
raise # Re-raise other errors
|
||||
# If all retries fail, log and continue without affinity
|
||||
cloudlog.error(f"Failed to set core affinity after retries: {cores}")
|
||||
|
||||
|
||||
def config_realtime_process(cores: int | list[int], priority: int) -> None:
|
||||
|
||||
@@ -88,7 +88,7 @@ def handle_error(destination, error_message, error, download_param, progress_par
|
||||
if destination:
|
||||
delete_file(destination)
|
||||
|
||||
if progress_param and "404" not in error_message:
|
||||
if params_memory and progress_param and "404" not in error_message:
|
||||
print(f"Error occurred: {error}")
|
||||
params_memory.put(progress_param, error_message)
|
||||
params_memory.remove(download_param)
|
||||
|
||||
@@ -107,7 +107,7 @@ class ModelManager:
|
||||
self.downloading_model = False
|
||||
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)
|
||||
filenames = [
|
||||
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_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:
|
||||
model_path = MODELS_PATH / filename
|
||||
model_url = f"{repo_url}/Models/{filename}"
|
||||
@@ -208,13 +213,18 @@ class ModelManager:
|
||||
except Exception:
|
||||
model_version = None
|
||||
|
||||
if model_version in ("v8", "v9", "v10", "v11"):
|
||||
if model_version in ("v8", "v9", "v10", "v11", "v12"):
|
||||
v8_v9_files = [
|
||||
f"{model}_driving_policy_tinygrad.pkl",
|
||||
f"{model}_driving_vision_tinygrad.pkl",
|
||||
f"{model}_driving_policy_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):
|
||||
downloaded_models.add(model)
|
||||
elif model_version == "v7":
|
||||
@@ -259,13 +269,18 @@ class ModelManager:
|
||||
except Exception:
|
||||
model_version = None
|
||||
|
||||
if model_version in ("v8", "v9", "v10", "v11"):
|
||||
if model_version in ("v8", "v9", "v10", "v11", "v12"):
|
||||
v8_v9_files = [
|
||||
f"{model}_driving_policy_tinygrad.pkl",
|
||||
f"{model}_driving_vision_tinygrad.pkl",
|
||||
f"{model}_driving_policy_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:
|
||||
path = MODELS_PATH / filename
|
||||
expected_size = model_sizes.get(filename.rsplit(".", 1)[0])
|
||||
@@ -296,7 +311,10 @@ class ModelManager:
|
||||
params.put("AvailableModels", ",".join(self.available_models))
|
||||
params.put("AvailableModelNames", ",".join([model["name"] for model in model_info]))
|
||||
params.put("AvailableModelSeries", ",".join(self.model_series))
|
||||
params.put("CommunityFavorites", ",".join([model["id"] for model in model_info if model.get("community_favorite", False)]))
|
||||
params.put("ModelReleasedDates", ",".join([model.get("released", "2023-01-01") for model in model_info]))
|
||||
params.put("ModelVersions", ",".join(self.model_versions))
|
||||
params.put("CommunityFavorites", ",".join([model["id"] for model in model_info if model.get("community_favorite", False)]))
|
||||
params.put("AvailableModelSeries", ",".join(self.model_series))
|
||||
print("Models list updated successfully")
|
||||
|
||||
@@ -375,13 +393,18 @@ class ModelManager:
|
||||
handle_error(None, "Download cancelled...", "Download cancelled...", MODEL_DOWNLOAD_ALL_PARAM, DOWNLOAD_PROGRESS_PARAM, params_memory)
|
||||
return
|
||||
|
||||
if model_version in ("v8", "v9", "v10", "v11"):
|
||||
if model_version in ("v8", "v9", "v10", "v11", "v12"):
|
||||
required_files = [
|
||||
f"{model}_driving_policy_tinygrad.pkl",
|
||||
f"{model}_driving_vision_tinygrad.pkl",
|
||||
f"{model}_driving_policy_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()]
|
||||
if missing:
|
||||
print(f"Tinygrad model {model} is missing files. Preparing to download...")
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
{"input_std":[[9.281861],[1.8477924],[0.7977224],[0.047467366],[1.7969038],[1.8168812],[1.8351218],[1.785757],[1.7335743],[1.6658221],[1.5893887],[0.047346078],[0.0473731],[0.047383286],[0.047291175],[0.047300573],[0.04712479],[0.046799928]],"model_test_loss":0.027355343103408813,"input_size":18,"current_date_and_time":"2023-08-05_05-11-44","input_mean":[[21.655252],[-0.07694559],[-0.006081294],[-0.007598456],[-0.07309746],[-0.075890236],[-0.07804942],[-0.076106496],[-0.07184982],[-0.06528668],[-0.060404416],[-0.0077262702],[-0.0077046235],[-0.0076850485],[-0.007687444],[-0.007708868],[-0.0077959923],[-0.008017422]],"input_vars":["v_ego","lateral_accel","lateral_jerk","roll","lateral_accel_m03","lateral_accel_m02","lateral_accel_m01","lateral_accel_p03","lateral_accel_p06","lateral_accel_p10","lateral_accel_p15","roll_m03","roll_m02","roll_m01","roll_p03","roll_p06","roll_p10","roll_p15"],"output_size":1,"layers":[{"dense_1_b":[[-0.35776415],[-0.126288],[0.007988413],[0.03850029],[-0.056796823],[0.0072075897],[0.17376427]],"dense_1_W":[[0.010538558,6.7293744,-0.007391298,-1.035045,-0.47446147,1.0940393,0.08225446,-0.5795131,0.573115,1.82923,-0.16999252,0.8818023,0.03560901,-0.9470653,-1.042151,1.1532398,1.9009485,-1.2265956],[0.009010456,-1.3618345,0.039026346,0.22943486,-0.6669799,-0.768271,-0.16828564,-0.13406865,0.19760236,-0.18953702,-0.019137766,0.1468623,0.26367718,0.4732375,0.73679143,0.62450147,0.30198866,-0.93340015],[-0.044318866,2.2138615,9.620889,-0.66480356,-0.06849887,-0.038568456,-0.30580127,-0.088089585,0.31187677,0.5968372,-1.1462088,0.13234706,0.29166338,-0.69978577,-0.01790655,-0.097928315,-0.56950736,0.7560642],[1.3758256,0.8700429,-0.24295154,0.20832618,-0.7735097,1.0379355,-0.60753095,-0.5457418,-1.0892137,-0.6708325,0.24982774,0.09251328,0.08596103,-0.58034134,-0.3046114,-0.19754426,0.006461508,0.5989185],[0.06314328,-2.492993,-0.28200585,0.49902886,0.8513198,-0.5704965,1.0960953,-0.08426956,-0.76074624,0.10669376,0.02775254,-0.42194095,-0.34657434,-0.10863868,0.17019278,0.0963825,-0.10169116,0.21243806],[0.007984091,-1.9276509,-0.0013926353,0.04057924,1.4438432,1.3440262,-2.506722,1.700801,0.72410774,0.13471895,-0.18753268,0.7303607,0.018133093,-0.71643597,0.07050904,-0.30161944,0.085108586,0.061202843],[0.9413167,-0.9954305,-0.19510143,-0.4711845,-0.12398665,-0.45175523,1.0616771,0.28550953,-0.55543137,-0.21576759,-0.2364377,-0.012782618,-0.050565187,0.257694,-0.20975965,0.00022543047,-0.08760746,0.4983852]],"activation":"σ"},{"dense_2_W":[[-0.71804935,0.017023304,-0.099854074,-0.3262651,-0.402829,-0.12073083,0.13537839],[-0.44002575,-0.1071093,-0.58886194,-0.17319413,-0.21134079,0.23135148,0.0006880979],[-0.55711204,-0.8693639,-0.6443761,-0.7382846,0.18980889,-0.6082511,-0.63103676],[0.11338112,-0.5327033,0.2856197,0.32239884,-0.72682667,0.5302305,-0.45094746],[-0.35197002,-0.14440043,-0.025249843,-0.48697743,0.3340018,-0.25992322,0.0050561456],[0.34757507,0.15670523,-0.14263277,0.50704384,-0.020171141,0.6408679,-0.3074123],[0.40258837,-0.59363264,0.35948923,-0.060853776,-0.0072541097,0.89743376,-0.49789146],[-0.63476,0.29580453,0.1689314,-0.5061521,0.24901053,-0.23218995,0.57968193],[-0.66173035,0.50861925,-0.5845035,-0.6602214,0.8341883,-0.31437424,0.8046359],[0.038493533,0.15464582,-0.04848341,-0.57820857,-0.25891733,-0.47527292,0.21441916],[-0.15464531,-0.07454202,-0.8215851,-0.12614948,-0.5924209,0.00017916794,0.24154592],[0.6091424,-0.112086505,0.1144111,-0.31035227,-0.9237534,0.041003596,-0.3542808],[0.2989792,-0.23780549,0.116059326,-0.6056522,0.5499526,-0.9001413,0.5200723]],"activation":"σ","dense_2_b":[[-0.2638964],[-0.24607328],[-0.15493082],[-0.0071187904],[-0.23515384],[-0.09098133],[-0.034066215],[0.03609036],[-0.03842933],[-0.042302527],[-0.2439947],[-0.16342077],[-0.01030317]]},{"dense_3_W":[[0.45771673,-0.2084603,0.3570187,0.35835707,0.13684571,-0.582958,0.29889587,0.43543494,0.11841301,-0.26185623,-0.4988437,0.5752996,-0.28057483],[-0.19594137,0.050280698,-0.29057446,-0.2829161,-0.16987291,-0.21278952,-0.59946907,0.21295123,0.7040468,0.53549695,-0.52553934,-0.19560973,0.6233473],[-0.19091003,0.08669418,-0.5792192,0.57799137,-0.36263424,0.6037143,0.27898273,-0.30951327,-0.3572644,0.46720102,-0.5403428,0.32415462,-0.60570025]],"activation":"identity","dense_3_b":[[-0.0047377176],[0.023170695],[-0.021546118]]},{"dense_4_W":[[-0.12453941,-1.006034,0.96776205]],"dense_4_b":[[-0.02351544]],"activation":"identity"}]}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 503 KiB After Width: | Height: | Size: 858 KiB |
@@ -98,7 +98,7 @@ class ThemeManager:
|
||||
|
||||
repo_url = get_repository_url()
|
||||
if not repo_url:
|
||||
handle_error(None, "GitHub and GitLab are offline...", "Repository unavailable", asset_param, DOWNLOAD_PROGRESS_PARAM)
|
||||
handle_error(None, "GitHub and GitLab are offline...", "Repository unavailable", asset_param, DOWNLOAD_PROGRESS_PARAM, params_memory)
|
||||
self.downloading_theme = False
|
||||
return
|
||||
|
||||
@@ -122,16 +122,16 @@ class ThemeManager:
|
||||
delete_file(theme_path)
|
||||
|
||||
print(f"Downloading theme from GitHub: {theme_name}")
|
||||
download_file(CANCEL_DOWNLOAD_PARAM, theme_path, DOWNLOAD_PROGRESS_PARAM, theme_url, asset_param, self.session)
|
||||
download_file(CANCEL_DOWNLOAD_PARAM, theme_path, DOWNLOAD_PROGRESS_PARAM, theme_url, asset_param, params_memory)
|
||||
|
||||
if params_memory.get_bool(CANCEL_DOWNLOAD_PARAM):
|
||||
delete_file(theme_path)
|
||||
handle_error(None, "Download cancelled...", "Download cancelled...", asset_param, DOWNLOAD_PROGRESS_PARAM)
|
||||
handle_error(None, "Download cancelled...", "Download cancelled...", asset_param, DOWNLOAD_PROGRESS_PARAM, params_memory)
|
||||
|
||||
self.downloading_theme = False
|
||||
return
|
||||
|
||||
if verify_download(theme_path, theme_url, self.session):
|
||||
if verify_download(theme_path, theme_url):
|
||||
print(f"Theme {theme_name} downloaded and verified successfully from GitHub!")
|
||||
self.update_theme_size(theme_component, theme_name, theme_path.stat().st_size)
|
||||
|
||||
@@ -149,7 +149,7 @@ class ThemeManager:
|
||||
elif self.handle_verification_failure(extension, theme_component, theme_name, asset_param, theme_path, download_path, frogpilot_toggles):
|
||||
return
|
||||
|
||||
handle_error(download_path, "Download failed...", "Download failed...", asset_param, DOWNLOAD_PROGRESS_PARAM)
|
||||
handle_error(download_path, "Download failed...", "Download failed...", asset_param, DOWNLOAD_PROGRESS_PARAM, params_memory)
|
||||
self.downloading_theme = False
|
||||
|
||||
def fetch_assets(self, repo_url, frogpilot_toggles):
|
||||
@@ -332,9 +332,9 @@ class ThemeManager:
|
||||
|
||||
theme_url = download_link + extension
|
||||
print(f"Downloading theme from GitLab: {theme_name}")
|
||||
download_file(CANCEL_DOWNLOAD_PARAM, theme_path, DOWNLOAD_PROGRESS_PARAM, theme_url, asset_param, self.session)
|
||||
download_file(CANCEL_DOWNLOAD_PARAM, theme_path, DOWNLOAD_PROGRESS_PARAM, theme_url, asset_param, params_memory)
|
||||
|
||||
if verify_download(theme_path, theme_url, self.session):
|
||||
if verify_download(theme_path, theme_url):
|
||||
print(f"Theme {theme_name} downloaded and verified successfully from GitLab!")
|
||||
self.update_theme_size(theme_component, theme_name, theme_path.stat().st_size)
|
||||
|
||||
@@ -350,7 +350,7 @@ class ThemeManager:
|
||||
self.update_themes(frogpilot_toggles)
|
||||
return True
|
||||
|
||||
handle_error(None, "Download failed...", "Download failed...", asset_param, DOWNLOAD_PROGRESS_PARAM)
|
||||
handle_error(None, "Download failed...", "Download failed...", asset_param, DOWNLOAD_PROGRESS_PARAM, params_memory)
|
||||
self.downloading_theme = False
|
||||
return False
|
||||
|
||||
|
||||
@@ -296,12 +296,12 @@ def update_openpilot():
|
||||
if params.get("UpdaterState", encoding="utf-8") != "idle":
|
||||
return
|
||||
|
||||
while params.get_bool("IsOnroad") or params_memory.get_bool("UpdateSpeedLimits") or running_threads.get("lock_doors", threading.Thread()).is_alive():
|
||||
time.sleep(60)
|
||||
|
||||
if not update_available():
|
||||
return
|
||||
|
||||
while params.get_bool("IsOnroad") or params_memory.get_bool("UpdateSpeedLimits") or running_threads.get("lock_doors", threading.Thread()).is_alive():
|
||||
time.sleep(60)
|
||||
|
||||
while True:
|
||||
if not update_available():
|
||||
break
|
||||
|
||||
@@ -13,7 +13,8 @@ from openpilot.common.conversions import Conversions as CV
|
||||
from openpilot.common.params import Params
|
||||
from openpilot.selfdrive.car import gen_empty_fingerprint
|
||||
from openpilot.selfdrive.car.car_helpers import interfaces
|
||||
from openpilot.selfdrive.car.gm.values import GMFlags
|
||||
from openpilot.selfdrive.car.gm.values import EV_CAR as GM_EV_CAR, GMFlags
|
||||
from openpilot.selfdrive.car.hyundai.values import EV_CAR as HYUNDAI_EV_CAR
|
||||
from openpilot.selfdrive.car.interfaces import CarInterfaceBase
|
||||
from openpilot.selfdrive.car.mock.interface import CarInterface
|
||||
from openpilot.selfdrive.car.mock.values import CAR as MOCK
|
||||
@@ -29,11 +30,10 @@ params = Params()
|
||||
params_cache = Params("/cache/params")
|
||||
params_default = Params("/dev/shm/params_default")
|
||||
params_memory = Params("/dev/shm/params")
|
||||
params_tracking = Params("/cache/tracking")
|
||||
params_tracking = Params("/cache/tracking")
|
||||
|
||||
GearShifter = car.CarState.GearShifter
|
||||
SafetyModel = car.CarParams.SafetyModel
|
||||
TransmissionType = car.CarParams.TransmissionType
|
||||
|
||||
CITY_SPEED_LIMIT = 25 # 55mph is typically the minimum speed for highways
|
||||
CRUISING_SPEED = 5 # Roughly the speed cars go when not touching the gas while in drive
|
||||
@@ -75,7 +75,7 @@ MAPD_PATH = Path("/data/media/0/osm/mapd")
|
||||
MAPS_PATH = Path("/data/media/0/osm/offline")
|
||||
NNFF_MODELS_PATH = Path(BASEDIR) / "frogpilot/assets/nnff_models"
|
||||
|
||||
DEFAULT_MODEL = "firehose"
|
||||
DEFAULT_MODEL = "bd2"
|
||||
DEFAULT_MODEL_NAME = "Firehose (Default) 👀📡"
|
||||
DEFAULT_MODEL_VERSION = "v11"
|
||||
|
||||
@@ -96,6 +96,8 @@ EXCLUDED_KEYS = {
|
||||
}
|
||||
|
||||
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_tinygrad.pkl", "policy model"),
|
||||
("driving_vision_metadata.pkl", "vision metadata"),
|
||||
@@ -128,9 +130,11 @@ frogpilot_default_params: list[tuple[str, str | bytes, int, str]] = [
|
||||
("AdjacentPath", "0", 3, "0"),
|
||||
("AdjacentPathMetrics", "0", 3, "0"),
|
||||
("AdvancedCustomUI", "0", 2, "0"),
|
||||
("AdvancedLateralTune", "0", 2, "0"),
|
||||
("AdvancedLateralTune", "1", 2, "0"),
|
||||
("AdvancedLongitudinalTune", "0", 3, "0"),
|
||||
("EVTuning", "", 3, "0"),
|
||||
("AggressiveFollow", "1.25", 2, "1.25"),
|
||||
("AggressiveFollowHigh", "1.25", 2, "1.25"),
|
||||
("AggressiveJerkAcceleration", "50", 3, "50"),
|
||||
("AggressiveJerkDanger", "100", 3, "100"),
|
||||
("AggressiveJerkDeceleration", "50", 3, "50"),
|
||||
@@ -149,11 +153,13 @@ frogpilot_default_params: list[tuple[str, str | bytes, int, str]] = [
|
||||
("AvailableModelNames", "", 1, ""),
|
||||
("AvailableModelSeries", "", 1, ""),
|
||||
("AvailableModels", "", 1, ""),
|
||||
("CommunityFavorites", "", 1, ""),
|
||||
("UserFavorites", "", 0, ""),
|
||||
("BigMap", "0", 2, "0"),
|
||||
("BlacklistedModels", "", 2, ""),
|
||||
("BlindSpotMetrics", "1", 3, "0"),
|
||||
("BlindSpotPath", "1", 1, "0"),
|
||||
("BorderMetrics", "0", 3, "0"),
|
||||
("BorderMetrics", "1", 3, "0"),
|
||||
("CalibratedLateralAcceleration", str(DEFAULT_LATERAL_ACCELERATION), 2, str(DEFAULT_LATERAL_ACCELERATION)),
|
||||
("CalibrationProgress", "0", 3, "0"),
|
||||
("CameraView", "3", 2, "0"),
|
||||
@@ -165,16 +171,16 @@ frogpilot_default_params: list[tuple[str, str | bytes, int, str]] = [
|
||||
("CECurvesLead", "0", 1, "0"),
|
||||
("CELead", "0", 1, "0"),
|
||||
("CEModelStopTime", str(PLANNER_TIME - 2), 2, "0"),
|
||||
("CENavigation", "1", 2, "0"),
|
||||
("CENavigation", "0", 2, "0"),
|
||||
("CENavigationIntersections", "1", 2, "0"),
|
||||
("CENavigationLead", "1", 2, "0"),
|
||||
("CENavigationTurns", "1", 2, "0"),
|
||||
("CESignalSpeed", "55", 2, "0"),
|
||||
("CESignalLaneDetection", "1", 2, "0"),
|
||||
("CESlowerLead", "0", 1, "0"),
|
||||
("CESlowerLead", "1", 1, "0"),
|
||||
("CESpeed", "0", 1, "0"),
|
||||
("CESpeedLead", "0", 1, "0"),
|
||||
("CEStoppedLead", "0", 1, "0"),
|
||||
("CEStoppedLead", "1", 1, "0"),
|
||||
("ClusterOffset", "1.015", 2, "1.015"),
|
||||
("Compass", "0", 1, "0"),
|
||||
("ConditionalExperimental", "1", 1, "0"),
|
||||
@@ -192,7 +198,7 @@ frogpilot_default_params: list[tuple[str, str | bytes, int, str]] = [
|
||||
("CustomUI", "1", 1, "0"),
|
||||
("DecelerationProfile", "1", 2, "0"),
|
||||
("DeveloperMetrics", "1", 3, "0"),
|
||||
("DeveloperSidebar", "1", 3, "0"),
|
||||
("DeveloperSidebar", "0", 3, "0"),
|
||||
("DeveloperSidebarMetric1", "1", 3, "0"),
|
||||
("DeveloperSidebarMetric2", "2", 3, "0"),
|
||||
("DeveloperSidebarMetric3", "3", 3, "0"),
|
||||
@@ -201,7 +207,7 @@ frogpilot_default_params: list[tuple[str, str | bytes, int, str]] = [
|
||||
("DeveloperSidebarMetric6", "6", 3, "0"),
|
||||
("DeveloperSidebarMetric7", "7", 3, "0"),
|
||||
("DeveloperWidgets", "1", 3, "0"),
|
||||
("DeveloperUI", "0", 3, "0"),
|
||||
("DeveloperUI", "1", 3, "0"),
|
||||
("DeviceManagement", "1", 1, "0"),
|
||||
("DeviceShutdown", "9", 1, "33"),
|
||||
("DisableOnroadUploads", "0", 2, "0"),
|
||||
@@ -219,7 +225,7 @@ frogpilot_default_params: list[tuple[str, str | bytes, int, str]] = [
|
||||
("Fahrenheit", "0", 3, "0"),
|
||||
("FavoriteDestinations", "", 0, ""),
|
||||
("ForceAutoTune", "0", 2, "0"),
|
||||
("ForceAutoTuneOff", "0", 2, "0"),
|
||||
("ForceAutoTuneOff", "1", 2, "0"),
|
||||
("ForceFingerprint", "0", 2, "0"),
|
||||
("ForceMPHDashboard", "0", 2, "0"),
|
||||
("ForceStops", "0", 2, "0"),
|
||||
@@ -230,6 +236,7 @@ frogpilot_default_params: list[tuple[str, str | bytes, int, str]] = [
|
||||
("FrogsGoMoosTweak", "1", 2, "0"),
|
||||
("FullMap", "0", 2, "0"),
|
||||
("GasRegenCmd", "1", 2, "0"),
|
||||
("GMPedalLongitudinal", "1", 2, "1"),
|
||||
("GithubSshKeys", "", 0, ""),
|
||||
("GithubUsername", "", 0, ""),
|
||||
("GoatScream", "0", 1, "0"),
|
||||
@@ -269,6 +276,7 @@ frogpilot_default_params: list[tuple[str, str | bytes, int, str]] = [
|
||||
("LongitudinalActuatorDelay", "", 3, ""),
|
||||
("LongitudinalActuatorDelayStock", "", 3, ""),
|
||||
("LongitudinalTune", "1", 0, "0"),
|
||||
("TrailerLoad", "0", 2, "0"),
|
||||
("LongPitch", "1", 2, "0"),
|
||||
("LoudBlindspotAlert", "0", 0, "0"),
|
||||
("LowVoltageShutdown", str(VBATT_PAUSE_CHARGING), 2, str(VBATT_PAUSE_CHARGING)),
|
||||
@@ -284,14 +292,16 @@ frogpilot_default_params: list[tuple[str, str | bytes, int, str]] = [
|
||||
("Model", DEFAULT_MODEL, 1, DEFAULT_MODEL),
|
||||
("ModelDrivesAndScores", "", 2, ""),
|
||||
("ModelRandomizer", "0", 2, "0"),
|
||||
("ModelReleasedDates", "", 1, ""),
|
||||
("ModelUI", "1", 2, "0"),
|
||||
("ModelVersions", "", 2, ""),
|
||||
("SortModelsByDate", "0", 2, "0"),
|
||||
("NavigationUI", "1", 1, "0"),
|
||||
("NavSettingLeftSide", "0", 0, "0"),
|
||||
("NavSettingTime24h", "0", 0, "0"),
|
||||
("NewLongAPI", "0", 2, "1"),
|
||||
("NNFF", "1", 2, "0"),
|
||||
("NNFFLite", "1", 2, "0"),
|
||||
("NNFF", "0", 2, "0"),
|
||||
("NNFFLite", "0", 2, "0"),
|
||||
("NoLogging", "0", 2, "0"),
|
||||
("NoUploads", "0", 2, "0"),
|
||||
("NudgelessLaneChange", "0", 0, "0"),
|
||||
@@ -326,13 +336,14 @@ frogpilot_default_params: list[tuple[str, str | bytes, int, str]] = [
|
||||
("RecordFront", "0", 0, "0"),
|
||||
("RefuseVolume", "101", 2, "101"),
|
||||
("RelaxedFollow", "1.75", 2, "1.75"),
|
||||
("RelaxedFollowHigh", "1.75", 2, "1.75"),
|
||||
("RelaxedJerkAcceleration", "50", 3, "50"),
|
||||
("RelaxedJerkDanger", "100", 3, "100"),
|
||||
("RelaxedJerkDeceleration", "50", 3, "50"),
|
||||
("RelaxedJerkSpeed", "50", 3, "50"),
|
||||
("RelaxedJerkSpeedDecrease", "50", 3, "50"),
|
||||
("RelaxedPersonalityProfile", "1", 2, "0"),
|
||||
("ReverseCruise", "0", 1, "0"),
|
||||
("ReverseCruise", "1", 1, "0"),
|
||||
("RoadEdgesWidth", "2", 2, "2"),
|
||||
("RoadNameUI", "1", 2, "0"),
|
||||
("RotatingWheel", "1", 1, "0"),
|
||||
@@ -356,7 +367,7 @@ frogpilot_default_params: list[tuple[str, str | bytes, int, str]] = [
|
||||
("ShownToggleDescriptions", "", 0, ""),
|
||||
("ShowSLCOffset", "1", 0, "0"),
|
||||
("ShowSpeedLimits", "1", 1, "0"),
|
||||
("ShowSteering", "0", 3, "0"),
|
||||
("ShowSteering", "1", 3, "0"),
|
||||
("ShowStoppingPoint", "0", 2, "0"),
|
||||
("ShowStoppingPointMetrics", "0", 2, "0"),
|
||||
("ShowStorageLeft", "0", 3, "0"),
|
||||
@@ -383,6 +394,7 @@ frogpilot_default_params: list[tuple[str, str | bytes, int, str]] = [
|
||||
("StartupMessageBottom", "Human-tested, frog-approved 🐸", 0, "Always keep hands on wheel and eyes on road"),
|
||||
("StartupMessageTop", "Hop in and buckle up!", 0, "Be ready to take over at any time"),
|
||||
("StandardFollow", "1.45", 2, "1.45"),
|
||||
("StandardFollowHigh", "1.45", 2, "1.45"),
|
||||
("StandardJerkAcceleration", "50", 3, "50"),
|
||||
("StandardJerkDanger", "100", 3, "100"),
|
||||
("StandardJerkDeceleration", "50", 3, "50"),
|
||||
@@ -397,6 +409,8 @@ frogpilot_default_params: list[tuple[str, str | bytes, int, str]] = [
|
||||
("SteerDelayStock", "", 3, ""),
|
||||
("SteerFriction", "", 3, ""),
|
||||
("SteerFrictionStock", "", 3, ""),
|
||||
("SteerOffset", "", 3, ""),
|
||||
("SteerOffsetStock", "", 3, ""),
|
||||
("SteerKP", "", 3, ""),
|
||||
("SteerKPStock", "", 3, ""),
|
||||
("SteerLatAccel", "", 3, ""),
|
||||
@@ -419,8 +433,8 @@ frogpilot_default_params: list[tuple[str, str | bytes, int, str]] = [
|
||||
("TrafficJerkSpeed", "50", 3, "50"),
|
||||
("TrafficJerkSpeedDecrease", "50", 3, "50"),
|
||||
("TrafficPersonalityProfile", "1", 2, "0"),
|
||||
("TuningLevel", "0", 0, "0"),
|
||||
("TuningLevelConfirmed", "0", 0, "0"),
|
||||
("TuningLevel", "3", 0, "0"),
|
||||
("TuningLevelConfirmed", "1", 0, "0"),
|
||||
("TurnDesires", "0", 2, "0"),
|
||||
("UnlimitedLength", "1", 2, "0"),
|
||||
("UnlockDoors", "1", 0, "0"),
|
||||
@@ -438,7 +452,8 @@ frogpilot_default_params: list[tuple[str, str | bytes, int, str]] = [
|
||||
("WarningSoftVolume", "101", 2, "101"),
|
||||
("WheelIcon", "frog", 0, "stock"),
|
||||
("WheelSpeed", "0", 2, "0"),
|
||||
("StopDistance", "6", 3, "6")
|
||||
("StopDistance", "6", 3, "6"),
|
||||
("RecoveryPower", "1.0", 2, "1.0")
|
||||
]
|
||||
|
||||
misc_tuning_levels: list[tuple[str, str | bytes, int, str]] = [
|
||||
@@ -533,6 +548,10 @@ class FrogPilotVariables:
|
||||
safety_config.safetyModel = car.CarParams.SafetyModel.noOutput
|
||||
CP.safetyConfigs = [safety_config]
|
||||
|
||||
is_torque_car = CP.lateralTuning.which() == "torque"
|
||||
if not is_torque_car:
|
||||
CarInterfaceBase.configure_torque_tune(MOCK.MOCK, CP.lateralTuning)
|
||||
|
||||
fpmsg_bytes = params.get("FrogPilotCarParams" if started else "FrogPilotCarParamsPersistent", block=started)
|
||||
if fpmsg_bytes:
|
||||
with custom.FrogPilotCarParams.from_bytes(fpmsg_bytes) as fpcp_reader:
|
||||
@@ -541,34 +560,31 @@ class FrogPilotVariables:
|
||||
CarInterface, _, _ = interfaces[MOCK.MOCK]
|
||||
FPCP = CarInterface.get_frogpilot_params(MOCK.MOCK, gen_empty_fingerprint(), [], CP, toggle)
|
||||
|
||||
is_torque_car = FPCP.lateralTuning.which() == "torque"
|
||||
if not is_torque_car:
|
||||
CarInterfaceBase.configure_torque_tune(MOCK.MOCK, FPCP.lateralTuning)
|
||||
|
||||
|
||||
toggle.always_on_lateral_set = bool(CP.alternativeExperience & ALTERNATIVE_EXPERIENCE.ALWAYS_ON_LATERAL)
|
||||
toggle.car_make = CP.carName
|
||||
toggle.car_model = CP.carFingerprint
|
||||
toggle.disable_openpilot_long = params.get_bool("DisableOpenpilotLongitudinal") if tuning_level >= level["DisableOpenpilotLongitudinal"] else default.get_bool("DisableOpenpilotLongitudinal")
|
||||
friction = FPCP.lateralTuning.torque.friction
|
||||
has_auto_tune = toggle.car_make in {"hyundai", "toyota"} and FPCP.lateralTuning.which() == "torque"
|
||||
friction = CP.lateralTuning.torque.friction
|
||||
has_auto_tune = toggle.car_make in {"hyundai", "toyota"} and CP.lateralTuning.which() == "torque"
|
||||
has_bsm = CP.enableBsm
|
||||
toggle.has_cc_long = toggle.car_make == "gm" and bool(CP.flags & GMFlags.CC_LONG.value)
|
||||
has_nnff = nnff_supported(toggle.car_model)
|
||||
toggle.has_pedal = CP.enableGasInterceptor
|
||||
has_radar = not CP.radarUnavailable
|
||||
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
|
||||
toggle.has_zss = toggle.car_make == "toyota" and bool(FPCP.fpFlags & ToyotaFrogPilotFlags.ZSS.value)
|
||||
is_angle_car = CP.steerControlType == car.CarParams.SteerControlType.angle
|
||||
latAccelFactor = FPCP.lateralTuning.torque.latAccelFactor
|
||||
latAccelFactor = CP.lateralTuning.torque.latAccelFactor
|
||||
longitudinalActuatorDelay = CP.longitudinalActuatorDelay
|
||||
toggle.openpilot_longitudinal = CP.openpilotLongitudinalControl and not toggle.disable_openpilot_long
|
||||
pcm_cruise = CP.pcmCruise
|
||||
startAccel = CP.startAccel
|
||||
stopAccel = CP.stopAccel
|
||||
steerActuatorDelay = CP.steerActuatorDelay
|
||||
steerKp = FPCP.lateralTuning.torque.kp
|
||||
steerKp = CP.lateralTuning.torque.kp
|
||||
steerRatio = CP.steerRatio
|
||||
toggle.stoppingDecelRate = CP.stoppingDecelRate
|
||||
taco_hacks_allowed = CP.safetyConfigs[0].safetyModel == SafetyModel.hyundaiCanfd
|
||||
@@ -601,14 +617,22 @@ 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.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.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.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.5, latAccelFactor * 1.25) if advanced_lateral_tuning and tuning_level >= level["SteerLatAccel"] else latAccelFactor
|
||||
toggle.use_custom_latAccelFactor = bool(round(toggle.latAccelFactor, 2) != round(latAccelFactor, 2)) and is_torque_car and not toggle.force_auto_tune or toggle.force_auto_tune_off
|
||||
toggle.steerRatio = np.clip(params.get_float("SteerRatio"), steerRatio * 0.5, steerRatio * 1.5) if advanced_lateral_tuning and tuning_level >= level["SteerRatio"] else steerRatio
|
||||
toggle.steerRatio = np.clip(params.get_float("SteerRatio"), steerRatio * 0.25, steerRatio * 1.5) if advanced_lateral_tuning and tuning_level >= level["SteerRatio"] else steerRatio
|
||||
toggle.use_custom_steerRatio = bool(round(toggle.steerRatio, 2) != round(steerRatio, 2)) and not toggle.force_auto_tune or toggle.force_auto_tune_off
|
||||
|
||||
advanced_longitudinal_tuning = params.get_bool("AdvancedLongitudinalTune") if tuning_level >= level["AdvancedLongitudinalTune"] else default.get_bool("AdvancedLongitudinalTune")
|
||||
ev_vehicle = toggle.car_make == "gm" and toggle.car_model != "CHEVROLET_VOLT" and CP.carFingerprint in GM_EV_CAR or toggle.car_make == "hyundai" and CP.carFingerprint in HYUNDAI_EV_CAR
|
||||
ev_vehicle |= CP.transmissionType == TransmissionType.direct
|
||||
|
||||
if params.get("EVTuning") == b"":
|
||||
params.put_bool("EVTuning", ev_vehicle)
|
||||
|
||||
toggle.ev_tuning = params.get_bool("EVTuning") if advanced_longitudinal_tuning and tuning_level >= level["EVTuning"] else ev_vehicle
|
||||
toggle.longitudinalActuatorDelay = np.clip(params.get_float("LongitudinalActuatorDelay"), 0, 1) if advanced_longitudinal_tuning and tuning_level >= level["LongitudinalActuatorDelay"] else longitudinalActuatorDelay
|
||||
toggle.startAccel = np.clip(params.get_float("StartAccel"), 0, 4) if advanced_longitudinal_tuning and tuning_level >= level["StartAccel"] else startAccel
|
||||
toggle.stopAccel = np.clip(params.get_float("StopAccel"), -4, 0) if advanced_longitudinal_tuning and tuning_level >= level["StopAccel"] else stopAccel
|
||||
@@ -618,6 +642,8 @@ class FrogPilotVariables:
|
||||
|
||||
toggle.stop_distance = params.get_float("StopDistance") if advanced_longitudinal_tuning and tuning_level >= level["StopDistance"] else 6.0
|
||||
|
||||
toggle.recovery_power = np.clip(params.get_float("RecoveryPower"), 0.5, 2.0) if advanced_longitudinal_tuning and tuning_level >= level["RecoveryPower"] else 1.0
|
||||
|
||||
toggle.alert_volume_controller = params.get_bool("AlertVolumeControl") if tuning_level >= level["AlertVolumeControl"] else default.get_bool("AlertVolumeControl")
|
||||
toggle.disengage_volume = params.get_int("DisengageVolume") if toggle.alert_volume_controller and tuning_level >= level["DisengageVolume"] else default.get_int("DisengageVolume")
|
||||
toggle.engage_volume = params.get_int("EngageVolume") if toggle.alert_volume_controller and tuning_level >= level["EngageVolume"] else default.get_int("EngageVolume")
|
||||
@@ -633,7 +659,7 @@ class FrogPilotVariables:
|
||||
toggle.always_on_lateral_main = toggle.always_on_lateral_set and not toggle.use_lkas_for_aol and (params.get_bool("AlwaysOnLateralMain") if tuning_level >= level["AlwaysOnLateralMain"] else default.get_bool("AlwaysOnLateralMain"))
|
||||
toggle.always_on_lateral_pause_speed = params.get_int("PauseAOLOnBrake") if toggle.always_on_lateral_set and tuning_level >= level["PauseAOLOnBrake"] else default.get_int("PauseAOLOnBrake")
|
||||
|
||||
toggle.automatic_updates = (params.get_bool("AutomaticUpdates") if tuning_level >= level["AutomaticUpdates"] and (self.release_branch or self.vetting_branch) else default.get_bool("AutomaticUpdates")) and not BACKUP_PATH.is_file()
|
||||
toggle.automatic_updates = (params.get_bool("AutomaticUpdates") if tuning_level >= level["AutomaticUpdates"] else default.get_bool("AutomaticUpdates")) and not BACKUP_PATH.is_file()
|
||||
|
||||
toggle.car_model = params.get("CarModel", encoding="utf-8") or toggle.car_model
|
||||
|
||||
@@ -673,28 +699,31 @@ class FrogPilotVariables:
|
||||
toggle.aggressive_jerk_danger = np.clip(params.get_int("AggressiveJerkDanger") / 100, 0.25, 2) if aggressive_profile and tuning_level >= level["AggressiveJerkDanger"] else default.get_int("AggressiveJerkDanger") / 100
|
||||
toggle.aggressive_jerk_speed = np.clip(params.get_int("AggressiveJerkSpeed") / 100, 0.25, 2) if aggressive_profile and tuning_level >= level["AggressiveJerkSpeed"] else default.get_int("AggressiveJerkSpeed") / 100
|
||||
toggle.aggressive_jerk_speed_decrease = np.clip(params.get_int("AggressiveJerkSpeedDecrease") / 100, 0.25, 2) if aggressive_profile and tuning_level >= level["AggressiveJerkSpeedDecrease"] else default.get_int("AggressiveJerkSpeedDecrease") / 100
|
||||
toggle.aggressive_follow = np.clip(params.get_float("AggressiveFollow"), 1, MAX_T_FOLLOW) if aggressive_profile and tuning_level >= level["AggressiveFollow"] else default.get_float("AggressiveFollow")
|
||||
toggle.aggressive_follow = [np.clip(params.get_float("AggressiveFollow"), 1, MAX_T_FOLLOW) if aggressive_profile and tuning_level >= level["AggressiveFollow"] else default.get_float("AggressiveFollow"),
|
||||
np.clip(params.get_float("AggressiveFollowHigh"), 1, MAX_T_FOLLOW) if aggressive_profile and tuning_level >= level["AggressiveFollowHigh"] else default.get_float("AggressiveFollowHigh")]
|
||||
standard_profile = toggle.custom_personalities and (params.get_bool("StandardPersonalityProfile") if tuning_level >= level["StandardPersonalityProfile"] else default.get_bool("StandardPersonalityProfile"))
|
||||
toggle.standard_jerk_acceleration = np.clip(params.get_int("StandardJerkAcceleration") / 100, 0.25, 2) if standard_profile and tuning_level >= level["StandardJerkAcceleration"] else default.get_int("StandardJerkAcceleration") / 100
|
||||
toggle.standard_jerk_deceleration = np.clip(params.get_int("StandardJerkDeceleration") / 100, 0.25, 2) if standard_profile and tuning_level >= level["StandardJerkDeceleration"] else default.get_int("StandardJerkDeceleration") / 100
|
||||
toggle.standard_jerk_danger = np.clip(params.get_int("StandardJerkDanger") / 100, 0.25, 2) if standard_profile and tuning_level >= level["StandardJerkDanger"] else default.get_int("StandardJerkDanger") / 100
|
||||
toggle.standard_jerk_speed = np.clip(params.get_int("StandardJerkSpeed") / 100, 0.25, 2) if standard_profile and tuning_level >= level["StandardJerkSpeed"] else default.get_int("StandardJerkSpeed") / 100
|
||||
toggle.standard_jerk_speed_decrease = np.clip(params.get_int("StandardJerkSpeedDecrease") / 100, 0.25, 2) if standard_profile and tuning_level >= level["StandardJerkSpeedDecrease"] else default.get_int("StandardJerkSpeedDecrease") / 100
|
||||
toggle.standard_follow = np.clip(params.get_float("StandardFollow"), 1, MAX_T_FOLLOW) if standard_profile and tuning_level >= level["StandardFollow"] else default.get_float("StandardFollow")
|
||||
toggle.standard_follow = [np.clip(params.get_float("StandardFollow"), 1, MAX_T_FOLLOW) if standard_profile and tuning_level >= level["StandardFollow"] else default.get_float("StandardFollow"),
|
||||
np.clip(params.get_float("StandardFollowHigh"), 1, MAX_T_FOLLOW) if standard_profile and tuning_level >= level["StandardFollowHigh"] else default.get_float("StandardFollowHigh")]
|
||||
relaxed_profile = toggle.custom_personalities and (params.get_bool("RelaxedPersonalityProfile") if tuning_level >= level["RelaxedPersonalityProfile"] else default.get_bool("RelaxedPersonalityProfile"))
|
||||
toggle.relaxed_jerk_acceleration = np.clip(params.get_int("RelaxedJerkAcceleration") / 100, 0.25, 2) if relaxed_profile and tuning_level >= level["RelaxedJerkAcceleration"] else default.get_int("RelaxedJerkAcceleration") / 100
|
||||
toggle.relaxed_jerk_deceleration = np.clip(params.get_int("RelaxedJerkDeceleration") / 100, 0.25, 2) if relaxed_profile and tuning_level >= level["RelaxedJerkDeceleration"] else default.get_int("RelaxedJerkDeceleration") / 100
|
||||
toggle.relaxed_jerk_danger = np.clip(params.get_int("RelaxedJerkDanger") / 100, 0.25, 2) if relaxed_profile and tuning_level >= level["RelaxedJerkDanger"] else default.get_int("RelaxedJerkDanger") / 100
|
||||
toggle.relaxed_jerk_speed = np.clip(params.get_int("RelaxedJerkSpeed") / 100, 0.25, 2) if relaxed_profile and tuning_level >= level["RelaxedJerkSpeed"] else default.get_int("RelaxedJerkSpeed") / 100
|
||||
toggle.relaxed_jerk_speed_decrease = np.clip(params.get_int("RelaxedJerkSpeedDecrease") / 100, 0.25, 2) if relaxed_profile and tuning_level >= level["RelaxedJerkSpeedDecrease"] else default.get_int("RelaxedJerkSpeedDecrease") / 100
|
||||
toggle.relaxed_follow = np.clip(params.get_float("RelaxedFollow"), 1, MAX_T_FOLLOW) if relaxed_profile and tuning_level >= level["RelaxedFollow"] else default.get_float("RelaxedFollow")
|
||||
toggle.relaxed_follow = [np.clip(params.get_float("RelaxedFollow"), 1, MAX_T_FOLLOW) if relaxed_profile and tuning_level >= level["RelaxedFollow"] else default.get_float("RelaxedFollow"),
|
||||
np.clip(params.get_float("RelaxedFollowHigh"), 1, MAX_T_FOLLOW) if relaxed_profile and tuning_level >= level["RelaxedFollowHigh"] else default.get_float("RelaxedFollowHigh")]
|
||||
traffic_profile = toggle.custom_personalities and (params.get_bool("TrafficPersonalityProfile") if tuning_level >= level["TrafficPersonalityProfile"] else default.get_bool("TrafficPersonalityProfile"))
|
||||
toggle.traffic_mode_jerk_acceleration = [np.clip(params.get_int("TrafficJerkAcceleration") / 100, 0.25, 2) if traffic_profile and tuning_level >= level["TrafficJerkAcceleration"] else default.get_int("TrafficJerkAcceleration") / 100, toggle.aggressive_jerk_acceleration]
|
||||
toggle.traffic_mode_jerk_deceleration = [np.clip(params.get_int("TrafficJerkDeceleration") / 100, 0.25, 2) if traffic_profile and tuning_level >= level["TrafficJerkDeceleration"] else default.get_int("TrafficJerkDeceleration") / 100, toggle.aggressive_jerk_deceleration]
|
||||
toggle.traffic_mode_jerk_danger = [np.clip(params.get_int("TrafficJerkDanger") / 100, 0.25, 2) if traffic_profile and tuning_level >= level["TrafficJerkDanger"] else default.get_int("TrafficJerkDanger") / 100, toggle.aggressive_jerk_danger]
|
||||
toggle.traffic_mode_jerk_speed = [np.clip(params.get_int("TrafficJerkSpeed") / 100, 0.25, 2) if traffic_profile and tuning_level >= level["TrafficJerkSpeed"] else default.get_int("TrafficJerkSpeed") / 100, toggle.aggressive_jerk_speed]
|
||||
toggle.traffic_mode_jerk_speed_decrease = [np.clip(params.get_int("TrafficJerkSpeedDecrease") / 100, 0.25, 2) if traffic_profile and tuning_level >= level["TrafficJerkSpeedDecrease"] else default.get_int("TrafficJerkSpeedDecrease") / 100, toggle.aggressive_jerk_speed_decrease]
|
||||
toggle.traffic_mode_follow = [np.clip(params.get_float("TrafficFollow"), 0.5, MAX_T_FOLLOW) if traffic_profile and tuning_level >= level["TrafficFollow"] else default.get_float("TrafficFollow"), toggle.aggressive_follow]
|
||||
toggle.traffic_mode_follow = [np.clip(params.get_float("TrafficFollow"), 0.5, MAX_T_FOLLOW) if traffic_profile and tuning_level >= level["TrafficFollow"] else default.get_float("TrafficFollow"), toggle.aggressive_follow[0]]
|
||||
|
||||
custom_ui = params.get_bool("CustomUI") if tuning_level >= level["CustomUI"] else default.get_bool("CustomUI")
|
||||
toggle.acceleration_path = toggle.openpilot_longitudinal and (custom_ui and (params.get_bool("AccelerationPath") if tuning_level >= level["AccelerationPath"] else default.get_bool("AccelerationPath")) or toggle.debug_mode)
|
||||
@@ -823,13 +852,17 @@ class FrogPilotVariables:
|
||||
toggle.human_following = longitudinal_tuning and (params.get_bool("HumanFollowing") if tuning_level >= level["HumanFollowing"] else default.get_bool("HumanFollowing"))
|
||||
toggle.lead_detection_probability = np.clip(params.get_int("LeadDetectionThreshold") / 100, 0.25, 0.50) if longitudinal_tuning and tuning_level >= level["LeadDetectionThreshold"] else default.get_int("LeadDetectionThreshold") / 100
|
||||
toggle.max_desired_acceleration = np.clip(params.get_float("MaxDesiredAcceleration"), 0.1, 4.0) if longitudinal_tuning and tuning_level >= level["MaxDesiredAcceleration"] else default.get_float("MaxDesiredAcceleration")
|
||||
toggle.trailer_load_kg = (np.clip(params.get_int("TrailerLoad"), 0, 15000) if longitudinal_tuning and tuning_level >= level["TrailerLoad"] else default.get_int("TrailerLoad")) * CV.LB_TO_KG
|
||||
toggle.taco_tune = longitudinal_tuning and (params.get_bool("TacoTune") if tuning_level >= level["TacoTune"] else default.get_bool("TacoTune"))
|
||||
|
||||
toggle.available_models = params.get("AvailableModels", encoding="utf-8") or ""
|
||||
toggle.available_model_names = params.get("AvailableModelNames", encoding="utf-8") or ""
|
||||
toggle.available_model_series = params.get("AvailableModelSeries", encoding="utf-8") or ""
|
||||
toggle.community_favorites = params.get("CommunityFavorites", encoding="utf-8") or ""
|
||||
toggle.model_released_dates = params.get("ModelReleasedDates", encoding="utf-8") or ""
|
||||
toggle.model_versions = params.get("ModelVersions", encoding="utf-8") or ""
|
||||
toggle.available_model_series = params.get("AvailableModelSeries", encoding="utf-8") or ""
|
||||
toggle.sort_models_by_date = params.get_bool("SortModelsByDate") if tuning_level >= level["SortModelsByDate"] else default.get_bool("SortModelsByDate")
|
||||
toggle.user_favorites = params.get("UserFavorites", encoding="utf-8") or ""
|
||||
downloaded_models = [model for model in toggle.available_models.split(",") if any(MODELS_PATH.glob(f"{model}*"))]
|
||||
toggle.model_randomizer = downloaded_models and (params.get_bool("ModelRandomizer") if tuning_level >= level["ModelRandomizer"] else default.get_bool("ModelRandomizer"))
|
||||
if toggle.available_models and toggle.available_model_names and downloaded_models and toggle.model_versions:
|
||||
@@ -860,7 +893,7 @@ class FrogPilotVariables:
|
||||
toggle.model_version = DEFAULT_MODEL_VERSION
|
||||
toggle.classic_longitudinal = 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.model_ui = params.get_bool("ModelUI") if tuning_level >= level["ModelUI"] else default.get_bool("ModelUI")
|
||||
@@ -975,5 +1008,7 @@ class FrogPilotVariables:
|
||||
|
||||
toggle.volt_sng = toggle.car_model == "CHEVROLET_VOLT" and (params.get_bool("VoltSNG") if tuning_level >= level["VoltSNG"] else default.get_bool("VoltSNG"))
|
||||
|
||||
toggle.gm_pedal_longitudinal = params.get_bool("GMPedalLongitudinal") if tuning_level >= level["GMPedalLongitudinal"] else default.get_bool("GMPedalLongitudinal")
|
||||
|
||||
params_memory.put("FrogPilotToggles", json.dumps(toggle.__dict__))
|
||||
params_memory.remove("FrogPilotTogglesUpdated")
|
||||
|
||||
@@ -9,7 +9,7 @@ from openpilot.common.conversions import Conversions as CV
|
||||
from openpilot.common.filter_simple import FirstOrderFilter
|
||||
from openpilot.common.realtime import DT_MDL
|
||||
from openpilot.selfdrive.controls.lib.drive_helpers import V_CRUISE_MAX
|
||||
from openpilot.selfdrive.controls.lib.longitudinal_mpc_lib.long_mpc import A_CHANGE_COST, DANGER_ZONE_COST, J_EGO_COST
|
||||
from openpilot.selfdrive.controls.lib.longitudinal_mpc_lib.long_mpc import A_CHANGE_COST, COMFORT_BRAKE, DANGER_ZONE_COST, J_EGO_COST
|
||||
|
||||
from openpilot.frogpilot.common.frogpilot_utilities import calculate_lane_width, calculate_road_curvature
|
||||
from openpilot.frogpilot.common.frogpilot_variables import CRUISING_SPEED, MINIMUM_LATERAL_ACCELERATION, PLANNER_TIME, THRESHOLD, params, params_memory
|
||||
@@ -65,6 +65,8 @@ class FrogPilotPlanner:
|
||||
self.cem.curve_detected = False
|
||||
self.cem.stop_sign_and_light(v_ego, sm, PLANNER_TIME - 2)
|
||||
|
||||
|
||||
|
||||
self.driving_in_curve = abs(self.lateral_acceleration) >= MINIMUM_LATERAL_ACCELERATION
|
||||
|
||||
self.frogpilot_events.update(v_cruise, sm, frogpilot_toggles)
|
||||
@@ -85,7 +87,7 @@ class FrogPilotPlanner:
|
||||
|
||||
params_memory.remove("LastGPSPosition")
|
||||
|
||||
self.lateral_acceleration = v_ego**2 * (sm["carState"].steeringAngleDeg - sm["liveParameters"].angleOffsetDeg) * CV.DEG_TO_RAD / (self.CP.steerRatio * self.CP.wheelbase)
|
||||
self.lateral_acceleration = v_ego**2 * sm["controlsState"].curvature
|
||||
|
||||
check_lane_width = frogpilot_toggles.adjacent_paths or frogpilot_toggles.adjacent_path_metrics or frogpilot_toggles.blind_spot_path or frogpilot_toggles.lane_detection
|
||||
if check_lane_width and v_ego >= frogpilot_toggles.minimum_lane_change_speed:
|
||||
@@ -140,6 +142,8 @@ class FrogPilotPlanner:
|
||||
|
||||
frogpilotPlan.desiredFollowDistance = self.frogpilot_following.desired_follow_distance
|
||||
|
||||
frogpilotPlan.disableThrottle = self.frogpilot_following.disable_throttle
|
||||
|
||||
frogpilotPlan.experimentalMode = self.cem.experimental_mode or self.frogpilot_vcruise.slc.experimental_mode
|
||||
|
||||
frogpilotPlan.forcingStop = self.frogpilot_vcruise.forcing_stop
|
||||
|
||||
@@ -8,36 +8,36 @@ def cubic_interp(x, xp, fp):
|
||||
return fp[0]
|
||||
elif x >= xp[-1]:
|
||||
return fp[-1]
|
||||
|
||||
|
||||
# Find interval
|
||||
i = np.searchsorted(xp, x) - 1
|
||||
i = max(0, min(i, len(xp)-2)) # clamp the index
|
||||
|
||||
|
||||
# Normalized position
|
||||
t = (x - xp[i]) / float(xp[i+1] - xp[i])
|
||||
|
||||
|
||||
# Hermite cubic formula
|
||||
return fp[i]*(1 - 3*t**2 + 2*t**3) + fp[i+1]*(3*t**2 - 2*t**3)
|
||||
|
||||
|
||||
def akima_interp(x, xp, fp):
|
||||
"""Akima-inspired interpolation with reduced overshoot characteristics."""
|
||||
if x <= xp[0]:
|
||||
return fp[0]
|
||||
elif x >= xp[-1]:
|
||||
return fp[-1]
|
||||
|
||||
|
||||
i = np.searchsorted(xp, x) - 1
|
||||
i = max(0, min(i, len(xp)-2)) # clamp the index
|
||||
|
||||
|
||||
t = (x - xp[i]) / float(xp[i+1] - xp[i])
|
||||
|
||||
|
||||
# Quintic polynomial to reduce overshoot
|
||||
t2 = t*t
|
||||
t4 = t2*t2
|
||||
t3 = t2*t
|
||||
return (fp[i]*(1 - 10*t3 + 15*t4 - 6*t3*t2)
|
||||
+ fp[i+1]*(10*t3 - 15*t4 + 6*t3*t2))
|
||||
|
||||
|
||||
from openpilot.selfdrive.controls.lib.longitudinal_planner import A_CRUISE_MIN, get_max_accel
|
||||
|
||||
from openpilot.frogpilot.common.frogpilot_variables import CITY_SPEED_LIMIT
|
||||
@@ -47,18 +47,18 @@ A_CRUISE_MIN_SPORT = A_CRUISE_MIN * 2
|
||||
|
||||
# MPH = [0.0, 11, 22, 34, 45, 56, 89]
|
||||
A_CRUISE_MAX_BP_CUSTOM = [0.0, 5., 10., 15., 20., 25., 40.]
|
||||
A_CRUISE_MAX_VALS_ECO = [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0]
|
||||
A_CRUISE_MAX_VALS_SPORT = [1.5, 1.5, 1.25, 1.5, 1.5, 1.5, 2.0]
|
||||
A_CRUISE_MAX_VALS_SPORT_PLUS = [2.5, 2.5, 3.0, 2.5, 2.5, 2.5, 2.5]
|
||||
A_CRUISE_MAX_VALS_ECO_EV = [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0]
|
||||
A_CRUISE_MAX_VALS_SPORT_EV = [1.25, 1.25, 1.25, 1.25, 1.5, 1.5, 2.0]
|
||||
A_CRUISE_MAX_VALS_ECO_GAS = [2.0, 1.5, 1.0, 0.8, 0.6, 0.4, 0.2]
|
||||
A_CRUISE_MAX_VALS_SPORT_GAS = [3.0, 2.5, 2.0, 1.5, 1.0, 0.8, 0.6]
|
||||
|
||||
def get_max_accel_eco(v_ego):
|
||||
return float(akima_interp(v_ego, A_CRUISE_MAX_BP_CUSTOM, A_CRUISE_MAX_VALS_ECO))
|
||||
def get_max_accel_eco(v_ego, ev_tuning=True):
|
||||
cruise_vals = A_CRUISE_MAX_VALS_ECO_EV if ev_tuning else A_CRUISE_MAX_VALS_ECO_GAS
|
||||
return float(akima_interp(v_ego, A_CRUISE_MAX_BP_CUSTOM, cruise_vals))
|
||||
|
||||
def get_max_accel_sport(v_ego):
|
||||
return float(akima_interp(v_ego, A_CRUISE_MAX_BP_CUSTOM, A_CRUISE_MAX_VALS_SPORT))
|
||||
|
||||
def get_max_accel_sport_plus(v_ego):
|
||||
return float(akima_interp(v_ego, A_CRUISE_MAX_BP_CUSTOM, A_CRUISE_MAX_VALS_SPORT_PLUS))
|
||||
def get_max_accel_sport(v_ego, ev_tuning=True):
|
||||
cruise_vals = A_CRUISE_MAX_VALS_SPORT_EV if ev_tuning else A_CRUISE_MAX_VALS_SPORT_GAS
|
||||
return float(akima_interp(v_ego, A_CRUISE_MAX_BP_CUSTOM, cruise_vals))
|
||||
|
||||
def get_max_accel_low_speeds(max_accel, v_cruise):
|
||||
return float(akima_interp(v_cruise, [0., CITY_SPEED_LIMIT / 2, CITY_SPEED_LIMIT], [max_accel / 4, max_accel / 2, max_accel]))
|
||||
@@ -79,24 +79,25 @@ class FrogPilotAcceleration:
|
||||
def update(self, v_ego, sm, frogpilot_toggles):
|
||||
eco_gear = sm["frogpilotCarState"].ecoGear
|
||||
sport_gear = sm["frogpilotCarState"].sportGear
|
||||
ev_tuning = frogpilot_toggles.ev_tuning
|
||||
|
||||
if sm["frogpilotCarState"].trafficModeEnabled:
|
||||
self.max_accel = get_max_accel(v_ego)
|
||||
elif frogpilot_toggles.map_acceleration and (eco_gear or sport_gear):
|
||||
if eco_gear:
|
||||
self.max_accel = get_max_accel_eco(v_ego)
|
||||
self.max_accel = get_max_accel_eco(v_ego, ev_tuning)
|
||||
else:
|
||||
if frogpilot_toggles.sport_plus:
|
||||
self.max_accel = get_max_accel_sport_plus(v_ego)
|
||||
if frogpilot_toggles.acceleration_profile == 2:
|
||||
self.max_accel = get_max_accel_sport(v_ego, ev_tuning)
|
||||
else:
|
||||
self.max_accel = get_max_accel_sport(v_ego)
|
||||
self.max_accel = get_max_allowed_accel(v_ego)
|
||||
else:
|
||||
if frogpilot_toggles.acceleration_profile == 1:
|
||||
self.max_accel = get_max_accel_eco(v_ego)
|
||||
self.max_accel = get_max_accel_eco(v_ego, ev_tuning)
|
||||
elif frogpilot_toggles.acceleration_profile == 2:
|
||||
self.max_accel = get_max_accel_sport(v_ego)
|
||||
elif frogpilot_toggles.sport_plus:
|
||||
self.max_accel = get_max_accel_sport_plus(v_ego)
|
||||
self.max_accel = get_max_accel_sport(v_ego, ev_tuning)
|
||||
elif frogpilot_toggles.acceleration_profile == 3:
|
||||
self.max_accel = get_max_allowed_accel(v_ego)
|
||||
else:
|
||||
self.max_accel = get_max_accel(v_ego)
|
||||
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
#!/usr/bin/env python3
|
||||
import numpy as np
|
||||
|
||||
from openpilot.common.conversions import Conversions as CV
|
||||
from openpilot.selfdrive.controls.lib.longitudinal_mpc_lib.long_mpc import COMFORT_BRAKE, desired_follow_distance, get_jerk_factor, get_T_FOLLOW
|
||||
|
||||
from openpilot.frogpilot.common.frogpilot_variables import CITY_SPEED_LIMIT
|
||||
|
||||
TRAFFIC_MODE_BP = [0., CITY_SPEED_LIMIT]
|
||||
PERSONALITY_BP = [20. * CV.KPH_TO_MS, 90. * CV.KPH_TO_MS]
|
||||
|
||||
class FrogPilotFollowing:
|
||||
def __init__(self, FrogPilotPlanner):
|
||||
self.frogpilot_planner = FrogPilotPlanner
|
||||
|
||||
self.disable_throttle = False
|
||||
self.following_lead = False
|
||||
self.slower_lead = False
|
||||
|
||||
@@ -47,12 +50,16 @@ class FrogPilotFollowing:
|
||||
frogpilot_toggles.custom_personalities, sm["controlsState"].personality
|
||||
)
|
||||
|
||||
self.t_follow = get_T_FOLLOW(
|
||||
t_follow_param = get_T_FOLLOW(
|
||||
frogpilot_toggles.aggressive_follow,
|
||||
frogpilot_toggles.standard_follow,
|
||||
frogpilot_toggles.relaxed_follow,
|
||||
frogpilot_toggles.custom_personalities, sm["controlsState"].personality
|
||||
)
|
||||
if isinstance(t_follow_param, list):
|
||||
self.t_follow = float(np.interp(v_ego, PERSONALITY_BP, t_follow_param))
|
||||
else:
|
||||
self.t_follow = float(t_follow_param)
|
||||
else:
|
||||
self.base_acceleration_jerk = 0
|
||||
self.base_danger_jerk = 0
|
||||
@@ -63,7 +70,12 @@ class FrogPilotFollowing:
|
||||
self.danger_jerk = self.base_danger_jerk
|
||||
self.speed_jerk = self.base_speed_jerk
|
||||
|
||||
self.following_lead = self.frogpilot_planner.tracking_lead and self.frogpilot_planner.lead_one.dRel < (self.t_follow + 1) * v_ego
|
||||
self.following_lead = self.frogpilot_planner.tracking_lead and self.frogpilot_planner.lead_one.dRel < (self.t_follow * 2) * v_ego
|
||||
|
||||
|
||||
self.disable_throttle = self.frogpilot_planner.tracking_lead and not self.following_lead
|
||||
self.disable_throttle &= self.frogpilot_planner.lead_one.dRel + 6.0 < (self.t_follow * 2 * 2) * v_ego
|
||||
self.disable_throttle &= self.frogpilot_planner.lead_one.vLead < v_ego * 0.75
|
||||
|
||||
if sm["controlsState"].enabled and self.frogpilot_planner.tracking_lead:
|
||||
self.update_follow_values(self.frogpilot_planner.lead_one.dRel, v_ego, self.frogpilot_planner.lead_one.vLead, frogpilot_toggles)
|
||||
|
||||
@@ -51,7 +51,7 @@ class FrogPilotTracking:
|
||||
self.sound = FrogPilotAudibleAlert.none
|
||||
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):
|
||||
v_cruise = min(sm["controlsState"].vCruiseCluster, V_CRUISE_MAX) * CV.KPH_TO_MS
|
||||
|
||||
@@ -18,6 +18,7 @@ class FrogPilotVCruise:
|
||||
self.override_force_stop = False
|
||||
|
||||
self.override_force_stop_timer = 0
|
||||
self.force_stop_timer = 0.0
|
||||
|
||||
def update(self, gps_position, now, time_validated, v_cruise, v_ego, sm, frogpilot_toggles):
|
||||
force_stop = self.frogpilot_planner.cem.stop_light_detected and sm["controlsState"].enabled and frogpilot_toggles.force_stops
|
||||
@@ -58,16 +59,6 @@ class FrogPilotVCruise:
|
||||
|
||||
self.csc_target = v_cruise
|
||||
|
||||
# Mike's extended lead linear braking
|
||||
if self.frogpilot_planner.lead_one.vLead < v_ego > CRUISING_SPEED and sm["controlsState"].enabled and self.frogpilot_planner.tracking_lead and frogpilot_toggles.human_following:
|
||||
if not self.frogpilot_planner.frogpilot_following.following_lead:
|
||||
decel_rate = (v_ego - self.frogpilot_planner.lead_one.vLead)**2 / self.frogpilot_planner.lead_one.dRel
|
||||
self.braking_target = max(v_ego - (decel_rate * DT_MDL), self.frogpilot_planner.lead_one.vLead + CRUISING_SPEED)
|
||||
else:
|
||||
self.braking_target = v_cruise
|
||||
else:
|
||||
self.braking_target = v_cruise
|
||||
|
||||
# Pfeiferj's Speed Limit Controller
|
||||
self.slc.frogpilot_toggles = frogpilot_toggles
|
||||
|
||||
@@ -97,7 +88,7 @@ class FrogPilotVCruise:
|
||||
|
||||
self.tracked_model_length = self.frogpilot_planner.model_length
|
||||
|
||||
targets = [self.braking_target, self.csc_target, v_cruise]
|
||||
targets = [self.csc_target, v_cruise]
|
||||
if frogpilot_toggles.speed_limit_controller:
|
||||
targets.append(max(self.slc.overridden_speed, self.slc_target + self.slc_offset) - v_ego_diff)
|
||||
|
||||
|
||||
@@ -1,17 +1,20 @@
|
||||
#!/usr/bin/env python3
|
||||
# Twilsonco's Lateral Neural Network Feedforward
|
||||
from collections import deque
|
||||
from difflib import SequenceMatcher
|
||||
from typing import NamedTuple
|
||||
|
||||
# Twilsonco's Lateral Neural Network Feedforward Controller
|
||||
import json
|
||||
import math
|
||||
import numpy as np
|
||||
import os
|
||||
|
||||
from collections import deque
|
||||
from difflib import SequenceMatcher
|
||||
from cereal import log
|
||||
from openpilot.common.filter_simple import FirstOrderFilter
|
||||
from openpilot.common.numpy_fast import interp
|
||||
from openpilot.common.params import Params
|
||||
from openpilot.selfdrive.controls.lib.drive_helpers import CONTROL_N
|
||||
from openpilot.selfdrive.controls.lib.latcontrol import LatControl
|
||||
from openpilot.selfdrive.controls.lib.pid import PIDController
|
||||
from openpilot.selfdrive.controls.lib.vehicle_model import ACCELERATION_DUE_TO_GRAVITY
|
||||
from openpilot.selfdrive.modeld.constants import ModelConstants
|
||||
|
||||
from openpilot.frogpilot.common.frogpilot_variables import NNFF_MODELS_PATH, get_nnff_model_files, params
|
||||
@@ -31,8 +34,7 @@ from openpilot.frogpilot.common.frogpilot_variables import NNFF_MODELS_PATH, get
|
||||
ACTIVATION_FUNCTION_NAMES = {'σ': 'sigmoid'}
|
||||
|
||||
LOW_SPEED_X = [0, 10, 20, 30]
|
||||
LOW_SPEED_Y = [15, 13, 10, 5]
|
||||
LOW_SPEED_Y_NN = [12, 3, 1, 0]
|
||||
LOW_SPEED_Y = [12, 3, 1, 0]
|
||||
|
||||
LAT_PLAN_MIN_IDX = 5
|
||||
|
||||
@@ -126,7 +128,7 @@ def get_nn_model_path(car, eps_firmware) -> str | None:
|
||||
def find_valid_model(*queries):
|
||||
for query in queries:
|
||||
path, score = best_model_path(query)
|
||||
if path and car in path and score >= 0.9:
|
||||
if path and score >= 0.9:
|
||||
return path
|
||||
return None
|
||||
|
||||
@@ -152,21 +154,18 @@ def sign(x):
|
||||
def similarity(s1: str, s2: str) -> float:
|
||||
return SequenceMatcher(None, s1, s2).ratio()
|
||||
|
||||
class LatControlInputs(NamedTuple):
|
||||
lateral_acceleration: float
|
||||
roll_compensation: float
|
||||
vego: float
|
||||
aego: float
|
||||
|
||||
class NeuralNetworkFeedforward:
|
||||
def __init__(self, CP, LatControlTorque):
|
||||
self.lat_control_torque = LatControlTorque
|
||||
|
||||
class LatControlNNFF(LatControl):
|
||||
def __init__(self, CP, CI, dt):
|
||||
super().__init__(CP, CI, dt)
|
||||
self.lat_torque_nn_model = get_nn_model(CP.carFingerprint, str(next((fw.fwVersion for fw in CP.carFw if fw.ecu == "eps"), "")).replace("\\", ""))
|
||||
self.nnff_loaded = self.lat_torque_nn_model is not None
|
||||
|
||||
self.torque_from_lateral_accel = self.lat_control_torque.torque_from_lateral_accel
|
||||
|
||||
self.use_steering_angle = self.lat_control_torque.torque_params.useSteeringAngle
|
||||
self.torque_params = CP.lateralTuning.torque
|
||||
self.pid = PIDController(self.torque_params.kp, self.torque_params.ki,
|
||||
pos_limit=self.steer_max, neg_limit=-self.steer_max)
|
||||
self.torque_from_lateral_accel = CI.torque_from_lateral_accel()
|
||||
self.use_steering_angle = self.torque_params.useSteeringAngle
|
||||
self.steering_angle_deadzone_deg = self.torque_params.steeringAngleDeadzoneDeg
|
||||
|
||||
# Instantaneous lateral jerk changes very rapidly, making it not useful on its own,
|
||||
# however, we can "look ahead" to the future planned lateral jerk in order to gauge
|
||||
@@ -184,7 +183,6 @@ class NeuralNetworkFeedforward:
|
||||
self.lat_jerk_friction_factor = 0.4
|
||||
|
||||
# precompute time differences between ModelConstants.T_IDXS
|
||||
self.lateral_delay = CP.steerActuatorDelay
|
||||
self.t_diffs = np.diff(ModelConstants.T_IDXS)
|
||||
|
||||
self.pitch = FirstOrderFilter(0.0, 0.5, 0.01)
|
||||
@@ -196,7 +194,7 @@ class NeuralNetworkFeedforward:
|
||||
|
||||
# setup future time offsets
|
||||
self.future_times = [0.3, 0.6, 1.0, 1.5] # seconds in the future
|
||||
self.nn_future_times = [time + self.lateral_delay for time in self.future_times]
|
||||
self.nn_future_times = [time + CP.steerActuatorDelay for time in self.future_times]
|
||||
|
||||
# setup past time offsets
|
||||
self.past_times = [-0.3, -0.2, -0.1]
|
||||
@@ -207,97 +205,150 @@ class NeuralNetworkFeedforward:
|
||||
self.roll_deque = deque(maxlen=history_check_frames[0])
|
||||
|
||||
def update_live_delay(self, lateral_delay):
|
||||
self.lateral_delay = lateral_delay
|
||||
|
||||
self.nn_future_times = [time + self.lateral_delay for time in self.future_times]
|
||||
self.nn_future_times = [time + lateral_delay for time in self.future_times]
|
||||
self.past_future_len = len(self.past_times) + len(self.nn_future_times)
|
||||
|
||||
def compute_nnff(self, CS, VM, actual_lateral_accel, desired_lateral_accel, gravity_adjusted_lateral_accel, lateral_accel_deadzone, llk, measurement, model_data, params, pid_log, roll_compensation, setpoint, frogpilot_toggles):
|
||||
if self.use_steering_angle:
|
||||
actual_curvature_rate = -VM.calc_curvature(math.radians(CS.steeringRateDeg), CS.vEgo, 0.0)
|
||||
actual_lateral_jerk = actual_curvature_rate * CS.vEgo ** 2
|
||||
def update_live_torque_params(self, latAccelFactor, latAccelOffset, friction):
|
||||
self.torque_params.latAccelFactor = latAccelFactor
|
||||
self.torque_params.latAccelOffset = latAccelOffset
|
||||
self.torque_params.friction = friction
|
||||
|
||||
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.LateralTorqueState.new_message()
|
||||
if not active:
|
||||
output_torque = 0.0
|
||||
pid_log.active = False
|
||||
else:
|
||||
actual_lateral_jerk = 0.0
|
||||
actual_curvature_vm = -VM.calc_curvature(math.radians(CS.steeringAngleDeg - params.angleOffsetDeg), CS.vEgo, params.roll)
|
||||
roll_compensation = params.roll * ACCELERATION_DUE_TO_GRAVITY
|
||||
if self.use_steering_angle:
|
||||
actual_curvature = actual_curvature_vm
|
||||
curvature_deadzone = abs(VM.calc_curvature(math.radians(self.steering_angle_deadzone_deg), CS.vEgo, 0.0))
|
||||
else:
|
||||
actual_curvature_llk = llk.angularVelocityCalibrated.value[2] / CS.vEgo
|
||||
actual_curvature = interp(CS.vEgo, [2.0, 5.0], [actual_curvature_vm, actual_curvature_llk])
|
||||
curvature_deadzone = 0.0
|
||||
desired_lateral_accel = desired_curvature * CS.vEgo ** 2
|
||||
|
||||
model_good = model_data is not None and len(model_data.orientation.x) >= CONTROL_N
|
||||
# desired rate is the desired rate of change in the setpoint, not the absolute desired curvature
|
||||
# desired_lateral_jerk = desired_curvature_rate * CS.vEgo ** 2
|
||||
actual_lateral_accel = actual_curvature * CS.vEgo ** 2
|
||||
lateral_accel_deadzone = curvature_deadzone * CS.vEgo ** 2
|
||||
|
||||
if model_good:
|
||||
# prepare "look-ahead" desired lateral jerk
|
||||
lookahead = interp(CS.vEgo, self.friction_look_ahead_bp, self.friction_look_ahead_v)
|
||||
friction_upper_idx = next((idxs for idxs, value in enumerate(ModelConstants.T_IDXS) if value > lookahead), 16)
|
||||
low_speed_factor = interp(CS.vEgo, LOW_SPEED_X, LOW_SPEED_Y)**2
|
||||
setpoint = desired_lateral_accel + low_speed_factor * desired_curvature
|
||||
measurement = actual_lateral_accel + low_speed_factor * actual_curvature
|
||||
gravity_adjusted_lateral_accel = desired_lateral_accel - roll_compensation
|
||||
if self.nnff_loaded and frogpilot_toggles.nnff or frogpilot_toggles.nnff_lite:
|
||||
if self.use_steering_angle:
|
||||
actual_curvature_rate = -VM.calc_curvature(math.radians(CS.steeringRateDeg), CS.vEgo, 0.0)
|
||||
actual_lateral_jerk = actual_curvature_rate * CS.vEgo ** 2
|
||||
else:
|
||||
actual_lateral_jerk = 0.0
|
||||
|
||||
predicted_lateral_jerk = get_predicted_lateral_jerk(model_data.acceleration.y, self.t_diffs)
|
||||
desired_lateral_jerk = (interp(self.lateral_delay, ModelConstants.T_IDXS, model_data.acceleration.y) - desired_lateral_accel) / self.lateral_delay
|
||||
model_good = model_data is not None and len(model_data.orientation.x) >= CONTROL_N
|
||||
|
||||
lookahead_lateral_jerk = get_lookahead_value(predicted_lateral_jerk[LAT_PLAN_MIN_IDX:friction_upper_idx], desired_lateral_jerk)
|
||||
if model_good:
|
||||
# prepare "look-ahead" desired lateral jerk
|
||||
lookahead = interp(CS.vEgo, self.friction_look_ahead_bp, self.friction_look_ahead_v)
|
||||
friction_upper_idx = next((idxs for idxs, value in enumerate(ModelConstants.T_IDXS) if value > lookahead), 16)
|
||||
|
||||
if not self.use_steering_angle or lookahead_lateral_jerk == 0.0:
|
||||
lookahead_lateral_jerk = 0.0
|
||||
actual_lateral_jerk = 0.0
|
||||
self.lat_accel_friction_factor = 1.0
|
||||
predicted_lateral_jerk = get_predicted_lateral_jerk(model_data.acceleration.y, self.t_diffs)
|
||||
desired_lateral_jerk = (interp(lat_delay, ModelConstants.T_IDXS, model_data.acceleration.y) - desired_lateral_accel) / lat_delay
|
||||
|
||||
lateral_jerk_setpoint = self.lat_jerk_friction_factor * lookahead_lateral_jerk
|
||||
lateral_jerk_measurement = self.lat_jerk_friction_factor * actual_lateral_jerk
|
||||
else:
|
||||
lateral_jerk_setpoint = 0
|
||||
lateral_jerk_measurement = 0
|
||||
lookahead_lateral_jerk = 0
|
||||
lookahead_lateral_jerk = get_lookahead_value(predicted_lateral_jerk[LAT_PLAN_MIN_IDX:friction_upper_idx], desired_lateral_jerk)
|
||||
|
||||
if self.lat_control_torque.nnff_loaded and model_good and frogpilot_toggles.nnff:
|
||||
# update past data
|
||||
pitch = 0
|
||||
roll = params.roll
|
||||
if len(llk.calibratedOrientationNED.value) > 1:
|
||||
pitch = self.pitch.update(llk.calibratedOrientationNED.value[1])
|
||||
roll = roll_pitch_adjust(roll, pitch)
|
||||
if not self.use_steering_angle or lookahead_lateral_jerk == 0.0:
|
||||
lookahead_lateral_jerk = 0.0
|
||||
actual_lateral_jerk = 0.0
|
||||
self.lat_accel_friction_factor = 1.0
|
||||
|
||||
self.roll_deque.append(roll)
|
||||
self.lateral_accel_desired_deque.append(desired_lateral_accel)
|
||||
lateral_jerk_setpoint = self.lat_jerk_friction_factor * lookahead_lateral_jerk
|
||||
lateral_jerk_measurement = self.lat_jerk_friction_factor * actual_lateral_jerk
|
||||
else:
|
||||
lateral_jerk_setpoint = 0
|
||||
lateral_jerk_measurement = 0
|
||||
lookahead_lateral_jerk = 0
|
||||
|
||||
# prepare past and future values
|
||||
# adjust future times to account for longitudinal acceleration
|
||||
adjusted_future_times = [time + 0.5 * CS.aEgo * (time / max(CS.vEgo, 1.0)) for time in self.nn_future_times]
|
||||
past_rolls = [self.roll_deque[min(len(self.roll_deque)-1, offset)] for offset in self.history_frame_offsets]
|
||||
future_rolls = [roll_pitch_adjust(interp(time, ModelConstants.T_IDXS, model_data.orientation.x) + roll, interp(time, ModelConstants.T_IDXS, model_data.orientation.y) + pitch) for time in adjusted_future_times]
|
||||
if self.nnff_loaded and model_good and frogpilot_toggles.nnff:
|
||||
# update past data
|
||||
pitch = 0
|
||||
roll = params.roll
|
||||
if len(llk.calibratedOrientationNED.value) > 1:
|
||||
pitch = self.pitch.update(llk.calibratedOrientationNED.value[1])
|
||||
roll = roll_pitch_adjust(roll, pitch)
|
||||
|
||||
past_lateral_accels_desired = [self.lateral_accel_desired_deque[min(len(self.lateral_accel_desired_deque)-1, offset)] for offset in self.history_frame_offsets]
|
||||
future_lateral_accels = [interp(time, ModelConstants.T_IDXS[:CONTROL_N], model_data.acceleration.y) for time in adjusted_future_times]
|
||||
self.roll_deque.append(roll)
|
||||
self.lateral_accel_desired_deque.append(desired_lateral_accel)
|
||||
|
||||
base_input = [CS.vEgo, roll]
|
||||
nnff_common = past_rolls + future_rolls
|
||||
# prepare past and future values
|
||||
# adjust future times to account for longitudinal acceleration
|
||||
adjusted_future_times = [time + 0.5 * CS.aEgo * (time / max(CS.vEgo, 1.0)) for time in self.nn_future_times]
|
||||
past_rolls = [self.roll_deque[min(len(self.roll_deque)-1, offset)] for offset in self.history_frame_offsets]
|
||||
future_rolls = [roll_pitch_adjust(interp(time, ModelConstants.T_IDXS, model_data.orientation.x) + roll, interp(time, ModelConstants.T_IDXS, model_data.orientation.y) + pitch) for time in adjusted_future_times]
|
||||
|
||||
# compute NNFF error response
|
||||
nnff_setpoint_input = base_input[:1] + [setpoint, lateral_jerk_setpoint] + base_input[1:] + [setpoint] * self.past_future_len + nnff_common
|
||||
nnff_measurement_input = base_input[:1] + [measurement, lateral_jerk_measurement] + base_input[1:] + [measurement] * self.past_future_len + nnff_common
|
||||
past_lateral_accels_desired = [self.lateral_accel_desired_deque[min(len(self.lateral_accel_desired_deque)-1, offset)] for offset in self.history_frame_offsets]
|
||||
future_lateral_accels = [interp(time, ModelConstants.T_IDXS[:CONTROL_N], model_data.acceleration.y) for time in adjusted_future_times]
|
||||
|
||||
torque_from_setpoint = self.lat_torque_nn_model.evaluate(nnff_setpoint_input)
|
||||
torque_from_measurement = self.lat_torque_nn_model.evaluate(nnff_measurement_input)
|
||||
base_input = [CS.vEgo, roll]
|
||||
nnff_common = past_rolls + future_rolls
|
||||
|
||||
pid_log.error = torque_from_setpoint - torque_from_measurement
|
||||
# compute NNFF error response
|
||||
nnff_setpoint_input = base_input[:1] + [setpoint, lateral_jerk_setpoint] + base_input[1:] + [setpoint] * self.past_future_len + nnff_common
|
||||
nnff_measurement_input = base_input[:1] + [measurement, lateral_jerk_measurement] + base_input[1:] + [measurement] * self.past_future_len + nnff_common
|
||||
|
||||
error_blend = interp(abs(desired_lateral_accel), [1.0, 2.0], [0.0, 1.0])
|
||||
if error_blend > 0.0: # blend in stronger error response when in high lat accel
|
||||
torque_from_error = self.lat_torque_nn_model.evaluate([CS.vEgo, setpoint - measurement, lateral_jerk_setpoint - lateral_jerk_measurement, 0.0])
|
||||
if sign(pid_log.error) == sign(torque_from_error) and abs(pid_log.error) < abs(torque_from_error):
|
||||
pid_log.error = pid_log.error * (1.0 - error_blend) + torque_from_error * error_blend
|
||||
torque_from_setpoint = self.lat_torque_nn_model.evaluate(nnff_setpoint_input)
|
||||
torque_from_measurement = self.lat_torque_nn_model.evaluate(nnff_measurement_input)
|
||||
|
||||
# compute feedforward (same as nn setpoint output)
|
||||
error = setpoint - measurement
|
||||
friction_input = self.lat_accel_friction_factor * error + self.lat_jerk_friction_factor * lookahead_lateral_jerk
|
||||
nn_input = [CS.vEgo, desired_lateral_accel, friction_input, roll] + past_lateral_accels_desired + future_lateral_accels + nnff_common
|
||||
ff = self.lat_torque_nn_model.evaluate(nn_input)
|
||||
pid_log.error = torque_from_setpoint - torque_from_measurement
|
||||
|
||||
# apply friction override for cars with low NN friction response
|
||||
if self.nn_friction_override:
|
||||
pid_log.error += self.torque_from_lateral_accel(0.0, self.lat_control_torque.torque_params)
|
||||
else:
|
||||
torque_from_measurement = self.torque_from_lateral_accel(measurement, self.lat_control_torque.torque_params)
|
||||
torque_from_setpoint = self.torque_from_lateral_accel(setpoint, self.lat_control_torque.torque_params)
|
||||
error_blend = interp(abs(desired_lateral_accel), [1.0, 2.0], [0.0, 1.0])
|
||||
if error_blend > 0.0: # blend in stronger error response when in high lat accel
|
||||
torque_from_error = self.lat_torque_nn_model.evaluate([CS.vEgo, setpoint - measurement, lateral_jerk_setpoint - lateral_jerk_measurement, 0.0])
|
||||
if sign(pid_log.error) == sign(torque_from_error) and abs(pid_log.error) < abs(torque_from_error):
|
||||
pid_log.error = pid_log.error * (1.0 - error_blend) + torque_from_error * error_blend
|
||||
|
||||
pid_log.error = float(torque_from_setpoint - torque_from_measurement)
|
||||
# compute feedforward (same as nn setpoint output)
|
||||
error = setpoint - measurement
|
||||
friction_input = self.lat_accel_friction_factor * error + self.lat_jerk_friction_factor * lookahead_lateral_jerk
|
||||
nn_input = [CS.vEgo, desired_lateral_accel, friction_input, roll] + past_lateral_accels_desired + future_lateral_accels + nnff_common
|
||||
ff = self.lat_torque_nn_model.evaluate(nn_input)
|
||||
|
||||
error = desired_lateral_accel - actual_lateral_accel
|
||||
friction_input = self.lat_accel_friction_factor * error + self.lat_jerk_friction_factor * lookahead_lateral_jerk
|
||||
ff = self.torque_from_lateral_accel(gravity_adjusted_lateral_accel, self.lat_control_torque.torque_params)
|
||||
# apply friction override for cars with low NN friction response
|
||||
if self.nn_friction_override:
|
||||
pid_log.error += self.torque_from_lateral_accel(0.0, self.torque_params)
|
||||
else:
|
||||
torque_from_measurement = self.torque_from_lateral_accel(measurement, self.torque_params)
|
||||
torque_from_setpoint = self.torque_from_lateral_accel(setpoint, self.torque_params)
|
||||
|
||||
return pid_log, ff
|
||||
pid_log.error = float(torque_from_setpoint - torque_from_measurement)
|
||||
|
||||
error = desired_lateral_accel - actual_lateral_accel
|
||||
friction_input = self.lat_accel_friction_factor * error + self.lat_jerk_friction_factor * lookahead_lateral_jerk
|
||||
ff = self.torque_from_lateral_accel(gravity_adjusted_lateral_accel, self.torque_params)
|
||||
else:
|
||||
torque_from_measurement = self.torque_from_lateral_accel(measurement, self.torque_params)
|
||||
torque_from_setpoint = self.torque_from_lateral_accel(setpoint, self.torque_params)
|
||||
|
||||
pid_log.error = float(torque_from_setpoint - torque_from_measurement)
|
||||
|
||||
ff = self.torque_from_lateral_accel(gravity_adjusted_lateral_accel, self.torque_params)
|
||||
|
||||
freeze_integrator = steer_limited_by_safety or CS.steeringPressed or CS.vEgo < 5
|
||||
output_torque = self.pid.update(pid_log.error,
|
||||
feedforward=ff,
|
||||
speed=CS.vEgo,
|
||||
freeze_integrator=freeze_integrator)
|
||||
|
||||
pid_log.active = True
|
||||
pid_log.p = float(self.pid.p)
|
||||
pid_log.i = float(self.pid.i)
|
||||
pid_log.d = float(self.pid.d)
|
||||
pid_log.f = float(self.pid.f)
|
||||
pid_log.output = float(-output_torque)
|
||||
pid_log.actualLateralAccel = float(actual_lateral_accel)
|
||||
pid_log.desiredLateralAccel = float(desired_lateral_accel)
|
||||
pid_log.saturated = bool(self._check_saturation(self.steer_max - abs(output_torque) < 1e-3, CS, steer_limited_by_safety, curvature_limited))
|
||||
|
||||
# TODO left is positive in this convention
|
||||
return -output_torque, 0.0, pid_log
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -20,6 +20,30 @@ from openpilot.frogpilot.common.frogpilot_variables import get_frogpilot_toggles
|
||||
|
||||
BASE_URL = "https://nominatim.openstreetmap.org"
|
||||
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):
|
||||
try:
|
||||
@@ -44,14 +68,7 @@ def get_city_center(latitude, longitude):
|
||||
|
||||
if data:
|
||||
tags = data[0]
|
||||
population = (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
|
||||
population_value = get_population_value((tags.get("extratags") or {}).get("population"))
|
||||
|
||||
if population_value is not None and population_value >= MINIMUM_POPULATION:
|
||||
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
|
||||
|
||||
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}"
|
||||
response = session.get(f"{BASE_URL}/search", params={"addressdetails": 1, "extratags": 1, "format": "jsonv2", "limit": 5, "q": query}, timeout=10)
|
||||
response.raise_for_status()
|
||||
@@ -97,6 +118,19 @@ def get_city_center(latitude, longitude):
|
||||
print(f"Falling back to (0, 0) for {latitude}, {longitude}")
|
||||
return float(0.0), float(0.0), "N/A", "N/A", "N/A"
|
||||
|
||||
def update_branch_commits(now):
|
||||
points = []
|
||||
branch = get_build_metadata().channel # Current running branch
|
||||
try:
|
||||
response = requests.get(f"https://api.github.com/repos/firestar5683/StarPilot/commits/{branch}")
|
||||
response.raise_for_status()
|
||||
sha = response.json()["sha"]
|
||||
points.append(Point("branch_commits").field("commit", sha).tag("branch", branch).time(now))
|
||||
except Exception as e:
|
||||
print(f"Failed to fetch commit for {branch}: {e}")
|
||||
|
||||
return points
|
||||
|
||||
def is_up_to_date(build_metadata):
|
||||
remote_commit = run_cmd(["git", "ls-remote", "origin", build_metadata.channel], f"Fetched remote commit", "Failed to fetch remote commit", report=False)
|
||||
|
||||
@@ -116,11 +150,9 @@ def send_stats():
|
||||
if frogpilot_toggles.car_make == "mock":
|
||||
return
|
||||
|
||||
bucket = os.environ.get("STATS_BUCKET", "")
|
||||
org_ID = os.environ.get("STATS_ORG_ID", "")
|
||||
token = os.environ.get("STATS_TOKEN", "")
|
||||
url = os.environ.get("STATS_URL", "")
|
||||
|
||||
bucket = "StarPilot"
|
||||
org_ID = "StarPilot"
|
||||
url = "https://stats.firestar.link"
|
||||
frogpilot_stats = json.loads(params.get("FrogPilotStats") or "{}")
|
||||
|
||||
location = json.loads(params.get("LastGPSPosition") or "{}")
|
||||
@@ -144,15 +176,23 @@ def send_stats():
|
||||
|
||||
selected_theme = random.choice([item for item, count in most_common if count == max_count]).replace("-user_created", "").replace("_", " ")
|
||||
|
||||
point = (Point("user_stats")
|
||||
now = datetime.now(timezone.utc)
|
||||
|
||||
user_point = (
|
||||
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("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("device", HARDWARE.get_device_type())
|
||||
.field("driving_model", clean_model_name(frogpilot_toggles.model_name))
|
||||
.field("event", 1)
|
||||
.field("frogpilot_drives", int(frogpilot_stats.get("FrogPilotDrives", 0)))
|
||||
.field("frogpilot_hours", float(frogpilot_stats.get("FrogPilotSeconds", 0)) / (60 * 60))
|
||||
@@ -162,13 +202,12 @@ def send_stats():
|
||||
.field("has_openpilot_longitudinal", frogpilot_toggles.openpilot_longitudinal)
|
||||
.field("has_pedal", frogpilot_toggles.has_pedal)
|
||||
.field("has_sdsu", frogpilot_toggles.has_sdsu)
|
||||
.field("has_sascm", frogpilot_toggles.has_sascm)
|
||||
.field("has_zss", frogpilot_toggles.has_zss)
|
||||
.field("latitude", latitude)
|
||||
.field("longitude", longitude)
|
||||
.field("rainbow_path", frogpilot_toggles.rainbow_path)
|
||||
.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_lateral_seconds", float(frogpilot_stats.get("LateralTime", 0)))
|
||||
.field("total_longitudinal_seconds", float(frogpilot_stats.get("LongitudinalTime", 0)))
|
||||
@@ -177,13 +216,13 @@ def send_stats():
|
||||
.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))
|
||||
|
||||
.tag("branch", build_metadata.channel)
|
||||
.tag("dongle_id", params.get("FrogPilotDongleId", encoding="utf-8"))
|
||||
|
||||
.time(datetime.now(timezone.utc))
|
||||
.time(now)
|
||||
)
|
||||
|
||||
InfluxDBClient(org=org_ID, token=token, url=url).write_api(write_options=SYNCHRONOUS).write(bucket=bucket, org=org_ID, record=point)
|
||||
all_points = [user_point] + update_branch_commits(now)
|
||||
|
||||
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)
|
||||
print("Successfully sent FrogPilot stats!")
|
||||
except Exception as exception:
|
||||
print(f"Failed to send FrogPilot stats: {exception}")
|
||||
|
||||
@@ -11,16 +11,15 @@ ConfidenceClass = log.ModelDataV2.ConfidenceClass
|
||||
|
||||
# Return curvature for lateral action. If the model outputs desired_curvature and we're not in mlsim mode,
|
||||
# use it directly; otherwise derive from the plan using yaw and yaw-rate.
|
||||
def get_curvature_from_output(output: dict, v_ego: float, lat_action_t: float, mlsim: bool) -> float:
|
||||
def get_curvature_from_output(output: dict, plan: np.ndarray, v_ego: float, lat_action_t: float, mlsim: bool) -> float:
|
||||
if not mlsim:
|
||||
desired = output.get('desired_curvature')
|
||||
if desired is not None:
|
||||
return float(desired[0, 0])
|
||||
|
||||
plan_out = output['plan'][0]
|
||||
# Use yaw (index 2) and yaw_rate (index 2)
|
||||
theta = plan_out[:, Plan.T_FROM_CURRENT_EULER][:, 2]
|
||||
theta_dot = plan_out[:, Plan.ORIENTATION_RATE][:, 2]
|
||||
theta = plan[:, Plan.T_FROM_CURRENT_EULER][:, 2]
|
||||
theta_dot = plan[:, Plan.ORIENTATION_RATE][:, 2]
|
||||
return float(get_curvature_from_plan(theta, theta_dot, ModelConstants.T_IDXS, v_ego, lat_action_t))
|
||||
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -97,12 +97,12 @@ class Parser:
|
||||
self.parse_mdn('lead', outs, in_N=ModelConstants.LEAD_MHP_N, out_N=ModelConstants.LEAD_MHP_SELECTION,
|
||||
out_shape=(ModelConstants.LEAD_TRAJ_LEN, ModelConstants.LEAD_WIDTH))
|
||||
if 'plan' in outs:
|
||||
if outs['plan'].shape[1] == 2 * ModelConstants.IDX_N * ModelConstants.PLAN_WIDTH:
|
||||
self.parse_mdn('plan', outs, in_N=0, out_N=0,
|
||||
out_shape=(ModelConstants.IDX_N, ModelConstants.PLAN_WIDTH))
|
||||
else:
|
||||
self.parse_mdn('plan', outs, in_N=ModelConstants.PLAN_MHP_N, out_N=ModelConstants.PLAN_MHP_SELECTION,
|
||||
out_shape=(ModelConstants.IDX_N, ModelConstants.PLAN_WIDTH))
|
||||
plan_mhp = outs['plan'].shape[1] != 2 * ModelConstants.IDX_N * ModelConstants.PLAN_WIDTH
|
||||
plan_in_N, plan_out_N = (ModelConstants.PLAN_MHP_N, ModelConstants.PLAN_MHP_SELECTION) if plan_mhp else (0, 0)
|
||||
self.parse_mdn('plan', outs, in_N=plan_in_N, out_N=plan_out_N,
|
||||
out_shape=(ModelConstants.IDX_N, ModelConstants.PLAN_WIDTH))
|
||||
if 'planplus' in outs:
|
||||
self.parse_mdn('planplus', outs, in_N=plan_in_N, out_N=plan_out_N, out_shape=(ModelConstants.IDX_N, ModelConstants.PLAN_WIDTH))
|
||||
if 'lane_lines' in outs:
|
||||
self.parse_mdn('lane_lines', outs, in_N=0, out_N=0,
|
||||
out_shape=(ModelConstants.NUM_LANE_LINES, ModelConstants.IDX_N, ModelConstants.LANE_LINES_WIDTH))
|
||||
|
||||
@@ -35,14 +35,17 @@ PROCESS_NAME = "frogpilot.tinygrad_modeld.tinygrad_modeld"
|
||||
SEND_RAW_PRED = os.getenv('SEND_RAW_PRED')
|
||||
|
||||
|
||||
LAT_SMOOTH_SECONDS = 0.1
|
||||
LAT_SMOOTH_SECONDS = 0.0
|
||||
LONG_SMOOTH_SECONDS = 0.3
|
||||
MIN_LAT_CONTROL_SPEED = 0.3
|
||||
|
||||
|
||||
def get_action_from_model(model_output: dict[str, np.ndarray], prev_action: log.ModelDataV2.Action,
|
||||
lat_action_t: float, long_action_t: float, v_ego: float, mlsim: bool, is_v9: bool) -> log.ModelDataV2.Action:
|
||||
lat_action_t: float, long_action_t: float, v_ego: float, mlsim: bool, is_v9: bool, frogpilot_toggles) -> log.ModelDataV2.Action:
|
||||
plan = model_output['plan'][0]
|
||||
if 'planplus' in model_output:
|
||||
plan = plan + frogpilot_toggles.recovery_power*model_output['planplus'][0]
|
||||
cloudlog.error(f"planplus applied: shape {model_output['planplus'].shape}, RECOVERY_POWER {frogpilot_toggles.recovery_power}")
|
||||
desired_accel, should_stop = get_accel_from_plan_tomb_raider(plan[:,Plan.VELOCITY][:,0],
|
||||
plan[:,Plan.ACCELERATION][:,0],
|
||||
ModelConstants.T_IDXS,
|
||||
@@ -56,7 +59,7 @@ def get_action_from_model(model_output: dict[str, np.ndarray], prev_action: log.
|
||||
else:
|
||||
desired_curvature = prev_action.desiredCurvature
|
||||
else:
|
||||
desired_curvature = get_curvature_from_output(model_output, v_ego, lat_action_t, mlsim=mlsim)
|
||||
desired_curvature = get_curvature_from_output(model_output, plan, v_ego, lat_action_t, mlsim=mlsim)
|
||||
if v_ego > MIN_LAT_CONTROL_SPEED:
|
||||
desired_curvature = smooth_value(desired_curvature, prev_action.desiredCurvature, LAT_SMOOTH_SECONDS)
|
||||
else:
|
||||
@@ -81,6 +84,34 @@ class ModelState:
|
||||
output: np.ndarray
|
||||
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):
|
||||
# Dynamically build paths based on current model ID
|
||||
params = Params()
|
||||
@@ -94,10 +125,22 @@ class ModelState:
|
||||
cloudlog.warning(f"ModelVersion parameter not available: {e}")
|
||||
|
||||
model_dir = MODELS_PATH
|
||||
VISION_PKL_PATH = model_dir / f"{model_id}_driving_vision_tinygrad.pkl"
|
||||
POLICY_PKL_PATH = model_dir / f"{model_id}_driving_policy_tinygrad.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"
|
||||
# For the default "bd2" model, use built-in files from the models directory
|
||||
if model_id == "bd2":
|
||||
models_dir = Path(__file__).parent / "models"
|
||||
VISION_PKL_PATH = models_dir / "driving_vision_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"
|
||||
POLICY_METADATA_PATH = models_dir / "driving_policy_metadata.pkl"
|
||||
OFF_POLICY_METADATA_PATH = models_dir / "driving_off_policy_metadata.pkl"
|
||||
else:
|
||||
VISION_PKL_PATH = model_dir / f"{model_id}_driving_vision_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"
|
||||
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 not model_version:
|
||||
@@ -149,7 +192,7 @@ class ModelState:
|
||||
self.policy_generation = model_version or "v8"
|
||||
self.is_v11 = (self.policy_generation == "v11")
|
||||
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.prev_desire = np.zeros(ModelConstants.DESIRE_LEN, dtype=np.float32)
|
||||
@@ -160,33 +203,50 @@ class ModelState:
|
||||
|
||||
|
||||
# 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)
|
||||
desire_key_init = next((k for k in self.policy_input_shapes if k.startswith('desire')), None)
|
||||
if desire_key_init:
|
||||
self.numpy_inputs[desire_key_init] = np.zeros((1, ModelConstants.INPUT_HISTORY_BUFFER_LEN, ModelConstants.DESIRE_LEN), dtype=np.float32)
|
||||
if 'traffic_convention' in self.policy_input_shapes:
|
||||
self.numpy_inputs['traffic_convention'] = np.zeros((1, ModelConstants.TRAFFIC_CONVENTION_LEN), dtype=np.float32)
|
||||
if 'features_buffer' in self.policy_input_shapes:
|
||||
self.numpy_inputs['features_buffer'] = np.zeros((1, ModelConstants.INPUT_HISTORY_BUFFER_LEN, ModelConstants.FEATURE_LEN), dtype=np.float32)
|
||||
# Off-policy model (optional)
|
||||
self.off_policy_enabled = False
|
||||
self.off_policy_input_shapes: dict[str, tuple[int, ...]] = {}
|
||||
self.off_policy_output_slices: dict[str, slice] = {}
|
||||
self.off_policy_numpy_inputs: dict[str, np.ndarray] = {}
|
||||
self.off_policy_prev_desired_curv_key: str | None = None
|
||||
self.off_policy_desire_key: str | None = None
|
||||
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)
|
||||
# Lateral control params
|
||||
if 'lateral_control_params' in self.policy_input_shapes:
|
||||
self.numpy_inputs['lateral_control_params'] = np.zeros((1, ModelConstants.LATERAL_CONTROL_PARAMS_LEN), dtype=np.float32)
|
||||
off_policy_metadata = None
|
||||
if self.policy_generation == "v12" or OFF_POLICY_METADATA_PATH.is_file() or OFF_POLICY_PKL_PATH.is_file():
|
||||
try:
|
||||
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
|
||||
self.prev_desired_curv_key = None
|
||||
if 'prev_desired_curv' in self.policy_input_shapes:
|
||||
self.prev_desired_curv_key = 'prev_desired_curv'
|
||||
self.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 self.policy_input_shapes:
|
||||
self.prev_desired_curv_key = 'prev_desired_curvs'
|
||||
self.numpy_inputs['prev_desired_curvs'] = np.zeros((1, ModelConstants.INPUT_HISTORY_BUFFER_LEN, ModelConstants.PREV_DESIRED_CURV_LEN), dtype=np.float32)
|
||||
if off_policy_metadata is not None:
|
||||
self.off_policy_input_shapes = off_policy_metadata['input_shapes']
|
||||
self.off_policy_output_slices = off_policy_metadata['output_slices']
|
||||
off_policy_output_size = off_policy_metadata['output_shapes']['outputs'][1]
|
||||
self.off_policy_numpy_inputs, self.off_policy_prev_desired_curv_key = self._build_policy_inputs(self.off_policy_input_shapes)
|
||||
self.off_policy_desire_key = next((k for k in self.off_policy_numpy_inputs if k.startswith('desire')), None)
|
||||
self.off_policy_inputs = {k: Tensor(v, device='NPY').realize() for k, v in self.off_policy_numpy_inputs.items()}
|
||||
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)
|
||||
if getattr(self, 'prev_desired_curv_key', None) is not None:
|
||||
# Optional temporal buffer for previous desired curvature (allocate only if any model expects it)
|
||||
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)
|
||||
|
||||
|
||||
@@ -196,6 +256,7 @@ class ModelState:
|
||||
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.parser = Parser()
|
||||
self.off_policy_parser = Parser(ignore_missing=True)
|
||||
|
||||
with open(VISION_PKL_PATH, "rb") as f:
|
||||
self.vision_run = pickle.load(f)
|
||||
@@ -221,10 +282,18 @@ class ModelState:
|
||||
self.full_desire[0,:-1] = self.full_desire[0,1:]
|
||||
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)
|
||||
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:
|
||||
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:
|
||||
return None
|
||||
@@ -246,7 +315,10 @@ class ModelState:
|
||||
|
||||
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.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()
|
||||
policy_outputs_dict = self.parser.parse_policy_outputs(self.slice_outputs(self.policy_output, self.policy_output_slices))
|
||||
@@ -263,9 +335,24 @@ class ModelState:
|
||||
else:
|
||||
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}
|
||||
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:
|
||||
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
|
||||
|
||||
@@ -434,7 +521,7 @@ def main(demo=False):
|
||||
drivingdata_send = messaging.new_message('drivingModelData')
|
||||
posenet_send = messaging.new_message('cameraOdometry')
|
||||
|
||||
action = get_action_from_model(model_output, prev_action, lat_delay + DT_MDL, long_delay + DT_MDL, v_ego, model.mlsim, model.is_v9)
|
||||
action = get_action_from_model(model_output, prev_action, lat_delay + DT_MDL, long_delay + DT_MDL, v_ego, model.mlsim, model.is_v9, frogpilot_toggles)
|
||||
prev_action = action
|
||||
fill_model_msg(drivingdata_send, modelv2_send, model_output, action,
|
||||
publish_state, meta_main.frame_id, meta_extra.frame_id, frame_id,
|
||||
@@ -473,4 +560,4 @@ if __name__ == "__main__":
|
||||
cloudlog.warning(f"child {PROCESS_NAME} got SIGINT")
|
||||
except Exception:
|
||||
sentry.capture_exception()
|
||||
raise
|
||||
raise
|
||||
|
||||
@@ -1,19 +1,74 @@
|
||||
#include "frogpilot/ui/qt/offroad/expandable_multi_option_dialog.h"
|
||||
|
||||
#include <QPushButton>
|
||||
#include <QButtonGroup>
|
||||
#include <QVBoxLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QScrollBar>
|
||||
#include <QTimer>
|
||||
#include <QHBoxLayout>
|
||||
#include <QSpacerItem>
|
||||
#include <QLayout>
|
||||
#include <QLayoutItem>
|
||||
#include <QGridLayout>
|
||||
#include <QPoint>
|
||||
#include <QSize>
|
||||
#include <QSizePolicy>
|
||||
#include <QSet>
|
||||
#include <QVector>
|
||||
#include <QSignalBlocker>
|
||||
#include <QScroller>
|
||||
#include <QPointer>
|
||||
#include <QObject>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "selfdrive/ui/qt/widgets/scrollview.h"
|
||||
|
||||
ExpandableMultiOptionDialog::ExpandableMultiOptionDialog(const QString &prompt_text,
|
||||
const QMap<QString, QStringList> &seriesToModels,
|
||||
const QString ¤t, QWidget *parent)
|
||||
: DialogBase(parent), seriesToModels(seriesToModels) {
|
||||
const QMap<QString, QStringList> &seriesToModels,
|
||||
const QString ¤t, QWidget *parent,
|
||||
const QStringList &userFavorites,
|
||||
const QStringList &communityFavorites,
|
||||
const QMap<QString, QString> &modelReleasedDates,
|
||||
const QMap<QString, QString> &modelFileToNameMap,
|
||||
const QString &initialSortMode)
|
||||
: DialogBase(parent), seriesToModels(seriesToModels), currentSortMode(initialSortMode.isEmpty() ? QString("alphabetical") : initialSortMode),
|
||||
userFavorites(userFavorites), communityFavorites(communityFavorites), modelReleasedDates(modelReleasedDates),
|
||||
modelFileToNameMap(modelFileToNameMap), currentSelection(current) {
|
||||
|
||||
baseSeriesToModels = seriesToModels;
|
||||
|
||||
for (auto it = this->modelFileToNameMap.constBegin(); it != this->modelFileToNameMap.constEnd(); ++it) {
|
||||
modelNameToFileMap.insert(it.value(), it.key());
|
||||
}
|
||||
|
||||
for (auto it = seriesToModels.constBegin(); it != seriesToModels.constEnd(); ++it) {
|
||||
const QStringList &models = it.value();
|
||||
for (const QString &modelName : models) {
|
||||
if (modelName.isEmpty() || modelNameToFileMap.contains(modelName)) {
|
||||
continue;
|
||||
}
|
||||
this->modelFileToNameMap.insert(modelName, modelName);
|
||||
modelNameToFileMap.insert(modelName, modelName);
|
||||
}
|
||||
}
|
||||
|
||||
currentSelectionKey = modelNameToFileMap.value(currentSelection);
|
||||
if (!currentSelectionKey.isEmpty()) {
|
||||
selectionKey = currentSelectionKey;
|
||||
selection = this->modelFileToNameMap.value(currentSelectionKey, currentSelection);
|
||||
currentSelection = selection;
|
||||
} else {
|
||||
selectionKey.clear();
|
||||
selection.clear();
|
||||
currentSelection.clear();
|
||||
}
|
||||
|
||||
if (currentSortMode != "alphabetical" && currentSortMode != "date" &&
|
||||
currentSortMode != "favorites" && currentSortMode != "date_oldest") {
|
||||
currentSortMode = "alphabetical";
|
||||
}
|
||||
|
||||
QFrame *container = new QFrame(this);
|
||||
container->setStyleSheet(R"(
|
||||
@@ -50,6 +105,43 @@ ExpandableMultiOptionDialog::ExpandableMultiOptionDialog(const QString &prompt_t
|
||||
padding-left: 80px;
|
||||
}
|
||||
QPushButton.series-header:hover { background-color: #404040; }
|
||||
QPushButton.favorite-button {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
font-size: 60px;
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
min-width: 80px;
|
||||
max-width: 80px;
|
||||
}
|
||||
QPushButton.favorite-button:hover { background-color: #404040; }
|
||||
QComboBox {
|
||||
background-color: #4F4F4F;
|
||||
border: 2px solid transparent;
|
||||
border-radius: 10px;
|
||||
padding: 10px;
|
||||
font-size: 50px;
|
||||
color: white;
|
||||
min-width: 200px;
|
||||
}
|
||||
QComboBox:hover { background-color: #5A5A5A; }
|
||||
QComboBox::drop-down {
|
||||
border: none;
|
||||
width: 50px;
|
||||
}
|
||||
QComboBox::down-arrow {
|
||||
image: url("../../frogpilot/assets/toggle_icons/icon_dropdown.png");
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
}
|
||||
QComboBox QAbstractItemView {
|
||||
background-color: #4F4F4F;
|
||||
border: 2px solid #FFFFFF;
|
||||
border-radius: 10px;
|
||||
color: white;
|
||||
selection-background-color: #465BEA;
|
||||
font-size: 50px;
|
||||
}
|
||||
)");
|
||||
|
||||
QVBoxLayout *main_layout = new QVBoxLayout(container);
|
||||
@@ -60,85 +152,103 @@ ExpandableMultiOptionDialog::ExpandableMultiOptionDialog(const QString &prompt_t
|
||||
main_layout->addWidget(title, 0, Qt::AlignLeft | Qt::AlignTop);
|
||||
main_layout->addSpacing(25);
|
||||
|
||||
QWidget *listWidget = new QWidget(this);
|
||||
QVBoxLayout *listLayout = new QVBoxLayout(listWidget);
|
||||
listLayout->setSpacing(10);
|
||||
// Sort controls - simple cycling button
|
||||
QHBoxLayout *sortLayout = new QHBoxLayout();
|
||||
sortLayout->setContentsMargins(0, 0, 0, 0);
|
||||
sortLayout->setSpacing(20);
|
||||
sortLayout->addStretch(); // Push to the right
|
||||
|
||||
QButtonGroup *group = new QButtonGroup(listWidget);
|
||||
group->setExclusive(true);
|
||||
QLabel *sortLabel = new QLabel(tr("Sort by:"), this);
|
||||
sortLabel->setStyleSheet("font-size: 50px; color: white;");
|
||||
sortLayout->addWidget(sortLabel);
|
||||
|
||||
QPushButton *confirm_btn = new QPushButton(tr("Select"));
|
||||
confirm_btn->setObjectName("confirm_btn");
|
||||
confirm_btn->setEnabled(false);
|
||||
|
||||
ScrollView *scroll_view = new ScrollView(listWidget, this);
|
||||
scroll_view->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
||||
|
||||
// Create series headers and their expandable content
|
||||
for (const QString &series : seriesToModels.keys()) {
|
||||
// Series header button
|
||||
QPushButton *seriesHeader = new QPushButton("▶ " + series);
|
||||
seriesHeader->setProperty("class", "series-header");
|
||||
seriesHeader->setCheckable(false);
|
||||
seriesExpanded[series] = false;
|
||||
|
||||
QObject::connect(seriesHeader, &QPushButton::clicked, [this, series, seriesHeader, scroll_view]() {
|
||||
toggleSeries(series, seriesHeader, scroll_view);
|
||||
});
|
||||
|
||||
listLayout->addWidget(seriesHeader);
|
||||
|
||||
// Container for series models (initially hidden)
|
||||
QWidget *seriesContainer = new QWidget();
|
||||
QVBoxLayout *seriesLayout = new QVBoxLayout(seriesContainer);
|
||||
seriesLayout->setContentsMargins(20, 0, 0, 0);
|
||||
seriesLayout->setSpacing(10);
|
||||
seriesContainer->hide();
|
||||
|
||||
// Add models for this series
|
||||
for (const QString &model : seriesToModels[series]) {
|
||||
QPushButton *modelButton = new QPushButton(model);
|
||||
modelButton->setCheckable(true);
|
||||
modelButton->setChecked(model == current);
|
||||
modelButton->setProperty("class", "model-option");
|
||||
|
||||
QObject::connect(modelButton, &QPushButton::toggled, [=](bool checked) mutable {
|
||||
if (checked) {
|
||||
selection = model;
|
||||
confirm_btn->setEnabled(true);
|
||||
// Manually apply selected style
|
||||
modelButton->setStyleSheet("QPushButton {"
|
||||
"background-color: #465BEA;"
|
||||
"border: 3px solid #FFFFFF;"
|
||||
"color: white;"
|
||||
"font-weight: 500;"
|
||||
"height: 135;"
|
||||
"padding: 0px 50px;"
|
||||
"text-align: left;"
|
||||
"font-size: 55px;"
|
||||
"border-radius: 10px;"
|
||||
"}");
|
||||
} else {
|
||||
if (selection == model) {
|
||||
confirm_btn->setEnabled(false);
|
||||
}
|
||||
// Reset to default style
|
||||
modelButton->setStyleSheet("");
|
||||
}
|
||||
});
|
||||
|
||||
group->addButton(modelButton);
|
||||
seriesLayout->addWidget(modelButton);
|
||||
QPushButton *sortButton = new QPushButton(tr("Alphabetical"), this);
|
||||
sortButton->setStyleSheet(R"(
|
||||
QPushButton {
|
||||
background-color: #4F4F4F;
|
||||
border: 2px solid transparent;
|
||||
border-radius: 10px;
|
||||
padding: 10px 20px;
|
||||
font-size: 50px;
|
||||
color: white;
|
||||
min-width: 250px;
|
||||
text-align: center;
|
||||
}
|
||||
QPushButton:hover { background-color: #5A5A5A; }
|
||||
)");
|
||||
|
||||
seriesWidgets[series] = seriesContainer;
|
||||
listLayout->addWidget(seriesContainer);
|
||||
// Set initial button text based on sort mode
|
||||
if (currentSortMode == "date") {
|
||||
sortButton->setText(tr("Date (Newest)"));
|
||||
} else if (currentSortMode == "date_oldest") {
|
||||
sortButton->setText(tr("Date (Oldest)"));
|
||||
} else if (currentSortMode == "favorites") {
|
||||
sortButton->setText(tr("Favorites First"));
|
||||
} else {
|
||||
sortButton->setText(tr("Alphabetical"));
|
||||
}
|
||||
|
||||
// Add stretch to keep buttons spaced correctly
|
||||
listLayout->addStretch(1);
|
||||
QWidget *sortWidget = new QWidget(container);
|
||||
sortWidget->setLayout(sortLayout);
|
||||
sortWidget->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
|
||||
sortLayout->setSizeConstraint(QLayout::SetFixedSize);
|
||||
sortWidget->setStyleSheet("background: transparent;");
|
||||
|
||||
main_layout->addWidget(scroll_view);
|
||||
sortLayout->addWidget(sortButton);
|
||||
|
||||
auto updateSortOverlayGeometry = [sortWidget, sortLayout]() {
|
||||
if (!sortWidget) return;
|
||||
const QSize hint = sortLayout->sizeHint();
|
||||
sortWidget->setFixedSize(hint);
|
||||
};
|
||||
updateSortOverlayGeometry();
|
||||
|
||||
QObject::connect(sortButton, &QPushButton::clicked, [this, sortButton, updateSortOverlayGeometry]() {
|
||||
if (currentSortMode == "alphabetical") {
|
||||
currentSortMode = "date";
|
||||
sortButton->setText(tr("Date (Newest)"));
|
||||
} else if (currentSortMode == "date") {
|
||||
currentSortMode = "date_oldest";
|
||||
sortButton->setText(tr("Date (Oldest)"));
|
||||
} else if (currentSortMode == "date_oldest") {
|
||||
currentSortMode = "favorites";
|
||||
sortButton->setText(tr("Favorites First"));
|
||||
} else {
|
||||
currentSortMode = "alphabetical";
|
||||
sortButton->setText(tr("Alphabetical"));
|
||||
}
|
||||
updateSortOverlayGeometry();
|
||||
updateSorting();
|
||||
});
|
||||
|
||||
listWidgetContainer = new QWidget(this);
|
||||
listLayout = new QVBoxLayout(listWidgetContainer);
|
||||
listLayout->setSpacing(10);
|
||||
listLayout->setContentsMargins(0, 0, 0, 0);
|
||||
|
||||
confirmButton = new QPushButton(tr("Select"));
|
||||
confirmButton->setObjectName("confirm_btn");
|
||||
confirmButton->setEnabled(!selectionKey.isEmpty());
|
||||
|
||||
scrollView = new ScrollView(listWidgetContainer, this);
|
||||
scrollView->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
||||
if (scrollView->viewport()) {
|
||||
scrollView->viewport()->setAttribute(Qt::WA_AcceptTouchEvents, true);
|
||||
}
|
||||
|
||||
QWidget *listContainer = new QWidget(container);
|
||||
QGridLayout *overlayLayout = new QGridLayout(listContainer);
|
||||
overlayLayout->setContentsMargins(0, 0, 0, 0);
|
||||
overlayLayout->setSpacing(0);
|
||||
overlayLayout->addWidget(scrollView, 0, 0);
|
||||
overlayLayout->setRowStretch(0, 1);
|
||||
overlayLayout->setColumnStretch(0, 1);
|
||||
overlayLayout->addWidget(sortWidget, 0, 0, Qt::AlignRight | Qt::AlignTop);
|
||||
|
||||
// Create series headers and their expandable content
|
||||
rebuildModelList(seriesToModels.keys(), seriesToModels);
|
||||
|
||||
main_layout->addWidget(listContainer);
|
||||
main_layout->addSpacing(35);
|
||||
|
||||
// Cancel + confirm buttons
|
||||
@@ -148,18 +258,25 @@ ExpandableMultiOptionDialog::ExpandableMultiOptionDialog(const QString &prompt_t
|
||||
|
||||
QPushButton *cancel_btn = new QPushButton(tr("Cancel"));
|
||||
QObject::connect(cancel_btn, &QPushButton::clicked, this, &ConfirmationDialog::reject);
|
||||
QObject::connect(confirm_btn, &QPushButton::clicked, this, &ConfirmationDialog::accept);
|
||||
QObject::connect(confirmButton, &QPushButton::clicked, this, &ConfirmationDialog::accept);
|
||||
blayout->addWidget(cancel_btn);
|
||||
blayout->addWidget(confirm_btn);
|
||||
blayout->addWidget(confirmButton);
|
||||
|
||||
QVBoxLayout *outer_layout = new QVBoxLayout(this);
|
||||
outer_layout->setContentsMargins(50, 50, 50, 50);
|
||||
outer_layout->addWidget(container);
|
||||
|
||||
// Initial sorting
|
||||
updateSorting();
|
||||
}
|
||||
|
||||
void ExpandableMultiOptionDialog::toggleSeries(const QString &series, QPushButton *headerButton, ScrollView *scrollView) {
|
||||
void ExpandableMultiOptionDialog::toggleSeries(const QString &series, QPushButton *headerButton) {
|
||||
if (!headerButton) return;
|
||||
|
||||
QWidget *container = seriesWidgets.value(series, nullptr);
|
||||
if (!container) return;
|
||||
|
||||
bool expanded = seriesExpanded[series];
|
||||
QWidget *container = seriesWidgets[series];
|
||||
QString seriesName = series;
|
||||
|
||||
if (expanded) {
|
||||
@@ -171,21 +288,18 @@ void ExpandableMultiOptionDialog::toggleSeries(const QString &series, QPushButto
|
||||
seriesExpanded[series] = true;
|
||||
headerButton->setText("▼ " + seriesName);
|
||||
|
||||
// Auto-scroll to show expanded content
|
||||
// Auto-scroll to place the series at the top of the viewport when expanded
|
||||
if (scrollView) {
|
||||
QTimer::singleShot(50, [container, scrollView]() {
|
||||
QRect containerRect = container->geometry();
|
||||
QScrollBar *vScrollBar = scrollView->verticalScrollBar();
|
||||
if (vScrollBar) {
|
||||
int currentValue = vScrollBar->value();
|
||||
int containerBottom = containerRect.bottom();
|
||||
int viewportHeight = scrollView->viewport()->height();
|
||||
|
||||
// If container extends beyond viewport, scroll to show it
|
||||
if (containerBottom > currentValue + viewportHeight) {
|
||||
int targetValue = containerBottom - viewportHeight + 50; // Add some padding
|
||||
vScrollBar->setValue(targetValue);
|
||||
}
|
||||
QPointer<QPushButton> headerPtr(headerButton);
|
||||
QPointer<ScrollView> scrollPtr(scrollView);
|
||||
QTimer::singleShot(50, [headerPtr, scrollPtr]() {
|
||||
if (!scrollPtr || !headerPtr) return;
|
||||
QWidget *contents = scrollPtr->widget();
|
||||
if (!contents) return;
|
||||
if (QScrollBar *vScrollBar = scrollPtr->verticalScrollBar()) {
|
||||
QPoint headerTop = headerPtr->mapTo(contents, QPoint(0, 0));
|
||||
int targetValue = qMax(headerTop.y() - 20, 0);
|
||||
vScrollBar->setValue(targetValue);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -196,11 +310,457 @@ void ExpandableMultiOptionDialog::toggleSeries(const QString &series, QPushButto
|
||||
}
|
||||
|
||||
QString ExpandableMultiOptionDialog::getSelection(const QString &prompt_text,
|
||||
const QMap<QString, QStringList> &seriesToModels,
|
||||
const QString ¤t, QWidget *parent) {
|
||||
ExpandableMultiOptionDialog d = ExpandableMultiOptionDialog(prompt_text, seriesToModels, current, parent);
|
||||
const QMap<QString, QStringList> &seriesToModels,
|
||||
const QString ¤t, QWidget *parent,
|
||||
const QStringList &userFavorites,
|
||||
const QStringList &communityFavorites,
|
||||
const QMap<QString, QString> &modelReleasedDates,
|
||||
const QMap<QString, QString> &modelFileToNameMap,
|
||||
const QString &initialSortMode) {
|
||||
ExpandableMultiOptionDialog d(prompt_text, seriesToModels, current, parent,
|
||||
userFavorites, communityFavorites, modelReleasedDates, modelFileToNameMap, initialSortMode);
|
||||
if (d.exec()) {
|
||||
return d.selection;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
QStringList ExpandableMultiOptionDialog::getUserFavorites() const {
|
||||
QStringList filteredFavorites;
|
||||
for (const QString &fav : userFavorites) {
|
||||
if (modelFileToNameMap.contains(fav) && !filteredFavorites.contains(fav)) {
|
||||
filteredFavorites.append(fav);
|
||||
}
|
||||
}
|
||||
return filteredFavorites;
|
||||
}
|
||||
|
||||
void ExpandableMultiOptionDialog::stopActiveScroll() {
|
||||
if (!scrollView) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (QScroller *scroller = QScroller::scroller(scrollView->viewport())) {
|
||||
if (scroller->state() == QScroller::Scrolling) {
|
||||
scroller->stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ExpandableMultiOptionDialog::stopActiveScrollForInteraction() {
|
||||
if (!scrollView) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (QScroller *scroller = QScroller::scroller(scrollView->viewport())) {
|
||||
const QScroller::State state = scroller->state();
|
||||
if (state == QScroller::Scrolling || state == QScroller::Dragging || state == QScroller::Pressed) {
|
||||
scroller->stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ExpandableMultiOptionDialog::createModelButton(const QString &modelKey, const QString &modelName, const QString &displayName,
|
||||
QVBoxLayout *layout) {
|
||||
QString effectiveKey = modelKey.isEmpty() ? modelName : modelKey;
|
||||
if (effectiveKey.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!modelFileToNameMap.contains(effectiveKey)) {
|
||||
const QString storedName = !modelName.isEmpty() ? modelName : displayName;
|
||||
modelFileToNameMap.insert(effectiveKey, storedName);
|
||||
}
|
||||
|
||||
if (!modelName.isEmpty()) {
|
||||
modelNameToFileMap.insert(modelName, effectiveKey);
|
||||
}
|
||||
|
||||
QWidget *modelWidget = new QWidget();
|
||||
QHBoxLayout *modelLayout = new QHBoxLayout(modelWidget);
|
||||
modelLayout->setContentsMargins(0, 0, 0, 0);
|
||||
modelLayout->setSpacing(10);
|
||||
|
||||
// Star button
|
||||
QPushButton *starButton = new QPushButton();
|
||||
starButton->setProperty("class", "favorite-button");
|
||||
starButton->setCheckable(true);
|
||||
starButton->setCursor(Qt::PointingHandCursor);
|
||||
starButton->setFocusPolicy(Qt::NoFocus);
|
||||
|
||||
// Check if this model is a favorite
|
||||
bool isCommunityFav = communityFavorites.contains(effectiveKey);
|
||||
bool isUserFav = userFavorites.contains(effectiveKey);
|
||||
bool isFavorite = isCommunityFav || isUserFav;
|
||||
|
||||
starButton->setChecked(isFavorite);
|
||||
starButton->setText(isFavorite ? QString::fromUtf16(u"\u2665") : QString::fromUtf16(u"\u2661"));
|
||||
|
||||
QObject::connect(starButton, &QPushButton::clicked, [this, effectiveKey]() {
|
||||
stopActiveScrollForInteraction();
|
||||
toggleFavorite(effectiveKey);
|
||||
});
|
||||
|
||||
favoriteButtons[effectiveKey].append(starButton);
|
||||
modelLayout->addWidget(starButton);
|
||||
|
||||
// Model button
|
||||
QPushButton *modelButton = new QPushButton(displayName);
|
||||
modelButton->setCheckable(true);
|
||||
modelButton->setProperty("class", "model-option");
|
||||
modelButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
|
||||
modelButton->setCursor(Qt::PointingHandCursor);
|
||||
modelButton->setFocusPolicy(Qt::NoFocus);
|
||||
modelButton->setProperty("modelKey", effectiveKey);
|
||||
modelButton->setProperty("modelName", modelName);
|
||||
|
||||
modelButtons[effectiveKey].append(modelButton);
|
||||
if (selectionKey == effectiveKey && currentSelectionButton.isNull()) {
|
||||
currentSelectionButton = modelButton;
|
||||
}
|
||||
modelLayout->addWidget(modelButton);
|
||||
|
||||
const QString resolvedSelection = modelFileToNameMap.value(effectiveKey, !modelName.isEmpty() ? modelName : displayName);
|
||||
|
||||
QObject::connect(modelButton, &QPushButton::clicked, this, [this, effectiveKey, modelButton, resolvedSelection]() {
|
||||
stopActiveScrollForInteraction();
|
||||
selectionKey = effectiveKey;
|
||||
currentSelectionKey = effectiveKey;
|
||||
selection = resolvedSelection;
|
||||
currentSelection = resolvedSelection;
|
||||
currentSelectionButton = modelButton;
|
||||
if (confirmButton) {
|
||||
confirmButton->setEnabled(true);
|
||||
}
|
||||
|
||||
updateButtonStyles();
|
||||
});
|
||||
|
||||
layout->addWidget(modelWidget);
|
||||
}
|
||||
|
||||
void ExpandableMultiOptionDialog::toggleFavorite(const QString &modelKey) {
|
||||
// Update local state
|
||||
if (modelKey.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (userFavorites.contains(modelKey)) {
|
||||
userFavorites.removeAll(modelKey);
|
||||
} else {
|
||||
userFavorites.append(modelKey);
|
||||
}
|
||||
|
||||
updateSorting();
|
||||
}
|
||||
|
||||
void ExpandableMultiOptionDialog::updateSorting() {
|
||||
const QString favoritesSeriesName = QStringLiteral("♥ Favorites");
|
||||
QMap<QString, QStringList> newSeriesToModels;
|
||||
QStringList orderedSeries;
|
||||
QSet<QString> validSeries;
|
||||
QSet<QString> favoriteModelKeys;
|
||||
QSet<QString> availableModelKeys;
|
||||
displayOverrides.clear();
|
||||
|
||||
const bool sortByDate = (currentSortMode == "date" || currentSortMode == "date_oldest");
|
||||
const bool sortDateNewestFirst = (currentSortMode == "date");
|
||||
|
||||
for (auto it = baseSeriesToModels.constBegin(); it != baseSeriesToModels.constEnd(); ++it) {
|
||||
const QStringList &models = it.value();
|
||||
for (const QString &modelName : models) {
|
||||
const QString modelKey = modelNameToFileMap.value(modelName, modelName);
|
||||
if (!modelKey.isEmpty()) {
|
||||
availableModelKeys.insert(modelKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (currentSortMode == "favorites") {
|
||||
QStringList favoritesList;
|
||||
|
||||
for (const QString &modelKey : communityFavorites) {
|
||||
if (availableModelKeys.contains(modelKey)) {
|
||||
const QString modelName = modelFileToNameMap.value(modelKey);
|
||||
favoritesList.append(modelName);
|
||||
favoriteModelKeys.insert(modelKey);
|
||||
displayOverrides.insert(modelKey, tr("%1 (Community Fav)").arg(modelName));
|
||||
}
|
||||
}
|
||||
|
||||
for (const QString &modelKey : userFavorites) {
|
||||
if (availableModelKeys.contains(modelKey) && !favoriteModelKeys.contains(modelKey)) {
|
||||
favoritesList.append(modelFileToNameMap.value(modelKey));
|
||||
favoriteModelKeys.insert(modelKey);
|
||||
}
|
||||
}
|
||||
|
||||
if (!favoritesList.isEmpty()) {
|
||||
std::sort(favoritesList.begin(), favoritesList.end());
|
||||
newSeriesToModels.insert(favoritesSeriesName, favoritesList);
|
||||
orderedSeries.append(favoritesSeriesName);
|
||||
validSeries.insert(favoritesSeriesName);
|
||||
seriesExpanded.insert(favoritesSeriesName, true);
|
||||
} else {
|
||||
seriesExpanded.remove(favoritesSeriesName);
|
||||
}
|
||||
} else {
|
||||
seriesExpanded.remove(favoritesSeriesName);
|
||||
}
|
||||
|
||||
struct SeriesInfo {
|
||||
QString name;
|
||||
QStringList models;
|
||||
QString newestDate;
|
||||
QString oldestDate;
|
||||
};
|
||||
|
||||
QVector<SeriesInfo> seriesInfos;
|
||||
|
||||
for (auto it = baseSeriesToModels.constBegin(); it != baseSeriesToModels.constEnd(); ++it) {
|
||||
QString series = it.key();
|
||||
QStringList models = it.value();
|
||||
|
||||
if (sortByDate) {
|
||||
std::sort(models.begin(), models.end(), [this, sortDateNewestFirst](const QString &a, const QString &b) {
|
||||
QString keyA = modelNameToFileMap.value(a, a);
|
||||
QString keyB = modelNameToFileMap.value(b, b);
|
||||
QString dateA = modelReleasedDates.value(keyA, QStringLiteral("1970-01-01"));
|
||||
QString dateB = modelReleasedDates.value(keyB, QStringLiteral("1970-01-01"));
|
||||
if (dateA == dateB) {
|
||||
return a < b;
|
||||
}
|
||||
return sortDateNewestFirst ? (dateA > dateB) : (dateA < dateB);
|
||||
});
|
||||
} else {
|
||||
std::sort(models.begin(), models.end());
|
||||
}
|
||||
|
||||
if (currentSortMode == "favorites" && !favoriteModelKeys.isEmpty()) {
|
||||
QStringList filteredModels;
|
||||
for (const QString &modelName : models) {
|
||||
QString key = modelNameToFileMap.value(modelName, modelName);
|
||||
if (!favoriteModelKeys.contains(key)) {
|
||||
filteredModels.append(modelName);
|
||||
}
|
||||
}
|
||||
models = filteredModels;
|
||||
}
|
||||
|
||||
if (models.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
QString newestDate = QStringLiteral("1970-01-01");
|
||||
QString oldestDate = QStringLiteral("1970-01-01");
|
||||
bool hasDate = false;
|
||||
for (const QString &modelName : models) {
|
||||
const QString key = modelNameToFileMap.value(modelName, modelName);
|
||||
const QString date = modelReleasedDates.value(key, QStringLiteral("1970-01-01"));
|
||||
if (!hasDate) {
|
||||
newestDate = date;
|
||||
oldestDate = date;
|
||||
hasDate = true;
|
||||
} else {
|
||||
if (date > newestDate) {
|
||||
newestDate = date;
|
||||
}
|
||||
if (date < oldestDate) {
|
||||
oldestDate = date;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasDate) {
|
||||
oldestDate = QStringLiteral("1970-01-01");
|
||||
}
|
||||
|
||||
seriesInfos.push_back({series, models, newestDate, oldestDate});
|
||||
newSeriesToModels.insert(series, models);
|
||||
}
|
||||
|
||||
if (sortByDate) {
|
||||
std::sort(seriesInfos.begin(), seriesInfos.end(), [sortDateNewestFirst](const SeriesInfo &a, const SeriesInfo &b) {
|
||||
if (sortDateNewestFirst) {
|
||||
if (a.newestDate == b.newestDate) {
|
||||
return a.name < b.name;
|
||||
}
|
||||
return a.newestDate > b.newestDate;
|
||||
} else {
|
||||
if (a.oldestDate == b.oldestDate) {
|
||||
return a.name < b.name;
|
||||
}
|
||||
return a.oldestDate < b.oldestDate;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
std::sort(seriesInfos.begin(), seriesInfos.end(), [](const SeriesInfo &a, const SeriesInfo &b) {
|
||||
return a.name < b.name;
|
||||
});
|
||||
}
|
||||
|
||||
for (const SeriesInfo &info : seriesInfos) {
|
||||
orderedSeries.append(info.name);
|
||||
validSeries.insert(info.name);
|
||||
}
|
||||
|
||||
for (auto it = seriesExpanded.begin(); it != seriesExpanded.end(); ) {
|
||||
if (!validSeries.contains(it.key())) {
|
||||
it = seriesExpanded.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
rebuildModelList(orderedSeries, newSeriesToModels);
|
||||
refreshFavoriteIcons();
|
||||
}
|
||||
|
||||
void ExpandableMultiOptionDialog::rebuildModelList(const QStringList &orderedSeries, const QMap<QString, QStringList> &newSeriesToModels) {
|
||||
if (!listLayout) return;
|
||||
|
||||
stopActiveScroll();
|
||||
|
||||
while (QLayoutItem *item = listLayout->takeAt(0)) {
|
||||
if (QWidget *w = item->widget()) {
|
||||
delete w;
|
||||
} else if (QLayout *layout = item->layout()) {
|
||||
delete layout;
|
||||
}
|
||||
delete item;
|
||||
}
|
||||
|
||||
seriesWidgets.clear();
|
||||
modelButtons.clear();
|
||||
favoriteButtons.clear();
|
||||
currentSelectionButton = nullptr;
|
||||
|
||||
for (const QString &series : orderedSeries) {
|
||||
const QStringList models = newSeriesToModels.value(series);
|
||||
if (models.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
QPushButton *seriesHeader = new QPushButton("▶ " + series);
|
||||
seriesHeader->setProperty("class", "series-header");
|
||||
seriesHeader->setCheckable(false);
|
||||
|
||||
bool expanded = seriesExpanded.value(series, false);
|
||||
seriesExpanded.insert(series, expanded);
|
||||
|
||||
QObject::connect(seriesHeader, &QPushButton::clicked, [this, series, seriesHeader]() {
|
||||
toggleSeries(series, seriesHeader);
|
||||
});
|
||||
|
||||
QWidget *seriesContainer = new QWidget();
|
||||
QVBoxLayout *seriesLayout = new QVBoxLayout(seriesContainer);
|
||||
seriesLayout->setContentsMargins(20, 0, 0, 0);
|
||||
seriesLayout->setSpacing(10);
|
||||
|
||||
for (const QString &modelName : models) {
|
||||
QString modelKey = modelNameToFileMap.value(modelName, modelName);
|
||||
if (!modelFileToNameMap.contains(modelKey)) {
|
||||
modelFileToNameMap.insert(modelKey, modelName);
|
||||
}
|
||||
QString displayName = displayOverrides.value(modelKey, modelName);
|
||||
createModelButton(modelKey, modelName, displayName, seriesLayout);
|
||||
}
|
||||
|
||||
if (expanded) {
|
||||
seriesContainer->show();
|
||||
seriesHeader->setText("▼ " + series);
|
||||
} else {
|
||||
seriesContainer->hide();
|
||||
seriesHeader->setText("▶ " + series);
|
||||
}
|
||||
|
||||
seriesWidgets.insert(series, seriesContainer);
|
||||
|
||||
listLayout->addWidget(seriesHeader);
|
||||
listLayout->addWidget(seriesContainer);
|
||||
}
|
||||
|
||||
listLayout->addStretch(1);
|
||||
|
||||
seriesToModels = newSeriesToModels;
|
||||
|
||||
listWidgetContainer->updateGeometry();
|
||||
listWidgetContainer->adjustSize();
|
||||
if (scrollView && scrollView->widget()) {
|
||||
scrollView->widget()->updateGeometry();
|
||||
scrollView->widget()->adjustSize();
|
||||
}
|
||||
|
||||
updateButtonStyles();
|
||||
}
|
||||
|
||||
void ExpandableMultiOptionDialog::refreshFavoriteIcons() {
|
||||
for (auto it = favoriteButtons.begin(); it != favoriteButtons.end(); ++it) {
|
||||
const QString &modelKey = it.key();
|
||||
const QList<QPushButton*> &buttons = it.value();
|
||||
bool isCommunityFav = communityFavorites.contains(modelKey);
|
||||
bool isUserFav = userFavorites.contains(modelKey);
|
||||
bool isFavorite = isCommunityFav || isUserFav;
|
||||
|
||||
for (QPushButton *button : buttons) {
|
||||
if (!button) continue;
|
||||
button->setChecked(isFavorite);
|
||||
button->setText(isFavorite ? QString::fromUtf16(u"\u2665") : QString::fromUtf16(u"\u2661"));
|
||||
}
|
||||
}
|
||||
|
||||
if (confirmButton && !selectionKey.isEmpty()) {
|
||||
confirmButton->setEnabled(true);
|
||||
}
|
||||
|
||||
updateButtonStyles();
|
||||
}
|
||||
|
||||
void ExpandableMultiOptionDialog::updateButtonStyles() {
|
||||
const QString selectedKey = selectionKey;
|
||||
const QString selectedStyle = QStringLiteral(
|
||||
"QPushButton {"
|
||||
"background-color: #465BEA;"
|
||||
"border: 3px solid #FFFFFF;"
|
||||
"color: white;"
|
||||
"font-weight: 500;"
|
||||
"height: 135;"
|
||||
"padding: 0px 50px;"
|
||||
"text-align: left;"
|
||||
"font-size: 55px;"
|
||||
"border-radius: 10px;"
|
||||
"}");
|
||||
|
||||
if (selectedKey.isEmpty()) {
|
||||
currentSelectionButton = nullptr;
|
||||
}
|
||||
|
||||
QPushButton *explicitButton = currentSelectionButton.data();
|
||||
if (explicitButton && explicitButton->property("modelKey").toString() != selectedKey) {
|
||||
explicitButton = nullptr;
|
||||
}
|
||||
|
||||
for (auto it = modelButtons.begin(); it != modelButtons.end(); ++it) {
|
||||
const QString &modelKey = it.key();
|
||||
const QList<QPushButton*> &buttons = it.value();
|
||||
const bool keyMatches = (!selectedKey.isEmpty() && modelKey == selectedKey);
|
||||
bool activatedForKey = false;
|
||||
|
||||
for (QPushButton *button : buttons) {
|
||||
if (!button) continue;
|
||||
|
||||
bool isActive = false;
|
||||
if (explicitButton) {
|
||||
isActive = (button == explicitButton);
|
||||
} else if (keyMatches && !activatedForKey) {
|
||||
isActive = true;
|
||||
activatedForKey = true;
|
||||
currentSelectionButton = button;
|
||||
}
|
||||
|
||||
QSignalBlocker blocker(button);
|
||||
button->setChecked(isActive);
|
||||
button->setStyleSheet(isActive ? selectedStyle : QString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,23 +6,71 @@
|
||||
#include <QWidget>
|
||||
#include <QMap>
|
||||
#include <QList>
|
||||
#include <QPointer>
|
||||
#include <QComboBox>
|
||||
#include <QMenu>
|
||||
|
||||
#include "selfdrive/ui/qt/widgets/input.h"
|
||||
#include "selfdrive/ui/qt/widgets/scrollview.h"
|
||||
|
||||
class QPushButton;
|
||||
class ExpandableMultiOptionDialog : public DialogBase {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ExpandableMultiOptionDialog(const QString &prompt_text, const QMap<QString, QStringList> &seriesToModels,
|
||||
const QString ¤t, QWidget *parent);
|
||||
const QString ¤t, QWidget *parent,
|
||||
const QStringList &userFavorites = QStringList(),
|
||||
const QStringList &communityFavorites = QStringList(),
|
||||
const QMap<QString, QString> &modelReleasedDates = QMap<QString, QString>(),
|
||||
const QMap<QString, QString> &modelFileToNameMap = QMap<QString, QString>(),
|
||||
const QString &initialSortMode = "alphabetical");
|
||||
static QString getSelection(const QString &prompt_text, const QMap<QString, QStringList> &seriesToModels,
|
||||
const QString ¤t, QWidget *parent);
|
||||
const QString ¤t, QWidget *parent,
|
||||
const QStringList &userFavorites = QStringList(),
|
||||
const QStringList &communityFavorites = QStringList(),
|
||||
const QMap<QString, QString> &modelReleasedDates = QMap<QString, QString>(),
|
||||
const QMap<QString, QString> &modelFileToNameMap = QMap<QString, QString>(),
|
||||
const QString &initialSortMode = QString());
|
||||
QString selection;
|
||||
|
||||
QString getCurrentSortMode() const { return currentSortMode; }
|
||||
QStringList getUserFavorites() const;
|
||||
|
||||
private:
|
||||
void toggleSeries(const QString &series, QPushButton *headerButton, ScrollView *scrollView);
|
||||
void toggleSeries(const QString &series, QPushButton *headerButton);
|
||||
void toggleFavorite(const QString &modelKey);
|
||||
void updateSorting();
|
||||
void rebuildModelList(const QStringList &orderedSeries, const QMap<QString, QStringList> &newSeriesToModels);
|
||||
void createModelButton(const QString &modelKey, const QString &modelName, const QString &displayName,
|
||||
QVBoxLayout *layout);
|
||||
void refreshFavoriteIcons();
|
||||
void updateButtonStyles();
|
||||
void stopActiveScroll();
|
||||
void stopActiveScrollForInteraction();
|
||||
|
||||
QMap<QString, QStringList> seriesToModels;
|
||||
QMap<QString, QStringList> baseSeriesToModels;
|
||||
QMap<QString, QWidget*> seriesWidgets;
|
||||
QMap<QString, bool> seriesExpanded;
|
||||
};
|
||||
QMap<QString, QList<QPushButton*>> modelButtons;
|
||||
QMap<QString, QList<QPushButton*>> favoriteButtons;
|
||||
|
||||
QStringList userFavorites;
|
||||
QStringList communityFavorites;
|
||||
QMap<QString, QString> modelReleasedDates;
|
||||
QMap<QString, QString> modelFileToNameMap;
|
||||
QMap<QString, QString> modelNameToFileMap;
|
||||
QMap<QString, QString> displayOverrides;
|
||||
|
||||
QString currentSortMode;
|
||||
QString currentSelection;
|
||||
QString currentSelectionKey;
|
||||
QString selectionKey;
|
||||
|
||||
ScrollView *scrollView = nullptr;
|
||||
QVBoxLayout *listLayout = nullptr;
|
||||
QPushButton *confirmButton = nullptr;
|
||||
QWidget *listWidgetContainer = nullptr;
|
||||
QPointer<QPushButton> currentSelectionButton;
|
||||
};
|
||||
|
||||
@@ -269,6 +269,7 @@ void FrogPilotSettingsWindow::updateVariables() {
|
||||
hasPedal = CP.getEnableGasInterceptor();
|
||||
hasRadar = !CP.getRadarUnavailable();
|
||||
hasSDSU = frogpilot_toggles.value("has_sdsu").toBool();
|
||||
hasSASCM = frogpilot_toggles.value("has_sascm").toBool();
|
||||
hasSNG = hasOpenpilotLongitudinal && CP.getAutoResumeSng();
|
||||
hasZSS = frogpilot_toggles.value("has_zss").toBool();
|
||||
isAngleCar = CP.getSteerControlType() == cereal::CarParams::SteerControlType::ANGLE;
|
||||
@@ -277,20 +278,26 @@ void FrogPilotSettingsWindow::updateVariables() {
|
||||
isHKG = carMake == "hyundai";
|
||||
isHKGCanFd = isHKG && safetyModel == cereal::CarParams::SafetyModel::HYUNDAI_CANFD;
|
||||
isSubaru = carMake == "subaru";
|
||||
isTorqueCar = CP.getLateralTuning().which() == cereal::CarParams::LateralTuning::TORQUE;
|
||||
isToyota = carMake == "toyota";
|
||||
isTSK = CP.getSecOcRequired();
|
||||
isVolt = carFingerprint == "CHEVROLET_VOLT";
|
||||
longitudinalActuatorDelay = CP.getLongitudinalActuatorDelay();
|
||||
startAccel = CP.getStartAccel();
|
||||
steerActuatorDelay = CP.getSteerActuatorDelay();
|
||||
steerOffset = 0.0f;
|
||||
steerKp = CP.getLateralTuning().which() == cereal::CarParams::LateralTuning::PID ? CP.getLateralTuning().getPid().getKpV()[0] : 0.6;
|
||||
steerRatio = CP.getSteerRatio();
|
||||
stopAccel = CP.getStopAccel();
|
||||
stoppingDecelRate = CP.getStoppingDecelRate();
|
||||
vEgoStarting = CP.getVEgoStarting();
|
||||
vEgoStopping = CP.getVEgoStopping();
|
||||
friction = CP.getLateralTuning().getTorque().getFriction();
|
||||
latAccelFactor = CP.getLateralTuning().getTorque().getLatAccelFactor();
|
||||
|
||||
float currentDelayStock = params.getFloat("SteerDelayStock");
|
||||
float currentFrictionStock = params.getFloat("SteerFrictionStock");
|
||||
float currentSteerOffsetStock = params.getFloat("SteerOffsetStock");
|
||||
float currentKPStock = params.getFloat("SteerKPStock");
|
||||
float currentLatAccelStock = params.getFloat("SteerLatAccelStock");
|
||||
float currentLongDelayStock = params.getFloat("LongitudinalActuatorDelayStock");
|
||||
@@ -315,6 +322,13 @@ void FrogPilotSettingsWindow::updateVariables() {
|
||||
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 (params.getFloat("SteerKP") == currentKPStock || currentKPStock == 0) {
|
||||
params.putFloat("SteerKP", steerKp);
|
||||
@@ -387,12 +401,18 @@ void FrogPilotSettingsWindow::updateVariables() {
|
||||
|
||||
canUsePedal = FPCP.getCanUsePedal();
|
||||
canUseSDSU = FPCP.getCanUseSDSU();
|
||||
friction = FPCP.getLateralTuning().getTorque().getFriction();
|
||||
hasAutoTune = (carMake == "hyundai" || carMake == "toyota") && FPCP.getLateralTuning().which() == cereal::FrogPilotCarParams::LateralTuning::TORQUE;
|
||||
isTorqueCar = FPCP.getLateralTuning().which() == cereal::FrogPilotCarParams::LateralTuning::TORQUE;
|
||||
latAccelFactor = FPCP.getLateralTuning().getTorque().getLatAccelFactor();
|
||||
canUseSASCM = FPCP.getCanUseSASCM();
|
||||
openpilotLongitudinalControlDisabled = FPCP.getOpenpilotLongitudinalControlDisabled();
|
||||
steerKp = FPCP.getLateralTuning().getTorque().getKp();
|
||||
}
|
||||
|
||||
std::string liveTorqueParameters = params.get("LiveTorqueParameters");
|
||||
if (!liveTorqueParameters.empty()) {
|
||||
AlignedBuffer aligned_buf;
|
||||
capnp::FlatArrayMessageReader reader(aligned_buf.align(liveTorqueParameters.data(), liveTorqueParameters.size()));
|
||||
cereal::Event::Reader event = reader.getRoot<cereal::Event>();
|
||||
cereal::LiveTorqueParametersData::Reader LTP = event.getLiveTorqueParameters();
|
||||
|
||||
hasAutoTune = LTP.getUseParams();
|
||||
}
|
||||
|
||||
isC3 = util::read_file("/sys/firmware/devicetree/base/model").find("tici") != std::string::npos;
|
||||
|
||||
@@ -13,6 +13,7 @@ public:
|
||||
|
||||
bool canUsePedal = false;
|
||||
bool canUseSDSU = false;
|
||||
bool canUseSASCM = false;
|
||||
bool forceOpenDescriptions = false;
|
||||
bool hasAutoTune = true;
|
||||
bool hasBSM = true;
|
||||
@@ -24,6 +25,7 @@ public:
|
||||
bool hasPedal = false;
|
||||
bool hasRadar = true;
|
||||
bool hasSDSU = false;
|
||||
bool hasSASCM = false;
|
||||
bool hasSNG = false;
|
||||
bool hasZSS = false;
|
||||
bool isAngleCar = false;
|
||||
@@ -45,6 +47,7 @@ public:
|
||||
float longitudinalActuatorDelay;
|
||||
float startAccel;
|
||||
float steerActuatorDelay;
|
||||
float steerOffset;
|
||||
float steerKp;
|
||||
float steerRatio;
|
||||
float stopAccel;
|
||||
|
||||
@@ -39,11 +39,12 @@ FrogPilotLateralPanel::FrogPilotLateralPanel(FrogPilotSettingsWindow *parent) :
|
||||
|
||||
const std::vector<std::tuple<QString, QString, QString, QString>> lateralToggles {
|
||||
{"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", steerActuatorDelay != 0 ? QString(tr("Actuator Delay (Default: %1)")).arg(QString::number(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", friction != 0 ? QString(tr("Friction (Default: %1)")).arg(QString::number(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."), ""},
|
||||
{"SteerKP", steerKp != 0 ? QString(tr("Kp Factor (Default: %1)")).arg(QString::number(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", latAccelFactor != 0 ? QString(tr("Lateral Acceleration (Default: %1)")).arg(QString::number(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", steerRatio != 0 ? QString(tr("Steer Ratio (Default: %1)")).arg(QString::number(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."), ""},
|
||||
{"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."), ""},
|
||||
{"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."), ""},
|
||||
{"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."), ""},
|
||||
{"ForceAutoTune", tr("Force Auto-Tune On"), tr("<b>Force-enable openpilot's live auto-tuning for \"Friction\" and \"Lateral Acceleration\".</b>"), ""},
|
||||
{"ForceAutoTuneOff", tr("Force Auto-Tune Off"), tr("<b>Force-disable openpilot's live auto-tuning for \"Friction\" and \"Lateral Acceleration\" and use the set value instead.</b>"), ""},
|
||||
{"ForceTorqueController", tr("Force Torque Controller"), tr("<b>Use torque-based steering control instead of angle-based control for smoother lane keeping, especially in curves.</b>"), ""},
|
||||
@@ -87,15 +88,18 @@ FrogPilotLateralPanel::FrogPilotLateralPanel(FrogPilotSettingsWindow *parent) :
|
||||
} else if (param == "SteerFriction") {
|
||||
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);
|
||||
} 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") {
|
||||
std::vector<QString> steerKPButton{"Reset"};
|
||||
lateralToggle = new FrogPilotParamValueButtonControl(param, title, desc, icon, steerKp * 0.5, 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);
|
||||
} else if (param == "SteerLatAccel") {
|
||||
std::vector<QString> steerLatAccelButton{"Reset"};
|
||||
lateralToggle = new FrogPilotParamValueButtonControl(param, title, desc, icon, latAccelFactor * 0.75, latAccelFactor * 1.25, QString(), std::map<float, QString>(), 0.01, false, {}, steerLatAccelButton, false, false);
|
||||
lateralToggle = new FrogPilotParamValueButtonControl(param, title, desc, icon, parent->latAccelFactor * 0.5, parent->latAccelFactor * 1.25, QString(), std::map<float, QString>(), 0.01, false, {}, steerLatAccelButton, false, false);
|
||||
} else if (param == "SteerRatio") {
|
||||
std::vector<QString> steerRatioButton{"Reset"};
|
||||
lateralToggle = new FrogPilotParamValueButtonControl(param, title, desc, icon, steerRatio * 0.5, steerRatio * 1.5, QString(), std::map<float, QString>(), 0.01, false, {}, steerRatioButton, false, false);
|
||||
lateralToggle = new FrogPilotParamValueButtonControl(param, title, desc, icon, parent->steerRatio * 0.25, parent->steerRatio * 1.5, QString(), std::map<float, QString>(), 0.01, false, {}, steerRatioButton, false, false);
|
||||
|
||||
} else if (param == "AlwaysOnLateral") {
|
||||
FrogPilotManageControl *aolToggle = new FrogPilotManageControl(param, title, desc, icon);
|
||||
@@ -191,12 +195,6 @@ FrogPilotLateralPanel::FrogPilotLateralPanel(FrogPilotSettingsWindow *parent) :
|
||||
if (FrogPilotConfirmationDialog::toggleReboot(this)) {
|
||||
Hardware::reboot();
|
||||
}
|
||||
} else if (key == "NNFF" || key == "NNFFLite") {
|
||||
if (!isTorqueCar) {
|
||||
if (FrogPilotConfirmationDialog::toggleReboot(this)) {
|
||||
Hardware::reboot();
|
||||
}
|
||||
}
|
||||
} else if (key != "AlwaysOnLateral") {
|
||||
if (FrogPilotConfirmationDialog::toggleReboot(this)) {
|
||||
Hardware::reboot();
|
||||
@@ -207,41 +205,49 @@ FrogPilotLateralPanel::FrogPilotLateralPanel(FrogPilotSettingsWindow *parent) :
|
||||
}
|
||||
|
||||
steerDelayToggle = static_cast<FrogPilotParamValueButtonControl*>(toggles["SteerDelay"]);
|
||||
QObject::connect(steerDelayToggle, &FrogPilotParamValueButtonControl::buttonClicked, [this]() {
|
||||
QObject::connect(steerDelayToggle, &FrogPilotParamValueButtonControl::buttonClicked, [parent, this]() {
|
||||
if (FrogPilotConfirmationDialog::yesorno(tr("Reset <b>Actuator Delay</b> to its default value?"), this)) {
|
||||
params.putFloat("SteerDelay", steerActuatorDelay);
|
||||
params.putFloat("SteerDelay", parent->steerActuatorDelay);
|
||||
steerDelayToggle->refresh();
|
||||
}
|
||||
});
|
||||
|
||||
steerFrictionToggle = static_cast<FrogPilotParamValueButtonControl*>(toggles["SteerFriction"]);
|
||||
QObject::connect(steerFrictionToggle, &FrogPilotParamValueButtonControl::buttonClicked, [this]() {
|
||||
QObject::connect(steerFrictionToggle, &FrogPilotParamValueButtonControl::buttonClicked, [parent, this]() {
|
||||
if (FrogPilotConfirmationDialog::yesorno(tr("Reset <b>Friction</b> to its default value?"), this)) {
|
||||
params.putFloat("SteerFriction", friction);
|
||||
params.putFloat("SteerFriction", parent->friction);
|
||||
steerFrictionToggle->refresh();
|
||||
}
|
||||
});
|
||||
|
||||
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"]);
|
||||
QObject::connect(steerKPToggle, &FrogPilotParamValueButtonControl::buttonClicked, [this]() {
|
||||
QObject::connect(steerKPToggle, &FrogPilotParamValueButtonControl::buttonClicked, [parent, this]() {
|
||||
if (FrogPilotConfirmationDialog::yesorno(tr("Reset <b>Kp Factor</b> to its default value?"), this)) {
|
||||
params.putFloat("SteerKP", steerKp);
|
||||
params.putFloat("SteerKP", parent->steerKp);
|
||||
steerKPToggle->refresh();
|
||||
}
|
||||
});
|
||||
|
||||
steerLatAccelToggle = static_cast<FrogPilotParamValueButtonControl*>(toggles["SteerLatAccel"]);
|
||||
QObject::connect(steerLatAccelToggle, &FrogPilotParamValueButtonControl::buttonClicked, [this]() {
|
||||
QObject::connect(steerLatAccelToggle, &FrogPilotParamValueButtonControl::buttonClicked, [parent, this]() {
|
||||
if (FrogPilotConfirmationDialog::yesorno(tr("Reset <b>Lateral Accel</b> to its default value?"), this)) {
|
||||
params.putFloat("SteerLatAccel", latAccelFactor);
|
||||
params.putFloat("SteerLatAccel", parent->latAccelFactor);
|
||||
steerLatAccelToggle->refresh();
|
||||
}
|
||||
});
|
||||
|
||||
steerRatioToggle = static_cast<FrogPilotParamValueButtonControl*>(toggles["SteerRatio"]);
|
||||
QObject::connect(steerRatioToggle, &FrogPilotParamValueButtonControl::buttonClicked, [this]() {
|
||||
QObject::connect(steerRatioToggle, &FrogPilotParamValueButtonControl::buttonClicked, [parent, this]() {
|
||||
if (FrogPilotConfirmationDialog::yesorno(tr("Reset <b>Steer Ratio</b> to its default value?"), this)) {
|
||||
params.putFloat("SteerRatio", steerRatio);
|
||||
params.putFloat("SteerRatio", parent->steerRatio);
|
||||
steerRatioToggle->refresh();
|
||||
}
|
||||
});
|
||||
@@ -258,27 +264,16 @@ FrogPilotLateralPanel::FrogPilotLateralPanel(FrogPilotSettingsWindow *parent) :
|
||||
|
||||
void FrogPilotLateralPanel::showEvent(QShowEvent *event) {
|
||||
frogpilotToggleLevels = parent->frogpilotToggleLevels;
|
||||
friction = parent->friction;
|
||||
hasAutoTune = parent->hasAutoTune;
|
||||
hasNNFFLog = parent->hasNNFFLog;
|
||||
hasOpenpilotLongitudinal = parent->hasOpenpilotLongitudinal;
|
||||
isAngleCar = parent->isAngleCar;
|
||||
isHKGCanFd = parent->isHKGCanFd;
|
||||
isTorqueCar = parent->isTorqueCar;
|
||||
latAccelFactor = parent->latAccelFactor;
|
||||
steerActuatorDelay = parent->steerActuatorDelay;
|
||||
steerKp = parent->steerKp;
|
||||
steerRatio = parent->steerRatio;
|
||||
tuningLevel = parent->tuningLevel;
|
||||
|
||||
steerDelayToggle->setTitle(QString(tr("Actuator Delay (Default: %1)")).arg(QString::number(steerActuatorDelay, 'f', 2)));
|
||||
steerFrictionToggle->setTitle(QString(tr("Friction (Default: %1)")).arg(QString::number(friction, 'f', 2)));
|
||||
steerKPToggle->setTitle(QString(tr("Kp Factor (Default: %1)")).arg(QString::number(steerKp, 'f', 2)));
|
||||
steerKPToggle->updateControl(steerKp * 0.5, steerKp * 1.5);
|
||||
steerLatAccelToggle->setTitle(QString(tr("Lateral Accel (Default: %1)")).arg(QString::number(latAccelFactor, 'f', 2)));
|
||||
steerLatAccelToggle->updateControl(latAccelFactor * 0.75, latAccelFactor * 1.25);
|
||||
steerRatioToggle->setTitle(QString(tr("Steer Ratio (Default: %1)")).arg(QString::number(steerRatio, 'f', 2)));
|
||||
steerRatioToggle->updateControl(steerRatio * 0.5, steerRatio * 1.5);
|
||||
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)));
|
||||
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->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->updateControl(parent->latAccelFactor * 0.5, parent->latAccelFactor * 1.25);
|
||||
steerRatioToggle->setTitle(QString(tr("Steer Ratio (Default: %1)")).arg(QString::number(parent->steerRatio, 'f', 2)));
|
||||
steerRatioToggle->updateControl(parent->steerRatio * 0.25, parent->steerRatio * 1.5);
|
||||
|
||||
updateToggles();
|
||||
}
|
||||
@@ -358,41 +353,40 @@ void FrogPilotLateralPanel::updateToggles() {
|
||||
}
|
||||
}
|
||||
|
||||
bool forcingAutoTune = !hasAutoTune && params.getBool("ForceAutoTune");
|
||||
bool forcingAutoTuneOff = hasAutoTune && params.getBool("ForceAutoTuneOff");
|
||||
bool forcingTorqueController = !isAngleCar && params.getBool("ForceTorqueController");
|
||||
bool usingNNFF = hasNNFFLog && params.getBool("LateralTune") && params.getBool("NNFF");
|
||||
bool forcingAutoTuneOff = parent->hasAutoTune && params.getBool("ForceAutoTuneOff");
|
||||
bool forcingTorqueController = !parent->isAngleCar && params.getBool("ForceTorqueController");
|
||||
bool usingNNFF = parent->hasNNFFLog && params.getBool("LateralTune") && params.getBool("NNFF");
|
||||
|
||||
for (auto &[key, toggle] : toggles) {
|
||||
if (parentKeys.contains(key)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool setVisible = tuningLevel >= frogpilotToggleLevels[key].toDouble();
|
||||
bool setVisible = parent->tuningLevel >= frogpilotToggleLevels[key].toDouble();
|
||||
|
||||
if (key == "AlwaysOnLateralLKAS") {
|
||||
setVisible &= isHKGCanFd;
|
||||
setVisible &= !hasOpenpilotLongitudinal;
|
||||
setVisible &= parent->isHKGCanFd;
|
||||
setVisible &= !parent->hasOpenpilotLongitudinal;
|
||||
}
|
||||
|
||||
else if (key == "AlwaysOnLateralMain") {
|
||||
setVisible &= !isHKGCanFd;
|
||||
setVisible |= hasOpenpilotLongitudinal;
|
||||
setVisible &= !parent->isHKGCanFd;
|
||||
setVisible |= parent->hasOpenpilotLongitudinal;
|
||||
}
|
||||
|
||||
else if (key == "ForceAutoTune") {
|
||||
setVisible &= !hasAutoTune;
|
||||
setVisible &= !isAngleCar;
|
||||
setVisible &= isTorqueCar || forcingTorqueController;
|
||||
setVisible &= !parent->hasAutoTune;
|
||||
setVisible &= !parent->isAngleCar;
|
||||
setVisible &= parent->isTorqueCar || forcingTorqueController;
|
||||
}
|
||||
|
||||
else if (key == "ForceAutoTuneOff") {
|
||||
setVisible &= hasAutoTune;
|
||||
setVisible &= parent->hasAutoTune;
|
||||
}
|
||||
|
||||
else if (key == "ForceTorqueController") {
|
||||
setVisible &= !isAngleCar;
|
||||
setVisible &= !isTorqueCar;
|
||||
setVisible &= !parent->isAngleCar;
|
||||
setVisible &= !parent->isTorqueCar;
|
||||
}
|
||||
|
||||
else if (key == "LaneChangeTime") {
|
||||
@@ -404,42 +398,47 @@ void FrogPilotLateralPanel::updateToggles() {
|
||||
}
|
||||
|
||||
else if (key == "NNFF") {
|
||||
setVisible &= hasNNFFLog;
|
||||
setVisible &= !isAngleCar;
|
||||
setVisible &= parent->hasNNFFLog;
|
||||
setVisible &= !parent->isAngleCar;
|
||||
}
|
||||
|
||||
else if (key == "NNFFLite") {
|
||||
setVisible &= !usingNNFF;
|
||||
setVisible &= !isAngleCar;
|
||||
setVisible &= !parent->isAngleCar;
|
||||
}
|
||||
|
||||
else if (key == "SteerDelay") {
|
||||
setVisible &= steerActuatorDelay != 0;
|
||||
setVisible &= parent->steerActuatorDelay != 0;
|
||||
}
|
||||
|
||||
else if (key == "SteerFriction") {
|
||||
setVisible &= friction != 0;
|
||||
setVisible &= hasAutoTune ? forcingAutoTuneOff : !forcingAutoTune;
|
||||
setVisible &= isTorqueCar || forcingTorqueController;
|
||||
setVisible &= parent->friction != 0;
|
||||
setVisible &= parent->hasAutoTune ? forcingAutoTuneOff : true;
|
||||
setVisible &= parent->isTorqueCar || forcingTorqueController;
|
||||
setVisible &= !usingNNFF;
|
||||
}
|
||||
|
||||
else if (key == "SteerOffset") {
|
||||
setVisible &= parent->isGM;
|
||||
setVisible &= parent->isTorqueCar || forcingTorqueController;
|
||||
setVisible &= !usingNNFF;
|
||||
}
|
||||
|
||||
else if (key == "SteerKP") {
|
||||
setVisible &= steerKp != 0;
|
||||
setVisible &= hasAutoTune ? forcingAutoTuneOff : !forcingAutoTune;
|
||||
setVisible &= isTorqueCar || forcingTorqueController;
|
||||
setVisible &= parent->steerKp != 0;
|
||||
setVisible &= !parent->isAngleCar;
|
||||
}
|
||||
|
||||
else if (key == "SteerLatAccel") {
|
||||
setVisible &= latAccelFactor != 0;
|
||||
setVisible &= hasAutoTune ? forcingAutoTuneOff : !forcingAutoTune;
|
||||
setVisible &= isTorqueCar || forcingTorqueController;
|
||||
setVisible &= parent->latAccelFactor != 0;
|
||||
setVisible &= parent->hasAutoTune ? forcingAutoTuneOff : true;
|
||||
setVisible &= parent->isTorqueCar || forcingTorqueController;
|
||||
setVisible &= !usingNNFF;
|
||||
}
|
||||
|
||||
else if (key == "SteerRatio") {
|
||||
setVisible &= steerRatio != 0;
|
||||
setVisible &= hasAutoTune ? forcingAutoTuneOff : !forcingAutoTune;
|
||||
setVisible &= parent->steerRatio != 0;
|
||||
setVisible &= parent->hasAutoTune ? forcingAutoTuneOff : true;
|
||||
}
|
||||
|
||||
toggle->setVisible(setVisible);
|
||||
|
||||
@@ -31,6 +31,7 @@ private:
|
||||
float friction;
|
||||
float latAccelFactor;
|
||||
float steerActuatorDelay;
|
||||
float steerOffset;
|
||||
float steerKp;
|
||||
float steerRatio;
|
||||
|
||||
@@ -38,7 +39,7 @@ private:
|
||||
|
||||
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> laneChangeKeys = {"LaneChangeTime", "LaneDetectionWidth", "MinimumLaneChangeSpeed", "NudgelessLaneChange", "OneLaneChange"};
|
||||
QSet<QString> lateralTuneKeys = {"NNFF", "NNFFLite", "TurnDesires"};
|
||||
@@ -48,6 +49,7 @@ private:
|
||||
|
||||
FrogPilotParamValueButtonControl *steerDelayToggle;
|
||||
FrogPilotParamValueButtonControl *steerFrictionToggle;
|
||||
FrogPilotParamValueButtonControl *steerOffsetToggle;
|
||||
FrogPilotParamValueButtonControl *steerLatAccelToggle;
|
||||
FrogPilotParamValueButtonControl *steerKPToggle;
|
||||
FrogPilotParamValueButtonControl *steerRatioToggle;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -40,19 +40,19 @@ private:
|
||||
|
||||
std::map<QString, AbstractControl*> toggles;
|
||||
|
||||
QSet<QString> advancedLongitudinalTuneKeys = {"LongitudinalActuatorDelay", "StartAccel", "StopAccel", "StoppingDecelRate", "VEgoStarting", "VEgoStopping"};
|
||||
QSet<QString> aggressivePersonalityKeys = {"AggressiveFollow", "AggressiveJerkAcceleration", "AggressiveJerkDeceleration", "AggressiveJerkDanger", "AggressiveJerkSpeed", "AggressiveJerkSpeedDecrease", "ResetAggressivePersonality"};
|
||||
QSet<QString> advancedLongitudinalTuneKeys = {"EVTuning", "LongitudinalActuatorDelay", "StartAccel", "StopAccel", "StoppingDecelRate", "VEgoStarting", "VEgoStopping"};
|
||||
QSet<QString> aggressivePersonalityKeys = {"AggressiveFollow", "AggressiveFollowHigh", "AggressiveJerkAcceleration", "AggressiveJerkDeceleration", "AggressiveJerkDanger", "AggressiveJerkSpeed", "AggressiveJerkSpeedDecrease", "ResetAggressivePersonality"};
|
||||
QSet<QString> conditionalExperimentalKeys = {"CESpeed", "CESpeedLead", "CECurves", "CELead", "CEModelStopTime", "CENavigation", "CESignalSpeed", "ShowCEMStatus"};
|
||||
QSet<QString> curveSpeedKeys = {"CalibratedLateralAcceleration", "CalibrationProgress", "ResetCurveData", "ShowCSCStatus"};
|
||||
QSet<QString> customDrivingPersonalityKeys = {"AggressivePersonalityProfile", "RelaxedPersonalityProfile", "StandardPersonalityProfile", "TrafficPersonalityProfile"};
|
||||
QSet<QString> longitudinalTuneKeys = {"AccelerationProfile", "DecelerationProfile", "HumanAcceleration", "HumanFollowing", "LeadDetectionThreshold", "MaxDesiredAcceleration", "TacoTune"};
|
||||
QSet<QString> longitudinalTuneKeys = {"AccelerationProfile", "DecelerationProfile", "HumanAcceleration", "HumanFollowing", "LeadDetectionThreshold", "MaxDesiredAcceleration", "TrailerLoad", "TacoTune"};
|
||||
QSet<QString> qolKeys = {"CustomCruise", "CustomCruiseLong", "ForceStops", "IncreasedStoppedDistance", "MapGears", "ReverseCruise", "SetSpeedOffset"};
|
||||
QSet<QString> relaxedPersonalityKeys = {"RelaxedFollow", "RelaxedJerkAcceleration", "RelaxedJerkDeceleration", "RelaxedJerkDanger", "RelaxedJerkSpeed", "RelaxedJerkSpeedDecrease", "ResetRelaxedPersonality"};
|
||||
QSet<QString> relaxedPersonalityKeys = {"RelaxedFollow", "RelaxedFollowHigh", "RelaxedJerkAcceleration", "RelaxedJerkDeceleration", "RelaxedJerkDanger", "RelaxedJerkSpeed", "RelaxedJerkSpeedDecrease", "ResetRelaxedPersonality"};
|
||||
QSet<QString> speedLimitControllerKeys = {"SLCOffsets", "SLCFallback", "SLCOverride", "SLCPriority", "SLCQOL", "SLCVisuals"};
|
||||
QSet<QString> speedLimitControllerOffsetsKeys = {"Offset1", "Offset2", "Offset3", "Offset4", "Offset5", "Offset6", "Offset7"};
|
||||
QSet<QString> speedLimitControllerQOLKeys = {"ForceMPHDashboard", "SetSpeedLimit", "SLCConfirmation", "SLCLookaheadHigher", "SLCLookaheadLower", "SLCMapboxFiller"};
|
||||
QSet<QString> speedLimitControllerVisualKeys = {"ShowSLCOffset", "SpeedLimitSources"};
|
||||
QSet<QString> standardPersonalityKeys = {"StandardFollow", "StandardJerkAcceleration", "StandardJerkDeceleration", "StandardJerkDanger", "StandardJerkSpeed", "StandardJerkSpeedDecrease", "ResetStandardPersonality"};
|
||||
QSet<QString> standardPersonalityKeys = {"StandardFollow", "StandardFollowHigh", "StandardJerkAcceleration", "StandardJerkDeceleration", "StandardJerkDanger", "StandardJerkSpeed", "StandardJerkSpeedDecrease", "ResetStandardPersonality"};
|
||||
QSet<QString> trafficPersonalityKeys = {"TrafficFollow", "TrafficJerkAcceleration", "TrafficJerkDeceleration", "TrafficJerkDanger", "TrafficJerkSpeed", "TrafficJerkSpeedDecrease", "ResetTrafficPersonality"};
|
||||
|
||||
QSet<QString> parentKeys;
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
#include "frogpilot/ui/qt/offroad/model_settings.h"
|
||||
#include "frogpilot/ui/qt/offroad/expandable_multi_option_dialog.h"
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QDoubleSpinBox>
|
||||
#include <QPushButton>
|
||||
#include <QDialog>
|
||||
#include <algorithm>
|
||||
|
||||
FrogPilotModelPanel::FrogPilotModelPanel(FrogPilotSettingsWindow *parent) : FrogPilotListWidget(parent), parent(parent) {
|
||||
QStackedLayout *modelLayout = new QStackedLayout();
|
||||
@@ -27,12 +30,14 @@ FrogPilotModelPanel::FrogPilotModelPanel(FrogPilotSettingsWindow *parent) : Frog
|
||||
{"DeleteModel", tr("Delete Driving Models"), tr("Delete driving models from the device."), ""},
|
||||
{"DownloadModel", tr("Download Driving Models"), tr("Download driving models to the device."), ""},
|
||||
{"ModelRandomizer", tr("Model Randomizer"), tr("Driving models are chosen at random each drive and feedback prompts are used to find the model that best suits your needs."), ""},
|
||||
{"RecoveryPower", tr("Recovery Power"), tr("Adjust the strength of planplus lane recovery corrections (0.5 to 2.0)."), ""},
|
||||
{"StopDistance", tr("Stop Distance"), tr("Adjust the model's stopping distance in meters (minimum 4 for safety). Most users prefer 6."), ""},
|
||||
{"ManageBlacklistedModels", tr("Manage Model Blacklist"), tr("Add or remove models from the <b>Model Randomizer</b>'s blacklist list."), ""},
|
||||
{"ManageScores", tr("Manage Model Ratings"), tr("Reset or view the saved ratings for the driving models."), ""},
|
||||
{"SelectModel", tr("Select Driving Model"), tr("Select the active driving model."), ""},
|
||||
};
|
||||
|
||||
FrogPilotParamValueButtonControl *recoveryPowerToggle = nullptr;
|
||||
FrogPilotParamValueButtonControl *stopDistanceToggle = nullptr;
|
||||
|
||||
for (const auto &[param, title, desc, icon] : modelToggles) {
|
||||
@@ -41,56 +46,72 @@ FrogPilotModelPanel::FrogPilotModelPanel(FrogPilotSettingsWindow *parent) : Frog
|
||||
if (param == "DeleteModel") {
|
||||
deleteModelButton = new FrogPilotButtonsControl(title, desc, icon, {tr("DELETE"), tr("DELETE ALL")});
|
||||
QObject::connect(deleteModelButton, &FrogPilotButtonsControl::buttonClicked, [this](int id) {
|
||||
QStringList deletableModels;
|
||||
for (const QString &file : modelDir.entryList(QDir::Files)) {
|
||||
QString base = QFileInfo(file).baseName();
|
||||
for (const QString &modelKey : modelFileToNameMapProcessed.keys()) {
|
||||
if (base.startsWith(modelKey)) {
|
||||
QString modelName = modelFileToNameMapProcessed.value(modelKey);
|
||||
if (!deletableModels.contains(modelName)) {
|
||||
deletableModels.append(modelName);
|
||||
}
|
||||
}
|
||||
}
|
||||
QMap<QString, QString> deletableModelsMap = getDeletableModelDisplayNames();
|
||||
noModelsDownloaded = deletableModelsMap.isEmpty();
|
||||
|
||||
if (noModelsDownloaded) {
|
||||
return;
|
||||
}
|
||||
deletableModels.removeAll(processModelName(currentModel));
|
||||
deletableModels.removeAll(modelFileToNameMapProcessed.value(QString::fromStdString(params_default.get("Model"))));
|
||||
deletableModels.removeAll("Space Lab");
|
||||
noModelsDownloaded = deletableModels.isEmpty();
|
||||
|
||||
if (id == 0) {
|
||||
// Group deletable models by series
|
||||
// Group deletable models by series and keep a lookup for selected names
|
||||
QMap<QString, QStringList> deletableSeriesToModels;
|
||||
for (const QString &modelName : deletableModels) {
|
||||
QString modelKey = modelFileToNameMapProcessed.key(modelName);
|
||||
QString series = modelSeriesMap.value(modelKey, "Custom Series");
|
||||
deletableSeriesToModels[series].append(modelName);
|
||||
QMap<QString, QString> displayNameToKey;
|
||||
QMap<QString, QString> deletableFileToNameMap;
|
||||
for (auto it = deletableModelsMap.constBegin(); it != deletableModelsMap.constEnd(); ++it) {
|
||||
const QString &modelKey = it.key();
|
||||
const QString &displayName = it.value();
|
||||
QString series = modelSeriesMap.value(modelKey, tr("Custom Series"));
|
||||
deletableSeriesToModels[series].append(displayName);
|
||||
displayNameToKey.insert(displayName, modelKey);
|
||||
deletableFileToNameMap.insert(modelKey, displayName);
|
||||
}
|
||||
|
||||
// Sort models within each series
|
||||
for (QString &series : deletableSeriesToModels.keys()) {
|
||||
deletableSeriesToModels[series].sort();
|
||||
QStringList &models = deletableSeriesToModels[series];
|
||||
models.removeDuplicates();
|
||||
std::sort(models.begin(), models.end());
|
||||
}
|
||||
|
||||
QString modelToDelete = ExpandableMultiOptionDialog::getSelection(tr("Select a driving model to delete"), deletableSeriesToModels, "", this);
|
||||
if (!modelToDelete.isEmpty() && ConfirmationDialog::confirm(tr("Are you sure you want to delete the \"%1\" model?").arg(modelToDelete), tr("Delete"), this)) {
|
||||
QString modelFile = modelFileToNameMapProcessed.key(modelToDelete);
|
||||
for (const QString &file : modelDir.entryList(QDir::Files)) {
|
||||
QString base = QFileInfo(file).baseName();
|
||||
if (base.startsWith(modelFile)) {
|
||||
QFile::remove(modelDir.filePath(file));
|
||||
QString savedSortMode = QString::fromStdString(params.get("ModelSortMode"));
|
||||
if (savedSortMode.isEmpty()) savedSortMode = "alphabetical";
|
||||
|
||||
QString modelToDelete = ExpandableMultiOptionDialog::getSelection(tr("Select a driving model to delete"), deletableSeriesToModels, "", this,
|
||||
QStringList(), QStringList(), QMap<QString, QString>(),
|
||||
deletableFileToNameMap, savedSortMode);
|
||||
if (!modelToDelete.isEmpty()) {
|
||||
QString modelKey = displayNameToKey.value(modelToDelete);
|
||||
if (modelKey.isEmpty()) {
|
||||
QString processedName = processModelName(modelToDelete);
|
||||
for (auto it = deletableModelsMap.constBegin(); it != deletableModelsMap.constEnd(); ++it) {
|
||||
if (processModelName(it.value()) == processedName) {
|
||||
modelKey = it.key();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
allModelsDownloaded = false;
|
||||
if (!modelKey.isEmpty() && ConfirmationDialog::confirm(tr("Are you sure you want to delete the \"%1\" model?").arg(modelToDelete), tr("Delete"), this)) {
|
||||
for (const QString &file : modelDir.entryList(QDir::Files)) {
|
||||
QString base = QFileInfo(file).baseName();
|
||||
if (base.startsWith(modelKey)) {
|
||||
QFile::remove(modelDir.filePath(file));
|
||||
}
|
||||
}
|
||||
|
||||
allModelsDownloaded = false;
|
||||
noModelsDownloaded = getDeletableModelDisplayNames().isEmpty();
|
||||
deleteModelButton->setEnabled(!(allModelsDownloading || modelDownloading || noModelsDownloaded));
|
||||
}
|
||||
}
|
||||
} else if (id == 1) {
|
||||
if (ConfirmationDialog::confirm(tr("Are you sure you want to delete all of your downloaded driving models?"), tr("Delete"), this)) {
|
||||
const QList<QString> deletableKeys = deletableModelsMap.keys();
|
||||
for (const QString &file : modelDir.entryList(QDir::Files)) {
|
||||
QString base = QFileInfo(file).baseName();
|
||||
for (const QString &modelKey : modelFileToNameMapProcessed.keys()) {
|
||||
QString modelName = modelFileToNameMapProcessed.value(modelKey);
|
||||
if (deletableModels.contains(modelName) && base.startsWith(modelKey)) {
|
||||
for (const QString &modelKey : deletableKeys) {
|
||||
if (base.startsWith(modelKey)) {
|
||||
QFile::remove(modelDir.filePath(file));
|
||||
break;
|
||||
}
|
||||
@@ -99,6 +120,7 @@ FrogPilotModelPanel::FrogPilotModelPanel(FrogPilotSettingsWindow *parent) : Frog
|
||||
|
||||
allModelsDownloaded = false;
|
||||
noModelsDownloaded = true;
|
||||
deleteModelButton->setEnabled(false);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -106,66 +128,70 @@ FrogPilotModelPanel::FrogPilotModelPanel(FrogPilotSettingsWindow *parent) : Frog
|
||||
} else if (param == "DownloadModel") {
|
||||
downloadModelButton = new FrogPilotButtonsControl(title, desc, icon, {tr("DOWNLOAD"), tr("DOWNLOAD ALL")});
|
||||
QObject::connect(downloadModelButton, &FrogPilotButtonsControl::buttonClicked, [this](int id) {
|
||||
auto isInstalled = [this](const QString &key) {
|
||||
bool has_thneed = false;
|
||||
bool has_policy_meta = false;
|
||||
bool has_policy_tg = false;
|
||||
bool has_vision_meta = false;
|
||||
bool has_vision_tg = false;
|
||||
|
||||
for (const QString &file : modelDir.entryList(QDir::Files)) {
|
||||
QFileInfo fi(modelDir.filePath(file));
|
||||
const QString base = fi.baseName();
|
||||
const QString ext = fi.suffix();
|
||||
if (!(base.startsWith(key) || base.startsWith(key + "_"))) continue;
|
||||
|
||||
if (ext == "thneed") {
|
||||
// Classic model (WD-40 etc.)
|
||||
has_thneed = true;
|
||||
} else if (ext == "pkl") {
|
||||
// TinyGrad bundle uses these four exact suffixes
|
||||
if (base.contains("_driving_policy_metadata")) has_policy_meta = true;
|
||||
else if (base.contains("_driving_policy_tinygrad")) has_policy_tg = true;
|
||||
else if (base.contains("_driving_vision_metadata")) has_vision_meta = true;
|
||||
else if (base.contains("_driving_vision_tinygrad")) has_vision_tg = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Classic models: any matching .thneed counts as installed
|
||||
if (has_thneed) return true;
|
||||
// TinyGrad models: require all four policy/vision files to be present
|
||||
return has_policy_meta && has_policy_tg && has_vision_meta && has_vision_tg;
|
||||
};
|
||||
if (id == 0) {
|
||||
if (modelDownloading) {
|
||||
params_memory.putBool("CancelModelDownload", true);
|
||||
|
||||
cancellingDownload = true;
|
||||
} else {
|
||||
QStringList downloadableModels = availableModelNames;
|
||||
for (const QString &modelKey : modelFileToNameMap.keys()) {
|
||||
QString modelName = modelFileToNameMap.value(modelKey);
|
||||
if (isInstalled(modelKey)) {
|
||||
downloadableModels.removeAll(modelName);
|
||||
}
|
||||
}
|
||||
downloadableModels.removeAll("Space Lab 👀📡");
|
||||
allModelsDownloaded = downloadableModels.isEmpty();
|
||||
} else {
|
||||
QMap<QString, QStringList> downloadableSeriesToModels;
|
||||
QStringList downloadableModelNames;
|
||||
|
||||
// Group downloadable models by series
|
||||
QMap<QString, QStringList> downloadableSeriesToModels;
|
||||
for (const QString &modelName : downloadableModels) {
|
||||
QString modelKey = modelFileToNameMap.key(modelName);
|
||||
QString series = modelSeriesMap.value(modelKey, "Custom Series");
|
||||
downloadableSeriesToModels[series].append(modelName);
|
||||
for (auto it = modelFileToNameMap.constBegin(); it != modelFileToNameMap.constEnd(); ++it) {
|
||||
const QString &modelKey = it.key();
|
||||
const QString &modelName = it.value();
|
||||
if (modelName.isEmpty() || isModelInstalled(modelKey)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Sort models within each series
|
||||
for (QString &series : downloadableSeriesToModels.keys()) {
|
||||
downloadableSeriesToModels[series].sort();
|
||||
QString series = modelSeriesMap.value(modelKey, tr("Custom Series"));
|
||||
downloadableSeriesToModels[series].append(modelName);
|
||||
if (!downloadableModelNames.contains(modelName)) {
|
||||
downloadableModelNames.append(modelName);
|
||||
}
|
||||
}
|
||||
|
||||
QString modelToDownload = ExpandableMultiOptionDialog::getSelection(tr("Select a driving model to download"), downloadableSeriesToModels, "", this);
|
||||
allModelsDownloaded = downloadableModelNames.isEmpty();
|
||||
if (allModelsDownloaded) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (QString &series : downloadableSeriesToModels.keys()) {
|
||||
QStringList &models = downloadableSeriesToModels[series];
|
||||
models.removeDuplicates();
|
||||
std::sort(models.begin(), models.end());
|
||||
}
|
||||
|
||||
QStringList userFavorites = QString::fromStdString(params.get("UserFavorites")).split(",");
|
||||
userFavorites.removeAll("");
|
||||
|
||||
QStringList communityFavorites = QString::fromStdString(params.get("CommunityFavorites")).split(",");
|
||||
communityFavorites.removeAll("");
|
||||
|
||||
QString savedSortMode = QString::fromStdString(params.get("ModelSortMode"));
|
||||
if (savedSortMode.isEmpty()) savedSortMode = "alphabetical";
|
||||
|
||||
ExpandableMultiOptionDialog dialog(
|
||||
tr("Select a driving model to download"),
|
||||
downloadableSeriesToModels,
|
||||
"",
|
||||
this,
|
||||
userFavorites,
|
||||
communityFavorites,
|
||||
modelReleasedDates,
|
||||
modelFileToNameMap,
|
||||
savedSortMode);
|
||||
|
||||
int dialogResult = dialog.exec();
|
||||
|
||||
QString sortMode = dialog.getCurrentSortMode();
|
||||
QStringList newUserFavs = dialog.getUserFavorites();
|
||||
params.put("ModelSortMode", sortMode.toStdString());
|
||||
params.put("UserFavorites", newUserFavs.join(",").toStdString());
|
||||
userFavorites = newUserFavs;
|
||||
|
||||
if (dialogResult == QDialog::Accepted) {
|
||||
QString modelToDownload = dialog.selection;
|
||||
if (!modelToDownload.isEmpty()) {
|
||||
QString modelKey = modelFileToNameMap.key(modelToDownload);
|
||||
params_memory.put("ModelToDownload", modelKey.toStdString());
|
||||
@@ -182,15 +208,16 @@ FrogPilotModelPanel::FrogPilotModelPanel(FrogPilotSettingsWindow *parent) : Frog
|
||||
}
|
||||
}
|
||||
}
|
||||
params_memory.put("ModelDownloadProgress", "Downloading...");
|
||||
params_memory.put("ModelDownloadProgress", "Downloading...");
|
||||
|
||||
downloadModelButton->setText(0, tr("CANCEL"));
|
||||
downloadModelButton->setText(0, tr("CANCEL"));
|
||||
|
||||
downloadModelButton->setValue("Downloading...");
|
||||
downloadModelButton->setValue("Downloading...");
|
||||
|
||||
downloadModelButton->setVisibleButton(1, false);
|
||||
downloadModelButton->setVisibleButton(1, false);
|
||||
|
||||
modelDownloading = true;
|
||||
modelDownloading = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (id == 1) {
|
||||
@@ -308,57 +335,32 @@ FrogPilotModelPanel::FrogPilotModelPanel(FrogPilotSettingsWindow *parent) : Frog
|
||||
} else if (param == "SelectModel") {
|
||||
selectModelButton = new ButtonControl(title, tr("SELECT"), desc);
|
||||
QObject::connect(selectModelButton, &ButtonControl::clicked, [this]() {
|
||||
auto isInstalled = [this](const QString &key) {
|
||||
bool has_thneed = false;
|
||||
bool has_policy_meta = false;
|
||||
bool has_policy_tg = false;
|
||||
bool has_vision_meta = false;
|
||||
bool has_vision_tg = false;
|
||||
// Group models by series for the enhanced dialog
|
||||
QMap<QString, QStringList> seriesToModels;
|
||||
QMap<QString, QString> installedModelFileToNameMap;
|
||||
QMap<QString, QString> installedReleasedDates;
|
||||
|
||||
for (const QString &file : modelDir.entryList(QDir::Files)) {
|
||||
QFileInfo fi(modelDir.filePath(file));
|
||||
const QString base = fi.baseName();
|
||||
const QString ext = fi.suffix();
|
||||
if (!(base.startsWith(key) || base.startsWith(key + "_"))) continue;
|
||||
|
||||
if (ext == "thneed") {
|
||||
// Classic model (WD-40 etc.)
|
||||
has_thneed = true;
|
||||
} else if (ext == "pkl") {
|
||||
// TinyGrad bundle uses these four exact suffixes
|
||||
if (base.contains("_driving_policy_metadata")) has_policy_meta = true;
|
||||
else if (base.contains("_driving_policy_tinygrad")) has_policy_tg = true;
|
||||
else if (base.contains("_driving_vision_metadata")) has_vision_meta = true;
|
||||
else if (base.contains("_driving_vision_tinygrad")) has_vision_tg = true;
|
||||
}
|
||||
// Add all available models by series
|
||||
for (const QString &modelKey : modelFileToNameMap.keys()) {
|
||||
if (!isModelInstalled(modelKey)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Classic models: any matching .thneed counts as installed
|
||||
if (has_thneed) return true;
|
||||
// TinyGrad models: require all four policy/vision files to be present
|
||||
return has_policy_meta && has_policy_tg && has_vision_meta && has_vision_tg;
|
||||
};
|
||||
// Group models by series
|
||||
QMap<QString, QStringList> seriesToModels;
|
||||
for (const QString &modelKey : modelFileToNameMap.keys()) {
|
||||
QString modelName = modelFileToNameMap.value(modelKey);
|
||||
if (modelName.contains("(Default)")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isInstalled(modelKey)) {
|
||||
QString series = modelSeriesMap.value(modelKey, "Dom Forgot To Label Me");
|
||||
seriesToModels[series].append(modelName);
|
||||
installedModelFileToNameMap.insert(modelKey, modelName);
|
||||
if (modelReleasedDates.contains(modelKey)) {
|
||||
installedReleasedDates.insert(modelKey, modelReleasedDates.value(modelKey));
|
||||
}
|
||||
|
||||
QString series = modelSeriesMap.value(modelKey, "Custom Series");
|
||||
seriesToModels[series].append(modelName);
|
||||
}
|
||||
|
||||
// Add Space Lab to Custom Series
|
||||
QString spaceLabName = modelFileToNameMap.value("space-lab");
|
||||
if (isInstalled("space-lab")) {
|
||||
seriesToModels["Custom Series"].append(spaceLabName);
|
||||
}
|
||||
|
||||
// Sort models within each series
|
||||
// Sort models alphabetically within each series
|
||||
for (QString &series : seriesToModels.keys()) {
|
||||
seriesToModels[series].sort();
|
||||
}
|
||||
@@ -371,54 +373,70 @@ FrogPilotModelPanel::FrogPilotModelPanel(FrogPilotSettingsWindow *parent) : Frog
|
||||
seriesToModels[defaultSeries].prepend(defaultModelName);
|
||||
}
|
||||
|
||||
QString modelToSelect = ExpandableMultiOptionDialog::getSelection(tr("Select a model - 🗺️ = Navigation | 📡 = Radar | 👀 = VOACC"), seriesToModels, currentModel, this);
|
||||
if (!modelToSelect.isEmpty()) {
|
||||
currentModel = modelToSelect;
|
||||
// Prepare favorites and dates for the enhanced dialog
|
||||
QStringList userFavs = QString::fromStdString(params.get("UserFavorites")).split(",");
|
||||
userFavs.removeAll("");
|
||||
|
||||
params.put("Model", modelFileToNameMap.key(modelToSelect).toStdString());
|
||||
// Sync ModelVersion with the selected model if known
|
||||
{
|
||||
QString modelKey = modelFileToNameMap.key(modelToSelect);
|
||||
QFile vf("/data/models/.model_versions.json");
|
||||
if (vf.open(QIODevice::ReadOnly)) {
|
||||
auto doc = QJsonDocument::fromJson(vf.readAll());
|
||||
if (doc.isObject()) {
|
||||
auto obj = doc.object();
|
||||
if (obj.contains(modelKey)) {
|
||||
params.put("ModelVersion", obj.value(modelKey).toString().toStdString());
|
||||
QStringList communityFavs = QString::fromStdString(params.get("CommunityFavorites")).split(",");
|
||||
communityFavs.removeAll("");
|
||||
|
||||
// Create dialog instance to access sort mode and favorites after selection
|
||||
QString savedSortMode = QString::fromStdString(params.get("ModelSortMode"));
|
||||
if (savedSortMode.isEmpty()) savedSortMode = "alphabetical";
|
||||
|
||||
ExpandableMultiOptionDialog dialog(tr("Select a model - 🗺️ = Navigation | 📡 = Radar | 👀 = VOACC"),
|
||||
seriesToModels, currentModel, this,
|
||||
userFavs, communityFavs, installedReleasedDates, installedModelFileToNameMap, savedSortMode);
|
||||
|
||||
int dialogResult = dialog.exec();
|
||||
|
||||
// Persist sort mode and user favorites even if no selection was made
|
||||
QString sortMode = dialog.getCurrentSortMode();
|
||||
QStringList newUserFavs = dialog.getUserFavorites();
|
||||
params.put("ModelSortMode", sortMode.toStdString());
|
||||
params.put("UserFavorites", newUserFavs.join(",").toStdString());
|
||||
|
||||
if (dialogResult == QDialog::Accepted) {
|
||||
QString modelToSelect = dialog.selection;
|
||||
if (!modelToSelect.isEmpty()) {
|
||||
currentModel = modelToSelect;
|
||||
|
||||
params.put("Model", modelFileToNameMap.key(modelToSelect).toStdString());
|
||||
// Sync ModelVersion with the selected model if known
|
||||
{
|
||||
QString modelKey = modelFileToNameMap.key(modelToSelect);
|
||||
QFile vf("/data/models/.model_versions.json");
|
||||
if (vf.open(QIODevice::ReadOnly)) {
|
||||
auto doc = QJsonDocument::fromJson(vf.readAll());
|
||||
if (doc.isObject()) {
|
||||
auto obj = doc.object();
|
||||
if (obj.contains(modelKey)) {
|
||||
params.put("ModelVersion", obj.value(modelKey).toString().toStdString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateFrogPilotToggles();
|
||||
updateFrogPilotToggles();
|
||||
|
||||
if (started) {
|
||||
if (FrogPilotConfirmationDialog::toggleReboot(this)) {
|
||||
Hardware::reboot();
|
||||
}
|
||||
}
|
||||
selectModelButton->setValue(modelToSelect);
|
||||
|
||||
QStringList deletableModels;
|
||||
for (const QString &file : modelDir.entryList(QDir::Files)) {
|
||||
QString base = QFileInfo(file).baseName();
|
||||
for (const QString &modelKey : modelFileToNameMapProcessed.keys()) {
|
||||
if (base.startsWith(modelKey)) {
|
||||
QString modelName = modelFileToNameMapProcessed.value(modelKey);
|
||||
if (!deletableModels.contains(modelName)) {
|
||||
deletableModels.append(modelName);
|
||||
}
|
||||
if (started) {
|
||||
if (FrogPilotConfirmationDialog::toggleReboot(this)) {
|
||||
Hardware::reboot();
|
||||
}
|
||||
}
|
||||
selectModelButton->setValue(modelToSelect);
|
||||
|
||||
noModelsDownloaded = getDeletableModelDisplayNames().isEmpty();
|
||||
deleteModelButton->setEnabled(!(allModelsDownloading || modelDownloading || noModelsDownloaded));
|
||||
}
|
||||
deletableModels.removeAll(processModelName(currentModel));
|
||||
deletableModels.removeAll(modelFileToNameMapProcessed.value(QString::fromStdString(params_default.get("Model"))));
|
||||
noModelsDownloaded = deletableModels.isEmpty();
|
||||
}
|
||||
});
|
||||
modelToggle = selectModelButton;
|
||||
|
||||
} else if (param == "RecoveryPower") {
|
||||
std::vector<QString> recoveryPowerButton{"Reset"};
|
||||
modelToggle = new FrogPilotParamValueButtonControl(param, title, desc, icon, 0.5, 2.0, QString(), std::map<float, QString>(), 0.1, false, {}, recoveryPowerButton, false, false);
|
||||
recoveryPowerToggle = static_cast<FrogPilotParamValueButtonControl*>(modelToggle);
|
||||
} else if (param == "StopDistance") {
|
||||
std::vector<QString> stopDistanceButton{"Reset"};
|
||||
modelToggle = new FrogPilotParamValueButtonControl(param, title, desc, icon, 4.0, 10.0, QString(), std::map<float, QString>(), 0.1, false, {}, stopDistanceButton, false, false);
|
||||
@@ -451,6 +469,16 @@ FrogPilotModelPanel::FrogPilotModelPanel(FrogPilotSettingsWindow *parent) : Frog
|
||||
}
|
||||
});
|
||||
|
||||
if (recoveryPowerToggle) {
|
||||
QObject::connect(recoveryPowerToggle, &FrogPilotParamValueButtonControl::buttonClicked, [this, recoveryPowerToggle]() {
|
||||
if (ConfirmationDialog::confirm(tr("Are you sure you want to reset your <b>Recovery Power</b> to the default of 1.0?"), tr("Reset"), this)) {
|
||||
params.putFloat("RecoveryPower", 1.0);
|
||||
recoveryPowerToggle->refresh();
|
||||
updateFrogPilotToggles();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (stopDistanceToggle) {
|
||||
QObject::connect(stopDistanceToggle, &FrogPilotParamValueButtonControl::buttonClicked, [this, stopDistanceToggle]() {
|
||||
if (ConfirmationDialog::confirm(tr("Are you sure you want to reset your <b>Stop Distance</b> to the default of 6 meters?"), tr("Reset"), this)) {
|
||||
@@ -465,6 +493,96 @@ FrogPilotModelPanel::FrogPilotModelPanel(FrogPilotSettingsWindow *parent) : Frog
|
||||
QObject::connect(uiState(), &UIState::uiUpdate, this, &FrogPilotModelPanel::updateState);
|
||||
}
|
||||
|
||||
bool FrogPilotModelPanel::isModelInstalled(const QString &key) const {
|
||||
if (key.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool has_thneed = false;
|
||||
bool has_policy_meta = false;
|
||||
bool has_policy_tg = false;
|
||||
bool has_vision_meta = false;
|
||||
bool has_vision_tg = false;
|
||||
bool has_off_policy_meta = false;
|
||||
bool has_off_policy_tg = false;
|
||||
bool foundAny = false;
|
||||
|
||||
for (const QString &file : modelDir.entryList(QDir::Files)) {
|
||||
QFileInfo fi(modelDir.filePath(file));
|
||||
const QString base = fi.baseName();
|
||||
const QString ext = fi.suffix();
|
||||
|
||||
if (!(base.startsWith(key) || base.startsWith(key + "_"))) continue;
|
||||
|
||||
foundAny = true;
|
||||
|
||||
if (ext == "thneed") {
|
||||
has_thneed = true;
|
||||
} else if (ext == "pkl") {
|
||||
if (base.contains("_driving_policy_metadata")) {
|
||||
has_policy_meta = true;
|
||||
} else if (base.contains("_driving_policy_tinygrad")) {
|
||||
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")) {
|
||||
has_vision_meta = true;
|
||||
} else if (base.contains("_driving_vision_tinygrad")) {
|
||||
has_vision_tg = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (has_thneed) {
|
||||
return true;
|
||||
}
|
||||
|
||||
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 foundAny;
|
||||
}
|
||||
|
||||
QMap<QString, QString> FrogPilotModelPanel::getDeletableModelDisplayNames() {
|
||||
QMap<QString, QString> deletable;
|
||||
|
||||
QString defaultModelKey = QString::fromStdString(params_default.get("Model"));
|
||||
QString defaultModelName = modelFileToNameMap.value(defaultModelKey);
|
||||
QString processedDefault = processModelName(defaultModelName);
|
||||
QString processedCurrent = processModelName(currentModel);
|
||||
|
||||
for (auto it = modelFileToNameMap.constBegin(); it != modelFileToNameMap.constEnd(); ++it) {
|
||||
const QString &modelKey = it.key();
|
||||
const QString &displayName = it.value();
|
||||
if (displayName.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isModelInstalled(modelKey)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
QString processedName = processModelName(displayName);
|
||||
if (!processedCurrent.isEmpty() && processedName == processedCurrent) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!processedDefault.isEmpty() && processedName == processedDefault) {
|
||||
continue;
|
||||
}
|
||||
|
||||
deletable.insert(modelKey, displayName);
|
||||
}
|
||||
|
||||
return deletable;
|
||||
}
|
||||
|
||||
void FrogPilotModelPanel::showEvent(QShowEvent *event) {
|
||||
FrogPilotUIState &fs = *frogpilotUIState();
|
||||
UIState &s = *uiState();
|
||||
@@ -478,6 +596,9 @@ void FrogPilotModelPanel::showEvent(QShowEvent *event) {
|
||||
QStringList availableModels = QString::fromStdString(params.get("AvailableModels")).split(",");
|
||||
availableModelNames = QString::fromStdString(params.get("AvailableModelNames")).split(",");
|
||||
availableModelSeries = QString::fromStdString(params.get("AvailableModelSeries")).split(",");
|
||||
QStringList releasedDatesParam = QString::fromStdString(params.get("ModelReleasedDates")).split(",");
|
||||
QStringList communityFavsParam = QString::fromStdString(params.get("CommunityFavorites")).split(",");
|
||||
QStringList userFavsParam = QString::fromStdString(params.get("UserFavorites")).split(",");
|
||||
|
||||
// Build a simple model->version map for quick lookups elsewhere
|
||||
{
|
||||
@@ -497,78 +618,54 @@ void FrogPilotModelPanel::showEvent(QShowEvent *event) {
|
||||
modelFileToNameMap.clear();
|
||||
modelFileToNameMapProcessed.clear();
|
||||
modelSeriesMap.clear();
|
||||
int size = qMin(qMin(availableModels.size(), availableModelNames.size()), availableModelSeries.size());
|
||||
modelReleasedDates.clear();
|
||||
int size = qMin(availableModels.size(), availableModelNames.size());
|
||||
for (int i = 0; i < size; ++i) {
|
||||
modelFileToNameMap.insert(availableModels[i], availableModelNames[i]);
|
||||
modelFileToNameMapProcessed.insert(availableModels[i], processModelName(availableModelNames[i]));
|
||||
modelSeriesMap.insert(availableModels[i], availableModelSeries[i]);
|
||||
}
|
||||
modelFileToNameMap.insert("space-lab", "Space Lab 👀📡");
|
||||
modelFileToNameMapProcessed.insert("space-lab", "Space Lab");
|
||||
modelSeriesMap.insert("space-lab", "Dom Forgot To Label Me");
|
||||
|
||||
auto isInstalled = [this](const QString &key) {
|
||||
bool has_thneed = false;
|
||||
bool has_policy_meta = false;
|
||||
bool has_policy_tg = false;
|
||||
bool has_vision_meta = false;
|
||||
bool has_vision_tg = false;
|
||||
|
||||
for (const QString &file : modelDir.entryList(QDir::Files)) {
|
||||
QFileInfo fi(modelDir.filePath(file));
|
||||
const QString base = fi.baseName();
|
||||
const QString ext = fi.suffix();
|
||||
if (!(base.startsWith(key) || base.startsWith(key + "_"))) continue;
|
||||
|
||||
if (ext == "thneed") {
|
||||
// Classic model (WD-40 etc.)
|
||||
has_thneed = true;
|
||||
} else if (ext == "pkl") {
|
||||
// TinyGrad bundle uses these four exact suffixes
|
||||
if (base.contains("_driving_policy_metadata")) has_policy_meta = true;
|
||||
else if (base.contains("_driving_policy_tinygrad")) has_policy_tg = true;
|
||||
else if (base.contains("_driving_vision_metadata")) has_vision_meta = true;
|
||||
else if (base.contains("_driving_vision_tinygrad")) has_vision_tg = true;
|
||||
}
|
||||
const QString modelKey = availableModels[i].trimmed();
|
||||
const QString modelName = availableModelNames[i].trimmed();
|
||||
if (modelKey.isEmpty() || modelName.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Classic models: any matching .thneed counts as installed
|
||||
if (has_thneed) return true;
|
||||
// TinyGrad models: require all four policy/vision files to be present
|
||||
return has_policy_meta && has_policy_tg && has_vision_meta && has_vision_tg;
|
||||
};
|
||||
QStringList downloadableModels = availableModelNames;
|
||||
for (const QString &modelKey : modelFileToNameMap.keys()) {
|
||||
QString modelName = modelFileToNameMap.value(modelKey);
|
||||
if (isInstalled(modelKey)) {
|
||||
downloadableModels.removeAll(modelName);
|
||||
QString series;
|
||||
if (i < availableModelSeries.size()) {
|
||||
series = availableModelSeries[i].trimmed();
|
||||
}
|
||||
if (series.isEmpty()) {
|
||||
series = tr("Custom Series");
|
||||
}
|
||||
}
|
||||
allModelsDownloaded = downloadableModels.isEmpty();
|
||||
|
||||
QStringList deletableModels;
|
||||
for (const QString &file : modelDir.entryList(QDir::Files)) {
|
||||
QString base = QFileInfo(file).baseName();
|
||||
for (const QString &modelKey : modelFileToNameMapProcessed.keys()) {
|
||||
if (base.startsWith(modelKey)) {
|
||||
QString modelName = modelFileToNameMapProcessed.value(modelKey);
|
||||
if (!deletableModels.contains(modelName)) {
|
||||
deletableModels.append(modelName);
|
||||
}
|
||||
modelFileToNameMap.insert(modelKey, modelName);
|
||||
modelFileToNameMapProcessed.insert(modelKey, processModelName(modelName));
|
||||
modelSeriesMap.insert(modelKey, series);
|
||||
|
||||
if (i < releasedDatesParam.size()) {
|
||||
const QString released = releasedDatesParam[i].trimmed();
|
||||
if (!released.isEmpty()) {
|
||||
this->modelReleasedDates.insert(modelKey, released);
|
||||
}
|
||||
}
|
||||
}
|
||||
deletableModels.removeAll(processModelName(currentModel));
|
||||
deletableModels.removeAll(modelFileToNameMapProcessed.value(QString::fromStdString(params_default.get("Model"))));
|
||||
noModelsDownloaded = deletableModels.isEmpty();
|
||||
allModelsDownloaded = true;
|
||||
for (auto it = modelFileToNameMap.constBegin(); it != modelFileToNameMap.constEnd(); ++it) {
|
||||
if (it.value().isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
if (!isModelInstalled(it.key())) {
|
||||
allModelsDownloaded = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
QString modelKey = QString::fromStdString(params.get("Model"));
|
||||
if (!isInstalled(modelKey)) {
|
||||
if (!isModelInstalled(modelKey)) {
|
||||
modelKey = QString::fromStdString(params_default.get("Model"));
|
||||
}
|
||||
currentModel = modelFileToNameMap.value(modelKey);
|
||||
selectModelButton->setValue(currentModel);
|
||||
|
||||
noModelsDownloaded = getDeletableModelDisplayNames().isEmpty();
|
||||
|
||||
bool parked = !s.scene.started || fs.frogpilot_scene.parked || fs.frogpilot_toggles.value("frogs_go_moo").toBool();
|
||||
|
||||
deleteModelButton->setEnabled(!(allModelsDownloading || modelDownloading || noModelsDownloaded));
|
||||
@@ -666,10 +763,10 @@ void FrogPilotModelPanel::updateToggles() {
|
||||
|
||||
if (key == "ManageBlacklistedModels" || key == "ManageScores") {
|
||||
setVisible &= params.getBool("ModelRandomizer");
|
||||
}
|
||||
|
||||
else if (key == "SelectModel") {
|
||||
} else if (key == "SelectModel") {
|
||||
setVisible &= !params.getBool("ModelRandomizer");
|
||||
} else if (key == "RecoveryPower") {
|
||||
setVisible &= (tuningLevel == 3); // Only visible in developer tuning level
|
||||
} else if (key == "StopDistance") {
|
||||
setVisible &= (tuningLevel == 3); // Only visible in developer tuning level
|
||||
}
|
||||
|
||||
@@ -20,6 +20,8 @@ private:
|
||||
void updateModelLabels(FrogPilotListWidget *labelsList);
|
||||
void updateState(const UIState &s, const FrogPilotUIState &fs);
|
||||
void updateToggles();
|
||||
bool isModelInstalled(const QString &key) const;
|
||||
QMap<QString, QString> getDeletableModelDisplayNames();
|
||||
|
||||
bool allModelsDownloaded;
|
||||
bool allModelsDownloading;
|
||||
@@ -55,10 +57,12 @@ private:
|
||||
|
||||
QMap<QString, QString> modelFileToNameMap;
|
||||
QMap<QString, QString> modelFileToNameMapProcessed;
|
||||
QMap<QString, QString> modelReleasedDates;
|
||||
QMap<QString, QString> modelSeriesMap;
|
||||
|
||||
QString currentModel;
|
||||
|
||||
|
||||
QStringList availableModelNames;
|
||||
QStringList availableModelSeries;
|
||||
};
|
||||
|
||||
@@ -168,6 +168,7 @@ FrogPilotVehiclesPanel::FrogPilotVehiclesPanel(FrogPilotSettingsWindow *parent)
|
||||
std::vector<std::tuple<QString, QString, QString, QString>> vehicleToggles {
|
||||
{"GMToggles", tr("General Motors Settings"), tr("<b>FrogPilot features for General Motors vehicles.</b>"), ""},
|
||||
{"ExperimentalGMTune", tr("FrogsGoMoo's Experimental Tune"), tr("<b>Experimental GM tune by FrogsGoMoo</b> that attempts to smoothen stopping and takeoff control. Use at your own risk!"), ""},
|
||||
{"GMPedalLongitudinal", tr("Use Pedal for Longitudinal Control"), tr("<b>Use the pedal interceptor for longitudinal control</b> instead of camera ACC/Redneck when available."), ""},
|
||||
{"LongPitch", tr("Smooth Pedal Response on Hills"), tr("<b>Smoothen acceleration and braking</b> when driving downhill/uphill."), ""},
|
||||
{"VoltSNG", tr("Stop-and-Go Hack"), tr("<b>Force stop-and-go</b> on the 2017 Chevy Volt."), ""},
|
||||
|
||||
@@ -188,6 +189,7 @@ FrogPilotVehiclesPanel::FrogPilotVehiclesPanel(FrogPilotSettingsWindow *parent)
|
||||
{"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>"), ""},
|
||||
{"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>"), ""},
|
||||
{"SNGSupport", tr("Stop-and-Go Support"), tr("<b>Does your vehicle support stop-and-go driving?</b>"), ""}
|
||||
};
|
||||
@@ -341,6 +343,7 @@ void FrogPilotVehiclesPanel::showEvent(QShowEvent *event) {
|
||||
|
||||
QStringList detected;
|
||||
if (hasPedal) detected << "comma Pedal";
|
||||
if (parent->hasSASCM) detected << "SASCM";
|
||||
if (parent->hasSDSU) detected << "SDSU";
|
||||
if (parent->hasZSS) detected << "ZSS";
|
||||
static_cast<LabelControl*>(toggles["HardwareDetected"])->setText(detected.isEmpty() ? tr("None") : detected.join(", "));
|
||||
@@ -349,6 +352,7 @@ void FrogPilotVehiclesPanel::showEvent(QShowEvent *event) {
|
||||
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["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["SNGSupport"])->setText(hasSNG ? tr("Yes") : tr("No"));
|
||||
|
||||
@@ -403,6 +407,10 @@ void FrogPilotVehiclesPanel::updateToggles() {
|
||||
setVisible &= isHKGCanFd;
|
||||
}
|
||||
|
||||
else if (key == "GMPedalLongitudinal") {
|
||||
setVisible &= hasPedal;
|
||||
}
|
||||
|
||||
else if (key == "VoltSNG") {
|
||||
setVisible &= isVolt && !hasSNG;
|
||||
}
|
||||
|
||||
@@ -36,11 +36,11 @@ private:
|
||||
|
||||
std::map<QString, AbstractControl*> toggles;
|
||||
|
||||
QSet<QString> gmKeys = {"ExperimentalGMTune", "LongPitch", "VoltSNG"};
|
||||
QSet<QString> gmKeys = {"ExperimentalGMTune", "GMPedalLongitudinal", "LongPitch", "VoltSNG"};
|
||||
QSet<QString> hkgKeys = {"NewLongAPI", "TacoTuneHacks"};
|
||||
QSet<QString> longitudinalKeys = {"ExperimentalGMTune", "FrogsGoMoosTweak", "LongPitch", "NewLongAPI", "SNGHack", "VoltSNG"};
|
||||
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;
|
||||
|
||||
|
||||
@@ -8,7 +8,114 @@ source "$BASEDIR/launch_env.sh"
|
||||
|
||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
|
||||
|
||||
# --- BEGIN: auto-fix persist from squashfs -> ext4 (one-time, preserves identity) ---
|
||||
function persist_convert_if_needed {
|
||||
LOG="/tmp/persist_fix.log"
|
||||
{
|
||||
echo "[persist-fix] ----- start $(date) -----"
|
||||
|
||||
# Guard: if we've already converted on this device, skip
|
||||
if [ -f /data/.persist_converted ] || [ -f /persist/.converted_to_ext4 ]; then
|
||||
echo "[persist-fix] Marker exists; skipping."
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Discover persist device
|
||||
DEV="$(blkid -t LABEL=persist -o device 2>/dev/null || true)"
|
||||
if [ -z "$DEV" ] && [ -e /dev/disk/by-partlabel/persist ]; then
|
||||
DEV="$(realpath /dev/disk/by-partlabel/persist)"
|
||||
fi
|
||||
if [ -z "$DEV" ]; then
|
||||
# Fallback commonly used path
|
||||
if lsblk -no PATH,LABEL | grep -E "persist$" >/dev/null 2>&1; then
|
||||
DEV="$(lsblk -no PATH,LABEL | awk '$2=="persist"{print $1; exit}')"
|
||||
else
|
||||
DEV="/dev/sda2"
|
||||
fi
|
||||
fi
|
||||
echo "[persist-fix] Using device: ${DEV}"
|
||||
|
||||
# Detect device filesystem type
|
||||
FSTYPE="$(blkid -o value -s TYPE "$DEV" 2>/dev/null || true)"
|
||||
echo "[persist-fix] Detected $DEV fstype='$FSTYPE'"
|
||||
UNSQS="$DIR/third_party/bin/unsquashfs"
|
||||
|
||||
# Detect current /persist mount status & fstype
|
||||
CUR_MNT_TYPE="$(mount | awk '$3==\"/persist\"{print $5}' | head -n1)"
|
||||
if mountpoint -q /persist; then
|
||||
echo "[persist-fix] /persist currently mounted as type='${CUR_MNT_TYPE}'"
|
||||
else
|
||||
echo "[persist-fix] /persist is not a mountpoint (empty dir)."
|
||||
fi
|
||||
|
||||
# Only proceed on NEW devices: either /persist is not mounted OR is squashfs,
|
||||
# AND the underlying persist partition is squashfs (factory RO image).
|
||||
if { ! mountpoint -q /persist || [ "${CUR_MNT_TYPE}" = "squashfs" ]; } && [ "${FSTYPE}" = "squashfs" ]; then
|
||||
echo "[persist-fix] NEW device detected (squashfs persist). Converting to ext4."
|
||||
|
||||
# Stream identity files using unsquashfs -cat directly
|
||||
for f in id_rsa id_rsa.pub color_cal dongle_id; do
|
||||
if sudo "$UNSQS" -cat "$DEV" "comma/$f" > "/data/$f" 2>/dev/null; then
|
||||
echo "[persist-fix] Preserved $f"
|
||||
else
|
||||
echo "[persist-fix] $f not found in squashfs (ok, may not exist)."
|
||||
fi
|
||||
done
|
||||
|
||||
# (Optional) raw backup of the original partition image (once)
|
||||
if [ ! -f /data/persist_backup.img ]; then
|
||||
echo "[persist-fix] Creating raw backup of ${DEV} to /data/persist_backup.img"
|
||||
sudo dd if="$DEV" of=/data/persist_backup.img bs=1M status=none || true
|
||||
sync
|
||||
fi
|
||||
|
||||
# Reformat persist as ext4 and label it
|
||||
echo "[persist-fix] Formatting ${DEV} as ext4..."
|
||||
if ! sudo mkfs.ext4 -F "$DEV"; then
|
||||
echo "[persist-fix][ERROR] mkfs.ext4 failed on ${DEV}. Aborting."
|
||||
return 0
|
||||
fi
|
||||
sudo e2label "$DEV" persist || true
|
||||
|
||||
# Mount the new ext4 persist RW
|
||||
if ! sudo mount -t ext4 -o rw,discard "$DEV" /persist; then
|
||||
echo "[persist-fix][ERROR] Failed to mount new ext4 persist. Aborting."
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Recreate expected structure and restore identity
|
||||
sudo mkdir -p /persist/{comma,params,tracking}
|
||||
sudo chmod 755 /persist /persist/{comma,params,tracking}
|
||||
for f in id_rsa id_rsa.pub color_cal dongle_id; do
|
||||
if [ -f "/data/$f" ]; then
|
||||
sudo cp -p "/data/$f" "/persist/comma/$f"
|
||||
fi
|
||||
done
|
||||
if [ -f /persist/comma/id_rsa ]; then sudo chmod 600 /persist/comma/id_rsa; fi
|
||||
sudo chown -R comma:comma /persist/ /persist/comma /persist/params /persist/tracking || true
|
||||
sudo touch /persist/tracking/.lock
|
||||
|
||||
# Seed minimal params (only if not present)
|
||||
[ -f /persist/params/HasAcceptedTerms ] || echo -n 1 | sudo tee /persist/params/HasAcceptedTerms >/dev/null
|
||||
[ -f /persist/params/AlwaysOnDM ] || echo -n 1 | sudo tee /persist/params/AlwaysOnDM >/dev/null
|
||||
|
||||
# Mark complete so we don't run again; reboot once
|
||||
echo "ext4" | sudo tee /persist/.converted_to_ext4 >/dev/null
|
||||
sudo touch /data/.persist_converted
|
||||
sync
|
||||
echo "[persist-fix] Conversion complete. Rebooting once to finalize..."
|
||||
sudo reboot
|
||||
else
|
||||
echo "[persist-fix] Device is not NEW/squashfs (persist already ext4 or mounted). Skipping."
|
||||
fi
|
||||
|
||||
echo "[persist-fix] ----- end $(date) -----"
|
||||
} >>"$LOG" 2>&1
|
||||
}
|
||||
# --- END: auto-fix persist from squashfs -> ext4 ---
|
||||
|
||||
function agnos_init {
|
||||
persist_convert_if_needed
|
||||
# TODO: move this to agnos
|
||||
sudo rm -f /data/etc/NetworkManager/system-connections/*.nmmeta
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,11 +1,11 @@
|
||||
const SteeringLimits GM_STEERING_LIMITS = {
|
||||
.max_steer = 300,
|
||||
.max_rate_up = 10,
|
||||
.max_rate_down = 15,
|
||||
.driver_torque_allowance = 65,
|
||||
.driver_torque_factor = 4,
|
||||
.max_rt_delta = 128,
|
||||
.max_rt_interval = 250000,
|
||||
.max_steer = 450,
|
||||
.max_rate_up = 15,
|
||||
.max_rate_down = 34,
|
||||
.driver_torque_allowance = 78,
|
||||
.driver_torque_factor = 6,
|
||||
.max_rt_delta = 345,
|
||||
.max_rt_interval = 200000,
|
||||
.type = TorqueDriverLimited,
|
||||
};
|
||||
|
||||
|
||||
+19
-15
@@ -804,7 +804,8 @@ class Panda:
|
||||
# The panda will NAK CAN writes when there is CAN congestion.
|
||||
# libusb will try to send it again, with a max timeout.
|
||||
# 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):
|
||||
self._handle.controlWrite(Panda.REQUEST_OUT, 0xc0, 0, 0, b'')
|
||||
@@ -812,18 +813,18 @@ class Panda:
|
||||
@ensure_can_packet_version
|
||||
def can_send_many(self, arr, timeout=CAN_SEND_TIMEOUT_MS):
|
||||
snds = pack_can_buffer(arr)
|
||||
while True:
|
||||
try:
|
||||
for tx in snds:
|
||||
while True:
|
||||
bs = self._handle.bulkWrite(3, tx, timeout=timeout)
|
||||
tx = tx[bs:]
|
||||
if len(tx) == 0:
|
||||
break
|
||||
logging.error("CAN: PARTIAL SEND MANY, RETRYING")
|
||||
break
|
||||
except (usb1.USBErrorIO, usb1.USBErrorOverflow):
|
||||
logging.error("CAN: BAD SEND MANY, RETRYING")
|
||||
for tx in snds:
|
||||
retries = 0
|
||||
while len(tx) > 0:
|
||||
bs = self._handle.bulkWrite(3, tx, timeout=timeout)
|
||||
if bs == 0:
|
||||
retries += 1
|
||||
if retries > self.CAN_MAX_RETRIES:
|
||||
logging.warning("CAN send: no progress after retries, dropping")
|
||||
break
|
||||
else:
|
||||
retries = 0
|
||||
tx = tx[bs:]
|
||||
|
||||
def can_send(self, addr, dat, bus, timeout=CAN_SEND_TIMEOUT_MS):
|
||||
self.can_send_many([[addr, None, dat, bus]], timeout=timeout)
|
||||
@@ -831,13 +832,16 @@ class Panda:
|
||||
@ensure_can_packet_version
|
||||
def can_recv(self):
|
||||
dat = bytearray()
|
||||
while True:
|
||||
for _ in range(self.CAN_MAX_RETRIES):
|
||||
try:
|
||||
dat = self._handle.bulkRead(1, 16384) # Max receive batch size + 2 extra reserve frames
|
||||
break
|
||||
except (usb1.USBErrorIO, usb1.USBErrorOverflow):
|
||||
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)
|
||||
return msgs
|
||||
|
||||
|
||||
+12
-1
@@ -27,7 +27,10 @@ NACK = 0x1F
|
||||
CHECKSUM_START = 0xAB
|
||||
|
||||
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_TIMEOUT_RETRIES = 5 # like C++
|
||||
|
||||
XFER_SIZE = 0x40*31
|
||||
|
||||
@@ -152,6 +155,8 @@ class PandaSpiHandle(BaseHandle):
|
||||
return cksum
|
||||
|
||||
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
|
||||
|
||||
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("==============================================")
|
||||
|
||||
# Fix timeout=0 infinite loop: default to DEFAULT_TIMEOUT_MS
|
||||
if timeout == 0:
|
||||
timeout = DEFAULT_TIMEOUT_MS
|
||||
|
||||
n = 0
|
||||
start_time = time.monotonic()
|
||||
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
|
||||
logging.debug("\ntry #%d", n)
|
||||
with self.dev.acquire() as spi:
|
||||
@@ -238,6 +248,7 @@ class PandaSpiHandle(BaseHandle):
|
||||
exc = e
|
||||
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
|
||||
|
||||
def get_protocol_version(self) -> bytes:
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 418 KiB After Width: | Height: | Size: 671 KiB |
@@ -76,6 +76,7 @@ class CarController(CarControllerBase):
|
||||
self.regen_paddle_pressed = False
|
||||
self.aego = 0.0
|
||||
self.regen_paddle_timer = 0
|
||||
self.planner_regen_hold = False
|
||||
|
||||
|
||||
|
||||
@@ -87,6 +88,7 @@ class CarController(CarControllerBase):
|
||||
|
||||
def calc_pedal_command(self, accel: float, long_active: bool, car_velocity) -> Tuple[float, bool]:
|
||||
if not long_active:
|
||||
self.planner_regen_hold = False
|
||||
return 0., False
|
||||
|
||||
# Regen paddle hysteresis (frame-based): hold 10 frames, with decrement dead-zone
|
||||
@@ -102,7 +104,7 @@ class CarController(CarControllerBase):
|
||||
|
||||
# Base paddle press hysteresis
|
||||
self.regen_paddle_pressed = self.regen_paddle_timer >= 10 # 10 frames
|
||||
press_regen_paddle = self.regen_paddle_pressed
|
||||
press_regen_paddle = self.regen_paddle_pressed or self.planner_regen_hold
|
||||
|
||||
|
||||
# Regen gain ratios from bin-averaged 60–0 deceleration sweep; Calculates stronger decel from paddle
|
||||
@@ -135,6 +137,21 @@ class CarController(CarControllerBase):
|
||||
actuators = CC.actuators
|
||||
accel = brake_accel = actuators.accel
|
||||
press_regen_paddle = False
|
||||
|
||||
# Planner-driven regen hold: gate by car support and OP long active, use commanded accel thresholds
|
||||
if (self.CP.enableGasInterceptor and self.CP.carFingerprint in CC_REGEN_PADDLE_CAR
|
||||
and self.CP.openpilotLongitudinalControl and CC.longActive):
|
||||
# Match original hysteresis intent: vehicle can usually stop without paddle up to ~1.0 m/s^2
|
||||
# Use the same thresholds as the aEgo-based hysteresis, but on commanded accel for preemption
|
||||
planner_press_threshold = -0.7
|
||||
planner_release_threshold = -0.3
|
||||
if accel <= planner_press_threshold:
|
||||
self.planner_regen_hold = True
|
||||
elif accel >= planner_release_threshold:
|
||||
self.planner_regen_hold = False
|
||||
else:
|
||||
self.planner_regen_hold = False
|
||||
|
||||
hud_control = CC.hudControl
|
||||
hud_alert = hud_control.visualAlert
|
||||
hud_v_cruise = hud_control.setSpeed
|
||||
@@ -150,7 +167,7 @@ class CarController(CarControllerBase):
|
||||
self.CP.openpilotLongitudinalControl and
|
||||
CC.longActive and
|
||||
self.CP.enableGasInterceptor and
|
||||
self.regen_paddle_timer >= 10 # raw hysteresis-only (10 frames)
|
||||
(self.regen_paddle_timer >= 10 or self.planner_regen_hold) # hysteresis or planner hint
|
||||
)
|
||||
regen_active = raw_regen_active
|
||||
|
||||
@@ -304,6 +321,9 @@ class CarController(CarControllerBase):
|
||||
else:
|
||||
apply_steer = 0
|
||||
|
||||
if (self.CP.flags & GMFlags.CC_LONG.value) and CC.enabled and not CS.out.cruiseState.enabled: # Send 0 so Panda doesn't error
|
||||
apply_steer = 0
|
||||
|
||||
# shift previous steer timestamp
|
||||
self.prev_steer_ts_ns = self.last_steer_ts_ns
|
||||
self.last_steer_ts_ns = now_nanos
|
||||
@@ -314,7 +334,7 @@ class CarController(CarControllerBase):
|
||||
|
||||
# Update regen_active state and last_regen_paddle_pressed for next loop
|
||||
self.last_regen_active = regen_active
|
||||
self.last_regen_paddle_pressed = self.regen_paddle_pressed
|
||||
self.last_regen_paddle_pressed = self.regen_paddle_pressed or self.planner_regen_hold
|
||||
|
||||
if paddle_sends:
|
||||
interval_ns = self.last_steer_ts_ns - self.prev_steer_ts_ns
|
||||
@@ -369,9 +389,12 @@ class CarController(CarControllerBase):
|
||||
idx = (self.frame // 4) % 4
|
||||
|
||||
if self.CP.flags & GMFlags.CC_LONG.value:
|
||||
if CC.longActive and CS.out.vEgo > self.CP.minEnableSpeed:
|
||||
if CC.longActive and CS.out.cruiseState.enabled and CS.out.vEgo > self.CP.minEnableSpeed:
|
||||
# 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))
|
||||
can_sends.extend(gmcan.create_gm_cc_spam_command(self.packer_pt, self, CS, actuators, frogpilot_toggles))
|
||||
elif (CS.out.cruiseState.enabled and 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):
|
||||
can_sends.append(gmcan.create_buttons(self.packer_pt, CanBus.POWERTRAIN, (CS.buttons_counter + 1) % 4, CruiseButtons.DECEL_SET))
|
||||
if self.CP.enableGasInterceptor:
|
||||
can_sends.append(create_gas_interceptor_command(self.packer_pt, interceptor_gas_cmd, idx))
|
||||
if self.CP.carFingerprint not in CC_ONLY_CAR:
|
||||
|
||||
+22
-25
@@ -205,44 +205,41 @@ def create_regen_paddle_command(packer, bus, press_regen_paddle):
|
||||
}
|
||||
return packer.make_can_msg("EBCMRegenPaddle", bus, values)
|
||||
|
||||
def create_gm_cc_spam_command(packer, controller, CS, actuators):
|
||||
if controller.params_.get_bool("IsMetric"):
|
||||
_CV = CV.MS_TO_KPH
|
||||
RATE_UP_MAX = 0.04
|
||||
RATE_DOWN_MAX = 0.04
|
||||
else:
|
||||
_CV = CV.MS_TO_MPH
|
||||
RATE_UP_MAX = 0.2
|
||||
RATE_DOWN_MAX = 0.2
|
||||
|
||||
accel = actuators.accel * _CV # m/s/s to mph/s
|
||||
speedSetPoint = int(round(CS.out.cruiseState.speed * _CV))
|
||||
def create_gm_cc_spam_command(packer, controller, CS, actuators, frogpilot_toggles):
|
||||
accel = actuators.accel
|
||||
Vego = CS.out.vEgo
|
||||
|
||||
cruiseBtn = CruiseButtons.INIT
|
||||
if speedSetPoint == CS.CP.minEnableSpeed and accel < -1:
|
||||
if abs(accel) <= 0.15:
|
||||
rate = 1
|
||||
else:
|
||||
rate = 0.2
|
||||
|
||||
MS_CONVERT = CV.MS_TO_KPH if frogpilot_toggles.is_metric else CV.MS_TO_MPH
|
||||
|
||||
speedSetPoint = int(round(CS.out.cruiseState.speed * MS_CONVERT))
|
||||
|
||||
if accel > 0:
|
||||
DesiredSetPoint = int(round((Vego * 1.01 + 3 * accel) * MS_CONVERT)) # 1.01 factor to match cluster speed better
|
||||
else: # accel <= 0
|
||||
DesiredSetPoint = int(round((Vego * 1.01 + 3 * accel) * MS_CONVERT))
|
||||
|
||||
if CS.CP.minEnableSpeed - (DesiredSetPoint / MS_CONVERT) > 3.25:
|
||||
cruiseBtn = CruiseButtons.CANCEL
|
||||
controller.apply_speed = 0
|
||||
rate = 0.04
|
||||
elif accel < 0:
|
||||
elif DesiredSetPoint < speedSetPoint and speedSetPoint > CS.CP.minEnableSpeed * MS_CONVERT + 1:
|
||||
cruiseBtn = CruiseButtons.DECEL_SET
|
||||
if speedSetPoint > (CS.out.vEgo * _CV) + 3.0: # If accel is changing directions, bring set speed to current speed as fast as possible
|
||||
rate = RATE_DOWN_MAX
|
||||
else:
|
||||
rate = max(-1 / accel, RATE_DOWN_MAX)
|
||||
controller.apply_speed = speedSetPoint - 1
|
||||
elif accel > 0:
|
||||
elif DesiredSetPoint > speedSetPoint:
|
||||
cruiseBtn = CruiseButtons.RES_ACCEL
|
||||
if speedSetPoint < (CS.out.vEgo * _CV) - 3.0:
|
||||
rate = RATE_UP_MAX
|
||||
else:
|
||||
rate = max(1 / accel, RATE_UP_MAX)
|
||||
controller.apply_speed = speedSetPoint + 1
|
||||
else:
|
||||
cruiseBtn = CruiseButtons.INIT
|
||||
controller.apply_speed = speedSetPoint
|
||||
rate = float('inf')
|
||||
|
||||
# Check rlogs closely - our message shouldn't show up on the pt bus for us
|
||||
# Or bus 2, since we're forwarding... but I think it does
|
||||
# TODO: Cleanup the timing - normal is every 30ms...
|
||||
if (cruiseBtn != CruiseButtons.INIT) and ((controller.frame - controller.last_button_frame) * DT_CTRL > rate):
|
||||
controller.last_button_frame = controller.frame
|
||||
idx = (CS.buttons_counter + 1) % 4 # Need to predict the next idx for '22-23 EUV
|
||||
|
||||
@@ -8,7 +8,7 @@ from openpilot.common.conversions import Conversions as CV
|
||||
from openpilot.selfdrive.car import create_button_events, get_safety_config
|
||||
from openpilot.selfdrive.car.gm.radar_interface import RADAR_HEADER_MSG
|
||||
from openpilot.selfdrive.car.gm.values import CAR, CruiseButtons, CarControllerParams, EV_CAR, CAMERA_ACC_CAR, CanBus, GMFlags, CC_ONLY_CAR, SDGM_CAR
|
||||
from openpilot.selfdrive.car.interfaces import CarInterfaceBase, TorqueFromLateralAccelCallbackType, FRICTION_THRESHOLD, LateralAccelFromTorqueCallbackType
|
||||
from openpilot.selfdrive.car.interfaces import CarInterfaceBase, TorqueFromLateralAccelCallbackType, FRICTION_THRESHOLD, LateralAccelFromTorqueCallbackType, get_friction_threshold
|
||||
from openpilot.selfdrive.controls.lib.drive_helpers import get_friction
|
||||
|
||||
ButtonType = car.CarState.ButtonEvent.Type
|
||||
@@ -27,14 +27,18 @@ CAM_MSG = 0x320 # AEBCmd
|
||||
ACCELERATOR_POS_MSG = 0xbe
|
||||
|
||||
NON_LINEAR_TORQUE_PARAMS = {
|
||||
CAR.CHEVROLET_BOLT_EUV: [2.15, 1.0, 0.21, -0.04],
|
||||
CAR.CHEVROLET_BOLT_CC: [2.15, 1.0, 0.21, -0.04],
|
||||
CAR.CHEVROLET_BOLT_EUV: [2.15, 1.0, 0.21, 0.0],
|
||||
CAR.CHEVROLET_BOLT_CC: [2.15, 1.0, 0.21, 0.0],
|
||||
CAR.GMC_ACADIA: [4.78003305, 1.0, 0.3122, 0.05591772],
|
||||
CAR.CHEVROLET_SILVERADO: [3.29974374, 1.0, 0.25571356, 0.0465122]
|
||||
}
|
||||
|
||||
|
||||
class CarInterface(CarInterfaceBase):
|
||||
def __init__(self, CP, FPCP, CarController, CarState):
|
||||
super().__init__(CP, FPCP, CarController, CarState)
|
||||
self.steer_offset = 0.0
|
||||
|
||||
@staticmethod
|
||||
def get_pid_accel_limits(CP, current_speed, cruise_speed):
|
||||
return CarControllerParams.ACCEL_MIN, CarControllerParams.ACCEL_MAX
|
||||
@@ -76,20 +80,28 @@ class CarInterface(CarInterfaceBase):
|
||||
torque_values, lataccel_values = self.get_lataccel_torque_siglin()
|
||||
|
||||
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
|
||||
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:
|
||||
if self.CP.carFingerprint in NON_LINEAR_TORQUE_PARAMS:
|
||||
torque_values, lataccel_values = self.get_lataccel_torque_siglin()
|
||||
|
||||
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
|
||||
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
|
||||
def _get_params(ret, candidate, fingerprint, car_fw, experimental_long, docs, frogpilot_toggles):
|
||||
@@ -97,6 +109,11 @@ class CarInterface(CarInterfaceBase):
|
||||
ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.gm)]
|
||||
ret.autoResumeSng = False
|
||||
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]:
|
||||
ret.enableGasInterceptor = True
|
||||
ret.safetyConfigs[0].safetyParam |= Panda.FLAG_GM_GAS_INTERCEPTOR
|
||||
@@ -165,6 +182,8 @@ class CarInterface(CarInterfaceBase):
|
||||
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.2], [0.00]]
|
||||
ret.lateralTuning.pid.kf = 0.00004 # full torque for 20 deg at 80mph means 0.00007818594
|
||||
ret.steerActuatorDelay = 0.1 # Default delay, not measured yet
|
||||
ret.longitudinalTuning.deadzoneBP = [0.]
|
||||
ret.longitudinalTuning.deadzoneV = [0.]
|
||||
|
||||
ret.steerLimitTimer = 0.4
|
||||
ret.radarTimeStep = 0.0667 # GM radar runs at 15Hz instead of standard 20Hz
|
||||
@@ -205,7 +224,6 @@ class CarInterface(CarInterfaceBase):
|
||||
elif candidate in (CAR.CHEVROLET_BOLT_EUV, CAR.CHEVROLET_BOLT_CC):
|
||||
ret.steerActuatorDelay = 0.2
|
||||
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
|
||||
ret.lateralTuning.torque.kp = 0.8
|
||||
|
||||
if ret.enableGasInterceptor:
|
||||
# ACC Bolts use pedal for full longitudinal control, not just sng
|
||||
@@ -262,7 +280,7 @@ class CarInterface(CarInterfaceBase):
|
||||
elif candidate == CAR.CHEVROLET_TRAX:
|
||||
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
|
||||
|
||||
if ret.enableGasInterceptor:
|
||||
if ret.enableGasInterceptor and frogpilot_toggles.gm_pedal_longitudinal:
|
||||
ret.networkLocation = NetworkLocation.fwdCamera
|
||||
ret.safetyConfigs[0].safetyParam |= Panda.FLAG_GM_HW_CAM
|
||||
ret.minEnableSpeed = -1
|
||||
@@ -277,7 +295,7 @@ class CarInterface(CarInterfaceBase):
|
||||
# Note: Low speed, stop and go not tested. Should be fairly smooth on highway
|
||||
ret.longitudinalTuning.kiBP = [0., 3., 6., 35.]
|
||||
ret.longitudinalTuning.kiV = [0.125, 0.175, 0.225, 0.33]
|
||||
ret.longitudinalTuning.kf = 0.25
|
||||
ret.longitudinalTuning.kfDEPRECATED = 0.25
|
||||
ret.stoppingDecelRate = 0.8
|
||||
else: # Pedal used for SNG, ACC for longitudinal control otherwise
|
||||
ret.safetyConfigs[0].safetyParam |= Panda.FLAG_GM_HW_CAM_LONG
|
||||
@@ -296,9 +314,9 @@ class CarInterface(CarInterfaceBase):
|
||||
|
||||
if not ret.enableGasInterceptor and candidate in CC_ONLY_CAR: #redneck tuning
|
||||
ret.longitudinalTuning.kpBP = [10.7, 10.8, 28.] # 10.7 m/s == 24 mph
|
||||
ret.longitudinalTuning.kpV = [0., 20., 20.] # set lower end to 0 since we can't drive below that speed
|
||||
ret.longitudinalTuning.deadzoneBP = [0.]
|
||||
ret.longitudinalTuning.deadzoneV = [0.56] # == 2 km/h/s, 1.25 mph/s
|
||||
ret.longitudinalTuning.kpV = [0., 5., 2.] # set lower end to 0 since we can't drive below that speed
|
||||
ret.longitudinalTuning.deadzoneBP = [0., 1.]
|
||||
ret.longitudinalTuning.deadzoneV = [0.9, 0.9] # == 2 km/h/s, 1.25 mph/s
|
||||
ret.longitudinalActuatorDelay = 1. # TODO: measure this
|
||||
ret.longitudinalTuning.kiBP = [0.]
|
||||
ret.longitudinalTuning.kiV = [0.1]
|
||||
@@ -351,8 +369,9 @@ class CarInterface(CarInterfaceBase):
|
||||
if ret.vEgo < self.CP.minSteerSpeed:
|
||||
events.add(EventName.belowSteerSpeed)
|
||||
|
||||
if (self.CP.flags & GMFlags.CC_LONG.value) and ret.vEgo < self.CP.minEnableSpeed and ret.cruiseState.enabled:
|
||||
events.add(EventName.speedTooLow)
|
||||
if (self.CP.flags & GMFlags.CC_LONG.value) and ret.vEgo < self.CP.minEnableSpeed:
|
||||
if ret.cruiseState.enabled or self.CS.out.cruiseState.enabled:
|
||||
events.add(EventName.speedTooLow)
|
||||
|
||||
if (self.CP.flags & GMFlags.PEDAL_LONG.value) and \
|
||||
self.CP.transmissionType == TransmissionType.direct and \
|
||||
|
||||
@@ -258,6 +258,8 @@ class GMFlags(IntFlag):
|
||||
CC_LONG = 2
|
||||
NO_CAMERA = 4
|
||||
NO_ACCELERATOR_POS_MSG = 8
|
||||
FORCE_BRAKE_C9 = 16
|
||||
SASCM = 32
|
||||
|
||||
|
||||
# In a Data Module, an identifier is a string used to recognize an object,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import math
|
||||
from collections import namedtuple
|
||||
|
||||
from cereal import car
|
||||
@@ -5,10 +6,12 @@ from openpilot.common.numpy_fast import clip, interp
|
||||
from openpilot.common.realtime import DT_CTRL
|
||||
from opendbc.can.packer import CANPacker
|
||||
from openpilot.selfdrive.car import create_gas_interceptor_command
|
||||
from openpilot.selfdrive.controls.lib.vehicle_model import ACCELERATION_DUE_TO_GRAVITY
|
||||
from openpilot.selfdrive.car.honda import hondacan
|
||||
from openpilot.selfdrive.car.honda.values import CruiseButtons, VISUAL_HUD, HONDA_BOSCH, HONDA_BOSCH_RADARLESS, HONDA_NIDEC_ALT_PCM_ACCEL, CarControllerParams
|
||||
from openpilot.selfdrive.car.interfaces import CarControllerBase
|
||||
from openpilot.selfdrive.controls.lib.drive_helpers import rate_limit
|
||||
from openpilot.selfdrive.controls.lib.pid import PIDController
|
||||
|
||||
VisualAlert = car.CarControl.HUDControl.VisualAlert
|
||||
LongCtrlState = car.CarControl.Actuators.LongControlState
|
||||
@@ -125,6 +128,10 @@ class CarController(CarControllerBase):
|
||||
self.gas = 0.0
|
||||
self.brake = 0.0
|
||||
self.last_steer = 0.0
|
||||
self.pitch = 0.0
|
||||
self.gasonly_pid = PIDController(k_p=([0,], [0,]),
|
||||
k_i=([0., 5., 35.], [1.2, 0.8, 0.5]),
|
||||
rate=1 / DT_CTRL / 2)
|
||||
|
||||
def update(self, CC, CS, now_nanos, frogpilot_toggles):
|
||||
actuators = CC.actuators
|
||||
@@ -133,6 +140,9 @@ class CarController(CarControllerBase):
|
||||
hud_v_cruise = hud_control.setSpeed / conversion if hud_control.speedVisible else 255
|
||||
pcm_cancel_cmd = CC.cruiseControl.cancel
|
||||
|
||||
if len(CC.orientationNED) == 3:
|
||||
self.pitch = CC.orientationNED[1]
|
||||
|
||||
if CC.longActive:
|
||||
accel = actuators.accel
|
||||
gas, brake = compute_gas_brake(actuators.accel, CS.out.vEgo, self.CP.carFingerprint)
|
||||
@@ -173,8 +183,11 @@ class CarController(CarControllerBase):
|
||||
CS.CP.openpilotLongitudinalControl))
|
||||
|
||||
# wind brake from air resistance decel at high speed
|
||||
wind_brake = interp(CS.out.vEgo, [0.0, 2.3, 35.0], [0.001, 0.002, 0.15])
|
||||
wind_brake_ms2 = interp(CS.out.vEgo, [0.0, 13.4, 22.4, 31.3, 40.2], [0.000, 0.049, 0.136, 0.267, 0.441]) # in m/s2 units
|
||||
hill_brake = math.sin(self.pitch) * ACCELERATION_DUE_TO_GRAVITY
|
||||
|
||||
# all of this is only relevant for HONDA NIDEC
|
||||
wind_brake = interp(CS.out.vEgo, [0.0, 2.3, 35.0], [0.001, 0.002, 0.15]) # not in m/s2 units
|
||||
max_accel = interp(CS.out.vEgo, self.params.NIDEC_MAX_ACCEL_BP, self.params.NIDEC_MAX_ACCEL_V)
|
||||
# TODO this 1.44 is just to maintain previous behavior
|
||||
pcm_speed_BP = [-wind_brake,
|
||||
@@ -217,12 +230,25 @@ class CarController(CarControllerBase):
|
||||
|
||||
if self.CP.carFingerprint in HONDA_BOSCH:
|
||||
self.accel = clip(accel, self.params.BOSCH_ACCEL_MIN, self.params.BOSCH_ACCEL_MAX)
|
||||
self.gas = interp(accel, self.params.BOSCH_GAS_LOOKUP_BP, self.params.BOSCH_GAS_LOOKUP_V)
|
||||
|
||||
if self.CP.carFingerprint in HONDA_BOSCH_RADARLESS:
|
||||
gas_pedal_force = self.accel # radarless does not need a pid
|
||||
elif (actuators.longControlState == LongCtrlState.pid) and not CS.out.gasPressed: # perform a gas-only pid
|
||||
gas_error = self.accel - CS.out.aEgo
|
||||
self.gasonly_pid.neg_limit = self.params.BOSCH_ACCEL_MIN
|
||||
self.gasonly_pid.pos_limit = self.params.BOSCH_ACCEL_MAX
|
||||
gas_pedal_force = self.gasonly_pid.update(gas_error, speed=CS.out.vEgo, feedforward=self.accel)
|
||||
gas_pedal_force += wind_brake_ms2 + hill_brake
|
||||
else:
|
||||
gas_pedal_force = self.accel
|
||||
self.gasonly_pid.reset()
|
||||
gas_pedal_force += wind_brake_ms2 + hill_brake
|
||||
self.gas = interp(gas_pedal_force, self.params.BOSCH_GAS_LOOKUP_BP, self.params.BOSCH_GAS_LOOKUP_V)
|
||||
|
||||
stopping = actuators.longControlState == LongCtrlState.stopping
|
||||
self.stopping_counter = self.stopping_counter + 1 if stopping else 0
|
||||
can_sends.extend(hondacan.create_acc_commands(self.packer, self.CAN, CC.enabled, CC.longActive, self.accel, self.gas,
|
||||
self.stopping_counter, self.CP.carFingerprint))
|
||||
self.stopping_counter, self.CP.carFingerprint, accel + wind_brake_ms2 + hill_brake))
|
||||
else:
|
||||
apply_brake = clip(self.brake_last - wind_brake, 0.0, 1.0)
|
||||
apply_brake = int(clip(apply_brake * self.params.NIDEC_BRAKE_MAX, 0, self.params.NIDEC_BRAKE_MAX - 1))
|
||||
|
||||
+18
-12
@@ -37,7 +37,12 @@ EventName = car.CarEvent.EventName
|
||||
MAX_CTRL_SPEED = (V_CRUISE_MAX + 4) * CV.KPH_TO_MS
|
||||
ACCEL_MAX = 2.0
|
||||
ACCEL_MIN = -3.5
|
||||
FRICTION_THRESHOLD = 0.3
|
||||
FRICTION_THRESHOLD = 0.09
|
||||
|
||||
def get_friction_threshold(v_ego):
|
||||
# Interpolate friction threshold from 0.09 at 50 mph to 0.15 at 75 mph
|
||||
from openpilot.common.numpy_fast import interp
|
||||
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_OVERRIDE_PATH = os.path.join(BASEDIR, 'selfdrive/car/torque_data/override.toml')
|
||||
@@ -147,14 +152,22 @@ class CarInterfaceBase(ABC):
|
||||
|
||||
ret = cls._get_params(ret, candidate, fingerprint, car_fw, experimental_long, docs, frogpilot_toggles)
|
||||
|
||||
trailer_load_kg = getattr(frogpilot_toggles, "trailer_load_kg", 0)
|
||||
|
||||
# Vehicle mass is published curb weight plus assumed payload such as a human driver; notCars have no assumed payload
|
||||
if not ret.notCar:
|
||||
ret.mass = ret.mass + trailer_load_kg
|
||||
ret.mass = ret.mass + STD_CARGO_KG
|
||||
|
||||
# Set params dependent on values set by the car interface
|
||||
ret.rotationalInertia = scale_rot_inertia(ret.mass, ret.wheelbase)
|
||||
ret.tireStiffnessFront, ret.tireStiffnessRear = scale_tire_stiffness(ret.mass, ret.wheelbase, ret.centerToFront, ret.tireStiffnessFactor)
|
||||
|
||||
# FrogPilot variables
|
||||
toggles_to_check = ("force_torque_controller", "nnff", "nnff_lite")
|
||||
if ret.steerControlType != car.CarParams.SteerControlType.angle and any(getattr(frogpilot_toggles, toggle, False) for toggle in toggles_to_check):
|
||||
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
|
||||
|
||||
return ret
|
||||
|
||||
@classmethod
|
||||
@@ -174,6 +187,7 @@ class CarInterfaceBase(ABC):
|
||||
|
||||
elif platform in GMCAR:
|
||||
fp_ret.canUsePedal = True
|
||||
fp_ret.canUseSASCM = True
|
||||
|
||||
elif platform in HondaCAR:
|
||||
if candidate == HondaCAR.HONDA_CLARITY:
|
||||
@@ -217,14 +231,6 @@ class CarInterfaceBase(ABC):
|
||||
fp_ret.canUsePedal = not CP.autoResumeSng
|
||||
fp_ret.canUseSDSU = not CP.enableDsu and candidate not in UNSUPPORTED_DSU_CAR and candidate not in TSS2_CAR
|
||||
|
||||
if CP.steerControlType != car.CarParams.SteerControlType.angle:
|
||||
if CP.lateralTuning.which() == "pid" and (frogpilot_toggles.force_torque_controller or frogpilot_toggles.nnff or frogpilot_toggles.nnff_lite):
|
||||
CarInterfaceBase.configure_torque_tune(candidate, fp_ret.lateralTuning)
|
||||
elif CP.lateralTuning.which() == "torque":
|
||||
CarInterfaceBase.configure_torque_tune(candidate, fp_ret.lateralTuning)
|
||||
else:
|
||||
fp_ret.lateralTuning.init("pid")
|
||||
|
||||
fp_ret.openpilotLongitudinalControlDisabled = frogpilot_toggles.disable_openpilot_long
|
||||
|
||||
return fp_ret
|
||||
@@ -286,7 +292,7 @@ class CarInterfaceBase(ABC):
|
||||
ret.vEgoStopping = 0.5
|
||||
ret.vEgoStarting = 0.5
|
||||
ret.stoppingControl = True
|
||||
ret.longitudinalTuning.kf = 1.
|
||||
ret.longitudinalTuning.kfDEPRECATED = 1.
|
||||
ret.longitudinalTuning.kpBP = [0.]
|
||||
ret.longitudinalTuning.kpV = [0.]
|
||||
ret.longitudinalTuning.kiBP = [0.]
|
||||
@@ -302,9 +308,9 @@ class CarInterfaceBase(ABC):
|
||||
|
||||
tune.init('torque')
|
||||
tune.torque.useSteeringAngle = use_steering_angle
|
||||
tune.torque.kf = 1.0
|
||||
tune.torque.kp = 1.0
|
||||
tune.torque.kp = 0.6
|
||||
tune.torque.ki = 0.3
|
||||
tune.torque.kd = 0.0
|
||||
tune.torque.friction = params['FRICTION']
|
||||
tune.torque.latAccelFactor = params['LAT_ACCEL_FACTOR']
|
||||
tune.torque.latAccelOffset = 0.0
|
||||
|
||||
@@ -43,7 +43,7 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"]
|
||||
"CADILLAC_ESCALADE" = [1.899999976158142, 1.842270016670227, 0.1120000034570694]
|
||||
"CADILLAC_ESCALADE_ESV_2019" = [1.15, 1.3, 0.2]
|
||||
"CADILLAC_XT4" = [1.45, 1.6, 0.2]
|
||||
"CHEVROLET_BOLT_EUV" = [2.0, 2.0, 0.05]
|
||||
"CHEVROLET_BOLT_EUV" = [2.0, 2.0, 0.09]
|
||||
"CHEVROLET_MALIBU_CC" = [1.85, 1.85, 0.075]
|
||||
"CHEVROLET_SILVERADO" = [1.9, 1.9, 0.112]
|
||||
"CHEVROLET_TRAILBLAZER" = [1.33, 1.9, 0.16]
|
||||
|
||||
@@ -53,7 +53,7 @@ def get_long_tune(CP, params):
|
||||
kiBP = [2., 5.]
|
||||
kiV = [0.5, 0.25]
|
||||
|
||||
return PIDController(0.0, (kiBP, kiV), k_f=1.0,
|
||||
return PIDController(0.0, (kiBP, kiV),
|
||||
pos_limit=params.ACCEL_MAX, neg_limit=params.ACCEL_MIN,
|
||||
rate=1 / (DT_CTRL * 3))
|
||||
|
||||
|
||||
@@ -29,10 +29,12 @@ from openpilot.selfdrive.controls.lib.latcontrol_angle import LatControlAngle, S
|
||||
from openpilot.selfdrive.controls.lib.latcontrol_torque import LatControlTorque
|
||||
from openpilot.selfdrive.controls.lib.longcontrol import LongControl
|
||||
from openpilot.selfdrive.controls.lib.vehicle_model import VehicleModel
|
||||
from openpilot.frogpilot.tinygrad_modeld.tinygrad_modeld import LAT_SMOOTH_SECONDS
|
||||
|
||||
from openpilot.system.hardware import HARDWARE
|
||||
|
||||
from openpilot.frogpilot.common.frogpilot_variables import get_frogpilot_toggles, params_memory
|
||||
from openpilot.frogpilot.controls.lib.neural_network_feedforward import LatControlNNFF
|
||||
|
||||
SOFT_DISABLE_TIME = 3 # seconds
|
||||
LDW_MIN_SPEED = 31 * CV.MPH_TO_MS
|
||||
@@ -135,11 +137,11 @@ class Controls:
|
||||
|
||||
self.LaC: LatControl
|
||||
if self.CP.steerControlType == car.CarParams.SteerControlType.angle:
|
||||
self.LaC = LatControlAngle(self.CP, self.CI)
|
||||
elif self.FPCP.lateralTuning.which() == 'pid':
|
||||
self.LaC = LatControlPID(self.CP, self.CI)
|
||||
elif self.FPCP.lateralTuning.which() == 'torque':
|
||||
self.LaC = LatControlTorque(self.CP, self.FPCP, self.CI)
|
||||
self.LaC = LatControlAngle(self.CP, self.CI, DT_CTRL)
|
||||
elif self.CP.lateralTuning.which() == 'pid':
|
||||
self.LaC = LatControlPID(self.CP, self.CI, DT_CTRL)
|
||||
elif self.CP.lateralTuning.which() == 'torque':
|
||||
self.LaC = LatControlTorque(self.CP, self.CI, DT_CTRL)
|
||||
|
||||
self.initialized = False
|
||||
self.state = State.disabled
|
||||
@@ -204,6 +206,12 @@ class Controls:
|
||||
|
||||
self.frogpilot_toggles = get_frogpilot_toggles()
|
||||
|
||||
if self.CP.lateralTuning.which() == "torque" and (self.frogpilot_toggles.nnff or self.frogpilot_toggles.nnff_lite):
|
||||
self.LaC = LatControlNNFF(self.CP, self.CI, DT_CTRL)
|
||||
|
||||
|
||||
self.frogpilot_toggles.is_metric = self.is_metric
|
||||
|
||||
def set_initial_state(self):
|
||||
if REPLAY:
|
||||
controls_state = self.params.get("ReplayControlsState")
|
||||
@@ -613,14 +621,36 @@ class Controls:
|
||||
self.curvature = -self.VM.calc_curvature(steer_angle_without_offset, CS.vEgo, lp.roll)
|
||||
|
||||
# Update Torque Params
|
||||
if self.FPCP.lateralTuning.which() == 'torque':
|
||||
if self.CP.lateralTuning.which() == 'torque':
|
||||
torque_params = self.sm['liveTorqueParameters']
|
||||
if self.sm.all_checks(['liveTorqueParameters']) and (torque_params.useParams or self.frogpilot_toggles.force_auto_tune):
|
||||
self.LaC.update_live_torque_params(torque_params.latAccelFactorFiltered, torque_params.latAccelOffsetFiltered,
|
||||
torque_params.frictionCoefficientFiltered)
|
||||
|
||||
if self.sm.updated['liveDelay'] and (self.frogpilot_toggles.nnff or self.frogpilot_toggles.nnff_lite):
|
||||
self.LaC.nnff.update_live_delay(self.sm['liveDelay'].lateralDelay)
|
||||
allow_lat_accel_learning = self.CP.carName in ['toyota', 'hyundai']
|
||||
allow_friction_learning = (allow_lat_accel_learning or self.CP.carName in ['gm'])
|
||||
use_live_params = self.sm.all_checks(['liveTorqueParameters']) and (torque_params.useParams or self.frogpilot_toggles.force_auto_tune)
|
||||
|
||||
# Defaults pulled from manual tuning values
|
||||
lat_accel_factor = self.params.get_float("SteerLatAccel")
|
||||
friction = self.params.get_float("SteerFriction")
|
||||
lat_accel_offset = self.CP.lateralTuning.torque.latAccelOffset
|
||||
|
||||
# Apply user overrides first
|
||||
if self.frogpilot_toggles.use_custom_latAccelFactor:
|
||||
lat_accel_factor = self.frogpilot_toggles.latAccelFactor
|
||||
if self.frogpilot_toggles.use_custom_friction:
|
||||
friction = self.frogpilot_toggles.friction
|
||||
|
||||
# Layer in live values only for parameters the platform allows to learn and only when not overridden
|
||||
if use_live_params:
|
||||
if allow_lat_accel_learning and not self.frogpilot_toggles.use_custom_latAccelFactor:
|
||||
lat_accel_factor = torque_params.latAccelFactorFiltered
|
||||
lat_accel_offset = torque_params.latAccelOffsetFiltered
|
||||
if allow_friction_learning and not self.frogpilot_toggles.use_custom_friction:
|
||||
friction = torque_params.frictionCoefficientFiltered
|
||||
|
||||
self.LaC.update_live_torque_params(lat_accel_factor, lat_accel_offset, friction)
|
||||
|
||||
if self.sm.updated['liveDelay'] and hasattr(self.LaC, "update_live_delay"):
|
||||
self.LaC.update_live_delay(self.sm['liveDelay'].lateralDelay)
|
||||
|
||||
long_plan = self.sm['longitudinalPlan']
|
||||
model_v2 = self.sm['modelV2']
|
||||
@@ -671,11 +701,12 @@ class Controls:
|
||||
# Reset desired curvature to current to avoid violating the limits on engage
|
||||
new_desired_curvature = model_v2.action.desiredCurvature if CC.latActive else self.curvature
|
||||
self.desired_curvature, curvature_limited = clip_curvature(CS.vEgo, self.desired_curvature, new_desired_curvature, lp.roll)
|
||||
lat_delay = self.sm["liveDelay"].lateralDelay + LAT_SMOOTH_SECONDS
|
||||
|
||||
actuators.curvature = self.desired_curvature
|
||||
steer, steeringAngleDeg, lac_log = self.LaC.update(CC.latActive, CS, self.VM, lp,
|
||||
self.steer_limited_by_safety, self.desired_curvature,
|
||||
curvature_limited,
|
||||
curvature_limited, lat_delay,
|
||||
self.sm['liveLocationKalman'],
|
||||
self.sm['modelV2'],
|
||||
self.frogpilot_toggles)
|
||||
@@ -715,8 +746,8 @@ class Controls:
|
||||
desired_lateral_accel = model_v2.action.desiredCurvature * (clipped_speed**2)
|
||||
undershooting = abs(desired_lateral_accel) / abs(1e-3 + actual_lateral_accel) > 1.2
|
||||
turning = abs(desired_lateral_accel) > 1.0
|
||||
# TODO: lac.saturated includes speed and other checks, should be pulled out
|
||||
if undershooting and turning and lac_log.saturated:
|
||||
commanded_torque_at_max = abs(lac_log.output) > 0.99
|
||||
if undershooting and turning and (lac_log.saturated or commanded_torque_at_max):
|
||||
if self.frogpilot_toggles.goat_scream_alert:
|
||||
self.frogpilot_events.add(FrogPilotEventName.goatSteerSaturated)
|
||||
else:
|
||||
@@ -764,7 +795,7 @@ class Controls:
|
||||
if self.frogpilot_toggles.conditional_experimental_mode or self.frogpilot_toggles.slc_fallback_experimental_mode:
|
||||
self.experimental_mode = self.sm['frogpilotPlan'].experimentalMode
|
||||
|
||||
if hasattr(self.LaC, "pid"):
|
||||
if hasattr(self.LaC, "pid") and self.CP.lateralTuning.which() != "pid":
|
||||
self.LaC.pid._k_p = self.frogpilot_toggles.steerKp
|
||||
|
||||
# Update FrogPilot variables
|
||||
@@ -888,7 +919,7 @@ class Controls:
|
||||
controlsState.experimentalMode = self.experimental_mode
|
||||
controlsState.personality = self.personality
|
||||
|
||||
lat_tuning = self.FPCP.lateralTuning.which()
|
||||
lat_tuning = self.CP.lateralTuning.which()
|
||||
if self.joystick_mode:
|
||||
controlsState.lateralControlState.debugState = lac_log
|
||||
elif self.CP.steerControlType == car.CarParams.SteerControlType.angle:
|
||||
|
||||
@@ -189,7 +189,7 @@ def smooth_value(val, prev_val, tau, dt=DT_MDL):
|
||||
alpha = 1 - np.exp(-dt/tau) if tau > 0 else 1
|
||||
return alpha * val + (1 - alpha) * prev_val
|
||||
|
||||
def clip_curvature(v_ego, prev_curvature, new_curvature, roll):
|
||||
def clip_curvature(v_ego, prev_curvature, new_curvature, roll) -> tuple[float, bool]:
|
||||
# This function respects ISO lateral jerk and acceleration limits + a max curvature
|
||||
v_ego = max(v_ego, MIN_SPEED)
|
||||
max_curvature_rate = MAX_LATERAL_JERK / (v_ego ** 2) # inexact calculation, check https://github.com/commaai/openpilot/pull/24755
|
||||
|
||||
@@ -982,7 +982,7 @@ EVENTS: dict[int, dict[str, Alert | AlertCallbackType]] = {
|
||||
"",
|
||||
AlertStatus.normal, AlertSize.full,
|
||||
Priority.LOWEST, VisualAlert.none, AudibleAlert.none, .2, creation_delay=0.5),
|
||||
ET.USER_DISABLE: ImmediateDisableAlert("Reverse Gear"),
|
||||
ET.USER_DISABLE: ImmediateDisableAlert("Wrong Gear"),
|
||||
ET.NO_ENTRY: NoEntryAlert("Reverse Gear"),
|
||||
},
|
||||
|
||||
|
||||
@@ -1,33 +1,31 @@
|
||||
import numpy as np
|
||||
from abc import abstractmethod, ABC
|
||||
|
||||
from openpilot.common.realtime import DT_CTRL
|
||||
|
||||
MIN_LATERAL_CONTROL_SPEED = 0.3 # m/s
|
||||
|
||||
|
||||
class LatControl(ABC):
|
||||
def __init__(self, CP, CI):
|
||||
self.sat_count_rate = 1.0 * DT_CTRL
|
||||
def __init__(self, CP, CI, dt):
|
||||
self.dt = dt
|
||||
self.sat_limit = CP.steerLimitTimer
|
||||
self.sat_count = 0.
|
||||
self.sat_time = 0.
|
||||
self.sat_check_min_speed = 10.
|
||||
|
||||
# we define the steer torque scale as [-1.0...1.0]
|
||||
self.steer_max = 1.0
|
||||
|
||||
@abstractmethod
|
||||
def update(self, active, CS, VM, params, steer_limited_by_safety, desired_curvature, curvature_limited, llk, model_data, frogpilot_toggles):
|
||||
def update(self, active: bool, CS, VM, params, steer_limited_by_safety: bool, desired_curvature: float, curvature_limited: bool, lat_delay: float, llk, model_data, frogpilot_toggles):
|
||||
pass
|
||||
|
||||
def reset(self):
|
||||
self.sat_count = 0.
|
||||
self.sat_time = 0.
|
||||
|
||||
def _check_saturation(self, saturated, CS, steer_limited_by_safety, curvature_limited):
|
||||
# Saturated only if control output is not being limited by car torque/angle rate limits
|
||||
if (saturated or curvature_limited) and CS.vEgo > self.sat_check_min_speed and not steer_limited_by_safety and not CS.steeringPressed:
|
||||
self.sat_count += self.sat_count_rate
|
||||
self.sat_time += self.dt
|
||||
else:
|
||||
self.sat_count -= self.sat_count_rate
|
||||
self.sat_count = np.clip(self.sat_count, 0.0, self.sat_limit)
|
||||
return self.sat_count > (self.sat_limit - 1e-3)
|
||||
self.sat_time -= self.dt
|
||||
self.sat_time = np.clip(self.sat_time, 0.0, self.sat_limit)
|
||||
return self.sat_time > (self.sat_limit - 1e-3)
|
||||
|
||||
@@ -8,12 +8,12 @@ STEER_ANGLE_SATURATION_THRESHOLD = 2.5 # Degrees
|
||||
|
||||
|
||||
class LatControlAngle(LatControl):
|
||||
def __init__(self, CP, CI):
|
||||
super().__init__(CP, CI)
|
||||
def __init__(self, CP, CI, dt):
|
||||
super().__init__(CP, CI, dt)
|
||||
self.sat_check_min_speed = 5.
|
||||
self.use_steer_limited_by_safety = CP.carName == "tesla"
|
||||
|
||||
def update(self, active, CS, VM, params, steer_limited_by_safety, desired_curvature, curvature_limited, 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):
|
||||
angle_log = log.ControlsState.LateralAngleState.new_message()
|
||||
|
||||
if not active:
|
||||
|
||||
@@ -1,19 +1,23 @@
|
||||
import math
|
||||
|
||||
from cereal import log
|
||||
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
|
||||
|
||||
|
||||
class LatControlPID(LatControl):
|
||||
def __init__(self, CP, CI):
|
||||
super().__init__(CP, CI)
|
||||
def __init__(self, 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),
|
||||
(CP.lateralTuning.pid.kiBP, CP.lateralTuning.pid.kiV),
|
||||
k_f=CP.lateralTuning.pid.kf, 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.get_steer_feedforward = CI.get_steer_feedforward_function()
|
||||
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, 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.steeringAngleDeg = float(CS.steeringAngleDeg)
|
||||
pid_log.steeringRateDeg = float(CS.steeringRateDeg)
|
||||
@@ -27,11 +31,17 @@ class LatControlPID(LatControl):
|
||||
if not active:
|
||||
output_torque = 0.0
|
||||
pid_log.active = False
|
||||
self.pid.reset()
|
||||
|
||||
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
|
||||
ff = self.get_steer_feedforward(angle_steers_des_no_offset, CS.vEgo)
|
||||
freeze_integrator = steer_limited_by_safety or CS.steeringPressed or CS.vEgo < 5
|
||||
ff = self.ff_factor * self.get_steer_feedforward(angle_steers_des_no_offset, CS.vEgo)
|
||||
if CS.vEgo < self.low_speed_reset_threshold:
|
||||
self.pid.reset()
|
||||
freeze_integrator = steer_limited_by_safety or CS.steeringPressed or CS.vEgo < self.low_speed_reset_threshold
|
||||
|
||||
output_torque = self.pid.update(error,
|
||||
feedforward=ff,
|
||||
@@ -45,4 +55,6 @@ class LatControlPID(LatControl):
|
||||
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))
|
||||
|
||||
self.prev_steering_pressed = CS.steeringPressed
|
||||
|
||||
return output_torque, angle_steers_des, pid_log
|
||||
|
||||
@@ -1,45 +1,60 @@
|
||||
import math
|
||||
import numpy as np
|
||||
from collections import deque
|
||||
|
||||
from cereal import log
|
||||
from openpilot.selfdrive.controls.lib.drive_helpers import get_friction
|
||||
from openpilot.selfdrive.car.interfaces import FRICTION_THRESHOLD
|
||||
from openpilot.selfdrive.controls.lib.latcontrol import LatControl
|
||||
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.common.filter_simple import FirstOrderFilter
|
||||
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.vehicle_model import ACCELERATION_DUE_TO_GRAVITY
|
||||
|
||||
from openpilot.frogpilot.controls.lib.neural_network_feedforward import LOW_SPEED_Y_NN, NeuralNetworkFeedforward
|
||||
|
||||
# At higher speeds (25+mph) we can assume:
|
||||
# Lateral acceleration achieved by a specific car correlates to
|
||||
# torque applied to the steering rack. It does not correlate to
|
||||
# wheel slip, or to speed.
|
||||
|
||||
# This controller applies torque to achieve desired lateral
|
||||
# accelerations. To compensate for the low speed effects we
|
||||
# use a LOW_SPEED_FACTOR in the error. Additionally, there is
|
||||
# friction in the steering wheel that needs to be overcome to
|
||||
# move it at all, this is compensated for too.
|
||||
# accelerations. To compensate for the low speed effects the
|
||||
# proportional gain is increased at low speeds by the PID controller.
|
||||
# Additionally, there is friction in the steering wheel that needs
|
||||
# to be overcome to move it at all, this is compensated for too.
|
||||
|
||||
KP = 0.6
|
||||
KI = 0.3
|
||||
|
||||
INTERP_SPEEDS = [1, 1.5, 2.0, 3.0, 5, 7.5, 10, 15, 30]
|
||||
KP_INTERP = [250, 120, 65, 30, 11.5, 5.5, 3.5, 2.0, KP]
|
||||
|
||||
LOW_SPEED_X = [0, 10, 20, 30]
|
||||
LOW_SPEED_Y = [15, 13, 10, 5]
|
||||
LOW_SPEED_Y = [12, 10.5, 8, 5]
|
||||
MAX_LAT_JERK_UP = 2.5 # m/s^3
|
||||
|
||||
LP_FILTER_CUTOFF_HZ = 1.2
|
||||
JERK_LOOKAHEAD_SECONDS = 0.19
|
||||
JERK_GAIN = 0.22
|
||||
LAT_ACCEL_REQUEST_BUFFER_SECONDS = 1.0
|
||||
VERSION = 2
|
||||
|
||||
class LatControlTorque(LatControl):
|
||||
def __init__(self, CP, FPCP, CI):
|
||||
super().__init__(CP, CI)
|
||||
self.torque_params = FPCP.lateralTuning.torque
|
||||
def __init__(self, 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_from_lateral_accel = CI.torque_from_lateral_accel()
|
||||
self.lateral_accel_from_torque = CI.lateral_accel_from_torque()
|
||||
self.pid = PIDController(self.torque_params.kp, self.torque_params.ki,
|
||||
k_f=self.torque_params.kf)
|
||||
self.pid = PIDController([INTERP_SPEEDS, KP_INTERP], KI, rate=1/self.dt)
|
||||
self.update_limits()
|
||||
self.steering_angle_deadzone_deg = self.torque_params.steeringAngleDeadzoneDeg
|
||||
|
||||
# FrogPilot variables
|
||||
self.nnff = NeuralNetworkFeedforward(CP, self)
|
||||
|
||||
self.nnff_loaded = self.nnff.lat_torque_nn_model != None
|
||||
self.lat_accel_request_buffer_len = int(LAT_ACCEL_REQUEST_BUFFER_SECONDS / self.dt)
|
||||
self.lat_accel_request_buffer = deque([0.] * self.lat_accel_request_buffer_len , maxlen=self.lat_accel_request_buffer_len)
|
||||
self.lookahead_frames = int(JERK_LOOKAHEAD_SECONDS / self.dt)
|
||||
self.jerk_filter = FirstOrderFilter(0.0, 1 / (2 * np.pi * LP_FILTER_CUTOFF_HZ), self.dt)
|
||||
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.low_speed_reset_threshold = max(CP.minSteerSpeed, MIN_LATERAL_CONTROL_SPEED)
|
||||
|
||||
def update_live_torque_params(self, latAccelFactor, latAccelOffset, friction):
|
||||
self.torque_params.latAccelFactor = latAccelFactor
|
||||
@@ -51,50 +66,57 @@ class LatControlTorque(LatControl):
|
||||
self.pid.set_limits(self.lateral_accel_from_torque(self.steer_max, self.torque_params),
|
||||
self.lateral_accel_from_torque(-self.steer_max, self.torque_params))
|
||||
|
||||
def update(self, active, CS, VM, params, steer_limited_by_safety, desired_curvature, curvature_limited, 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.LateralTorqueState.new_message()
|
||||
pid_log.version = VERSION
|
||||
if not active:
|
||||
output_torque = 0.0
|
||||
pid_log.active = False
|
||||
self.pid.reset()
|
||||
self.previous_measurement = 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)
|
||||
else:
|
||||
actual_curvature = -VM.calc_curvature(math.radians(CS.steeringAngleDeg - params.angleOffsetDeg), CS.vEgo, params.roll)
|
||||
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)
|
||||
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))
|
||||
|
||||
desired_lateral_accel = desired_curvature * CS.vEgo ** 2
|
||||
actual_lateral_accel = actual_curvature * CS.vEgo ** 2
|
||||
lateral_accel_deadzone = curvature_deadzone * CS.vEgo ** 2
|
||||
|
||||
low_speed_factor = np.interp(CS.vEgo, LOW_SPEED_X, LOW_SPEED_Y_NN if frogpilot_toggles.nnff else LOW_SPEED_Y)**2
|
||||
setpoint = desired_lateral_accel + low_speed_factor * desired_curvature
|
||||
measurement = actual_lateral_accel + low_speed_factor * actual_curvature
|
||||
gravity_adjusted_lateral_accel = desired_lateral_accel - roll_compensation
|
||||
delay_frames = int(np.clip(lat_delay / self.dt, 1, self.lat_accel_request_buffer_len))
|
||||
expected_lateral_accel = self.lat_accel_request_buffer[-delay_frames]
|
||||
future_desired_lateral_accel = desired_curvature * CS.vEgo ** 2
|
||||
self.lat_accel_request_buffer.append(future_desired_lateral_accel)
|
||||
raw_lateral_jerk = (future_desired_lateral_accel - expected_lateral_accel) / max(lat_delay, self.dt)
|
||||
raw_lateral_jerk = np.clip(raw_lateral_jerk, -MAX_LAT_JERK_UP, MAX_LAT_JERK_UP)
|
||||
desired_lateral_jerk = np.clip(self.jerk_filter.update(raw_lateral_jerk), -MAX_LAT_JERK_UP, MAX_LAT_JERK_UP)
|
||||
gravity_adjusted_future_lateral_accel = future_desired_lateral_accel - roll_compensation
|
||||
setpoint = expected_lateral_accel + desired_lateral_jerk * lat_delay
|
||||
|
||||
if self.nnff_loaded and frogpilot_toggles.nnff or frogpilot_toggles.nnff_lite:
|
||||
pid_log, ff = self.nnff.compute_nnff(
|
||||
CS, VM, actual_lateral_accel, desired_lateral_accel, gravity_adjusted_lateral_accel, lateral_accel_deadzone,
|
||||
llk, measurement, model_data, params, pid_log, roll_compensation, setpoint, frogpilot_toggles
|
||||
)
|
||||
measurement = measured_curvature * CS.vEgo ** 2
|
||||
measurement_rate = self.measurement_rate_filter.update((measurement - self.previous_measurement) / self.dt)
|
||||
measurement_rate = np.clip(measurement_rate, -MAX_LAT_JERK_UP, MAX_LAT_JERK_UP)
|
||||
self.previous_measurement = measurement
|
||||
|
||||
freeze_integrator = steer_limited_by_safety or CS.steeringPressed or CS.vEgo < 5
|
||||
output_torque = self.pid.update(pid_log.error,
|
||||
feedforward=ff,
|
||||
speed=CS.vEgo,
|
||||
freeze_integrator=freeze_integrator)
|
||||
else:
|
||||
# do error correction in lateral acceleration space, convert at end to handle non-linear torque responses correctly
|
||||
pid_log.error = float(setpoint - measurement)
|
||||
ff = gravity_adjusted_lateral_accel
|
||||
# latAccelOffset corrects roll compensation bias from device roll misalignment relative to car roll
|
||||
ff -= self.torque_params.latAccelOffset
|
||||
ff += get_friction(desired_lateral_accel - actual_lateral_accel, lateral_accel_deadzone, FRICTION_THRESHOLD, self.torque_params)
|
||||
low_speed_factor = (np.interp(CS.vEgo, LOW_SPEED_X, LOW_SPEED_Y) / max(CS.vEgo, MIN_SPEED)) ** 2
|
||||
current_kp = np.interp(CS.vEgo, self.pid._k_p[0], self.pid._k_p[1])
|
||||
error = setpoint - measurement
|
||||
error_with_lsf = error * (1 + low_speed_factor / max(current_kp, 1e-3))
|
||||
|
||||
freeze_integrator = steer_limited_by_safety or CS.steeringPressed or CS.vEgo < 5
|
||||
output_lataccel = self.pid.update(pid_log.error,
|
||||
feedforward=ff,
|
||||
speed=CS.vEgo,
|
||||
freeze_integrator=freeze_integrator)
|
||||
output_torque = self.torque_from_lateral_accel(output_lataccel, self.torque_params)
|
||||
# do error correction in lateral acceleration space, convert at end to handle non-linear torque responses correctly
|
||||
pid_log.error = float(error_with_lsf)
|
||||
ff = gravity_adjusted_future_lateral_accel
|
||||
# latAccelOffset corrects roll compensation bias from device roll misalignment relative to car roll
|
||||
ff -= self.torque_params.latAccelOffset
|
||||
ff += get_friction(error_with_lsf + JERK_GAIN * desired_lateral_jerk, lateral_accel_deadzone, get_friction_threshold(CS.vEgo), self.torque_params)
|
||||
|
||||
if CS.vEgo < self.low_speed_reset_threshold:
|
||||
self.pid.reset()
|
||||
freeze_integrator = steer_limited_by_safety or CS.steeringPressed or CS.vEgo < self.low_speed_reset_threshold
|
||||
output_lataccel = self.pid.update(pid_log.error, error_rate=-measurement_rate, speed=CS.vEgo, feedforward=ff, freeze_integrator=freeze_integrator)
|
||||
output_torque = self.torque_from_lateral_accel(output_lataccel, self.torque_params)
|
||||
|
||||
pid_log.active = True
|
||||
pid_log.p = float(self.pid.p)
|
||||
@@ -102,9 +124,12 @@ class LatControlTorque(LatControl):
|
||||
pid_log.d = float(self.pid.d)
|
||||
pid_log.f = float(self.pid.f)
|
||||
pid_log.output = float(-output_torque) # TODO: log lat accel?
|
||||
pid_log.actualLateralAccel = float(actual_lateral_accel)
|
||||
pid_log.desiredLateralAccel = float(desired_lateral_accel)
|
||||
pid_log.actualLateralAccel = float(measurement)
|
||||
pid_log.desiredLateralAccel = float(setpoint)
|
||||
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))
|
||||
|
||||
self.prev_steering_pressed = CS.steeringPressed
|
||||
|
||||
# TODO left is positive in this convention
|
||||
return -output_torque, 0.0, pid_log
|
||||
|
||||
@@ -92,10 +92,13 @@ class LongControl:
|
||||
self.CP = CP
|
||||
self.long_control_state = LongCtrlState.off
|
||||
self.experimental_mode = False
|
||||
pos_p_limit = 0.0 # if params("NoPositivePResponse") else None # put parameter-based control here
|
||||
self.pid = PIDController((CP.longitudinalTuning.kpBP, CP.longitudinalTuning.kpV),
|
||||
(CP.longitudinalTuning.kiBP, CP.longitudinalTuning.kiV),
|
||||
k_f=CP.longitudinalTuning.kf, rate=1 / DT_CTRL,
|
||||
pos_p_limit=None)
|
||||
rate=1 / DT_CTRL, pos_p_limit=pos_p_limit)
|
||||
# Preserve legacy behaviour when no feedforward gain is provided (default of 0.0)
|
||||
kf = getattr(CP.longitudinalTuning, 'kfDEPRECATED', 0.0)
|
||||
self.feedforward_gain = kf if kf != 0.0 else 1.0
|
||||
self.v_pid = 0.0
|
||||
self._mode_setup()
|
||||
self.last_output_accel = 0.0
|
||||
@@ -104,7 +107,7 @@ class LongControl:
|
||||
|
||||
def update_mpc_mode(self, experimental_mode):
|
||||
new_mode = 'blended' if experimental_mode else 'acc'
|
||||
|
||||
|
||||
if self.transitioning and self.prev_mode == 'blended' and self.current_mode == 'acc':
|
||||
self.mode_transition_timer = 0.0
|
||||
|
||||
@@ -158,9 +161,10 @@ class LongControl:
|
||||
else: # LongCtrlState.pid
|
||||
error = a_target - CS.aEgo
|
||||
self.update_mpc_mode(self.experimental_mode)
|
||||
raw_output_accel = self.pid.update(error, speed=CS.vEgo, feedforward=a_target)
|
||||
feedforward = a_target * self.feedforward_gain
|
||||
raw_output_accel = self.pid.update(error, speed=CS.vEgo, feedforward=feedforward)
|
||||
|
||||
|
||||
|
||||
if self.transitioning and self.prev_mode == 'acc' and self.current_mode == 'blended':
|
||||
if raw_output_accel < 0 and raw_output_accel < self.last_output_accel:
|
||||
progress = min(1.0, self.mode_transition_timer / self.mode_transition_duration)
|
||||
@@ -171,9 +175,29 @@ class LongControl:
|
||||
blend_factor = 1.0 - (1.0 - progress) * (1.0 - urgency_smooth)
|
||||
output_accel = self.last_output_accel + (raw_output_accel - self.last_output_accel) * blend_factor
|
||||
else:
|
||||
output_accel = raw_output_accel
|
||||
output_accel = raw_output_accel
|
||||
else:
|
||||
output_accel = raw_output_accel
|
||||
output_accel = raw_output_accel
|
||||
|
||||
if self.long_control_state == LongCtrlState.pid:
|
||||
# Smooth acceleration and deceleration with urgency-based rate limiting
|
||||
base_rate = 1.0
|
||||
|
||||
if output_accel < self.last_output_accel: # Deceleration requested
|
||||
decel_needed = self.last_output_accel - output_accel
|
||||
# Use a safe default for ACCEL_MIN if not available, to prevent division by zero
|
||||
max_decel = abs(CarControllerParams.ACCEL_MIN) if CarControllerParams.ACCEL_MIN != 0 else 4.0
|
||||
urgency = min(1.0, decel_needed / max_decel)
|
||||
|
||||
# Adjust rate based on urgency (1.0 m/s^3 for low urgency, up to 4.0 m/s^3 for high urgency)
|
||||
max_rate = 1.0 + 3.0 * urgency
|
||||
else:
|
||||
max_rate = base_rate # Acceleration is always smooth
|
||||
|
||||
max_accel_change = max_rate * DT_CTRL
|
||||
output_accel = clip(output_accel,
|
||||
self.last_output_accel - max_accel_change,
|
||||
self.last_output_accel + max_accel_change)
|
||||
|
||||
self.last_output_accel = clip(output_accel, accel_limits[0], accel_limits[1])
|
||||
return self.last_output_accel
|
||||
@@ -235,8 +259,9 @@ class LongControl:
|
||||
|
||||
error = self.v_pid - CS.vEgo
|
||||
error_deadzone = apply_deadzone(error, deadzone)
|
||||
feedforward = a_target * self.feedforward_gain
|
||||
output_accel = self.pid.update(error_deadzone, speed=CS.vEgo,
|
||||
feedforward=a_target,
|
||||
feedforward=feedforward,
|
||||
freeze_integrator=freeze_integrator)
|
||||
|
||||
self.last_output_accel = clip(output_accel, accel_limits[0], accel_limits[1])
|
||||
|
||||
@@ -5,7 +5,6 @@ import numpy as np
|
||||
from cereal import log
|
||||
from openpilot.common.numpy_fast import clip, interp
|
||||
from openpilot.common.realtime import DT_MDL
|
||||
from openpilot.common.swaglog import cloudlog
|
||||
from openpilot.common.filter_simple import FirstOrderFilter
|
||||
from openpilot.common.conversions import Conversions as CV
|
||||
# WARNING: imports outside of constants will not trigger a rebuild
|
||||
@@ -302,6 +301,9 @@ class LongitudinalMpc:
|
||||
self.current_filter_time = LEAD_FILTER_TIME_LOW
|
||||
self.lead_a_filter = FirstOrderFilter(0.0, self.current_filter_time, self.dt)
|
||||
self.lead_v_filter = FirstOrderFilter(0.0, self.current_filter_time, self.dt)
|
||||
# Slew-limited filter factor to avoid abrupt 0.50↔1.00 jumps
|
||||
self.filter_time_factor = 1.0
|
||||
self.slew_per_sec = 1.0
|
||||
# Instance variables to avoid global modifications
|
||||
self.current_x_ego_cost = X_EGO_OBSTACLE_COSTS[0]
|
||||
self.current_j_ego_cost = J_EGO_COSTS[0]
|
||||
@@ -357,7 +359,9 @@ class LongitudinalMpc:
|
||||
for i in range(N):
|
||||
self.solver.cost_set(i, 'Zl', Zl)
|
||||
|
||||
def set_weights(self, acceleration_jerk=1.0, danger_jerk=1.0, speed_jerk=1.0, prev_accel_constraint=True, personality=log.LongitudinalPersonality.standard, v_ego=0.0, lead_dist=50.0):
|
||||
def set_weights(self, acceleration_jerk=1.0, danger_jerk=1.0, speed_jerk=1.0, prev_accel_constraint=True,
|
||||
personality=log.LongitudinalPersonality.standard, v_ego=0.0, lead_dist=50.0,
|
||||
uncertainty=0.0, accel_reengage=False, panic_bypass=False):
|
||||
# Update parameters based on current speed with interpolation for smooth scaling
|
||||
speed_mph = v_ego * CV.MS_TO_MPH # Convert m/s to mph
|
||||
|
||||
@@ -371,10 +375,10 @@ class LongitudinalMpc:
|
||||
self.current_dist_adapt = get_speed_based_param(speed_mph, dist_adapt_array)
|
||||
|
||||
# Update filter time constants with interp and recreate filters if needed
|
||||
if speed_mph < 35:
|
||||
if speed_mph < 47:
|
||||
self.current_filter_time = 0.0
|
||||
else:
|
||||
self.current_filter_time = interp(speed_mph, [35, 45], [0.0, LEAD_FILTER_TIME_HIGH])
|
||||
self.current_filter_time = interp(speed_mph, [47, 65], [0.0, LEAD_FILTER_TIME_HIGH])
|
||||
if abs(self.current_filter_time - getattr(self, 'prev_filter_time', 0)) > 0.1: # Only update if significant change
|
||||
# Recreate filters with new time constant while preserving current values
|
||||
current_a = self.lead_a_filter.x if hasattr(self.lead_a_filter, 'x') else 0.0
|
||||
@@ -389,6 +393,34 @@ class LongitudinalMpc:
|
||||
danger_jerk *= dist_factor
|
||||
speed_jerk *= dist_factor
|
||||
|
||||
# Scene complexity adjustment based on model uncertainty
|
||||
prev_filter_time_factor = getattr(self, 'prev_filter_time_factor', 1.0)
|
||||
# Target factor from uncertainty
|
||||
if uncertainty <= 0.45:
|
||||
tgt_factor = 1.0
|
||||
elif uncertainty >= 0.70:
|
||||
tgt_factor = 0.0
|
||||
else:
|
||||
tgt_factor = float(np.interp(uncertainty, [0.45, 0.70], [1.0, 0.30]))
|
||||
|
||||
if accel_reengage:
|
||||
tgt_factor = min(tgt_factor, 0.5)
|
||||
|
||||
# Hard bypass of smoothing when approaching fast or magnitude trips
|
||||
if panic_bypass:
|
||||
tgt_factor = 0.0
|
||||
|
||||
# Slew-limit changes to avoid step-wise filter jumps
|
||||
max_step = self.slew_per_sec * self.dt
|
||||
delta = np.clip(tgt_factor - self.filter_time_factor, -max_step, max_step)
|
||||
self.filter_time_factor += float(delta)
|
||||
filter_time_factor = float(self.filter_time_factor)
|
||||
|
||||
# When uncertainty is moderately elevated, allow accel but cap jerk by increasing jerk cost
|
||||
if 0.45 <= uncertainty < 0.60:
|
||||
scale = float(np.interp(uncertainty, [0.45, 0.60], [1.2, 1.5]))
|
||||
speed_jerk *= scale
|
||||
|
||||
if self.mode == 'acc':
|
||||
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]
|
||||
@@ -401,6 +433,15 @@ class LongitudinalMpc:
|
||||
raise NotImplementedError(f'Planner mode {self.mode} not recognized in planner cost set')
|
||||
self.set_cost_weights(cost_weights, constraint_cost_weights)
|
||||
|
||||
# Adjust filter time constants for complex scenes
|
||||
if abs(filter_time_factor - getattr(self, 'prev_filter_time_factor', 1.0)) > 0.05:
|
||||
current_a = self.lead_a_filter.x if hasattr(self.lead_a_filter, 'x') else 0.0
|
||||
current_v = self.lead_v_filter.x if hasattr(self.lead_v_filter, 'x') else 0.0
|
||||
new_filter_time = self.current_filter_time * filter_time_factor
|
||||
self.lead_a_filter = FirstOrderFilter(current_a, new_filter_time, self.dt)
|
||||
self.lead_v_filter = FirstOrderFilter(current_v, new_filter_time, self.dt)
|
||||
self.prev_filter_time_factor = filter_time_factor
|
||||
|
||||
def set_cur_state(self, v, a):
|
||||
v_prev = self.x0[1]
|
||||
self.x0[1] = v
|
||||
@@ -582,11 +623,7 @@ class LongitudinalMpc:
|
||||
|
||||
self.prev_a = np.interp(T_IDXS + self.dt, T_IDXS, self.a_solution)
|
||||
|
||||
t = time.monotonic()
|
||||
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()
|
||||
# reset = 1
|
||||
# print(f"long_mpc timings: total internal {self.solve_time:.2e}, external: {(time.monotonic() - t0):.2e} qp {self.time_qp_solution:.2e}, \
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#!/usr/bin/env python3
|
||||
import math
|
||||
import numpy as np
|
||||
import time
|
||||
from openpilot.common.numpy_fast import clip, interp
|
||||
|
||||
import cereal.messaging as messaging
|
||||
@@ -16,13 +17,17 @@ from openpilot.selfdrive.controls.lib.drive_helpers import V_CRUISE_UNSET, CONTR
|
||||
from openpilot.common.swaglog import cloudlog
|
||||
|
||||
LON_MPC_STEP = 0.2 # first step is 0.2s
|
||||
A_CRUISE_MIN = -1.2
|
||||
A_CRUISE_MAX_VALS = [1.6, 1.2, 0.8, 0.6]
|
||||
A_CRUISE_MAX_BP = [0., 10.0, 25., 40.]
|
||||
A_CRUISE_MIN = -1.0
|
||||
A_CRUISE_MAX_BP = [0.0, 5., 10., 15., 20., 25., 40.]
|
||||
A_CRUISE_MAX_VALS = [1.125, 1.125, 1.125, 1.125, 1.25, 1.25, 1.5]
|
||||
CONTROL_N_T_IDX = ModelConstants.T_IDXS[:CONTROL_N]
|
||||
ALLOW_THROTTLE_THRESHOLD = 0.5
|
||||
MIN_ALLOW_THROTTLE_SPEED = 2.5
|
||||
|
||||
# Uncertainty-based filter disable thresholds
|
||||
UNCERT_SLOPE_TRIG = 0.12 # per second
|
||||
UNCERT_MAG_TRIG = 0.50
|
||||
|
||||
# Lookup table for turns
|
||||
_A_TOTAL_MAX_V = [1.7, 3.2]
|
||||
_A_TOTAL_MAX_BP = [20., 40.]
|
||||
@@ -107,9 +112,30 @@ class LongitudinalPlanner:
|
||||
self.j_desired_trajectory = np.zeros(CONTROL_N)
|
||||
self.solverExecutionTime = 0.0
|
||||
|
||||
# ---- Rubberband mitigation state ----
|
||||
# Two uncertainty tracks (slow/fast) for asymmetric gating
|
||||
self.uncert_slow = FirstOrderFilter(0.0, 1.6, self.dt) # ~lam=0.6
|
||||
self.uncert_fast = FirstOrderFilter(0.0, 0.9, self.dt) # faster cool-down for accel decisions
|
||||
# Lead stability tracking
|
||||
self.prev_lead_dist = None
|
||||
self.last_big_brake_t = 0.0
|
||||
self.stable_lead = False
|
||||
# Temporary accel nudge window
|
||||
self.accel_nudge_until = 0.0
|
||||
|
||||
# Hysteresis gate + dwell for accel re-engage and smoothed lead distance
|
||||
self.accel_gate = False
|
||||
self._t_arm = 0.0
|
||||
self._t_disarm = 0.0
|
||||
self.lead_dist_f = None
|
||||
|
||||
# Uncertainty slope tracking
|
||||
self._uncert_last = 0.0
|
||||
self._uncert_last_t = None
|
||||
|
||||
@property
|
||||
def mlsim(self):
|
||||
return self.generation in ("v8", "v10", "v11")
|
||||
return self.generation in ("v8", "v10", "v11", "v12")
|
||||
|
||||
def get_mpc_mode(self) -> str:
|
||||
"""
|
||||
@@ -199,6 +225,7 @@ class LongitudinalPlanner:
|
||||
x, v, a, j, throttle_prob = self.parse_model(sm['modelV2'], self.v_model_error, v_ego, frogpilot_toggles.taco_tune)
|
||||
# Don't clip at low speeds since throttle_prob doesn't account for creep
|
||||
self.allow_throttle = throttle_prob > ALLOW_THROTTLE_THRESHOLD or v_ego <= MIN_ALLOW_THROTTLE_SPEED
|
||||
self.allow_throttle &= not sm['frogpilotPlan'].disableThrottle
|
||||
|
||||
if not self.allow_throttle:
|
||||
clipped_accel_coast = max(accel_coast, accel_limits_turns[0])
|
||||
@@ -215,8 +242,145 @@ class LongitudinalPlanner:
|
||||
self.lead_two = sm['radarState'].leadTwo
|
||||
|
||||
lead_dist = self.lead_one.dRel if self.lead_one.status else 50.0
|
||||
self.mpc.set_weights(sm['frogpilotPlan'].accelerationJerk, sm['frogpilotPlan'].dangerJerk, sm['frogpilotPlan'].speedJerk, prev_accel_constraint,
|
||||
personality=sm['controlsState'].personality, v_ego=v_ego, lead_dist=lead_dist)
|
||||
|
||||
# Smooth lead distance (EMA) to avoid chatter in thresholds
|
||||
alpha = max(0.02, min(0.15, 0.05 + 0.002 * v_ego))
|
||||
if self.lead_dist_f is None:
|
||||
self.lead_dist_f = float(lead_dist)
|
||||
else:
|
||||
self.lead_dist_f += alpha * (float(lead_dist) - self.lead_dist_f)
|
||||
|
||||
# Lead stability estimation and recent-brake timer
|
||||
now_t = time.monotonic()
|
||||
# relative speed (ego - lead) positive when closing
|
||||
v_rel = (v_ego - self.lead_one.vLead) if self.lead_one.status else 0.0
|
||||
if self.prev_lead_dist is None:
|
||||
d_rel_dot = 0.0
|
||||
else:
|
||||
d_rel_dot = (lead_dist - self.prev_lead_dist) / max(self.dt, 1e-3)
|
||||
self.prev_lead_dist = lead_dist
|
||||
|
||||
# Remember time of last non-trivial model brake risk
|
||||
if 'raw_brake_max' in locals() and raw_brake_max is not None and raw_brake_max > 0.02:
|
||||
self.last_big_brake_t = now_t
|
||||
|
||||
# Stable lead heuristic (short window, cheap to compute)
|
||||
recently_braked = (now_t - self.last_big_brake_t) < 0.7
|
||||
self.stable_lead = (
|
||||
self.lead_one.status and
|
||||
abs(v_rel) < 0.5 and
|
||||
abs(d_rel_dot) < 0.5 and
|
||||
not recently_braked
|
||||
)
|
||||
|
||||
# Calculate scene uncertainty from model desire prediction entropy and disengage predictions
|
||||
uncertainty = 0.0
|
||||
if hasattr(sm['modelV2'], 'meta'):
|
||||
# Desire prediction entropy (maneuver uncertainty), normalized to [0, 1]
|
||||
desire_entropy = 0.0
|
||||
if hasattr(sm['modelV2'].meta, 'desirePrediction'):
|
||||
desire_probs = sm['modelV2'].meta.desirePrediction
|
||||
if len(desire_probs) > 1:
|
||||
probs = np.asarray(desire_probs, dtype=float)
|
||||
total = float(np.sum(probs))
|
||||
if total > 1e-6:
|
||||
p = probs / total
|
||||
entropy = -np.sum(p * np.log(p + 1e-10))
|
||||
max_entropy = np.log(len(p))
|
||||
desire_entropy = float(entropy / max(max_entropy, 1e-6)) # normalized entropy in [0,1]
|
||||
else:
|
||||
desire_entropy = 0.0 # guard against all-zero vector
|
||||
|
||||
# Disengage prediction risk (intervention likelihood)
|
||||
disengage_risk = 0.0
|
||||
raw_brake_max = -1.0
|
||||
lam = -1.0
|
||||
if hasattr(sm['modelV2'].meta, 'disengagePredictions'):
|
||||
# Use brake press probabilities as primary risk indicator
|
||||
brake_probs = sm['modelV2'].meta.disengagePredictions.brakePressProbs
|
||||
if len(brake_probs) > 0:
|
||||
# Exponentially decayed max over the full horizon
|
||||
probs = np.asarray(brake_probs, dtype=float)
|
||||
# Clip tiny brake blips so they don't inflate uncertainty
|
||||
if float(np.max(probs)) < 0.015:
|
||||
probs = probs * 0.5
|
||||
raw_brake_max = float(np.max(probs))
|
||||
# Time vector assuming model horizon step = DT_MDL
|
||||
t = np.arange(len(probs), dtype=float) * DT_MDL
|
||||
lam = 0.6 # decay rate per second (tunable: 0.5–0.9 typical)
|
||||
weights = np.exp(-lam * t)
|
||||
disengage_risk = float(np.max(probs * weights))
|
||||
|
||||
# Combined uncertainty metric (range roughly 0..2), with dual-track filtering
|
||||
raw_uncertainty = desire_entropy + disengage_risk
|
||||
# Update filters
|
||||
self.uncert_slow.update(raw_uncertainty)
|
||||
self.uncert_fast.update(raw_uncertainty)
|
||||
# Use a more permissive track for accel decisions
|
||||
uncertainty = self.uncert_slow.x
|
||||
uncertainty_accel = min(self.uncert_slow.x, self.uncert_fast.x)
|
||||
|
||||
# --- Slope-based panic bypass ---
|
||||
if self._uncert_last_t is None:
|
||||
uncert_slope = 0.0
|
||||
else:
|
||||
dt_u = max(1e-3, now_t - self._uncert_last_t)
|
||||
uncert_slope = (uncertainty - self._uncert_last) / dt_u
|
||||
self._uncert_last = uncertainty
|
||||
self._uncert_last_t = now_t
|
||||
|
||||
closing_fast = (self.lead_one.status and (v_ego - self.lead_one.vLead) > 0.5)
|
||||
# Trigger if either slope is high or magnitude is high; require a valid lead and closing
|
||||
panic_bypass = closing_fast and (uncert_slope > UNCERT_SLOPE_TRIG or uncertainty >= UNCERT_MAG_TRIG)
|
||||
|
||||
if panic_bypass:
|
||||
try:
|
||||
cloudlog.error(f"LON_SLOPE; slope={uncert_slope:.3f}/s; uncertainty={uncertainty:.3f}; v_ego={v_ego:.2f}; v_rel={(v_ego - self.lead_one.vLead) if self.lead_one.status else 0.0:.2f}; lead_dist={self.lead_dist_f if self.lead_dist_f is not None else -1:.2f}; trigger=True")
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# now_t defined earlier
|
||||
over = uncertainty > 1.0
|
||||
|
||||
# Asymmetric accel release with hysteresis + dwell to prevent on/off pulsing
|
||||
rise_dwell_s, fall_dwell_s = 0.6, 0.4
|
||||
good = (
|
||||
(self.a_desired > 0.0) and
|
||||
self.stable_lead and
|
||||
(uncertainty <= 0.425) and
|
||||
(desire_entropy < 0.41)
|
||||
)
|
||||
|
||||
# dwell timers for robust gating
|
||||
if good and not self.accel_gate:
|
||||
if now_t - self._t_arm >= rise_dwell_s:
|
||||
self.accel_gate = True
|
||||
else:
|
||||
self._t_arm = now_t
|
||||
|
||||
if (not good) and self.accel_gate:
|
||||
if now_t - self._t_disarm >= fall_dwell_s:
|
||||
self.accel_gate = False
|
||||
else:
|
||||
self._t_disarm = now_t
|
||||
|
||||
if self.accel_gate:
|
||||
# Ensure some positive headroom for MPC to exit coasting
|
||||
accel_limits_turns[1] = max(accel_limits_turns[1], 0.2)
|
||||
# Short self-canceling nudge to unstick (applied post-MPC)
|
||||
if now_t > self.accel_nudge_until:
|
||||
self.accel_nudge_until = now_t + 0.45
|
||||
|
||||
self.mpc.set_weights(sm['frogpilotPlan'].accelerationJerk,
|
||||
sm['frogpilotPlan'].dangerJerk,
|
||||
sm['frogpilotPlan'].speedJerk,
|
||||
prev_accel_constraint,
|
||||
personality=sm['controlsState'].personality,
|
||||
v_ego=v_ego,
|
||||
lead_dist=self.lead_dist_f if self.lead_dist_f is not None else lead_dist,
|
||||
uncertainty=uncertainty,
|
||||
accel_reengage=self.accel_gate,
|
||||
panic_bypass=panic_bypass)
|
||||
self.mpc.set_accel_limits(accel_limits_turns[0], accel_limits_turns[1])
|
||||
self.mpc.set_cur_state(self.v_desired_filter.x, self.a_desired)
|
||||
# After deciding the MPC mode via get_mpc_mode(), ensure MPC uses that mode when not mlsim
|
||||
@@ -249,6 +413,27 @@ class LongitudinalPlanner:
|
||||
self.a_desired = float(interp(self.dt, CONTROL_N_T_IDX, self.a_desired_trajectory))
|
||||
self.v_desired_filter.x = self.v_desired_filter.x + self.dt * (self.a_desired + a_prev) / 2.0
|
||||
|
||||
# Anticipatory pre-brake to avoid "coming in hot" when closing on a lead
|
||||
if self.lead_one.status:
|
||||
rel_v = max(0.0, v_ego - self.lead_one.vLead)
|
||||
# dynamic time headway adds a small buffer when uncertainty is elevated
|
||||
base_th = 1.6
|
||||
th = base_th + 0.6 * max(0.0, uncertainty - 0.42)
|
||||
desired_gap = th * v_ego
|
||||
if (self.lead_dist_f is not None and self.lead_dist_f < desired_gap and rel_v > 0.5):
|
||||
k_rel, k_unc = 0.04, 0.20
|
||||
pre_brake = k_rel * rel_v + k_unc * max(0.0, uncertainty - 0.42)
|
||||
pre_brake = min(pre_brake, 0.06)
|
||||
self.a_desired = float(self.a_desired - pre_brake)
|
||||
|
||||
# Apply tiny feed-forward nudge when released and safe
|
||||
if now_t < self.accel_nudge_until and self.a_desired > -0.1:
|
||||
self.a_desired = float(min(self.a_desired + 0.12, get_max_accel(v_ego)))
|
||||
|
||||
# Small deadzone around zero accel to kill micro-dithers
|
||||
if -0.05 < self.a_desired < 0.05:
|
||||
self.a_desired = 0.0
|
||||
|
||||
def publish(self, classic_model, tinygrad_model, sm, pm, frogpilot_toggles):
|
||||
plan_send = messaging.new_message('longitudinalPlan')
|
||||
|
||||
|
||||
@@ -1,17 +1,11 @@
|
||||
import numpy as np
|
||||
from numbers import Number
|
||||
|
||||
from openpilot.common.numpy_fast import clip, interp
|
||||
|
||||
|
||||
class PIDController:
|
||||
def __init__(self, k_p, k_i, k_f=0., k_d=0.,
|
||||
pos_limit=1e308, neg_limit=-1e308, rate=100,
|
||||
pos_p_limit=None, neg_p_limit=None):
|
||||
def __init__(self, k_p, k_i, k_d=0., pos_limit=1e308, neg_limit=-1e308, rate=100, pos_p_limit=None, neg_p_limit=None):
|
||||
self._k_p = k_p
|
||||
self._k_i = k_i
|
||||
self._k_d = k_d
|
||||
self.k_f = k_f # feedforward gain
|
||||
if isinstance(self._k_p, Number):
|
||||
self._k_p = [[0], [self._k_p]]
|
||||
if isinstance(self._k_i, Number):
|
||||
@@ -19,37 +13,24 @@ class PIDController:
|
||||
if isinstance(self._k_d, Number):
|
||||
self._k_d = [[0], [self._k_d]]
|
||||
|
||||
self.pos_limit = pos_limit
|
||||
self.neg_limit = neg_limit
|
||||
self.set_limits(pos_limit, neg_limit)
|
||||
|
||||
self.pos_p_limit = pos_p_limit
|
||||
self.neg_p_limit = neg_p_limit
|
||||
|
||||
self.i_unwind_rate = 0.3 / rate
|
||||
self.i_rate = 1.0 / rate
|
||||
self.i_dt = 1.0 / rate
|
||||
self.speed = 0.0
|
||||
|
||||
self.reset()
|
||||
|
||||
@property
|
||||
def k_p(self):
|
||||
return interp(self.speed, self._k_p[0], self._k_p[1])
|
||||
return np.interp(self.speed, self._k_p[0], self._k_p[1])
|
||||
|
||||
@property
|
||||
def k_i(self):
|
||||
return interp(self.speed, self._k_i[0], self._k_i[1])
|
||||
return np.interp(self.speed, self._k_i[0], self._k_i[1])
|
||||
|
||||
@property
|
||||
def k_d(self):
|
||||
return interp(self.speed, self._k_d[0], self._k_d[1])
|
||||
|
||||
@property
|
||||
def error_integral(self):
|
||||
return self.i/self.k_i
|
||||
|
||||
def set_limits(self, pos_limit, neg_limit):
|
||||
self.pos_limit = pos_limit
|
||||
self.neg_limit = neg_limit
|
||||
return np.interp(self.speed, self._k_d[0], self._k_d[1])
|
||||
|
||||
def reset(self):
|
||||
self.p = 0.0
|
||||
@@ -58,29 +39,25 @@ class PIDController:
|
||||
self.f = 0.0
|
||||
self.control = 0
|
||||
|
||||
def update(self, error, error_rate=0.0, speed=0.0, override=False, feedforward=0., freeze_integrator=False):
|
||||
def set_limits(self, pos_limit, neg_limit):
|
||||
self.pos_limit = pos_limit
|
||||
self.neg_limit = neg_limit
|
||||
|
||||
def update(self, error, error_rate=0.0, speed=0.0, feedforward=0., freeze_integrator=False):
|
||||
self.speed = speed
|
||||
self.p = self.k_p * float(error)
|
||||
self.d = self.k_d * error_rate
|
||||
self.f = feedforward
|
||||
|
||||
self.p = float(error) * self.k_p
|
||||
if self.pos_p_limit is not None and self.p > self.pos_p_limit:
|
||||
self.p = self.pos_p_limit
|
||||
elif self.neg_p_limit is not None and self.p < self.neg_p_limit:
|
||||
self.p = self.neg_p_limit
|
||||
self.f = feedforward * self.k_f
|
||||
self.d = error_rate * self.k_d
|
||||
if not freeze_integrator:
|
||||
i = self.i + self.k_i * self.i_dt * error
|
||||
|
||||
if override:
|
||||
self.i -= self.i_unwind_rate * float(np.sign(self.i))
|
||||
else:
|
||||
if not freeze_integrator:
|
||||
self.i = self.i + error * self.k_i * self.i_rate
|
||||
|
||||
# Clip i to prevent exceeding control limits
|
||||
control_no_i = self.p + self.d + self.f
|
||||
control_no_i = clip(control_no_i, self.neg_limit, self.pos_limit)
|
||||
self.i = clip(self.i, self.neg_limit - control_no_i, self.pos_limit - control_no_i)
|
||||
# Don't allow windup if already clipping
|
||||
test_control = self.p + i + self.d + self.f
|
||||
i_upperbound = self.i if test_control > self.pos_limit else self.pos_limit
|
||||
i_lowerbound = self.i if test_control < self.neg_limit else self.neg_limit
|
||||
self.i = np.clip(i, i_lowerbound, i_upperbound)
|
||||
|
||||
control = self.p + self.i + self.d + self.f
|
||||
|
||||
self.control = clip(control, self.neg_limit, self.pos_limit)
|
||||
self.control = np.clip(control, self.neg_limit, self.pos_limit)
|
||||
return self.control
|
||||
|
||||
@@ -16,6 +16,7 @@ from openpilot.common.swaglog import cloudlog
|
||||
from openpilot.common.simple_kalman import KF1D
|
||||
|
||||
from openpilot.frogpilot.common.frogpilot_variables import THRESHOLD, get_frogpilot_toggles
|
||||
from openpilot.selfdrive.controls.controlsd import LaneChangeDirection, LaneChangeState
|
||||
|
||||
# Default lead acceleration decay set to 50% at 1s
|
||||
_LEAD_ACCEL_TAU = 0.6
|
||||
@@ -149,7 +150,15 @@ def laplacian_pdf(x: float, mu: float, b: float):
|
||||
return math.exp(-abs(x-mu)/b)
|
||||
|
||||
|
||||
def match_vision_to_track(v_ego: float, lead: capnp._DynamicStructReader, tracks: dict[int, Track]):
|
||||
def match_vision_to_track(v_ego: float, lead: capnp._DynamicStructReader, model_data: capnp._DynamicStructReader, tracks: dict[int, Track], frogpilot_toggles: SimpleNamespace):
|
||||
if model_data.meta.laneChangeState == LaneChangeState.laneChangeStarting and frogpilot_toggles.human_lane_changes:
|
||||
direction = model_data.meta.laneChangeDirection
|
||||
|
||||
if direction == LaneChangeDirection.left:
|
||||
tracks = {k: v for k, v in tracks.items() if v.yRel > 0}
|
||||
elif direction == LaneChangeDirection.right:
|
||||
tracks = {k: v for k, v in tracks.items() if v.yRel < 0}
|
||||
|
||||
offset_vision_dist = lead.x[0] - RADAR_TO_CAMERA
|
||||
|
||||
def prob(c):
|
||||
@@ -194,11 +203,11 @@ def get_RadarState_from_vision(lead_msg: capnp._DynamicStructReader, v_ego: floa
|
||||
|
||||
def get_lead(v_ego: float, ready: bool, tracks: dict[int, Track], lead_msg: capnp._DynamicStructReader,
|
||||
model_v_ego: float, model_data: capnp._DynamicStructReader, standstill: bool,
|
||||
frogpilot_toggles: SimpleNamespace, frogpilotPlan: capnp._DynamicStructReader,
|
||||
frogpilotPlan: capnp._DynamicStructReader, frogpilot_toggles: SimpleNamespace,
|
||||
low_speed_override: bool = True) -> dict[str, Any]:
|
||||
# Determine leads, this is where the essential logic happens
|
||||
if len(tracks) > 0 and ready and lead_msg.prob > frogpilot_toggles.lead_detection_probability:
|
||||
track = match_vision_to_track(v_ego, lead_msg, tracks)
|
||||
track = match_vision_to_track(v_ego, lead_msg, model_data, tracks, frogpilot_toggles)
|
||||
else:
|
||||
track = None
|
||||
|
||||
@@ -315,8 +324,8 @@ class RadarD:
|
||||
model_v_ego = self.v_ego
|
||||
leads_v3 = sm['modelV2'].leadsV3
|
||||
if len(leads_v3) > 1:
|
||||
self.radar_state.leadOne = get_lead(self.v_ego, self.ready, self.tracks, leads_v3[0], model_v_ego, sm['modelV2'], sm['carState'].standstill, self.frogpilot_toggles, sm['frogpilotPlan'], low_speed_override=True)
|
||||
self.radar_state.leadTwo = get_lead(self.v_ego, self.ready, self.tracks, leads_v3[1], model_v_ego, sm['modelV2'], sm['carState'].standstill, self.frogpilot_toggles, sm['frogpilotPlan'], low_speed_override=False)
|
||||
self.radar_state.leadOne = get_lead(self.v_ego, self.ready, self.tracks, leads_v3[0], model_v_ego, sm['modelV2'], sm['carState'].standstill, sm['frogpilotPlan'], self.frogpilot_toggles, low_speed_override=True)
|
||||
self.radar_state.leadTwo = get_lead(self.v_ego, self.ready, self.tracks, leads_v3[1], model_v_ego, sm['modelV2'], sm['carState'].standstill, sm['frogpilotPlan'], self.frogpilot_toggles, low_speed_override=False)
|
||||
|
||||
if self.frogpilot_toggles.adjacent_lead_tracking and self.ready:
|
||||
self.frogpilot_radar_state.leadLeft = get_adjacent_lead(self.tracks, sm['carState'].standstill, sm['modelV2'], left=True)
|
||||
|
||||
@@ -135,7 +135,7 @@ def main():
|
||||
CP = msg
|
||||
cloudlog.info("paramsd got CarParams")
|
||||
|
||||
min_sr, max_sr = 0.5 * CP.steerRatio, 2.0 * CP.steerRatio
|
||||
min_sr, max_sr = 0.25 * CP.steerRatio, 2.0 * CP.steerRatio
|
||||
|
||||
params = params_reader.get("LiveParameters")
|
||||
|
||||
@@ -187,8 +187,6 @@ def main():
|
||||
# FrogPilot variables
|
||||
frogpilot_toggles = get_frogpilot_toggles()
|
||||
|
||||
with custom.FrogPilotCarParams.from_bytes(params_reader.get("FrogPilotCarParams", block=True)) as msg:
|
||||
FPCP = msg
|
||||
|
||||
while True:
|
||||
sm.update()
|
||||
@@ -240,7 +238,7 @@ def main():
|
||||
0.2 <= liveParameters.stiffnessFactor <= 5.0,
|
||||
min_sr <= liveParameters.steerRatio <= max_sr,
|
||||
))
|
||||
if CP.carFingerprint == "RAM_HD" or CP.carName == "subaru" and FPCP.lateralTuning.which() == "torque":
|
||||
if CP.carFingerprint == "RAM_HD" or CP.carName == "subaru" and CP.lateralTuning.which() == "torque":
|
||||
liveParameters.valid = True
|
||||
liveParameters.steerRatioStd = float(P[States.STEER_RATIO].item())
|
||||
liveParameters.stiffnessFactorStd = float(P[States.STIFFNESS].item())
|
||||
|
||||
@@ -34,7 +34,8 @@ MIN_BUCKET_POINTS = np.array([100, 300, 500, 500, 500, 500, 300, 100])
|
||||
MIN_ENGAGE_BUFFER = 2 # secs
|
||||
|
||||
VERSION = 1 # bump this to invalidate old parameter caches
|
||||
ALLOWED_CARS = ['toyota', 'hyundai']
|
||||
FULL_AUTO_CARS = ['toyota', 'hyundai']
|
||||
FRICTION_ONLY_CARS = ['gm']
|
||||
|
||||
|
||||
def slope2rot(slope):
|
||||
@@ -52,7 +53,7 @@ class TorqueBuckets(PointBuckets):
|
||||
|
||||
|
||||
class TorqueEstimator(ParameterEstimator):
|
||||
def __init__(self, CP, FPCP, decimated=False):
|
||||
def __init__(self, CP, decimated=False):
|
||||
self.hist_len = int(HISTORY / DT_MDL)
|
||||
self.lag = 0.0
|
||||
if decimated:
|
||||
@@ -72,11 +73,14 @@ class TorqueEstimator(ParameterEstimator):
|
||||
self.offline_friction = 0.0
|
||||
self.offline_latAccelFactor = 0.0
|
||||
self.resets = 0.0
|
||||
self.use_params = CP.carName in ALLOWED_CARS and FPCP.lateralTuning.which() == 'torque'
|
||||
self.allow_lat_accel_learning = CP.carName in FULL_AUTO_CARS and CP.lateralTuning.which() == 'torque'
|
||||
self.allow_friction_learning = (self.allow_lat_accel_learning or CP.carName in FRICTION_ONLY_CARS) \
|
||||
and CP.lateralTuning.which() == 'torque'
|
||||
self.use_params = self.allow_friction_learning
|
||||
|
||||
if FPCP.lateralTuning.which() == 'torque':
|
||||
self.offline_friction = FPCP.lateralTuning.torque.friction
|
||||
self.offline_latAccelFactor = FPCP.lateralTuning.torque.latAccelFactor
|
||||
if CP.lateralTuning.which() == 'torque':
|
||||
self.offline_friction = CP.lateralTuning.torque.friction
|
||||
self.offline_latAccelFactor = CP.lateralTuning.torque.latAccelFactor
|
||||
|
||||
self.reset()
|
||||
|
||||
@@ -102,13 +106,13 @@ class TorqueEstimator(ParameterEstimator):
|
||||
cache_ltp = log_evt.liveTorqueParameters
|
||||
with car.CarParams.from_bytes(params_cache) as msg:
|
||||
cache_CP = msg
|
||||
if self.get_restore_key(cache_CP, FPCP, cache_ltp.version) == self.get_restore_key(CP, FPCP, VERSION):
|
||||
if self.get_restore_key(cache_CP, cache_ltp.version) == self.get_restore_key(CP, VERSION):
|
||||
if cache_ltp.liveValid:
|
||||
initial_params = {
|
||||
'latAccelFactor': cache_ltp.latAccelFactorFiltered,
|
||||
'latAccelOffset': cache_ltp.latAccelOffsetFiltered,
|
||||
'frictionCoefficient': cache_ltp.frictionCoefficientFiltered
|
||||
}
|
||||
if self.allow_lat_accel_learning:
|
||||
initial_params['latAccelFactor'] = cache_ltp.latAccelFactorFiltered
|
||||
initial_params['latAccelOffset'] = cache_ltp.latAccelOffsetFiltered
|
||||
if self.allow_friction_learning:
|
||||
initial_params['frictionCoefficient'] = cache_ltp.frictionCoefficientFiltered
|
||||
initial_params['points'] = cache_ltp.points
|
||||
self.decay = cache_ltp.decay
|
||||
self.filtered_points.load_points(initial_params['points'])
|
||||
@@ -121,12 +125,12 @@ class TorqueEstimator(ParameterEstimator):
|
||||
for param in initial_params:
|
||||
self.filtered_params[param] = FirstOrderFilter(initial_params[param], self.decay, DT_MDL)
|
||||
|
||||
def get_restore_key(self, CP, FPCP, version):
|
||||
def get_restore_key(self, CP, version):
|
||||
a, b = None, None
|
||||
if FPCP.lateralTuning.which() == 'torque':
|
||||
a = FPCP.lateralTuning.torque.friction
|
||||
b = FPCP.lateralTuning.torque.latAccelFactor
|
||||
return (CP.carFingerprint, FPCP.lateralTuning.which(), a, b, version)
|
||||
if CP.lateralTuning.which() == 'torque':
|
||||
a = CP.lateralTuning.torque.friction
|
||||
b = CP.lateralTuning.torque.latAccelFactor
|
||||
return (CP.carFingerprint, CP.lateralTuning.which(), a, b, version)
|
||||
|
||||
def reset(self):
|
||||
self.resets += 1.0
|
||||
@@ -155,6 +159,10 @@ class TorqueEstimator(ParameterEstimator):
|
||||
def update_params(self, params):
|
||||
self.decay = min(self.decay + DT_MDL, MAX_FILTER_DECAY)
|
||||
for param, value in params.items():
|
||||
if param.startswith('latAccel') and not self.allow_lat_accel_learning:
|
||||
continue
|
||||
if param == 'frictionCoefficient' and not self.allow_friction_learning:
|
||||
continue
|
||||
self.filtered_params[param].update(value)
|
||||
self.filtered_params[param].update_alpha(self.decay)
|
||||
|
||||
@@ -227,14 +235,14 @@ def main(demo=False):
|
||||
sm = messaging.SubMaster(['carControl', 'carOutput', 'carState', 'liveLocationKalman', 'liveDelay', 'frogpilotPlan'], poll='liveLocationKalman')
|
||||
|
||||
params = Params()
|
||||
with car.CarParams.from_bytes(params.get("CarParams", block=True)) as CP, custom.FrogPilotCarParams.from_bytes(params.get("FrogPilotCarParams", block=True)) as FPCP:
|
||||
estimator = TorqueEstimator(CP, FPCP)
|
||||
with car.CarParams.from_bytes(params.get("CarParams", block=True)) as CP:
|
||||
estimator = TorqueEstimator(CP)
|
||||
|
||||
# FrogPilot variables
|
||||
frogpilot_toggles = get_frogpilot_toggles()
|
||||
|
||||
if not frogpilot_toggles.liveValid:
|
||||
estimator = TorqueEstimator(CP, FPCP, decimated=True)
|
||||
estimator = TorqueEstimator(CP, decimated=True)
|
||||
|
||||
while True:
|
||||
sm.update()
|
||||
|
||||
@@ -33,12 +33,10 @@ class DRIVER_MONITOR_SETTINGS:
|
||||
self._SG_THRESHOLD = 0.9
|
||||
self._BLINK_THRESHOLD = 0.865
|
||||
|
||||
self._EE_THRESH11 = 0.25
|
||||
self._EE_THRESH12 = 7.5
|
||||
self._EE_THRESH11 = 0.6
|
||||
self._EE_THRESH12 = 15.0
|
||||
self._EE_MAX_OFFSET1 = 0.06
|
||||
self._EE_MIN_OFFSET1 = 0.025
|
||||
self._EE_THRESH21 = 0.01
|
||||
self._EE_THRESH22 = 0.35
|
||||
|
||||
self._POSE_PITCH_THRESHOLD = 0.3133
|
||||
self._POSE_PITCH_THRESHOLD_SLACK = 0.3237
|
||||
@@ -46,9 +44,9 @@ class DRIVER_MONITOR_SETTINGS:
|
||||
self._POSE_YAW_THRESHOLD = 0.4020
|
||||
self._POSE_YAW_THRESHOLD_SLACK = 0.5042
|
||||
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._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_MIN_OFFSET = -0.0881
|
||||
self._YAW_MAX_OFFSET = 0.289
|
||||
@@ -57,7 +55,7 @@ class DRIVER_MONITOR_SETTINGS:
|
||||
self._POSESTD_THRESHOLD = 0.3
|
||||
self._HI_STD_FALLBACK_TIME = int(10 / self._DT_DMON) # fall back to wheel touch if model is uncertain for 10s
|
||||
self._DISTRACTED_FILTER_TS = 0.25 # 0.6Hz
|
||||
self._ALWAYS_ON_ALERT_MIN_SPEED = 7
|
||||
self._ALWAYS_ON_ALERT_MIN_SPEED = 11
|
||||
|
||||
self._POSE_CALIB_MIN_SPEED = 13 # 30 mph
|
||||
self._POSE_OFFSET_MIN_COUNT = int(60 / self._DT_DMON) # valid data counts before calibration completes, 1min cumulative
|
||||
@@ -136,11 +134,8 @@ class DriverMonitoring:
|
||||
self.pose = DriverPose(self.settings._POSE_OFFSET_MAX_COUNT)
|
||||
self.blink = DriverBlink()
|
||||
self.eev1 = 0.
|
||||
self.eev2 = 1.
|
||||
self.ee1_offseter = RunningStatFilter(max_trackable=self.settings._POSE_OFFSET_MAX_COUNT)
|
||||
self.ee2_offseter = RunningStatFilter(max_trackable=self.settings._POSE_OFFSET_MAX_COUNT)
|
||||
self.ee1_calibrated = False
|
||||
self.ee2_calibrated = False
|
||||
|
||||
self.always_on = always_on
|
||||
self.distracted_types = []
|
||||
@@ -258,7 +253,7 @@ class DriverMonitoring:
|
||||
driver_data = driver_state.rightDriverData if self.wheel_on_right else driver_state.leftDriverData
|
||||
if not all(len(x) > 0 for x in (driver_data.faceOrientation, driver_data.facePosition,
|
||||
driver_data.faceOrientationStd, driver_data.facePositionStd,
|
||||
driver_data.readyProb, driver_data.notReadyProb)):
|
||||
driver_data.notReadyProb)):
|
||||
return
|
||||
|
||||
self.face_detected = driver_data.faceProb > self.settings._FACE_THRESHOLD
|
||||
@@ -275,7 +270,6 @@ class DriverMonitoring:
|
||||
self.blink.right = driver_data.rightBlinkProb * (driver_data.rightEyeProb > self.settings._EYE_THRESHOLD) \
|
||||
* (driver_data.sunglassesProb < self.settings._SG_THRESHOLD)
|
||||
self.eev1 = driver_data.notReadyProb[0]
|
||||
self.eev2 = driver_data.readyProb[0]
|
||||
|
||||
self.distracted_types = self._get_distracted_types()
|
||||
self.driver_distracted = (DistractedType.DISTRACTED_E2E in self.distracted_types or DistractedType.DISTRACTED_POSE in self.distracted_types
|
||||
@@ -289,12 +283,10 @@ class DriverMonitoring:
|
||||
self.pose.pitch_offseter.push_and_update(self.pose.pitch)
|
||||
self.pose.yaw_offseter.push_and_update(self.pose.yaw)
|
||||
self.ee1_offseter.push_and_update(self.eev1)
|
||||
self.ee2_offseter.push_and_update(self.eev2)
|
||||
|
||||
self.pose.calibrated = self.pose.pitch_offseter.filtered_stat.n > self.settings._POSE_OFFSET_MIN_COUNT and \
|
||||
self.pose.yaw_offseter.filtered_stat.n > self.settings._POSE_OFFSET_MIN_COUNT
|
||||
self.ee1_calibrated = self.ee1_offseter.filtered_stat.n > self.settings._POSE_OFFSET_MIN_COUNT
|
||||
self.ee2_calibrated = self.ee2_offseter.filtered_stat.n > self.settings._POSE_OFFSET_MIN_COUNT
|
||||
|
||||
self.is_model_uncertain = self.hi_stds > self.settings._HI_STD_FALLBACK_TIME
|
||||
self._set_timers(self.face_detected and not self.is_model_uncertain)
|
||||
|
||||
@@ -24,8 +24,6 @@ def make_msg(face_detected, distracted=False, model_uncertain=False):
|
||||
ds.leftDriverData.rightBlinkProb = 1. * distracted
|
||||
ds.leftDriverData.faceOrientationStd = [1.*model_uncertain, 1.*model_uncertain, 1.*model_uncertain]
|
||||
ds.leftDriverData.facePositionStd = [1.*model_uncertain, 1.*model_uncertain]
|
||||
# TODO: test both separately when e2e is used
|
||||
ds.leftDriverData.readyProb = [0., 0., 0., 0.]
|
||||
ds.leftDriverData.notReadyProb = [0., 0.]
|
||||
return ds
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -32,7 +32,6 @@ SoftwarePanel::SoftwarePanel(QWidget* parent) : ListWidget(parent) {
|
||||
// automatic updates toggle
|
||||
ParamControl *automaticUpdatesToggle = new ParamControl("AutomaticUpdates", tr("Automatically Update FrogPilot"),
|
||||
tr("FrogPilot will automatically update itself and it's assets when you're offroad and have an active internet connection."), "");
|
||||
automaticUpdatesToggle->setVisible(params.getBool("IsReleaseBranch"));
|
||||
addItem(automaticUpdatesToggle);
|
||||
|
||||
// download update btn
|
||||
|
||||
@@ -433,6 +433,26 @@
|
||||
</context>
|
||||
<context>
|
||||
<name>ExpandableMultiOptionDialog</name>
|
||||
<message>
|
||||
<source>Sort by:</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Alphabetical</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Date (Newest)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Date (Oldest)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Favorites First</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Select</source>
|
||||
<translation type="unfinished">اختيار</translation>
|
||||
@@ -441,6 +461,10 @@
|
||||
<source>Cancel</source>
|
||||
<translation type="unfinished">إلغاء</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>%1 (Community Fav)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ExperimentalModeButton</name>
|
||||
@@ -1175,6 +1199,22 @@
|
||||
<source><b>Twilsonco's torque-based adjustments to smoothen out steering in curves.</b></source>
|
||||
<translation type="gpt-5-generated"><b>تعديلات Twilsonco المعتمدة على العزم لتنعيم التوجيه في المنعطفات.</b></translation>
|
||||
</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><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.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reset <b>Steer Offset</b> to its default value?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FrogPilotLongitudinalPanel</name>
|
||||
@@ -2086,6 +2126,42 @@
|
||||
<source><b>Following behavior that mimics human drivers</b> by closing gaps behind faster vehicles for quicker takeoffs and dynamically adjusting the desired following distance for gentler, more efficient braking.</source>
|
||||
<translation type="gpt-5-generated"><b>سلوك متابعة يحاكي السائقين البشر</b> عبر تقليل الفجوات خلف المركبات الأسرع لانطلاق أسرع وضبط مسافة المتابعة المطلوبة ديناميكياً لكبح ألطف وأكثر كفاءة.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>EV Tuning</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>Use acceleration profiles tuned for EVs.</b> Defaults to the vehicle's detected powertrain type but can be overridden if the automatic choice doesn't match.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>High Speed Following Distance</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>How many seconds openpilot follows behind lead vehicles when using the "Aggressive" profile at high speeds.</b> Increase for more space; decrease for tighter gaps.<br><br>Default: 1.25 seconds.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>How many seconds openpilot follows behind lead vehicles when using the "Standard" profile at high speeds.</b> Increase for more space; decrease for tighter gaps.<br><br>Default: 1.45 seconds.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>How many seconds openpilot follows behind lead vehicles when using the "Relaxed" profile at high speeds.</b> Increase for more space; decrease for tighter gaps.<br><br>Default: 1.75 seconds.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Trailer Load</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>Increase the vehicle mass to account for towing.</b> Adjust in 500 lb steps up to 15,000 lbs to fine-tune gas and brake behavior when pulling a trailer.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source> lbs</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FrogPilotManageControl</name>
|
||||
@@ -2503,6 +2579,14 @@
|
||||
<source>Driving models are chosen at random each drive and feedback prompts are used to find the model that best suits your needs.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Recovery Power</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Adjust the strength of planplus lane recovery corrections (0.5 to 2.0).</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Stop Distance</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@@ -2523,6 +2607,10 @@
|
||||
<source>Select the active driving model.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Custom Series</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>There are no more models to blacklist! The only available model is "%1"!</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@@ -2552,13 +2640,17 @@
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to reset your <b>Stop Distance</b> to the default of 6 meters?</source>
|
||||
<source>Are you sure you want to reset your <b>Recovery Power</b> to the default of 1.0?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reset</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to reset your <b>Stop Distance</b> to the default of 6 meters?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FrogPilotModelReview</name>
|
||||
@@ -3714,6 +3806,22 @@ Developer - Highly customizable settings for seasoned enthusiasts</source>
|
||||
<source>comma Pedal Support</source>
|
||||
<translation type="gpt-5-generated">دعم comma Pedal</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Use Pedal for Longitudinal Control</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>Use the pedal interceptor for longitudinal control</b> instead of camera ACC/Redneck when available.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>SASCM Support</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>Does your vehicle support "SASCMs"?</b></source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FrogPilotVisualsPanel</name>
|
||||
|
||||
@@ -434,6 +434,26 @@
|
||||
</context>
|
||||
<context>
|
||||
<name>ExpandableMultiOptionDialog</name>
|
||||
<message>
|
||||
<source>Sort by:</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Alphabetical</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Date (Newest)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Date (Oldest)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Favorites First</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Select</source>
|
||||
<translation type="unfinished">Pick</translation>
|
||||
@@ -442,6 +462,10 @@
|
||||
<source>Cancel</source>
|
||||
<translation type="unfinished">Stop</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>%1 (Community Fav)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ExperimentalModeButton</name>
|
||||
@@ -1176,6 +1200,22 @@
|
||||
<source><b>Twilsonco's torque-based adjustments to smoothen out steering in curves.</b></source>
|
||||
<translation type="gpt-5-generated"><b>Twilsonco make torque tweak. Steering smooth in curve.</b></translation>
|
||||
</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><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.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reset <b>Steer Offset</b> to its default value?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FrogPilotLongitudinalPanel</name>
|
||||
@@ -2088,6 +2128,42 @@
|
||||
<source><b>Following behavior that mimics human drivers</b> by closing gaps behind faster vehicles for quicker takeoffs and dynamically adjusting the desired following distance for gentler, more efficient braking.</source>
|
||||
<translation type="gpt-5-generated"><b>Make car follow like human</b>. Close gap behind fast car for quick takeoff. Change follow distance on the fly for soft, smart brake.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>EV Tuning</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>Use acceleration profiles tuned for EVs.</b> Defaults to the vehicle's detected powertrain type but can be overridden if the automatic choice doesn't match.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>High Speed Following Distance</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>How many seconds openpilot follows behind lead vehicles when using the "Aggressive" profile at high speeds.</b> Increase for more space; decrease for tighter gaps.<br><br>Default: 1.25 seconds.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>How many seconds openpilot follows behind lead vehicles when using the "Standard" profile at high speeds.</b> Increase for more space; decrease for tighter gaps.<br><br>Default: 1.45 seconds.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>How many seconds openpilot follows behind lead vehicles when using the "Relaxed" profile at high speeds.</b> Increase for more space; decrease for tighter gaps.<br><br>Default: 1.75 seconds.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Trailer Load</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>Increase the vehicle mass to account for towing.</b> Adjust in 500 lb steps up to 15,000 lbs to fine-tune gas and brake behavior when pulling a trailer.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source> lbs</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FrogPilotManageControl</name>
|
||||
@@ -2505,6 +2581,14 @@
|
||||
<source>Driving models are chosen at random each drive and feedback prompts are used to find the model that best suits your needs.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Recovery Power</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Adjust the strength of planplus lane recovery corrections (0.5 to 2.0).</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Stop Distance</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@@ -2525,6 +2609,10 @@
|
||||
<source>Select the active driving model.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Custom Series</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>There are no more models to blacklist! The only available model is "%1"!</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@@ -2554,13 +2642,17 @@
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to reset your <b>Stop Distance</b> to the default of 6 meters?</source>
|
||||
<source>Are you sure you want to reset your <b>Recovery Power</b> to the default of 1.0?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reset</source>
|
||||
<translation type="unfinished">Reset</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to reset your <b>Stop Distance</b> to the default of 6 meters?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FrogPilotModelReview</name>
|
||||
@@ -3718,6 +3810,22 @@ Developer - Many custom setting for seasoned enthusiast</translation>
|
||||
<source>comma Pedal Support</source>
|
||||
<translation type="gpt-5-generated">comma Pedal Help</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Use Pedal for Longitudinal Control</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>Use the pedal interceptor for longitudinal control</b> instead of camera ACC/Redneck when available.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>SASCM Support</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>Does your vehicle support "SASCMs"?</b></source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FrogPilotVisualsPanel</name>
|
||||
|
||||
@@ -433,6 +433,26 @@
|
||||
</context>
|
||||
<context>
|
||||
<name>ExpandableMultiOptionDialog</name>
|
||||
<message>
|
||||
<source>Sort by:</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Alphabetical</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Date (Newest)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Date (Oldest)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Favorites First</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Select</source>
|
||||
<translation type="unfinished">Auswählen</translation>
|
||||
@@ -441,6 +461,10 @@
|
||||
<source>Cancel</source>
|
||||
<translation type="unfinished">Abbrechen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>%1 (Community Fav)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ExperimentalModeButton</name>
|
||||
@@ -1175,6 +1199,22 @@
|
||||
<source><b>Twilsonco's torque-based adjustments to smoothen out steering in curves.</b></source>
|
||||
<translation type="gpt-5-generated"><b>Twilsoncos drehmomentbasierte Anpassungen zur Glättung der Lenkung in Kurven.</b></translation>
|
||||
</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><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.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reset <b>Steer Offset</b> to its default value?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FrogPilotLongitudinalPanel</name>
|
||||
@@ -2086,6 +2126,42 @@
|
||||
<source><b>Following behavior that mimics human drivers</b> by closing gaps behind faster vehicles for quicker takeoffs and dynamically adjusting the desired following distance for gentler, more efficient braking.</source>
|
||||
<translation type="gpt-5-generated"><b>Dem Fahrverhalten menschlicher Fahrer nachempfunden</b>, indem Lücken hinter schnelleren Fahrzeugen geschlossen werden, um schneller anzufahren, und der gewünschte Folgeabstand dynamisch angepasst wird, um sanfteres und effizienteres Bremsen zu ermöglichen.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>EV Tuning</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>Use acceleration profiles tuned for EVs.</b> Defaults to the vehicle's detected powertrain type but can be overridden if the automatic choice doesn't match.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>High Speed Following Distance</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>How many seconds openpilot follows behind lead vehicles when using the "Aggressive" profile at high speeds.</b> Increase for more space; decrease for tighter gaps.<br><br>Default: 1.25 seconds.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>How many seconds openpilot follows behind lead vehicles when using the "Standard" profile at high speeds.</b> Increase for more space; decrease for tighter gaps.<br><br>Default: 1.45 seconds.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>How many seconds openpilot follows behind lead vehicles when using the "Relaxed" profile at high speeds.</b> Increase for more space; decrease for tighter gaps.<br><br>Default: 1.75 seconds.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Trailer Load</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>Increase the vehicle mass to account for towing.</b> Adjust in 500 lb steps up to 15,000 lbs to fine-tune gas and brake behavior when pulling a trailer.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source> lbs</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FrogPilotManageControl</name>
|
||||
@@ -2503,6 +2579,14 @@
|
||||
<source>Driving models are chosen at random each drive and feedback prompts are used to find the model that best suits your needs.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Recovery Power</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Adjust the strength of planplus lane recovery corrections (0.5 to 2.0).</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Stop Distance</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@@ -2523,6 +2607,10 @@
|
||||
<source>Select the active driving model.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Custom Series</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>There are no more models to blacklist! The only available model is "%1"!</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@@ -2552,13 +2640,17 @@
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to reset your <b>Stop Distance</b> to the default of 6 meters?</source>
|
||||
<source>Are you sure you want to reset your <b>Recovery Power</b> to the default of 1.0?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reset</source>
|
||||
<translation type="unfinished">Zurücksetzen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to reset your <b>Stop Distance</b> to the default of 6 meters?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FrogPilotModelReview</name>
|
||||
@@ -3714,6 +3806,22 @@ Entwickler – Hochgradig anpassbare Einstellungen für versierte Enthusiasten</
|
||||
<source>comma Pedal Support</source>
|
||||
<translation type="gpt-5-generated">Unterstützung für comma Pedal</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Use Pedal for Longitudinal Control</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>Use the pedal interceptor for longitudinal control</b> instead of camera ACC/Redneck when available.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>SASCM Support</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>Does your vehicle support "SASCMs"?</b></source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FrogPilotVisualsPanel</name>
|
||||
|
||||
@@ -433,6 +433,26 @@
|
||||
</context>
|
||||
<context>
|
||||
<name>ExpandableMultiOptionDialog</name>
|
||||
<message>
|
||||
<source>Sort by:</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Alphabetical</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Date (Newest)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Date (Oldest)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Favorites First</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Select</source>
|
||||
<translation type="unfinished">Quack-select!</translation>
|
||||
@@ -441,6 +461,10 @@
|
||||
<source>Cancel</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>%1 (Community Fav)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ExperimentalModeButton</name>
|
||||
@@ -1177,6 +1201,22 @@
|
||||
<source><b>Twilsonco's torque-based adjustments to smoothen out steering in curves.</b></source>
|
||||
<translation type="gpt-5-generated"><b>Quack! Twilsonco’s torque tweaks to smooth out steering in curves, waddle-waddle.</b></translation>
|
||||
</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><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.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reset <b>Steer Offset</b> to its default value?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FrogPilotLongitudinalPanel</name>
|
||||
@@ -2088,6 +2128,42 @@
|
||||
<source><b>Following behavior that mimics human drivers</b> by closing gaps behind faster vehicles for quicker takeoffs and dynamically adjusting the desired following distance for gentler, more efficient braking.</source>
|
||||
<translation type="gpt-5-generated"><b>Quack! Mimic human drivers</b> by waddling up to close gaps behind faster cars for zippy takeoffs, and duckily tweak the following distance for smoother, more efficient braking.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>EV Tuning</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>Use acceleration profiles tuned for EVs.</b> Defaults to the vehicle's detected powertrain type but can be overridden if the automatic choice doesn't match.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>High Speed Following Distance</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>How many seconds openpilot follows behind lead vehicles when using the "Aggressive" profile at high speeds.</b> Increase for more space; decrease for tighter gaps.<br><br>Default: 1.25 seconds.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>How many seconds openpilot follows behind lead vehicles when using the "Standard" profile at high speeds.</b> Increase for more space; decrease for tighter gaps.<br><br>Default: 1.45 seconds.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>How many seconds openpilot follows behind lead vehicles when using the "Relaxed" profile at high speeds.</b> Increase for more space; decrease for tighter gaps.<br><br>Default: 1.75 seconds.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Trailer Load</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>Increase the vehicle mass to account for towing.</b> Adjust in 500 lb steps up to 15,000 lbs to fine-tune gas and brake behavior when pulling a trailer.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source> lbs</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FrogPilotManageControl</name>
|
||||
@@ -2505,6 +2581,14 @@
|
||||
<source>Driving models are chosen at random each drive and feedback prompts are used to find the model that best suits your needs.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Recovery Power</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Adjust the strength of planplus lane recovery corrections (0.5 to 2.0).</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Stop Distance</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@@ -2525,6 +2609,10 @@
|
||||
<source>Select the active driving model.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Custom Series</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>There are no more models to blacklist! The only available model is "%1"!</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@@ -2554,13 +2642,17 @@
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to reset your <b>Stop Distance</b> to the default of 6 meters?</source>
|
||||
<source>Are you sure you want to reset your <b>Recovery Power</b> to the default of 1.0?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reset</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to reset your <b>Stop Distance</b> to the default of 6 meters?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FrogPilotModelReview</name>
|
||||
@@ -3716,6 +3808,22 @@ Developer - Ultra-custom settings for seasoned duckthusiasts</translation>
|
||||
<source>comma Pedal Support</source>
|
||||
<translation type="gpt-5-generated">Quack! comma Pedal Support, waddle on!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Use Pedal for Longitudinal Control</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>Use the pedal interceptor for longitudinal control</b> instead of camera ACC/Redneck when available.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>SASCM Support</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>Does your vehicle support "SASCMs"?</b></source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FrogPilotVisualsPanel</name>
|
||||
|
||||
@@ -433,6 +433,26 @@
|
||||
</context>
|
||||
<context>
|
||||
<name>ExpandableMultiOptionDialog</name>
|
||||
<message>
|
||||
<source>Sort by:</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Alphabetical</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Date (Newest)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Date (Oldest)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Favorites First</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Select</source>
|
||||
<translation type="unfinished">Seleccione</translation>
|
||||
@@ -441,6 +461,10 @@
|
||||
<source>Cancel</source>
|
||||
<translation type="unfinished">Cancelar</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>%1 (Community Fav)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ExperimentalModeButton</name>
|
||||
@@ -1175,6 +1199,22 @@
|
||||
<source><b>Twilsonco's torque-based adjustments to smoothen out steering in curves.</b></source>
|
||||
<translation type="gpt-5-generated"><b>Ajustes basados en par de Twilsonco para suavizar la dirección en curvas.</b></translation>
|
||||
</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><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.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reset <b>Steer Offset</b> to its default value?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FrogPilotLongitudinalPanel</name>
|
||||
@@ -2086,6 +2126,42 @@
|
||||
<source><b>Following behavior that mimics human drivers</b> by closing gaps behind faster vehicles for quicker takeoffs and dynamically adjusting the desired following distance for gentler, more efficient braking.</source>
|
||||
<translation type="gpt-5-generated"><b>Comportamiento de seguimiento que imita a los conductores humanos</b> cerrando huecos detrás de vehículos más rápidos para salidas más rápidas y ajustando dinámicamente la distancia de seguimiento deseada para un frenado más suave y eficiente.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>EV Tuning</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>Use acceleration profiles tuned for EVs.</b> Defaults to the vehicle's detected powertrain type but can be overridden if the automatic choice doesn't match.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>High Speed Following Distance</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>How many seconds openpilot follows behind lead vehicles when using the "Aggressive" profile at high speeds.</b> Increase for more space; decrease for tighter gaps.<br><br>Default: 1.25 seconds.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>How many seconds openpilot follows behind lead vehicles when using the "Standard" profile at high speeds.</b> Increase for more space; decrease for tighter gaps.<br><br>Default: 1.45 seconds.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>How many seconds openpilot follows behind lead vehicles when using the "Relaxed" profile at high speeds.</b> Increase for more space; decrease for tighter gaps.<br><br>Default: 1.75 seconds.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Trailer Load</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>Increase the vehicle mass to account for towing.</b> Adjust in 500 lb steps up to 15,000 lbs to fine-tune gas and brake behavior when pulling a trailer.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source> lbs</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FrogPilotManageControl</name>
|
||||
@@ -2503,6 +2579,14 @@
|
||||
<source>Driving models are chosen at random each drive and feedback prompts are used to find the model that best suits your needs.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Recovery Power</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Adjust the strength of planplus lane recovery corrections (0.5 to 2.0).</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Stop Distance</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@@ -2523,6 +2607,10 @@
|
||||
<source>Select the active driving model.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Custom Series</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>There are no more models to blacklist! The only available model is "%1"!</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@@ -2552,13 +2640,17 @@
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to reset your <b>Stop Distance</b> to the default of 6 meters?</source>
|
||||
<source>Are you sure you want to reset your <b>Recovery Power</b> to the default of 1.0?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reset</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to reset your <b>Stop Distance</b> to the default of 6 meters?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FrogPilotModelReview</name>
|
||||
@@ -3713,6 +3805,22 @@ Desarrollador: configuración altamente personalizable para entusiastas veterano
|
||||
<source>comma Pedal Support</source>
|
||||
<translation type="gpt-5-generated">Compatibilidad con comma Pedal</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Use Pedal for Longitudinal Control</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>Use the pedal interceptor for longitudinal control</b> instead of camera ACC/Redneck when available.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>SASCM Support</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>Does your vehicle support "SASCMs"?</b></source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FrogPilotVisualsPanel</name>
|
||||
|
||||
@@ -433,6 +433,26 @@
|
||||
</context>
|
||||
<context>
|
||||
<name>ExpandableMultiOptionDialog</name>
|
||||
<message>
|
||||
<source>Sort by:</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Alphabetical</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Date (Newest)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Date (Oldest)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Favorites First</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Select</source>
|
||||
<translation type="unfinished">Sélectionner</translation>
|
||||
@@ -441,6 +461,10 @@
|
||||
<source>Cancel</source>
|
||||
<translation type="unfinished">Annuler</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>%1 (Community Fav)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ExperimentalModeButton</name>
|
||||
@@ -1175,6 +1199,22 @@
|
||||
<source><b>Twilsonco's torque-based adjustments to smoothen out steering in curves.</b></source>
|
||||
<translation type="gpt-5-generated"><b>Ajustements basés sur le couple de Twilsonco pour adoucir la direction dans les virages.</b></translation>
|
||||
</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><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.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reset <b>Steer Offset</b> to its default value?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FrogPilotLongitudinalPanel</name>
|
||||
@@ -2086,6 +2126,42 @@
|
||||
<source><b>Following behavior that mimics human drivers</b> by closing gaps behind faster vehicles for quicker takeoffs and dynamically adjusting the desired following distance for gentler, more efficient braking.</source>
|
||||
<translation type="gpt-5-generated"><b>Un comportement de suivi qui imite les conducteurs humains</b> en réduisant les écarts derrière les véhicules plus rapides pour des départs plus rapides et en ajustant dynamiquement la distance de suivi souhaitée pour un freinage plus doux et plus efficace.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>EV Tuning</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>Use acceleration profiles tuned for EVs.</b> Defaults to the vehicle's detected powertrain type but can be overridden if the automatic choice doesn't match.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>High Speed Following Distance</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>How many seconds openpilot follows behind lead vehicles when using the "Aggressive" profile at high speeds.</b> Increase for more space; decrease for tighter gaps.<br><br>Default: 1.25 seconds.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>How many seconds openpilot follows behind lead vehicles when using the "Standard" profile at high speeds.</b> Increase for more space; decrease for tighter gaps.<br><br>Default: 1.45 seconds.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>How many seconds openpilot follows behind lead vehicles when using the "Relaxed" profile at high speeds.</b> Increase for more space; decrease for tighter gaps.<br><br>Default: 1.75 seconds.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Trailer Load</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>Increase the vehicle mass to account for towing.</b> Adjust in 500 lb steps up to 15,000 lbs to fine-tune gas and brake behavior when pulling a trailer.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source> lbs</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FrogPilotManageControl</name>
|
||||
@@ -2503,6 +2579,14 @@
|
||||
<source>Driving models are chosen at random each drive and feedback prompts are used to find the model that best suits your needs.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Recovery Power</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Adjust the strength of planplus lane recovery corrections (0.5 to 2.0).</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Stop Distance</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@@ -2523,6 +2607,10 @@
|
||||
<source>Select the active driving model.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Custom Series</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>There are no more models to blacklist! The only available model is "%1"!</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@@ -2552,13 +2640,17 @@
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to reset your <b>Stop Distance</b> to the default of 6 meters?</source>
|
||||
<source>Are you sure you want to reset your <b>Recovery Power</b> to the default of 1.0?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reset</source>
|
||||
<translation type="unfinished">Réinitialiser</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to reset your <b>Stop Distance</b> to the default of 6 meters?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FrogPilotModelReview</name>
|
||||
@@ -3713,6 +3805,22 @@ Développeur – Paramètres hautement personnalisables pour passionnés chevron
|
||||
<source>comma Pedal Support</source>
|
||||
<translation type="gpt-5-generated">Prise en charge de comma Pedal</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Use Pedal for Longitudinal Control</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>Use the pedal interceptor for longitudinal control</b> instead of camera ACC/Redneck when available.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>SASCM Support</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>Does your vehicle support "SASCMs"?</b></source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FrogPilotVisualsPanel</name>
|
||||
|
||||
@@ -433,6 +433,26 @@
|
||||
</context>
|
||||
<context>
|
||||
<name>ExpandableMultiOptionDialog</name>
|
||||
<message>
|
||||
<source>Sort by:</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Alphabetical</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Date (Newest)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Date (Oldest)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Favorites First</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Select</source>
|
||||
<translation type="unfinished">Ribbit! Pick it, croak!</translation>
|
||||
@@ -441,6 +461,10 @@
|
||||
<source>Cancel</source>
|
||||
<translation type="unfinished">Ribbit! Cancel croak!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>%1 (Community Fav)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ExperimentalModeButton</name>
|
||||
@@ -1175,6 +1199,22 @@
|
||||
<source><b>Twilsonco's torque-based adjustments to smoothen out steering in curves.</b></source>
|
||||
<translation type="gpt-5-generated"><b>Ribbit! Twilsonco’s torque tweaks smooth steering through curves, croak.</b></translation>
|
||||
</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><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.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reset <b>Steer Offset</b> to its default value?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FrogPilotLongitudinalPanel</name>
|
||||
@@ -2086,6 +2126,42 @@
|
||||
<source><b>Following behavior that mimics human drivers</b> by closing gaps behind faster vehicles for quicker takeoffs and dynamically adjusting the desired following distance for gentler, more efficient braking.</source>
|
||||
<translation type="gpt-5-generated"><b>Croaky follow like humans</b>, ribbit! Hop to close gaps behind faster cars for quick takeoffs, and croak-adjust the follow distance for gentler, thriftier braking.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>EV Tuning</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>Use acceleration profiles tuned for EVs.</b> Defaults to the vehicle's detected powertrain type but can be overridden if the automatic choice doesn't match.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>High Speed Following Distance</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>How many seconds openpilot follows behind lead vehicles when using the "Aggressive" profile at high speeds.</b> Increase for more space; decrease for tighter gaps.<br><br>Default: 1.25 seconds.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>How many seconds openpilot follows behind lead vehicles when using the "Standard" profile at high speeds.</b> Increase for more space; decrease for tighter gaps.<br><br>Default: 1.45 seconds.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>How many seconds openpilot follows behind lead vehicles when using the "Relaxed" profile at high speeds.</b> Increase for more space; decrease for tighter gaps.<br><br>Default: 1.75 seconds.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Trailer Load</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>Increase the vehicle mass to account for towing.</b> Adjust in 500 lb steps up to 15,000 lbs to fine-tune gas and brake behavior when pulling a trailer.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source> lbs</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FrogPilotManageControl</name>
|
||||
@@ -2503,6 +2579,14 @@
|
||||
<source>Driving models are chosen at random each drive and feedback prompts are used to find the model that best suits your needs.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Recovery Power</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Adjust the strength of planplus lane recovery corrections (0.5 to 2.0).</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Stop Distance</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@@ -2523,6 +2607,10 @@
|
||||
<source>Select the active driving model.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Custom Series</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>There are no more models to blacklist! The only available model is "%1"!</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@@ -2552,13 +2640,17 @@
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to reset your <b>Stop Distance</b> to the default of 6 meters?</source>
|
||||
<source>Are you sure you want to reset your <b>Recovery Power</b> to the default of 1.0?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reset</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to reset your <b>Stop Distance</b> to the default of 6 meters?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FrogPilotModelReview</name>
|
||||
@@ -3714,6 +3806,22 @@ Developer - Highly customizable settings for seasoned swamp pros</translation>
|
||||
<source>comma Pedal Support</source>
|
||||
<translation type="gpt-5-generated">Ribbit! comma Pedal Support croak!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Use Pedal for Longitudinal Control</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>Use the pedal interceptor for longitudinal control</b> instead of camera ACC/Redneck when available.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>SASCM Support</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>Does your vehicle support "SASCMs"?</b></source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FrogPilotVisualsPanel</name>
|
||||
|
||||
@@ -433,6 +433,26 @@
|
||||
</context>
|
||||
<context>
|
||||
<name>ExpandableMultiOptionDialog</name>
|
||||
<message>
|
||||
<source>Sort by:</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Alphabetical</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Date (Newest)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Date (Oldest)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Favorites First</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Select</source>
|
||||
<translation type="unfinished">選択</translation>
|
||||
@@ -441,6 +461,10 @@
|
||||
<source>Cancel</source>
|
||||
<translation type="unfinished">キャンセル</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>%1 (Community Fav)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ExperimentalModeButton</name>
|
||||
@@ -1175,6 +1199,22 @@
|
||||
<source><b>Twilsonco's torque-based adjustments to smoothen out steering in curves.</b></source>
|
||||
<translation type="gpt-5-generated"><b>カーブでのステアリングを滑らかにするためのTwilsoncoのトルクベース調整。</b></translation>
|
||||
</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><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.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reset <b>Steer Offset</b> to its default value?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FrogPilotLongitudinalPanel</name>
|
||||
@@ -2086,6 +2126,42 @@
|
||||
<source><b>Following behavior that mimics human drivers</b> by closing gaps behind faster vehicles for quicker takeoffs and dynamically adjusting the desired following distance for gentler, more efficient braking.</source>
|
||||
<translation type="gpt-5-generated"><b>人間のドライバーを模倣する追従挙動</b>。より速い車両の後方で車間を詰めて発進を素早くし、望ましい追従距離を動的に調整して、より穏やかで効率的な減速を実現します。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>EV Tuning</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>Use acceleration profiles tuned for EVs.</b> Defaults to the vehicle's detected powertrain type but can be overridden if the automatic choice doesn't match.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>High Speed Following Distance</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>How many seconds openpilot follows behind lead vehicles when using the "Aggressive" profile at high speeds.</b> Increase for more space; decrease for tighter gaps.<br><br>Default: 1.25 seconds.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>How many seconds openpilot follows behind lead vehicles when using the "Standard" profile at high speeds.</b> Increase for more space; decrease for tighter gaps.<br><br>Default: 1.45 seconds.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>How many seconds openpilot follows behind lead vehicles when using the "Relaxed" profile at high speeds.</b> Increase for more space; decrease for tighter gaps.<br><br>Default: 1.75 seconds.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Trailer Load</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>Increase the vehicle mass to account for towing.</b> Adjust in 500 lb steps up to 15,000 lbs to fine-tune gas and brake behavior when pulling a trailer.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source> lbs</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FrogPilotManageControl</name>
|
||||
@@ -2503,6 +2579,14 @@
|
||||
<source>Driving models are chosen at random each drive and feedback prompts are used to find the model that best suits your needs.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Recovery Power</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Adjust the strength of planplus lane recovery corrections (0.5 to 2.0).</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Stop Distance</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@@ -2523,6 +2607,10 @@
|
||||
<source>Select the active driving model.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Custom Series</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>There are no more models to blacklist! The only available model is "%1"!</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@@ -2552,13 +2640,17 @@
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to reset your <b>Stop Distance</b> to the default of 6 meters?</source>
|
||||
<source>Are you sure you want to reset your <b>Recovery Power</b> to the default of 1.0?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reset</source>
|
||||
<translation type="unfinished">リセット</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to reset your <b>Stop Distance</b> to the default of 6 meters?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FrogPilotModelReview</name>
|
||||
@@ -3712,6 +3804,22 @@ Developer - こだわりのある上級者向けの高度にカスタマイズ
|
||||
<source>comma Pedal Support</source>
|
||||
<translation type="gpt-5-generated">comma Pedal 対応</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Use Pedal for Longitudinal Control</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>Use the pedal interceptor for longitudinal control</b> instead of camera ACC/Redneck when available.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>SASCM Support</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>Does your vehicle support "SASCMs"?</b></source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FrogPilotVisualsPanel</name>
|
||||
|
||||
@@ -433,6 +433,26 @@
|
||||
</context>
|
||||
<context>
|
||||
<name>ExpandableMultiOptionDialog</name>
|
||||
<message>
|
||||
<source>Sort by:</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Alphabetical</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Date (Newest)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Date (Oldest)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Favorites First</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Select</source>
|
||||
<translation type="unfinished">선택</translation>
|
||||
@@ -441,6 +461,10 @@
|
||||
<source>Cancel</source>
|
||||
<translation type="unfinished">취소</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>%1 (Community Fav)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ExperimentalModeButton</name>
|
||||
@@ -1175,6 +1199,22 @@
|
||||
<source><b>Twilsonco's torque-based adjustments to smoothen out steering in curves.</b></source>
|
||||
<translation type="gpt-5-generated"><b>커브에서 조향을 부드럽게 하기 위한 Twilsonco의 토크 기반 조정.</b></translation>
|
||||
</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><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.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reset <b>Steer Offset</b> to its default value?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FrogPilotLongitudinalPanel</name>
|
||||
@@ -2086,6 +2126,42 @@
|
||||
<source><b>Following behavior that mimics human drivers</b> by closing gaps behind faster vehicles for quicker takeoffs and dynamically adjusting the desired following distance for gentler, more efficient braking.</source>
|
||||
<translation type="gpt-5-generated"><b>사람 운전자와 유사한 추종 동작</b>으로, 더 빠른 차량 뒤 간격을 좁혀 신속한 출발을 돕고 원하는 추종 거리를 동적으로 조절해 더욱 부드럽고 효율적인 제동을 수행합니다.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>EV Tuning</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>Use acceleration profiles tuned for EVs.</b> Defaults to the vehicle's detected powertrain type but can be overridden if the automatic choice doesn't match.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>High Speed Following Distance</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>How many seconds openpilot follows behind lead vehicles when using the "Aggressive" profile at high speeds.</b> Increase for more space; decrease for tighter gaps.<br><br>Default: 1.25 seconds.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>How many seconds openpilot follows behind lead vehicles when using the "Standard" profile at high speeds.</b> Increase for more space; decrease for tighter gaps.<br><br>Default: 1.45 seconds.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>How many seconds openpilot follows behind lead vehicles when using the "Relaxed" profile at high speeds.</b> Increase for more space; decrease for tighter gaps.<br><br>Default: 1.75 seconds.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Trailer Load</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>Increase the vehicle mass to account for towing.</b> Adjust in 500 lb steps up to 15,000 lbs to fine-tune gas and brake behavior when pulling a trailer.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source> lbs</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FrogPilotManageControl</name>
|
||||
@@ -2503,6 +2579,14 @@
|
||||
<source>Driving models are chosen at random each drive and feedback prompts are used to find the model that best suits your needs.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Recovery Power</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Adjust the strength of planplus lane recovery corrections (0.5 to 2.0).</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Stop Distance</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@@ -2523,6 +2607,10 @@
|
||||
<source>Select the active driving model.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Custom Series</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>There are no more models to blacklist! The only available model is "%1"!</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@@ -2552,13 +2640,17 @@
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to reset your <b>Stop Distance</b> to the default of 6 meters?</source>
|
||||
<source>Are you sure you want to reset your <b>Recovery Power</b> to the default of 1.0?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reset</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to reset your <b>Stop Distance</b> to the default of 6 meters?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FrogPilotModelReview</name>
|
||||
@@ -3713,6 +3805,22 @@ Developer - Highly customizable settings for seasoned enthusiasts</source>
|
||||
<source>comma Pedal Support</source>
|
||||
<translation type="gpt-5-generated">comma Pedal 지원</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Use Pedal for Longitudinal Control</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>Use the pedal interceptor for longitudinal control</b> instead of camera ACC/Redneck when available.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>SASCM Support</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>Does your vehicle support "SASCMs"?</b></source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FrogPilotVisualsPanel</name>
|
||||
|
||||
@@ -433,6 +433,26 @@
|
||||
</context>
|
||||
<context>
|
||||
<name>ExpandableMultiOptionDialog</name>
|
||||
<message>
|
||||
<source>Sort by:</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Alphabetical</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Date (Newest)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Date (Oldest)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Favorites First</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Select</source>
|
||||
<translation type="unfinished">Be pickin'</translation>
|
||||
@@ -441,6 +461,10 @@
|
||||
<source>Cancel</source>
|
||||
<translation type="unfinished">Belay</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>%1 (Community Fav)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ExperimentalModeButton</name>
|
||||
@@ -1175,6 +1199,22 @@
|
||||
<source><b>Twilsonco's torque-based adjustments to smoothen out steering in curves.</b></source>
|
||||
<translation type="gpt-5-generated"><b>Twilsonco’s torque-based tweaks t’ smooth out steerin’ in curves, arr!</b></translation>
|
||||
</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><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.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reset <b>Steer Offset</b> to its default value?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FrogPilotLongitudinalPanel</name>
|
||||
@@ -2086,6 +2126,42 @@
|
||||
<source><b>Following behavior that mimics human drivers</b> by closing gaps behind faster vehicles for quicker takeoffs and dynamically adjusting the desired following distance for gentler, more efficient braking.</source>
|
||||
<translation type="gpt-5-generated"><b>Behavin’ like real hands at the wheel</b> by closin’ gaps astern o’ swifter wagons fer quicker shove-offs, an’ smartly trimmin’ the wanted followin’ distance fer gentler, more shipshape brak’n.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>EV Tuning</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>Use acceleration profiles tuned for EVs.</b> Defaults to the vehicle's detected powertrain type but can be overridden if the automatic choice doesn't match.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>High Speed Following Distance</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>How many seconds openpilot follows behind lead vehicles when using the "Aggressive" profile at high speeds.</b> Increase for more space; decrease for tighter gaps.<br><br>Default: 1.25 seconds.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>How many seconds openpilot follows behind lead vehicles when using the "Standard" profile at high speeds.</b> Increase for more space; decrease for tighter gaps.<br><br>Default: 1.45 seconds.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>How many seconds openpilot follows behind lead vehicles when using the "Relaxed" profile at high speeds.</b> Increase for more space; decrease for tighter gaps.<br><br>Default: 1.75 seconds.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Trailer Load</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>Increase the vehicle mass to account for towing.</b> Adjust in 500 lb steps up to 15,000 lbs to fine-tune gas and brake behavior when pulling a trailer.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source> lbs</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FrogPilotManageControl</name>
|
||||
@@ -2503,6 +2579,14 @@
|
||||
<source>Driving models are chosen at random each drive and feedback prompts are used to find the model that best suits your needs.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Recovery Power</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Adjust the strength of planplus lane recovery corrections (0.5 to 2.0).</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Stop Distance</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@@ -2523,6 +2607,10 @@
|
||||
<source>Select the active driving model.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Custom Series</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>There are no more models to blacklist! The only available model is "%1"!</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@@ -2552,13 +2640,17 @@
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to reset your <b>Stop Distance</b> to the default of 6 meters?</source>
|
||||
<source>Are you sure you want to reset your <b>Recovery Power</b> to the default of 1.0?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reset</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to reset your <b>Stop Distance</b> to the default of 6 meters?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FrogPilotModelReview</name>
|
||||
@@ -3714,6 +3806,22 @@ Developer - Highly customizable riggin’s fer seasoned enthusiasts</translation
|
||||
<source>comma Pedal Support</source>
|
||||
<translation type="gpt-5-generated">comma Pedal Support, arrr</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Use Pedal for Longitudinal Control</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>Use the pedal interceptor for longitudinal control</b> instead of camera ACC/Redneck when available.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>SASCM Support</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>Does your vehicle support "SASCMs"?</b></source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FrogPilotVisualsPanel</name>
|
||||
|
||||
@@ -433,6 +433,26 @@
|
||||
</context>
|
||||
<context>
|
||||
<name>ExpandableMultiOptionDialog</name>
|
||||
<message>
|
||||
<source>Sort by:</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Alphabetical</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Date (Newest)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Date (Oldest)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Favorites First</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Select</source>
|
||||
<translation type="unfinished">Selecione</translation>
|
||||
@@ -441,6 +461,10 @@
|
||||
<source>Cancel</source>
|
||||
<translation type="unfinished">Cancelar</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>%1 (Community Fav)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ExperimentalModeButton</name>
|
||||
@@ -1175,6 +1199,22 @@
|
||||
<source><b>Twilsonco's torque-based adjustments to smoothen out steering in curves.</b></source>
|
||||
<translation type="gpt-5-generated"><b>Ajustes baseados em torque do Twilsonco para suavizar a direção em curvas.</b></translation>
|
||||
</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><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.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reset <b>Steer Offset</b> to its default value?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FrogPilotLongitudinalPanel</name>
|
||||
@@ -2086,6 +2126,42 @@
|
||||
<source><b>Following behavior that mimics human drivers</b> by closing gaps behind faster vehicles for quicker takeoffs and dynamically adjusting the desired following distance for gentler, more efficient braking.</source>
|
||||
<translation type="gpt-5-generated"><b>Comportamento de acompanhamento que imita motoristas humanos</b> ao fechar lacunas atrás de veículos mais rápidos para arrancadas mais rápidas e ajustar dinamicamente a distância de seguimento desejada para frenagens mais suaves e eficientes.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>EV Tuning</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>Use acceleration profiles tuned for EVs.</b> Defaults to the vehicle's detected powertrain type but can be overridden if the automatic choice doesn't match.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>High Speed Following Distance</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>How many seconds openpilot follows behind lead vehicles when using the "Aggressive" profile at high speeds.</b> Increase for more space; decrease for tighter gaps.<br><br>Default: 1.25 seconds.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>How many seconds openpilot follows behind lead vehicles when using the "Standard" profile at high speeds.</b> Increase for more space; decrease for tighter gaps.<br><br>Default: 1.45 seconds.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>How many seconds openpilot follows behind lead vehicles when using the "Relaxed" profile at high speeds.</b> Increase for more space; decrease for tighter gaps.<br><br>Default: 1.75 seconds.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Trailer Load</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>Increase the vehicle mass to account for towing.</b> Adjust in 500 lb steps up to 15,000 lbs to fine-tune gas and brake behavior when pulling a trailer.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source> lbs</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FrogPilotManageControl</name>
|
||||
@@ -2503,6 +2579,14 @@
|
||||
<source>Driving models are chosen at random each drive and feedback prompts are used to find the model that best suits your needs.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Recovery Power</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Adjust the strength of planplus lane recovery corrections (0.5 to 2.0).</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Stop Distance</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@@ -2523,6 +2607,10 @@
|
||||
<source>Select the active driving model.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Custom Series</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>There are no more models to blacklist! The only available model is "%1"!</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@@ -2552,13 +2640,17 @@
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to reset your <b>Stop Distance</b> to the default of 6 meters?</source>
|
||||
<source>Are you sure you want to reset your <b>Recovery Power</b> to the default of 1.0?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reset</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to reset your <b>Stop Distance</b> to the default of 6 meters?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FrogPilotModelReview</name>
|
||||
@@ -3714,6 +3806,22 @@ Desenvolvedor - Configurações altamente personalizáveis para entusiastas expe
|
||||
<source>comma Pedal Support</source>
|
||||
<translation type="gpt-5-generated">Compatibilidade com comma Pedal</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Use Pedal for Longitudinal Control</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>Use the pedal interceptor for longitudinal control</b> instead of camera ACC/Redneck when available.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>SASCM Support</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>Does your vehicle support "SASCMs"?</b></source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FrogPilotVisualsPanel</name>
|
||||
|
||||
@@ -433,6 +433,26 @@
|
||||
</context>
|
||||
<context>
|
||||
<name>ExpandableMultiOptionDialog</name>
|
||||
<message>
|
||||
<source>Sort by:</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Alphabetical</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Date (Newest)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Date (Oldest)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Favorites First</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Select</source>
|
||||
<translation type="unfinished">Select</translation>
|
||||
@@ -441,6 +461,10 @@
|
||||
<source>Cancel</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>%1 (Community Fav)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ExperimentalModeButton</name>
|
||||
@@ -1179,6 +1203,22 @@
|
||||
<source><b>Twilsonco's torque-based adjustments to smoothen out steering in curves.</b></source>
|
||||
<translation type="gpt-5-generated"><b>Twilsonco’s torque-wrought tweaks to make steering flow smoother ’midst the curves.</b></translation>
|
||||
</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><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.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reset <b>Steer Offset</b> to its default value?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FrogPilotLongitudinalPanel</name>
|
||||
@@ -2092,6 +2132,42 @@
|
||||
<source><b>Following behavior that mimics human drivers</b> by closing gaps behind faster vehicles for quicker takeoffs and dynamically adjusting the desired following distance for gentler, more efficient braking.</source>
|
||||
<translation type="gpt-5-generated"><b>Following comportment that doth mirror mortal coachmen</b> by narrowing gaps behind swifter chariots for hastier set-offs and by dynamically tuning the desired following distance for gentler, more thrifty braking.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>EV Tuning</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>Use acceleration profiles tuned for EVs.</b> Defaults to the vehicle's detected powertrain type but can be overridden if the automatic choice doesn't match.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>High Speed Following Distance</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>How many seconds openpilot follows behind lead vehicles when using the "Aggressive" profile at high speeds.</b> Increase for more space; decrease for tighter gaps.<br><br>Default: 1.25 seconds.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>How many seconds openpilot follows behind lead vehicles when using the "Standard" profile at high speeds.</b> Increase for more space; decrease for tighter gaps.<br><br>Default: 1.45 seconds.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>How many seconds openpilot follows behind lead vehicles when using the "Relaxed" profile at high speeds.</b> Increase for more space; decrease for tighter gaps.<br><br>Default: 1.75 seconds.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Trailer Load</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>Increase the vehicle mass to account for towing.</b> Adjust in 500 lb steps up to 15,000 lbs to fine-tune gas and brake behavior when pulling a trailer.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source> lbs</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FrogPilotManageControl</name>
|
||||
@@ -2509,6 +2585,14 @@
|
||||
<source>Driving models are chosen at random each drive and feedback prompts are used to find the model that best suits your needs.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Recovery Power</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Adjust the strength of planplus lane recovery corrections (0.5 to 2.0).</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Stop Distance</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@@ -2529,6 +2613,10 @@
|
||||
<source>Select the active driving model.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Custom Series</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>There are no more models to blacklist! The only available model is "%1"!</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@@ -2558,13 +2646,17 @@
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to reset your <b>Stop Distance</b> to the default of 6 meters?</source>
|
||||
<source>Are you sure you want to reset your <b>Recovery Power</b> to the default of 1.0?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reset</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to reset your <b>Stop Distance</b> to the default of 6 meters?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FrogPilotModelReview</name>
|
||||
@@ -3724,6 +3816,22 @@ Developer - Most customizable settings for well-tried enthusiasts</translation>
|
||||
<source>comma Pedal Support</source>
|
||||
<translation type="gpt-5-generated">comma Pedal Support</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Use Pedal for Longitudinal Control</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>Use the pedal interceptor for longitudinal control</b> instead of camera ACC/Redneck when available.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>SASCM Support</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>Does your vehicle support "SASCMs"?</b></source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FrogPilotVisualsPanel</name>
|
||||
|
||||
@@ -433,6 +433,26 @@
|
||||
</context>
|
||||
<context>
|
||||
<name>ExpandableMultiOptionDialog</name>
|
||||
<message>
|
||||
<source>Sort by:</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Alphabetical</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Date (Newest)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Date (Oldest)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Favorites First</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Select</source>
|
||||
<translation type="unfinished">เลือก</translation>
|
||||
@@ -441,6 +461,10 @@
|
||||
<source>Cancel</source>
|
||||
<translation type="unfinished">ยกเลิก</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>%1 (Community Fav)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ExperimentalModeButton</name>
|
||||
@@ -1175,6 +1199,22 @@
|
||||
<source><b>Twilsonco's torque-based adjustments to smoothen out steering in curves.</b></source>
|
||||
<translation type="gpt-5-generated"><b>การปรับตามแรงบิดของ Twilsonco เพื่อทำให้การบังคับเลี้ยวในโค้งนุ่มนวลขึ้น</b></translation>
|
||||
</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><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.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reset <b>Steer Offset</b> to its default value?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FrogPilotLongitudinalPanel</name>
|
||||
@@ -2086,6 +2126,42 @@
|
||||
<source><b>Following behavior that mimics human drivers</b> by closing gaps behind faster vehicles for quicker takeoffs and dynamically adjusting the desired following distance for gentler, more efficient braking.</source>
|
||||
<translation type="gpt-5-generated"><b>พฤติกรรมการตามที่เลียนแบบผู้ขับขี่มนุษย์</b> โดยปิดช่องว่างด้านหลังรถที่เร็วกว่าเพื่อออกตัวได้เร็วขึ้น และปรับระยะห่างที่ต้องการแบบไดนามิกเพื่อการเบรกที่นุ่มนวลและมีประสิทธิภาพมากขึ้น</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>EV Tuning</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>Use acceleration profiles tuned for EVs.</b> Defaults to the vehicle's detected powertrain type but can be overridden if the automatic choice doesn't match.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>High Speed Following Distance</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>How many seconds openpilot follows behind lead vehicles when using the "Aggressive" profile at high speeds.</b> Increase for more space; decrease for tighter gaps.<br><br>Default: 1.25 seconds.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>How many seconds openpilot follows behind lead vehicles when using the "Standard" profile at high speeds.</b> Increase for more space; decrease for tighter gaps.<br><br>Default: 1.45 seconds.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>How many seconds openpilot follows behind lead vehicles when using the "Relaxed" profile at high speeds.</b> Increase for more space; decrease for tighter gaps.<br><br>Default: 1.75 seconds.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Trailer Load</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>Increase the vehicle mass to account for towing.</b> Adjust in 500 lb steps up to 15,000 lbs to fine-tune gas and brake behavior when pulling a trailer.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source> lbs</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FrogPilotManageControl</name>
|
||||
@@ -2503,6 +2579,14 @@
|
||||
<source>Driving models are chosen at random each drive and feedback prompts are used to find the model that best suits your needs.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Recovery Power</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Adjust the strength of planplus lane recovery corrections (0.5 to 2.0).</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Stop Distance</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@@ -2523,6 +2607,10 @@
|
||||
<source>Select the active driving model.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Custom Series</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>There are no more models to blacklist! The only available model is "%1"!</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@@ -2552,13 +2640,17 @@
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to reset your <b>Stop Distance</b> to the default of 6 meters?</source>
|
||||
<source>Are you sure you want to reset your <b>Recovery Power</b> to the default of 1.0?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reset</source>
|
||||
<translation type="unfinished">รีเซ็ต</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to reset your <b>Stop Distance</b> to the default of 6 meters?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FrogPilotModelReview</name>
|
||||
@@ -3714,6 +3806,22 @@ Developer - Highly customizable settings for seasoned enthusiasts</source>
|
||||
<source>comma Pedal Support</source>
|
||||
<translation type="gpt-5-generated">รองรับ comma Pedal</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Use Pedal for Longitudinal Control</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>Use the pedal interceptor for longitudinal control</b> instead of camera ACC/Redneck when available.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>SASCM Support</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>Does your vehicle support "SASCMs"?</b></source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FrogPilotVisualsPanel</name>
|
||||
|
||||
@@ -433,6 +433,26 @@
|
||||
</context>
|
||||
<context>
|
||||
<name>ExpandableMultiOptionDialog</name>
|
||||
<message>
|
||||
<source>Sort by:</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Alphabetical</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Date (Newest)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Date (Oldest)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Favorites First</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Select</source>
|
||||
<translation type="unfinished">Seç</translation>
|
||||
@@ -441,6 +461,10 @@
|
||||
<source>Cancel</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>%1 (Community Fav)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ExperimentalModeButton</name>
|
||||
@@ -1175,6 +1199,22 @@
|
||||
<source><b>Twilsonco's torque-based adjustments to smoothen out steering in curves.</b></source>
|
||||
<translation type="gpt-5-generated"><b>Virajlarda direksiyonu yumuşatmak için Twilsonco’nun torka dayalı ayarlamaları.</b></translation>
|
||||
</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><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.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reset <b>Steer Offset</b> to its default value?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FrogPilotLongitudinalPanel</name>
|
||||
@@ -2086,6 +2126,42 @@
|
||||
<source><b>Following behavior that mimics human drivers</b> by closing gaps behind faster vehicles for quicker takeoffs and dynamically adjusting the desired following distance for gentler, more efficient braking.</source>
|
||||
<translation type="gpt-5-generated"><b>İnsan sürücüleri taklit eden takip davranışı</b>: Daha hızlı araçların arkasındaki boşlukları kapatarak daha hızlı kalkışlar ve daha yumuşak, daha verimli frenleme için istenen takip mesafesini dinamik olarak ayarlama.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>EV Tuning</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>Use acceleration profiles tuned for EVs.</b> Defaults to the vehicle's detected powertrain type but can be overridden if the automatic choice doesn't match.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>High Speed Following Distance</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>How many seconds openpilot follows behind lead vehicles when using the "Aggressive" profile at high speeds.</b> Increase for more space; decrease for tighter gaps.<br><br>Default: 1.25 seconds.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>How many seconds openpilot follows behind lead vehicles when using the "Standard" profile at high speeds.</b> Increase for more space; decrease for tighter gaps.<br><br>Default: 1.45 seconds.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>How many seconds openpilot follows behind lead vehicles when using the "Relaxed" profile at high speeds.</b> Increase for more space; decrease for tighter gaps.<br><br>Default: 1.75 seconds.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Trailer Load</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>Increase the vehicle mass to account for towing.</b> Adjust in 500 lb steps up to 15,000 lbs to fine-tune gas and brake behavior when pulling a trailer.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source> lbs</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FrogPilotManageControl</name>
|
||||
@@ -2503,6 +2579,14 @@
|
||||
<source>Driving models are chosen at random each drive and feedback prompts are used to find the model that best suits your needs.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Recovery Power</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Adjust the strength of planplus lane recovery corrections (0.5 to 2.0).</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Stop Distance</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@@ -2523,6 +2607,10 @@
|
||||
<source>Select the active driving model.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Custom Series</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>There are no more models to blacklist! The only available model is "%1"!</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@@ -2552,13 +2640,17 @@
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to reset your <b>Stop Distance</b> to the default of 6 meters?</source>
|
||||
<source>Are you sure you want to reset your <b>Recovery Power</b> to the default of 1.0?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reset</source>
|
||||
<translation type="unfinished">Sıfırla</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to reset your <b>Stop Distance</b> to the default of 6 meters?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FrogPilotModelReview</name>
|
||||
@@ -3713,6 +3805,22 @@ Geliştirici - Tecrübeli meraklılar için yüksek özelleştirilebilir ayarlar
|
||||
<source>comma Pedal Support</source>
|
||||
<translation type="gpt-5-generated">comma Pedal Desteği</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Use Pedal for Longitudinal Control</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>Use the pedal interceptor for longitudinal control</b> instead of camera ACC/Redneck when available.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>SASCM Support</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>Does your vehicle support "SASCMs"?</b></source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FrogPilotVisualsPanel</name>
|
||||
|
||||
@@ -433,6 +433,26 @@
|
||||
</context>
|
||||
<context>
|
||||
<name>ExpandableMultiOptionDialog</name>
|
||||
<message>
|
||||
<source>Sort by:</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Alphabetical</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Date (Newest)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Date (Oldest)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Favorites First</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Select</source>
|
||||
<translation type="unfinished">选择</translation>
|
||||
@@ -441,6 +461,10 @@
|
||||
<source>Cancel</source>
|
||||
<translation type="unfinished">取消</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>%1 (Community Fav)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ExperimentalModeButton</name>
|
||||
@@ -1175,6 +1199,22 @@
|
||||
<source><b>Twilsonco's torque-based adjustments to smoothen out steering in curves.</b></source>
|
||||
<translation type="gpt-5-generated"><b>Twilsonco 基于扭矩的调整,用于在弯道中平滑转向。</b></translation>
|
||||
</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><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.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reset <b>Steer Offset</b> to its default value?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FrogPilotLongitudinalPanel</name>
|
||||
@@ -2086,6 +2126,42 @@
|
||||
<source><b>Following behavior that mimics human drivers</b> by closing gaps behind faster vehicles for quicker takeoffs and dynamically adjusting the desired following distance for gentler, more efficient braking.</source>
|
||||
<translation type="gpt-5-generated"><b>模仿人类驾驶员的跟车行为</b>,通过在更快车辆后方缩小车距以更快起步,并动态调整期望跟车距离,以实现更平顺、更高效的制动。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>EV Tuning</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>Use acceleration profiles tuned for EVs.</b> Defaults to the vehicle's detected powertrain type but can be overridden if the automatic choice doesn't match.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>High Speed Following Distance</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>How many seconds openpilot follows behind lead vehicles when using the "Aggressive" profile at high speeds.</b> Increase for more space; decrease for tighter gaps.<br><br>Default: 1.25 seconds.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>How many seconds openpilot follows behind lead vehicles when using the "Standard" profile at high speeds.</b> Increase for more space; decrease for tighter gaps.<br><br>Default: 1.45 seconds.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>How many seconds openpilot follows behind lead vehicles when using the "Relaxed" profile at high speeds.</b> Increase for more space; decrease for tighter gaps.<br><br>Default: 1.75 seconds.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Trailer Load</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>Increase the vehicle mass to account for towing.</b> Adjust in 500 lb steps up to 15,000 lbs to fine-tune gas and brake behavior when pulling a trailer.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source> lbs</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FrogPilotManageControl</name>
|
||||
@@ -2503,6 +2579,14 @@
|
||||
<source>Driving models are chosen at random each drive and feedback prompts are used to find the model that best suits your needs.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Recovery Power</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Adjust the strength of planplus lane recovery corrections (0.5 to 2.0).</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Stop Distance</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@@ -2523,6 +2607,10 @@
|
||||
<source>Select the active driving model.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Custom Series</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>There are no more models to blacklist! The only available model is "%1"!</source>
|
||||
<translation type="unfinished"></translation>
|
||||
@@ -2552,13 +2640,17 @@
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to reset your <b>Stop Distance</b> to the default of 6 meters?</source>
|
||||
<source>Are you sure you want to reset your <b>Recovery Power</b> to the default of 1.0?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reset</source>
|
||||
<translation type="unfinished">重置</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to reset your <b>Stop Distance</b> to the default of 6 meters?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FrogPilotModelReview</name>
|
||||
@@ -3714,6 +3806,22 @@ Developer - Highly customizable settings for seasoned enthusiasts</source>
|
||||
<source>comma Pedal Support</source>
|
||||
<translation type="gpt-5-generated">comma Pedal 支持</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Use Pedal for Longitudinal Control</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>Use the pedal interceptor for longitudinal control</b> instead of camera ACC/Redneck when available.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>SASCM Support</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source><b>Does your vehicle support "SASCMs"?</b></source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FrogPilotVisualsPanel</name>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user