Compare commits

..

2 Commits

Author SHA1 Message Date
github-actions[bot] ccd5141fe8 sunnypilot v2025.09.08-3000
version: sunnypilot v0.10.1 (dev)
date: 2025-09-08T03:37:03
master commit: 698e0ca00f
2025-09-08 03:37:03 +00:00
github-actions[bot] 50313b9374 sunnypilot v2025.09.08-3000 release 2025-09-08 03:36:51 +00:00
282 changed files with 8776 additions and 5421 deletions
+30 -17
View File
@@ -22,34 +22,24 @@ https://docs.sunnypilot.ai/ is your one stop shop for everything from features t
Detailed instructions for [how to mount the device in a car](https://comma.ai/setup).
## Installation
Please refer to [Recommended Branches](#-recommended-branches) to find your preferred/supported branch. This guide will assume you want to install the latest `release-c3` branch.
Please refer to [Recommended Branches](#-recommended-branches) to find your preferred/supported branch. This guide will assume you want to install the latest `staging-c3-new` branch.
### If you want to use our newest branches (our rewrite)
> [!TIP]
>You can see the rewrite state on our [rewrite project board](https://github.com/orgs/sunnypilot/projects/2), and to install the new branches, you can use the following links
* sunnypilot not installed or you installed a version before 0.8.17?
1. [Factory reset/uninstall](https://github.com/commaai/openpilot/wiki/FAQ#how-can-i-reset-the-device) the previous software if you have another software/fork installed.
2. After factory reset/uninstall and upon reboot, select `Custom Software` when given the option.
3. Input the installation URL per [Recommended Branches](#-recommended-branches). Example: ```release-c3.sunnypilot.ai```.
3. Input the installation URL per [Recommended Branches](#-recommended-branches). Example: ```https://staging-c3-new.sunnypilot.ai```.
4. Complete the rest of the installation following the onscreen instructions.
* sunnypilot already installed and you installed a version after 0.8.17?
1. On the comma three, go to `Settings` ▶️ `Software`.
2. At the `Download` option, press `CHECK`. This will fetch the list of latest branches from sunnypilot.
3. At the `Target Branch` option, press `SELECT` to open the Target Branch selector.
4. Scroll to select the desired branch per Recommended Branches (see below). Example: `release-c3`
4. Scroll to select the desired branch per Recommended Branches (see below). Example: `staging-c3-new`
| Branch | Installation URL |
|:------------:|:--------------------------------:|
| `release-c3` | https://release-c3.sunnypilot.ai |
| `staging-c3` | https://staging-c3.sunnypilot.ai |
| `dev-c3` | https://dev-c3.sunnypilot.ai |
### If you want to use our newest branches (our rewrite)
> [!TIP]
>You can see the rewrite state on our [rewrite project board](https://github.com/orgs/sunnypilot/projects/2), and to install the new branches, you can use the following links
> [!IMPORTANT]
> It is recommended to [re-flash AGNOS](https://flash.comma.ai/) if you intend to downgrade from the new branches.
> You can still restore the latest sunnylink backup made on the old branches.
| Branch | Installation URL |
|:----------------:|:---------------------------------------------:|
@@ -59,8 +49,31 @@ Please refer to [Recommended Branches](#-recommended-branches) to find your pref
| `release-c3-new` | **Not yet available**. |
> [!TIP]
> You can use sunnypilot/targetbranch as an install URL. Example: 'sunnypilot/staging-c3-new'.
> [!NOTE]
> Do you require further assistance with software installation? Join the [sunnypilot Discord server](https://discord.sunnypilot.com) and message us in the `#installation-help` channel.
<details>
<summary>Older legacy branches</summary>
### If you want to use our older legacy branches (*not recommended*)
> [**IMPORTANT**]
> It is recommended to [re-flash AGNOS](https://flash.comma.ai/) if you intend to downgrade from the new branches.
> You can still restore the latest sunnylink backup made on the old branches.
| Branch | Installation URL |
|:------------:|:--------------------------------:|
| `release-c3` | https://release-c3.sunnypilot.ai |
| `staging-c3` | https://staging-c3.sunnypilot.ai |
| `dev-c3` | https://dev-c3.sunnypilot.ai |
</details>
## 🎆 Pull Requests
We welcome both pull requests and issues on GitHub. Bug fixes are encouraged.
+9 -5
View File
@@ -1,18 +1,22 @@
Version 0.10.1 (2025-09-08)
========================
* Record driving feedback using LKAS button
* Honda City 2023 support thanks to drFritz!
Version 0.10.0 (2025-08-05)
========================
* New driving model
* New training architecture
* Architecture outlined in CVPR paper: "Learning to Drive from a World Model"
* Longitudinal MPC replaced by E2E planning from worldmodel in experimental mode
* Action from lateral MPC as training objective replaced by E2E planning from worldmodel
* Described in our CVPR paper: "Learning to Drive from a World Model"
* Longitudinal MPC replaced by E2E planning from World Model in Experimental Mode
* Action from lateral MPC as training objective replaced by E2E planning from World Model
* Low-speed lead car ground-truth fixes
* Enable live-learned steering actuation delay
* Record driving feedback using LKAS button when MADS is disabled
* Opt-in audio recording for dashcam video
* Acura MDX 2025 support thanks to vanillagorillaa and MVL!
* Honda Accord 2023-25 support thanks to vanillagorillaa and MVL!
* Honda CR-V 2023-25 support thanks to vanillagorillaa and MVL!
* Honda Pilot 2023-25 support thanks to vanillagorillaa and MVL!
Version 0.9.9 (2025-05-23)
========================
+10 -1
View File
@@ -172,6 +172,8 @@ struct OnroadEventSP @0xda96579883444c35 {
experimentalModeSwitched @14;
wrongCarModeAlertOnly @15;
pedalPressedAlertOnly @16;
laneTurnLeft @17;
laneTurnRight @18;
}
}
@@ -258,9 +260,16 @@ struct LiveMapDataSP @0xf416ec09499d9d19 {
roadName @5 :Text;
}
struct CustomReserved9 @0xa1680744031fdb2d {
struct ModelDataV2SP @0xa1680744031fdb2d {
laneTurnDirection @0 :TurnDirection;
}
enum TurnDirection {
none @0;
turnLeft @1;
turnRight @2;
}
struct CustomReserved10 @0xcb9fd56c7057593a {
}
+115 -39
View File
@@ -1793,7 +1793,7 @@ const ::capnp::_::RawSchema s_f6e831752fcdf793 = {
1, 11, i_f6e831752fcdf793, nullptr, nullptr, { &s_f6e831752fcdf793, nullptr, nullptr, 0, 0, nullptr }, false
};
#endif // !CAPNP_LITE
static const ::capnp::_::AlignedData<119> b_b8007ed8a646b5e6 = {
static const ::capnp::_::AlignedData<129> b_b8007ed8a646b5e6 = {
{ 0, 0, 0, 0, 5, 0, 6, 0,
230, 181, 70, 166, 216, 126, 0, 184,
27, 0, 0, 0, 2, 0, 0, 0,
@@ -1803,7 +1803,7 @@ static const ::capnp::_::AlignedData<119> b_b8007ed8a646b5e6 = {
21, 0, 0, 0, 42, 1, 0, 0,
37, 0, 0, 0, 7, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
33, 0, 0, 0, 159, 1, 0, 0,
33, 0, 0, 0, 207, 1, 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,
@@ -1812,57 +1812,63 @@ static const ::capnp::_::AlignedData<119> b_b8007ed8a646b5e6 = {
83, 80, 46, 69, 118, 101, 110, 116,
78, 97, 109, 101, 0, 0, 0, 0,
0, 0, 0, 0, 1, 0, 1, 0,
68, 0, 0, 0, 1, 0, 2, 0,
76, 0, 0, 0, 1, 0, 2, 0,
0, 0, 0, 0, 0, 0, 0, 0,
197, 0, 0, 0, 90, 0, 0, 0,
221, 0, 0, 0, 90, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
193, 0, 0, 0, 98, 0, 0, 0,
217, 0, 0, 0, 98, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
2, 0, 0, 0, 0, 0, 0, 0,
189, 0, 0, 0, 186, 0, 0, 0,
213, 0, 0, 0, 186, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
3, 0, 0, 0, 0, 0, 0, 0,
189, 0, 0, 0, 218, 0, 0, 0,
213, 0, 0, 0, 218, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
4, 0, 0, 0, 0, 0, 0, 0,
193, 0, 0, 0, 138, 0, 0, 0,
217, 0, 0, 0, 138, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
5, 0, 0, 0, 0, 0, 0, 0,
193, 0, 0, 0, 146, 0, 0, 0,
217, 0, 0, 0, 146, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
6, 0, 0, 0, 0, 0, 0, 0,
193, 0, 0, 0, 130, 0, 0, 0,
217, 0, 0, 0, 130, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
7, 0, 0, 0, 0, 0, 0, 0,
189, 0, 0, 0, 130, 0, 0, 0,
213, 0, 0, 0, 130, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
8, 0, 0, 0, 0, 0, 0, 0,
185, 0, 0, 0, 146, 0, 0, 0,
209, 0, 0, 0, 146, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
9, 0, 0, 0, 0, 0, 0, 0,
185, 0, 0, 0, 122, 0, 0, 0,
209, 0, 0, 0, 122, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
10, 0, 0, 0, 0, 0, 0, 0,
181, 0, 0, 0, 202, 0, 0, 0,
205, 0, 0, 0, 202, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
11, 0, 0, 0, 0, 0, 0, 0,
185, 0, 0, 0, 130, 0, 0, 0,
209, 0, 0, 0, 130, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
12, 0, 0, 0, 0, 0, 0, 0,
181, 0, 0, 0, 194, 0, 0, 0,
205, 0, 0, 0, 194, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
13, 0, 0, 0, 0, 0, 0, 0,
181, 0, 0, 0, 226, 0, 0, 0,
205, 0, 0, 0, 226, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
14, 0, 0, 0, 0, 0, 0, 0,
185, 0, 0, 0, 202, 0, 0, 0,
209, 0, 0, 0, 202, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
15, 0, 0, 0, 0, 0, 0, 0,
189, 0, 0, 0, 178, 0, 0, 0,
213, 0, 0, 0, 178, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
16, 0, 0, 0, 0, 0, 0, 0,
189, 0, 0, 0, 178, 0, 0, 0,
213, 0, 0, 0, 178, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
17, 0, 0, 0, 0, 0, 0, 0,
213, 0, 0, 0, 106, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
18, 0, 0, 0, 0, 0, 0, 0,
209, 0, 0, 0, 114, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
108, 107, 97, 115, 69, 110, 97, 98,
108, 101, 0, 0, 0, 0, 0, 0,
@@ -1912,14 +1918,18 @@ static const ::capnp::_::AlignedData<119> b_b8007ed8a646b5e6 = {
116, 79, 110, 108, 121, 0, 0, 0,
112, 101, 100, 97, 108, 80, 114, 101,
115, 115, 101, 100, 65, 108, 101, 114,
116, 79, 110, 108, 121, 0, 0, 0, }
116, 79, 110, 108, 121, 0, 0, 0,
108, 97, 110, 101, 84, 117, 114, 110,
76, 101, 102, 116, 0, 0, 0, 0,
108, 97, 110, 101, 84, 117, 114, 110,
82, 105, 103, 104, 116, 0, 0, 0, }
};
::capnp::word const* const bp_b8007ed8a646b5e6 = b_b8007ed8a646b5e6.words;
#if !CAPNP_LITE
static const uint16_t m_b8007ed8a646b5e6[] = {12, 14, 13, 1, 0, 3, 2, 16, 6, 9, 5, 4, 11, 8, 10, 7, 15};
static const uint16_t m_b8007ed8a646b5e6[] = {12, 14, 13, 17, 18, 1, 0, 3, 2, 16, 6, 9, 5, 4, 11, 8, 10, 7, 15};
const ::capnp::_::RawSchema s_b8007ed8a646b5e6 = {
0xb8007ed8a646b5e6, b_b8007ed8a646b5e6.words, 119, nullptr, m_b8007ed8a646b5e6,
0, 17, nullptr, nullptr, nullptr, { &s_b8007ed8a646b5e6, nullptr, nullptr, 0, 0, nullptr }, false
0xb8007ed8a646b5e6, b_b8007ed8a646b5e6.words, 129, nullptr, m_b8007ed8a646b5e6,
0, 19, nullptr, nullptr, nullptr, { &s_b8007ed8a646b5e6, nullptr, nullptr, 0, 0, nullptr }, false
};
#endif // !CAPNP_LITE
CAPNP_DEFINE_ENUM(EventName_b8007ed8a646b5e6, b8007ed8a646b5e6);
@@ -3016,32 +3026,98 @@ const ::capnp::_::RawSchema s_f416ec09499d9d19 = {
0, 6, i_f416ec09499d9d19, nullptr, nullptr, { &s_f416ec09499d9d19, nullptr, nullptr, 0, 0, nullptr }, false
};
#endif // !CAPNP_LITE
static const ::capnp::_::AlignedData<17> b_a1680744031fdb2d = {
static const ::capnp::_::AlignedData<35> b_a1680744031fdb2d = {
{ 0, 0, 0, 0, 5, 0, 6, 0,
45, 219, 31, 3, 68, 7, 104, 161,
13, 0, 0, 0, 1, 0, 0, 0,
13, 0, 0, 0, 1, 0, 1, 0,
89, 10, 85, 29, 102, 186, 38, 181,
0, 0, 7, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
21, 0, 0, 0, 234, 0, 0, 0,
21, 0, 0, 0, 218, 0, 0, 0,
33, 0, 0, 0, 7, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
29, 0, 0, 0, 63, 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, 67, 117, 115,
116, 111, 109, 82, 101, 115, 101, 114,
118, 101, 100, 57, 0, 0, 0, 0,
0, 0, 0, 0, 1, 0, 1, 0, }
97, 112, 110, 112, 58, 77, 111, 100,
101, 108, 68, 97, 116, 97, 86, 50,
83, 80, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 1, 0, 1, 0,
4, 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,
13, 0, 0, 0, 146, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
16, 0, 0, 0, 3, 0, 1, 0,
28, 0, 0, 0, 2, 0, 1, 0,
108, 97, 110, 101, 84, 117, 114, 110,
68, 105, 114, 101, 99, 116, 105, 111,
110, 0, 0, 0, 0, 0, 0, 0,
15, 0, 0, 0, 0, 0, 0, 0,
150, 169, 61, 176, 185, 17, 36, 191,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
15, 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_a1680744031fdb2d = b_a1680744031fdb2d.words;
#if !CAPNP_LITE
static const ::capnp::_::RawSchema* const d_a1680744031fdb2d[] = {
&s_bf2411b9b03da996,
};
static const uint16_t m_a1680744031fdb2d[] = {0};
static const uint16_t i_a1680744031fdb2d[] = {0};
const ::capnp::_::RawSchema s_a1680744031fdb2d = {
0xa1680744031fdb2d, b_a1680744031fdb2d.words, 17, nullptr, nullptr,
0, 0, nullptr, nullptr, nullptr, { &s_a1680744031fdb2d, nullptr, nullptr, 0, 0, nullptr }, false
0xa1680744031fdb2d, b_a1680744031fdb2d.words, 35, d_a1680744031fdb2d, m_a1680744031fdb2d,
1, 1, i_a1680744031fdb2d, nullptr, nullptr, { &s_a1680744031fdb2d, nullptr, nullptr, 0, 0, nullptr }, false
};
#endif // !CAPNP_LITE
static const ::capnp::_::AlignedData<32> b_bf2411b9b03da996 = {
{ 0, 0, 0, 0, 5, 0, 6, 0,
150, 169, 61, 176, 185, 17, 36, 191,
13, 0, 0, 0, 2, 0, 0, 0,
89, 10, 85, 29, 102, 186, 38, 181,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
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, 79, 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, 84, 117, 114,
110, 68, 105, 114, 101, 99, 116, 105,
111, 110, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 1, 0, 1, 0,
12, 0, 0, 0, 1, 0, 2, 0,
0, 0, 0, 0, 0, 0, 0, 0,
29, 0, 0, 0, 42, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
21, 0, 0, 0, 74, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
2, 0, 0, 0, 0, 0, 0, 0,
17, 0, 0, 0, 82, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
110, 111, 110, 101, 0, 0, 0, 0,
116, 117, 114, 110, 76, 101, 102, 116,
0, 0, 0, 0, 0, 0, 0, 0,
116, 117, 114, 110, 82, 105, 103, 104,
116, 0, 0, 0, 0, 0, 0, 0, }
};
::capnp::word const* const bp_bf2411b9b03da996 = b_bf2411b9b03da996.words;
#if !CAPNP_LITE
static const uint16_t m_bf2411b9b03da996[] = {0, 1, 2};
const ::capnp::_::RawSchema s_bf2411b9b03da996 = {
0xbf2411b9b03da996, b_bf2411b9b03da996.words, 32, nullptr, m_bf2411b9b03da996,
0, 3, nullptr, nullptr, nullptr, { &s_bf2411b9b03da996, nullptr, nullptr, 0, 0, nullptr }, false
};
#endif // !CAPNP_LITE
CAPNP_DEFINE_ENUM(TurnDirection_bf2411b9b03da996, bf2411b9b03da996);
static const ::capnp::_::AlignedData<17> b_cb9fd56c7057593a = {
{ 0, 0, 0, 0, 5, 0, 6, 0,
58, 89, 87, 112, 108, 213, 159, 203,
@@ -3609,15 +3685,15 @@ constexpr ::capnp::_::RawSchema const* LiveMapDataSP::_capnpPrivate::schema;
#endif // !CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
#endif // !CAPNP_LITE
// CustomReserved9
// ModelDataV2SP
#if CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
constexpr uint16_t CustomReserved9::_capnpPrivate::dataWordSize;
constexpr uint16_t CustomReserved9::_capnpPrivate::pointerCount;
constexpr uint16_t ModelDataV2SP::_capnpPrivate::dataWordSize;
constexpr uint16_t ModelDataV2SP::_capnpPrivate::pointerCount;
#endif // !CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
#if !CAPNP_LITE
#if CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
constexpr ::capnp::Kind CustomReserved9::_capnpPrivate::kind;
constexpr ::capnp::_::RawSchema const* CustomReserved9::_capnpPrivate::schema;
constexpr ::capnp::Kind ModelDataV2SP::_capnpPrivate::kind;
constexpr ::capnp::_::RawSchema const* ModelDataV2SP::_capnpPrivate::schema;
#endif // !CAPNP_NEED_REDUNDANT_CONSTEXPR_DECL
#endif // !CAPNP_LITE
+39 -9
View File
@@ -90,6 +90,8 @@ enum class EventName_b8007ed8a646b5e6: uint16_t {
EXPERIMENTAL_MODE_SWITCHED,
WRONG_CAR_MODE_ALERT_ONLY,
PEDAL_PRESSED_ALERT_ONLY,
LANE_TURN_LEFT,
LANE_TURN_RIGHT,
};
CAPNP_DECLARE_ENUM(EventName, b8007ed8a646b5e6);
CAPNP_DECLARE_SCHEMA(80ae746ee2596b11);
@@ -112,6 +114,13 @@ CAPNP_DECLARE_SCHEMA(9e62278160b7df26);
CAPNP_DECLARE_SCHEMA(b86e6369214c01c8);
CAPNP_DECLARE_SCHEMA(f416ec09499d9d19);
CAPNP_DECLARE_SCHEMA(a1680744031fdb2d);
CAPNP_DECLARE_SCHEMA(bf2411b9b03da996);
enum class TurnDirection_bf2411b9b03da996: uint16_t {
NONE,
TURN_LEFT,
TURN_RIGHT,
};
CAPNP_DECLARE_ENUM(TurnDirection, bf2411b9b03da996);
CAPNP_DECLARE_SCHEMA(cb9fd56c7057593a);
CAPNP_DECLARE_SCHEMA(c2243c65e0340384);
CAPNP_DECLARE_SCHEMA(9ccdc8676701b412);
@@ -531,21 +540,23 @@ struct LiveMapDataSP {
};
};
struct CustomReserved9 {
CustomReserved9() = delete;
struct ModelDataV2SP {
ModelDataV2SP() = delete;
class Reader;
class Builder;
class Pipeline;
struct _capnpPrivate {
CAPNP_DECLARE_STRUCT_HEADER(a1680744031fdb2d, 0, 0)
CAPNP_DECLARE_STRUCT_HEADER(a1680744031fdb2d, 1, 0)
#if !CAPNP_LITE
static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; }
#endif // !CAPNP_LITE
};
};
typedef ::capnp::schemas::TurnDirection_bf2411b9b03da996 TurnDirection;
struct CustomReserved10 {
CustomReserved10() = delete;
@@ -3249,9 +3260,9 @@ private:
};
#endif // !CAPNP_LITE
class CustomReserved9::Reader {
class ModelDataV2SP::Reader {
public:
typedef CustomReserved9 Reads;
typedef ModelDataV2SP Reads;
Reader() = default;
inline explicit Reader(::capnp::_::StructReader base): _reader(base) {}
@@ -3266,6 +3277,8 @@ public:
}
#endif // !CAPNP_LITE
inline ::cereal::TurnDirection getLaneTurnDirection() const;
private:
::capnp::_::StructReader _reader;
template <typename, ::capnp::Kind>
@@ -3278,9 +3291,9 @@ private:
friend class ::capnp::Orphanage;
};
class CustomReserved9::Builder {
class ModelDataV2SP::Builder {
public:
typedef CustomReserved9 Builds;
typedef ModelDataV2SP Builds;
Builder() = delete; // Deleted to discourage incorrect usage.
// You can explicitly initialize to nullptr instead.
@@ -3294,6 +3307,9 @@ public:
inline ::kj::StringTree toString() const { return asReader().toString(); }
#endif // !CAPNP_LITE
inline ::cereal::TurnDirection getLaneTurnDirection();
inline void setLaneTurnDirection( ::cereal::TurnDirection value);
private:
::capnp::_::StructBuilder _builder;
template <typename, ::capnp::Kind>
@@ -3304,9 +3320,9 @@ private:
};
#if !CAPNP_LITE
class CustomReserved9::Pipeline {
class ModelDataV2SP::Pipeline {
public:
typedef CustomReserved9 Pipelines;
typedef ModelDataV2SP Pipelines;
inline Pipeline(decltype(nullptr)): _typeless(nullptr) {}
inline explicit Pipeline(::capnp::AnyPointer::Pipeline&& typeless)
@@ -6509,6 +6525,20 @@ inline ::capnp::Orphan< ::capnp::Text> LiveMapDataSP::Builder::disownRoadName()
::capnp::bounded<0>() * ::capnp::POINTERS));
}
inline ::cereal::TurnDirection ModelDataV2SP::Reader::getLaneTurnDirection() const {
return _reader.getDataField< ::cereal::TurnDirection>(
::capnp::bounded<0>() * ::capnp::ELEMENTS);
}
inline ::cereal::TurnDirection ModelDataV2SP::Builder::getLaneTurnDirection() {
return _builder.getDataField< ::cereal::TurnDirection>(
::capnp::bounded<0>() * ::capnp::ELEMENTS);
}
inline void ModelDataV2SP::Builder::setLaneTurnDirection( ::cereal::TurnDirection value) {
_builder.setDataField< ::cereal::TurnDirection>(
::capnp::bounded<0>() * ::capnp::ELEMENTS, value);
}
} // namespace
CAPNP_END_HEADER
+4 -4
View File
@@ -31283,7 +31283,7 @@ static const ::capnp::_::AlignedData<2557> b_d314cfd957229c11 = {
96, 0, 141, 255, 0, 0, 0, 0,
0, 0, 1, 0, 116, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
165, 21, 0, 0, 130, 0, 0, 0,
165, 21, 0, 0, 114, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
164, 21, 0, 0, 3, 0, 1, 0,
176, 21, 0, 0, 2, 0, 1, 0,
@@ -32669,8 +32669,8 @@ static const ::capnp::_::AlignedData<2557> b_d314cfd957229c11 = {
16, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
99, 117, 115, 116, 111, 109, 82, 101,
115, 101, 114, 118, 101, 100, 57, 0,
109, 111, 100, 101, 108, 68, 97, 116,
97, 86, 50, 83, 80, 0, 0, 0,
16, 0, 0, 0, 0, 0, 0, 0,
45, 219, 31, 3, 68, 7, 104, 161,
0, 0, 0, 0, 0, 0, 0, 0,
@@ -33122,7 +33122,7 @@ static const ::capnp::_::RawSchema* const d_d314cfd957229c11[] = {
&s_fe346a9de48d9b50,
&s_fe35ad896ffaeacf,
};
static const uint16_t m_d314cfd957229c11[] = {98, 101, 133, 30, 20, 55, 42, 149, 113, 148, 60, 63, 5, 23, 112, 127, 69, 111, 22, 114, 28, 35, 7, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 116, 124, 125, 126, 6, 132, 70, 87, 76, 71, 59, 92, 128, 85, 26, 10, 91, 21, 48, 3, 41, 40, 99, 100, 1, 65, 64, 32, 96, 19, 146, 8, 46, 25, 72, 51, 44, 37, 62, 115, 36, 61, 129, 94, 131, 16, 14, 122, 119, 120, 117, 121, 118, 49, 18, 0, 24, 109, 95, 78, 105, 9, 108, 75, 82, 104, 83, 38, 84, 27, 134, 68, 110, 54, 58, 56, 47, 53, 45, 12, 81, 80, 33, 89, 90, 31, 13, 147, 2, 86, 15, 130, 107, 17, 4, 11, 73, 103, 97, 123, 52, 66, 135, 43, 34, 39, 102, 57, 50, 106, 79, 93, 67, 74, 88, 77, 29};
static const uint16_t m_d314cfd957229c11[] = {98, 101, 133, 30, 20, 55, 42, 149, 113, 148, 60, 63, 5, 23, 112, 127, 69, 111, 22, 114, 28, 35, 7, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 124, 125, 126, 6, 132, 70, 87, 76, 71, 59, 92, 128, 85, 26, 10, 91, 21, 48, 3, 41, 40, 99, 100, 1, 65, 64, 32, 96, 19, 146, 8, 46, 25, 72, 51, 44, 37, 62, 115, 36, 61, 129, 94, 131, 16, 14, 122, 119, 120, 117, 121, 118, 49, 18, 0, 24, 109, 95, 78, 105, 9, 116, 108, 75, 82, 104, 83, 38, 84, 27, 134, 68, 110, 54, 58, 56, 47, 53, 45, 12, 81, 80, 33, 89, 90, 31, 13, 147, 2, 86, 15, 130, 107, 17, 4, 11, 73, 103, 97, 123, 52, 66, 135, 43, 34, 39, 102, 57, 50, 106, 79, 93, 67, 74, 88, 77, 29};
static const uint16_t i_d314cfd957229c11[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 0, 67};
const ::capnp::_::RawSchema s_d314cfd957229c11 = {
0xd314cfd957229c11, b_d314cfd957229c11.words, 2557, d_d314cfd957229c11, m_d314cfd957229c11,
+38 -38
View File
@@ -2876,7 +2876,7 @@ struct Event {
BACKUP_MANAGER_S_P,
CAR_STATE_S_P,
LIVE_MAP_DATA_S_P,
CUSTOM_RESERVED9,
MODEL_DATA_V2_S_P,
LIVESTREAM_ROAD_ENCODE_IDX,
LIVESTREAM_WIDE_ROAD_ENCODE_IDX,
LIVESTREAM_DRIVER_ENCODE_IDX,
@@ -21598,9 +21598,9 @@ public:
inline bool hasLiveMapDataSP() const;
inline ::cereal::LiveMapDataSP::Reader getLiveMapDataSP() const;
inline bool isCustomReserved9() const;
inline bool hasCustomReserved9() const;
inline ::cereal::CustomReserved9::Reader getCustomReserved9() const;
inline bool isModelDataV2SP() const;
inline bool hasModelDataV2SP() const;
inline ::cereal::ModelDataV2SP::Reader getModelDataV2SP() const;
inline bool isLivestreamRoadEncodeIdx() const;
inline bool hasLivestreamRoadEncodeIdx() const;
@@ -22681,13 +22681,13 @@ public:
inline void adoptLiveMapDataSP(::capnp::Orphan< ::cereal::LiveMapDataSP>&& value);
inline ::capnp::Orphan< ::cereal::LiveMapDataSP> disownLiveMapDataSP();
inline bool isCustomReserved9();
inline bool hasCustomReserved9();
inline ::cereal::CustomReserved9::Builder getCustomReserved9();
inline void setCustomReserved9( ::cereal::CustomReserved9::Reader value);
inline ::cereal::CustomReserved9::Builder initCustomReserved9();
inline void adoptCustomReserved9(::capnp::Orphan< ::cereal::CustomReserved9>&& value);
inline ::capnp::Orphan< ::cereal::CustomReserved9> disownCustomReserved9();
inline bool isModelDataV2SP();
inline bool hasModelDataV2SP();
inline ::cereal::ModelDataV2SP::Builder getModelDataV2SP();
inline void setModelDataV2SP( ::cereal::ModelDataV2SP::Reader value);
inline ::cereal::ModelDataV2SP::Builder initModelDataV2SP();
inline void adoptModelDataV2SP(::capnp::Orphan< ::cereal::ModelDataV2SP>&& value);
inline ::capnp::Orphan< ::cereal::ModelDataV2SP> disownModelDataV2SP();
inline bool isLivestreamRoadEncodeIdx();
inline bool hasLivestreamRoadEncodeIdx();
@@ -57664,57 +57664,57 @@ inline ::capnp::Orphan< ::cereal::LiveMapDataSP> Event::Builder::disownLiveMapDa
::capnp::bounded<0>() * ::capnp::POINTERS));
}
inline bool Event::Reader::isCustomReserved9() const {
return which() == Event::CUSTOM_RESERVED9;
inline bool Event::Reader::isModelDataV2SP() const {
return which() == Event::MODEL_DATA_V2_S_P;
}
inline bool Event::Builder::isCustomReserved9() {
return which() == Event::CUSTOM_RESERVED9;
inline bool Event::Builder::isModelDataV2SP() {
return which() == Event::MODEL_DATA_V2_S_P;
}
inline bool Event::Reader::hasCustomReserved9() const {
if (which() != Event::CUSTOM_RESERVED9) return false;
inline bool Event::Reader::hasModelDataV2SP() const {
if (which() != Event::MODEL_DATA_V2_S_P) return false;
return !_reader.getPointerField(
::capnp::bounded<0>() * ::capnp::POINTERS).isNull();
}
inline bool Event::Builder::hasCustomReserved9() {
if (which() != Event::CUSTOM_RESERVED9) return false;
inline bool Event::Builder::hasModelDataV2SP() {
if (which() != Event::MODEL_DATA_V2_S_P) return false;
return !_builder.getPointerField(
::capnp::bounded<0>() * ::capnp::POINTERS).isNull();
}
inline ::cereal::CustomReserved9::Reader Event::Reader::getCustomReserved9() const {
KJ_IREQUIRE((which() == Event::CUSTOM_RESERVED9),
inline ::cereal::ModelDataV2SP::Reader Event::Reader::getModelDataV2SP() const {
KJ_IREQUIRE((which() == Event::MODEL_DATA_V2_S_P),
"Must check which() before get()ing a union member.");
return ::capnp::_::PointerHelpers< ::cereal::CustomReserved9>::get(_reader.getPointerField(
return ::capnp::_::PointerHelpers< ::cereal::ModelDataV2SP>::get(_reader.getPointerField(
::capnp::bounded<0>() * ::capnp::POINTERS));
}
inline ::cereal::CustomReserved9::Builder Event::Builder::getCustomReserved9() {
KJ_IREQUIRE((which() == Event::CUSTOM_RESERVED9),
inline ::cereal::ModelDataV2SP::Builder Event::Builder::getModelDataV2SP() {
KJ_IREQUIRE((which() == Event::MODEL_DATA_V2_S_P),
"Must check which() before get()ing a union member.");
return ::capnp::_::PointerHelpers< ::cereal::CustomReserved9>::get(_builder.getPointerField(
return ::capnp::_::PointerHelpers< ::cereal::ModelDataV2SP>::get(_builder.getPointerField(
::capnp::bounded<0>() * ::capnp::POINTERS));
}
inline void Event::Builder::setCustomReserved9( ::cereal::CustomReserved9::Reader value) {
inline void Event::Builder::setModelDataV2SP( ::cereal::ModelDataV2SP::Reader value) {
_builder.setDataField<Event::Which>(
::capnp::bounded<4>() * ::capnp::ELEMENTS, Event::CUSTOM_RESERVED9);
::capnp::_::PointerHelpers< ::cereal::CustomReserved9>::set(_builder.getPointerField(
::capnp::bounded<4>() * ::capnp::ELEMENTS, Event::MODEL_DATA_V2_S_P);
::capnp::_::PointerHelpers< ::cereal::ModelDataV2SP>::set(_builder.getPointerField(
::capnp::bounded<0>() * ::capnp::POINTERS), value);
}
inline ::cereal::CustomReserved9::Builder Event::Builder::initCustomReserved9() {
inline ::cereal::ModelDataV2SP::Builder Event::Builder::initModelDataV2SP() {
_builder.setDataField<Event::Which>(
::capnp::bounded<4>() * ::capnp::ELEMENTS, Event::CUSTOM_RESERVED9);
return ::capnp::_::PointerHelpers< ::cereal::CustomReserved9>::init(_builder.getPointerField(
::capnp::bounded<4>() * ::capnp::ELEMENTS, Event::MODEL_DATA_V2_S_P);
return ::capnp::_::PointerHelpers< ::cereal::ModelDataV2SP>::init(_builder.getPointerField(
::capnp::bounded<0>() * ::capnp::POINTERS));
}
inline void Event::Builder::adoptCustomReserved9(
::capnp::Orphan< ::cereal::CustomReserved9>&& value) {
inline void Event::Builder::adoptModelDataV2SP(
::capnp::Orphan< ::cereal::ModelDataV2SP>&& value) {
_builder.setDataField<Event::Which>(
::capnp::bounded<4>() * ::capnp::ELEMENTS, Event::CUSTOM_RESERVED9);
::capnp::_::PointerHelpers< ::cereal::CustomReserved9>::adopt(_builder.getPointerField(
::capnp::bounded<4>() * ::capnp::ELEMENTS, Event::MODEL_DATA_V2_S_P);
::capnp::_::PointerHelpers< ::cereal::ModelDataV2SP>::adopt(_builder.getPointerField(
::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value));
}
inline ::capnp::Orphan< ::cereal::CustomReserved9> Event::Builder::disownCustomReserved9() {
KJ_IREQUIRE((which() == Event::CUSTOM_RESERVED9),
inline ::capnp::Orphan< ::cereal::ModelDataV2SP> Event::Builder::disownModelDataV2SP() {
KJ_IREQUIRE((which() == Event::MODEL_DATA_V2_S_P),
"Must check which() before get()ing a union member.");
return ::capnp::_::PointerHelpers< ::cereal::CustomReserved9>::disown(_builder.getPointerField(
return ::capnp::_::PointerHelpers< ::cereal::ModelDataV2SP>::disown(_builder.getPointerField(
::capnp::bounded<0>() * ::capnp::POINTERS));
}
+1 -1
View File
@@ -2631,7 +2631,7 @@ struct Event {
backupManagerSP @113 :Custom.BackupManagerSP;
carStateSP @114 :Custom.CarStateSP;
liveMapDataSP @115 :Custom.LiveMapDataSP;
customReserved9 @116 :Custom.CustomReserved9;
modelDataV2SP @116 :Custom.ModelDataV2SP;
customReserved10 @136 :Custom.CustomReserved10;
customReserved11 @137 :Custom.CustomReserved11;
customReserved12 @138 :Custom.CustomReserved12;
Binary file not shown.
+1
View File
@@ -79,6 +79,7 @@ static std::map<std::string, service> services = {
{ "carControlSP", {"carControlSP", true, 100, 10}},
{ "carStateSP", {"carStateSP", true, 100, 10}},
{ "liveMapDataSP", {"liveMapDataSP", true, 1, 1}},
{ "modelDataV2SP", {"modelDataV2SP", true, 20, -1}},
{ "uiDebug", {"uiDebug", true, 0, 1}},
{ "testJoystick", {"testJoystick", true, 0, -1}},
{ "alertDebug", {"alertDebug", true, 20, 5}},
+1
View File
@@ -88,6 +88,7 @@ _services: dict[str, tuple] = {
"carControlSP": (True, 100., 10),
"carStateSP": (True, 100., 10),
"liveMapDataSP": (True, 1., 1),
"modelDataV2SP": (True, 20.),
# debug
"uiDebug": (True, 0., 1),
+1 -1
View File
@@ -1 +1 @@
#define DEFAULT_MODEL "Down To Ride (Default)"
#define DEFAULT_MODEL "Steam Powered (Default)"
+12 -5
View File
@@ -73,9 +73,9 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"LastOffroadStatusPacket", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, JSON}},
{"LastPowerDropDetected", {CLEAR_ON_MANAGER_START, STRING}},
{"LastUpdateException", {CLEAR_ON_MANAGER_START, STRING}},
{"LastUpdateRouteCount", {PERSISTENT, INT}},
{"LastUpdateRouteCount", {PERSISTENT, INT, "0"}},
{"LastUpdateTime", {PERSISTENT, TIME}},
{"LastUpdateUptimeOnroad", {PERSISTENT, FLOAT}},
{"LastUpdateUptimeOnroad", {PERSISTENT, FLOAT, "0.0"}},
{"LiveDelay", {PERSISTENT | BACKUP, BYTES}},
{"LiveParameters", {PERSISTENT, JSON}},
{"LiveParametersV2", {PERSISTENT, BYTES}},
@@ -146,14 +146,18 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"CustomAccLongPressIncrement", {PERSISTENT | BACKUP, INT, "5"}},
{"CustomAccShortPressIncrement", {PERSISTENT | BACKUP, INT, "1"}},
{"DeviceBootMode", {PERSISTENT | BACKUP, INT, "0"}},
{"EnableCopyparty", {PERSISTENT | BACKUP, BOOL}},
{"EnableGithubRunner", {PERSISTENT | BACKUP, BOOL}},
{"GithubRunnerSufficientVoltage", {CLEAR_ON_MANAGER_START , BOOL}},
{"InteractivityTimeout", {PERSISTENT | BACKUP, INT, "0"}},
{"IsDevelopmentBranch", {CLEAR_ON_MANAGER_START, BOOL}},
{"MaxTimeOffroad", {PERSISTENT | BACKUP, INT, "1800"}},
{"ModelRunnerTypeCache", {CLEAR_ON_ONROAD_TRANSITION, INT}},
{"OffroadMode", {CLEAR_ON_MANAGER_START, BOOL}},
{"Offroad_TiciSupport", {CLEAR_ON_MANAGER_START, JSON}},
{"QuickBootToggle", {PERSISTENT | BACKUP, BOOL, "0"}},
{"QuietMode", {PERSISTENT | BACKUP, BOOL, "0"}},
{"RainbowMode", {PERSISTENT | BACKUP, BOOL, "0"}},
{"ShowAdvancedControls", {PERSISTENT | BACKUP, BOOL, "0"}},
// MADS params
@@ -166,6 +170,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"ModelManager_ActiveBundle", {PERSISTENT, JSON}},
{"ModelManager_ClearCache", {CLEAR_ON_MANAGER_START, BOOL}},
{"ModelManager_DownloadIndex", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, INT, "0"}},
{"ModelManager_Favs", {PERSISTENT | BACKUP, STRING}},
{"ModelManager_LastSyncTime", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, INT, "0"}},
{"ModelManager_ModelsCache", {PERSISTENT | BACKUP, JSON}},
@@ -191,14 +196,16 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"DynamicExperimentalControl", {PERSISTENT | BACKUP, BOOL, "0"}},
{"BlindSpot", {PERSISTENT | BACKUP, BOOL, "0"}},
// model panel params
// sunnypilot model params
{"LagdToggle", {PERSISTENT | BACKUP, BOOL, "1"}},
{"LagdToggleDelay", {PERSISTENT | BACKUP, FLOAT, "0.2"}},
{"LagdValueCache", {PERSISTENT, FLOAT, "0.2"}},
{"LaneTurnDesire", {PERSISTENT | BACKUP, BOOL, "0"}},
{"LaneTurnValue", {PERSISTENT | BACKUP, FLOAT, "19.0"}},
// mapd
{"MapAdvisorySpeedLimit", {CLEAR_ON_ONROAD_TRANSITION, FLOAT}},
{"MapdVersion", {PERSISTENT, STRING, ""}},
{"MapdVersion", {PERSISTENT, STRING}},
{"MapSpeedLimit", {CLEAR_ON_ONROAD_TRANSITION, FLOAT, "0.0"}},
{"NextMapSpeedLimit", {CLEAR_ON_ONROAD_TRANSITION, JSON}},
{"Offroad_OSMUpdateRequired", {CLEAR_ON_MANAGER_START, JSON}},
@@ -214,5 +221,5 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"OsmStateName", {PERSISTENT, STRING, "All"}},
{"OsmStateTitle", {PERSISTENT, STRING}},
{"OsmWayTest", {PERSISTENT, STRING}},
{"RoadName", {CLEAR_ON_ONROAD_TRANSITION, STRING, ""}},
{"RoadName", {CLEAR_ON_ONROAD_TRANSITION, STRING}},
};
Binary file not shown.
+5 -2
View File
@@ -14,8 +14,7 @@ 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.i_rate = 1.0 / rate
self.speed = 0.0
@@ -41,6 +40,10 @@ class PIDController:
self.f = 0.0
self.control = 0
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 = float(error) * self.k_p
+15
View File
@@ -1,4 +1,6 @@
import subprocess
from contextlib import contextmanager
from subprocess import Popen, PIPE, TimeoutExpired
def run_cmd(cmd: list[str], cwd=None, env=None) -> str:
@@ -11,3 +13,16 @@ def run_cmd_default(cmd: list[str], default: str = "", cwd=None, env=None) -> st
except subprocess.CalledProcessError:
return default
@contextmanager
def managed_proc(cmd: list[str], env: dict[str, str]):
proc = Popen(cmd, env=env, stdout=PIPE, stderr=PIPE)
try:
yield proc
finally:
if proc.poll() is None:
proc.terminate()
try:
proc.wait(timeout=5)
except TimeoutExpired:
proc.kill()
File diff suppressed because it is too large Load Diff
Binary file not shown.
+1 -1
View File
@@ -1 +1 @@
#define COMMA_VERSION "2025.08.13-2695"
#define COMMA_VERSION "2025.09.08-3000"
+12
View File
@@ -857,6 +857,12 @@
"file": "/data/openpilot/selfdrive/ui/sunnypilot/qt/widgets/expandable_row.cc",
"output": "/data/openpilot/selfdrive/ui/sunnypilot/qt/widgets/expandable_row.o"
},
{
"command": "clang++ -o selfdrive/ui/sunnypilot/qt/widgets/external_storage.o -c -std=c++1z -DQCOM2 -mcpu=cortex-a57 -DSUNNYPILOT -D_REENTRANT -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_MESSAGELOGCONTEXT -Wno-deprecated-declarations -g -fPIC -O2 -Wunused -Werror -Wshadow -Wno-unknown-warning-option -Wno-inconsistent-missing-override -Wno-c99-designator -Wno-reorder-init-list -Wno-vla-cxx-extension -DQCOM2 -mcpu=cortex-a57 -DSUNNYPILOT -Ithird_party/opencl/include -I. -Ithird_party/acados/include -Ithird_party/acados/include/blasfeo/include -Ithird_party/acados/include/hpipm/include -Ithird_party/catch2/include -Ithird_party/libyuv/include -Ithird_party/json11 -Ithird_party/linux/include -Ithird_party/snpe/include -Ithird_party -Imsgq -I/usr/include -I/usr/include/aarch64-linux-gnu/qt5 -I/usr/include/aarch64-linux-gnu/qt5/QtGui/5.12.8/QtGui -I/usr/include/aarch64-linux-gnu/qt5/QtWidgets -I/usr/include/aarch64-linux-gnu/qt5/QtGui -I/usr/include/aarch64-linux-gnu/qt5/QtCore -I/usr/include/aarch64-linux-gnu/qt5/QtNetwork -I/usr/include/aarch64-linux-gnu/qt5/QtConcurrent -I/usr/include/aarch64-linux-gnu/qt5/QtDBus -I/usr/include/aarch64-linux-gnu/qt5/QtXml -Ithird_party/qrcode selfdrive/ui/sunnypilot/qt/widgets/external_storage.cc",
"directory": "/data/openpilot",
"file": "/data/openpilot/selfdrive/ui/sunnypilot/qt/widgets/external_storage.cc",
"output": "/data/openpilot/selfdrive/ui/sunnypilot/qt/widgets/external_storage.o"
},
{
"command": "clang++ -o selfdrive/ui/sunnypilot/qt/widgets/prime.o -c -std=c++1z -DQCOM2 -mcpu=cortex-a57 -DSUNNYPILOT -D_REENTRANT -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_MESSAGELOGCONTEXT -Wno-deprecated-declarations -g -fPIC -O2 -Wunused -Werror -Wshadow -Wno-unknown-warning-option -Wno-inconsistent-missing-override -Wno-c99-designator -Wno-reorder-init-list -Wno-vla-cxx-extension -DQCOM2 -mcpu=cortex-a57 -DSUNNYPILOT -Ithird_party/opencl/include -I. -Ithird_party/acados/include -Ithird_party/acados/include/blasfeo/include -Ithird_party/acados/include/hpipm/include -Ithird_party/catch2/include -Ithird_party/libyuv/include -Ithird_party/json11 -Ithird_party/linux/include -Ithird_party/snpe/include -Ithird_party -Imsgq -I/usr/include -I/usr/include/aarch64-linux-gnu/qt5 -I/usr/include/aarch64-linux-gnu/qt5/QtGui/5.12.8/QtGui -I/usr/include/aarch64-linux-gnu/qt5/QtWidgets -I/usr/include/aarch64-linux-gnu/qt5/QtGui -I/usr/include/aarch64-linux-gnu/qt5/QtCore -I/usr/include/aarch64-linux-gnu/qt5/QtNetwork -I/usr/include/aarch64-linux-gnu/qt5/QtConcurrent -I/usr/include/aarch64-linux-gnu/qt5/QtDBus -I/usr/include/aarch64-linux-gnu/qt5/QtXml -Ithird_party/qrcode selfdrive/ui/sunnypilot/qt/widgets/prime.cc",
"directory": "/data/openpilot",
@@ -1001,6 +1007,12 @@
"file": "/data/openpilot/selfdrive/ui/sunnypilot/qt/widgets/moc_expandable_row.cc",
"output": "/data/openpilot/selfdrive/ui/sunnypilot/qt/widgets/moc_expandable_row.o"
},
{
"command": "clang++ -o selfdrive/ui/sunnypilot/qt/widgets/moc_external_storage.o -c -std=c++1z -DQCOM2 -mcpu=cortex-a57 -DSUNNYPILOT -D_REENTRANT -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_MESSAGELOGCONTEXT -Wno-deprecated-declarations -g -fPIC -O2 -Wunused -Werror -Wshadow -Wno-unknown-warning-option -Wno-inconsistent-missing-override -Wno-c99-designator -Wno-reorder-init-list -Wno-vla-cxx-extension -DQCOM2 -mcpu=cortex-a57 -DSUNNYPILOT -Ithird_party/opencl/include -I. -Ithird_party/acados/include -Ithird_party/acados/include/blasfeo/include -Ithird_party/acados/include/hpipm/include -Ithird_party/catch2/include -Ithird_party/libyuv/include -Ithird_party/json11 -Ithird_party/linux/include -Ithird_party/snpe/include -Ithird_party -Imsgq -I/usr/include -I/usr/include/aarch64-linux-gnu/qt5 -I/usr/include/aarch64-linux-gnu/qt5/QtGui/5.12.8/QtGui -I/usr/include/aarch64-linux-gnu/qt5/QtWidgets -I/usr/include/aarch64-linux-gnu/qt5/QtGui -I/usr/include/aarch64-linux-gnu/qt5/QtCore -I/usr/include/aarch64-linux-gnu/qt5/QtNetwork -I/usr/include/aarch64-linux-gnu/qt5/QtConcurrent -I/usr/include/aarch64-linux-gnu/qt5/QtDBus -I/usr/include/aarch64-linux-gnu/qt5/QtXml -Ithird_party/qrcode selfdrive/ui/sunnypilot/qt/widgets/moc_external_storage.cc",
"directory": "/data/openpilot",
"file": "/data/openpilot/selfdrive/ui/sunnypilot/qt/widgets/moc_external_storage.cc",
"output": "/data/openpilot/selfdrive/ui/sunnypilot/qt/widgets/moc_external_storage.o"
},
{
"command": "clang++ -o selfdrive/ui/sunnypilot/qt/widgets/moc_prime.o -c -std=c++1z -DQCOM2 -mcpu=cortex-a57 -DSUNNYPILOT -D_REENTRANT -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_MESSAGELOGCONTEXT -Wno-deprecated-declarations -g -fPIC -O2 -Wunused -Werror -Wshadow -Wno-unknown-warning-option -Wno-inconsistent-missing-override -Wno-c99-designator -Wno-reorder-init-list -Wno-vla-cxx-extension -DQCOM2 -mcpu=cortex-a57 -DSUNNYPILOT -Ithird_party/opencl/include -I. -Ithird_party/acados/include -Ithird_party/acados/include/blasfeo/include -Ithird_party/acados/include/hpipm/include -Ithird_party/catch2/include -Ithird_party/libyuv/include -Ithird_party/json11 -Ithird_party/linux/include -Ithird_party/snpe/include -Ithird_party -Imsgq -I/usr/include -I/usr/include/aarch64-linux-gnu/qt5 -I/usr/include/aarch64-linux-gnu/qt5/QtGui/5.12.8/QtGui -I/usr/include/aarch64-linux-gnu/qt5/QtWidgets -I/usr/include/aarch64-linux-gnu/qt5/QtGui -I/usr/include/aarch64-linux-gnu/qt5/QtCore -I/usr/include/aarch64-linux-gnu/qt5/QtNetwork -I/usr/include/aarch64-linux-gnu/qt5/QtConcurrent -I/usr/include/aarch64-linux-gnu/qt5/QtDBus -I/usr/include/aarch64-linux-gnu/qt5/QtXml -Ithird_party/qrcode selfdrive/ui/sunnypilot/qt/widgets/moc_prime.cc",
"directory": "/data/openpilot",
+17 -4
View File
@@ -4,12 +4,13 @@
A supported vehicle is one that just works when you install a comma device. All supported cars provide a better experience than any stock system. Supported vehicles reference the US market unless otherwise specified.
# 321 Supported Cars
# 334 Supported Cars
|Make|Model|Supported Package|ACC|No ACC accel below|No ALC below|Steering Torque|Resume from stop|<a href="##"><img width=2000></a>Hardware Needed<br>&nbsp;|Video|Setup Video|
|---|---|---|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
|Acura|ILX 2016-18|Technology Plus Package or AcuraWatch Plus|openpilot|26 mph|25 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Acura ILX 2016-18">Buy Here</a></sub></details>|||
|Acura|ILX 2019|All|openpilot|26 mph|25 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Acura ILX 2019">Buy Here</a></sub></details>|||
|Acura|MDX 2025|All except Type S|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch C connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Acura MDX 2025">Buy Here</a></sub></details>|||
|Acura|RDX 2016-18|AcuraWatch Plus or Advance Package|openpilot|26 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Acura RDX 2016-18">Buy Here</a></sub></details>|||
|Acura|RDX 2019-21|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Acura RDX 2019-21">Buy Here</a></sub></details>|||
|Audi|A3 2014-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Audi A3 2014-19">Buy Here</a></sub></details>|||
@@ -72,19 +73,25 @@ A supported vehicle is one that just works when you install a comma device. All
|Genesis|GV80 2023[<sup>6</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai M connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Genesis GV80 2023">Buy Here</a></sub></details>|||
|GMC|Sierra 1500 2020-21|Driver Alert Package II|openpilot available[<sup>1</sup>](#footnotes)|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 GM connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=GMC Sierra 1500 2020-21">Buy Here</a></sub></details>|<a href="https://youtu.be/5HbNoBLzRwE" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Honda|Accord 2018-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Accord 2018-22">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=mrUwlj3Mi58" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Honda|Accord 2023|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch C connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Accord 2023">Buy Here</a></sub></details>|||
|Honda|Accord 2023-25|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch C connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Accord 2023-25">Buy Here</a></sub></details>|||
|Honda|Accord Hybrid 2018-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Accord Hybrid 2018-22">Buy Here</a></sub></details>|||
|Honda|Accord Hybrid 2023-25|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch C connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Accord Hybrid 2023-25">Buy Here</a></sub></details>|||
|Honda|City (Brazil only) 2023|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|14 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch B connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Honda City (Brazil only) 2023">Buy Here</a></sub></details>|||
|Honda|Civic 2016-18|Honda Sensing|openpilot|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Civic 2016-18">Buy Here</a></sub></details>|<a href="https://youtu.be/-IkImTe1NYE" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Honda|Civic 2019-21|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|2 mph[<sup>5</sup>](#footnotes)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Civic 2019-21">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=4Iz1Mz5LGF8" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Honda|Civic 2022-24|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch B connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Civic 2022-24">Buy Here</a></sub></details>|<a href="https://youtu.be/ytiOT5lcp6Q" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Honda|Civic Hatchback 2017-21|Honda Sensing|openpilot available[<sup>1</sup>](#footnotes)|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Civic Hatchback 2017-21">Buy Here</a></sub></details>|||
|Honda|Civic Hatchback 2017-18|Honda Sensing|openpilot available[<sup>1</sup>](#footnotes)|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Civic Hatchback 2017-18">Buy Here</a></sub></details>|||
|Honda|Civic Hatchback 2019-21|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Civic Hatchback 2019-21">Buy Here</a></sub></details>|||
|Honda|Civic Hatchback 2022-24|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch B connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Civic Hatchback 2022-24">Buy Here</a></sub></details>|<a href="https://youtu.be/ytiOT5lcp6Q" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Honda|Civic Hatchback Hybrid 2025|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch B connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Civic Hatchback Hybrid 2025">Buy Here</a></sub></details>|||
|Honda|Civic Hatchback Hybrid (Europe only) 2023|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch B connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Civic Hatchback Hybrid (Europe only) 2023">Buy Here</a></sub></details>|||
|Honda|Civic Hybrid 2025|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch B connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Civic Hybrid 2025">Buy Here</a></sub></details>|||
|Honda|Clarity 2018-21|Honda Sensing|openpilot|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector + Honda Clarity Proxy Board<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://shop.retropilot.org/product/honda-clarity-proxy-board-kit">Buy Here</a></sub></details>|||
|Honda|CR-V 2015-16|Touring Trim|openpilot|26 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Honda CR-V 2015-16">Buy Here</a></sub></details>|||
|Honda|CR-V 2017-22|Honda Sensing|openpilot available[<sup>1</sup>](#footnotes)|0 mph|15 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Honda CR-V 2017-22">Buy Here</a></sub></details>|||
|Honda|CR-V 2023-25|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch C connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Honda CR-V 2023-25">Buy Here</a></sub></details>|||
|Honda|CR-V Hybrid 2017-22|Honda Sensing|openpilot available[<sup>1</sup>](#footnotes)|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Honda CR-V Hybrid 2017-22">Buy Here</a></sub></details>|||
|Honda|CR-V Hybrid 2023-25|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch C connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Honda CR-V Hybrid 2023-25">Buy Here</a></sub></details>|||
|Honda|e 2020|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Honda e 2020">Buy Here</a></sub></details>|||
|Honda|Fit 2018-20|Honda Sensing|openpilot|26 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Fit 2018-20">Buy Here</a></sub></details>|||
|Honda|Freed 2020|Honda Sensing|openpilot|26 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Freed 2020">Buy Here</a></sub></details>|||
@@ -95,6 +102,7 @@ A supported vehicle is one that just works when you install a comma device. All
|Honda|Odyssey 2018-20|Honda Sensing|openpilot|26 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Odyssey 2018-20">Buy Here</a></sub></details>|||
|Honda|Passport 2019-25|All|openpilot|26 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Passport 2019-25">Buy Here</a></sub></details>|||
|Honda|Pilot 2016-22|Honda Sensing|openpilot|26 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Pilot 2016-22">Buy Here</a></sub></details>|||
|Honda|Pilot 2023-25|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Bosch C connector<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Pilot 2023-25">Buy Here</a></sub></details>|||
|Honda|Ridgeline 2017-25|Honda Sensing|openpilot|26 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Honda Nidec connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Honda Ridgeline 2017-25">Buy Here</a></sub></details>|||
|Hyundai|Azera 2022|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Azera 2022">Buy Here</a></sub></details>|||
|Hyundai|Azera Hybrid 2019|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai C connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Azera Hybrid 2019">Buy Here</a></sub></details>|||
@@ -105,6 +113,7 @@ A supported vehicle is one that just works when you install a comma device. All
|Hyundai|Elantra 2021-23|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Elantra 2021-23">Buy Here</a></sub></details>|<a href="https://youtu.be/_EdYQtV52-c" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Hyundai|Elantra GT 2017-20|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Elantra GT 2017-20">Buy Here</a></sub></details>|||
|Hyundai|Elantra Hybrid 2021-23|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Elantra Hybrid 2021-23">Buy Here</a></sub></details>|<a href="https://youtu.be/_EdYQtV52-c" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Hyundai|Elantra Non-SCC 2022|No Smart Cruise Control (Non-SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Elantra Non-SCC 2022">Buy Here</a></sub></details>|||
|Hyundai|Genesis 2015-16|Smart Cruise Control (SCC)|Stock|19 mph|37 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai J connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Genesis 2015-16">Buy Here</a></sub></details>|||
|Hyundai|i30 2017-19|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai i30 2017-19">Buy Here</a></sub></details>|||
|Hyundai|Ioniq 5 (Southeast Asia and Europe only) 2022-24[<sup>6</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai Q connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Ioniq 5 (Southeast Asia and Europe only) 2022-24">Buy Here</a></sub></details>|||
@@ -118,11 +127,13 @@ A supported vehicle is one that just works when you install a comma device. All
|Hyundai|Ioniq Plug-in Hybrid 2019|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai C connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Ioniq Plug-in Hybrid 2019">Buy Here</a></sub></details>|||
|Hyundai|Ioniq Plug-in Hybrid 2020-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Ioniq Plug-in Hybrid 2020-22">Buy Here</a></sub></details>|||
|Hyundai|Kona 2020|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|6 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai B connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Kona 2020">Buy Here</a></sub></details>|||
|Hyundai|Kona 2022|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai O connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Kona 2022">Buy Here</a></sub></details>|||
|Hyundai|Kona 2022-23|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai O connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Kona 2022-23">Buy Here</a></sub></details>|||
|Hyundai|Kona Electric 2018-21|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai G connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Kona Electric 2018-21">Buy Here</a></sub></details>|||
|Hyundai|Kona Electric 2022-23|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai O connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Kona Electric 2022-23">Buy Here</a></sub></details>|||
|Hyundai|Kona Electric (with HDA II, Korea only) 2023[<sup>6</sup>](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai R connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Kona Electric (with HDA II, Korea only) 2023">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=U2fOCmcQ8hw" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Hyundai|Kona Electric Non-SCC 2019|No Smart Cruise Control (Non-SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai G connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Kona Electric Non-SCC 2019">Buy Here</a></sub></details>|||
|Hyundai|Kona Hybrid 2020|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai I connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Kona Hybrid 2020">Buy Here</a></sub></details>|||
|Hyundai|Kona Non-SCC 2019|No Smart Cruise Control (Non-SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai B connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Kona Non-SCC 2019">Buy Here</a></sub></details>|||
|Hyundai|Nexo 2021|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Nexo 2021">Buy Here</a></sub></details>|||
|Hyundai|Palisade 2020-22|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai H connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Palisade 2020-22">Buy Here</a></sub></details>|<a href="https://youtu.be/TAnDqjF4fDY?t=456" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Hyundai|Santa Cruz 2022-24[<sup>6</sup>](#footnotes)|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai N connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Hyundai Santa Cruz 2022-24">Buy Here</a></sub></details>|||
@@ -146,6 +157,7 @@ A supported vehicle is one that just works when you install a comma device. All
|Kia|Carnival 2022-24[<sup>6</sup>](#footnotes)|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Carnival 2022-24">Buy Here</a></sub></details>|||
|Kia|Carnival (China only) 2023[<sup>6</sup>](#footnotes)|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai K connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Carnival (China only) 2023">Buy Here</a></sub></details>|||
|Kia|Ceed 2019-21|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai E connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Ceed 2019-21">Buy Here</a></sub></details>|||
|Kia|Ceed Plug-in Hybrid Non-SCC 2022|No Smart Cruise Control (Non-SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai I connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Kia Ceed Plug-in Hybrid Non-SCC 2022">Buy Here</a></sub></details>|||
|Kia|EV6 (Southeast Asia only) 2022-24[<sup>6</sup>](#footnotes)|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai P connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Kia EV6 (Southeast Asia only) 2022-24">Buy Here</a></sub></details>|||
|Kia|EV6 (with HDA II) 2022-24[<sup>6</sup>](#footnotes)|Highway Driving Assist II|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai P connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Kia EV6 (with HDA II) 2022-24">Buy Here</a></sub></details>|||
|Kia|EV6 (without HDA II) 2022-24[<sup>6</sup>](#footnotes)|Highway Driving Assist|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai L connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Kia EV6 (without HDA II) 2022-24">Buy Here</a></sub></details>|||
@@ -293,6 +305,7 @@ A supported vehicle is one that just works when you install a comma device. All
|Toyota|RAV4 Hybrid 2022|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota RAV4 Hybrid 2022">Buy Here</a></sub></details>|<a href="https://youtu.be/U0nH9cnrFB0" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Toyota|RAV4 Hybrid 2023-25|All|openpilot available[<sup>1</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota RAV4 Hybrid 2023-25">Buy Here</a></sub></details>|<a href="https://youtu.be/4eIsEq4L4Ng" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Toyota|Sienna 2018-20|All|openpilot available[<sup>2</sup>](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota Sienna 2018-20">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=q1UPOo4Sh68" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Toyota|Wildlander PHEV 2021|All|openpilot|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v3<br>- 1 harness box<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Toyota Wildlander PHEV 2021">Buy Here</a></sub></details>|||
|Volkswagen|Arteon 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Arteon 2018-23">Buy Here</a></sub></details>|<a href="https://youtu.be/FAomFKPFlDA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Volkswagen|Arteon eHybrid 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Arteon eHybrid 2020-23">Buy Here</a></sub></details>|<a href="https://youtu.be/FAomFKPFlDA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
|Volkswagen|Arteon R 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,16</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 USB-C coupler<br>- 1 VW J533 connector<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable (9.5 ft)<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x?harness=Volkswagen Arteon R 2020-23">Buy Here</a></sub></details>|<a href="https://youtu.be/FAomFKPFlDA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>||
+1 -1
View File
@@ -6,7 +6,7 @@ Development is coordinated through [Discord](https://discord.comma.ai) and GitHu
### Getting Started
* Setup your [development environment](../tools/)
* Set up your [development environment](/tools/)
* Join our [Discord](https://discord.comma.ai)
* Docs are at https://docs.comma.ai and https://blog.comma.ai
+2 -2
View File
@@ -1,11 +1,11 @@
# Turn the speed blue
*A getting started guide for openpilot development*
In 30 minutes, we'll get an openpilot development environment setup on your computer and make some changes to openpilot's UI.
In 30 minutes, we'll get an openpilot development environment set up on your computer and make some changes to openpilot's UI.
And if you have a comma 3/3X, we'll deploy the change to your device for testing.
## 1. Setup your development environment
## 1. Set up your development environment
Run this to clone openpilot and install all the dependencies:
```bash
+1 -1
View File
@@ -7,7 +7,7 @@ export OPENBLAS_NUM_THREADS=1
export VECLIB_MAXIMUM_THREADS=1
if [ -z "$AGNOS_VERSION" ]; then
export AGNOS_VERSION="12.6"
export AGNOS_VERSION="12.8"
fi
export STAGING_ROOT="/data/safe_staging"
+17
View File
@@ -1,3 +1,20 @@
#!/usr/bin/env bash
set -euo pipefail
IFS=$'\n\t'
# On any failure, run the fallback launcher
trap 'exec ./launch_chffrplus.sh' ERR
C3_LAUNCH_SH="./sunnypilot/system/hardware/c3/launch_chffrplus.sh"
MODEL="$(tr -d '\0' < "/sys/firmware/devicetree/base/model")"
export MODEL
if [ "$MODEL" = "comma tici" ]; then
# Force a failure if the launcher doesn't exist
[ -x "$C3_LAUNCH_SH" ] || false
# If it exists, run it
exec "$C3_LAUNCH_SH"
fi
exec ./launch_chffrplus.sh
Binary file not shown.
File diff suppressed because it is too large Load Diff
Binary file not shown.
+9 -9
View File
@@ -9,7 +9,7 @@
|Acura|Integra 2023-25|All|[Community](#community)|
|Acura|MDX 2015-16|Advance Package|[Community](#community)|
|Acura|MDX 2017-20|All|[Community](#community)|
|Acura|MDX 2025|All|[Community](#community)|
|Acura|MDX 2025|All except Type S|[Upstream](#upstream)|
|Acura|RDX 2016-18|AcuraWatch Plus or Advance Package|[Upstream](#upstream)|
|Acura|RDX 2019-21|All|[Upstream](#upstream)|
|Acura|RDX 2022-25|All|[Community](#community)|
@@ -82,9 +82,9 @@
|GMC|Yukon 2019-20|Adaptive Cruise Control (ACC) & LKAS|[Dashcam mode](#dashcam)|
|Honda|Accord 2016-17|Honda Sensing|[Community](#community)|
|Honda|Accord 2018-22|All|[Upstream](#upstream)|
|Honda|Accord 2023|All|[Upstream](#upstream)|
|Honda|Accord 2024-25|All|[Community](#community)|
|Honda|Accord 2023-25|All|[Upstream](#upstream)|
|Honda|Accord Hybrid 2018-22|All|[Upstream](#upstream)|
|Honda|Accord Hybrid 2023-25|All|[Upstream](#upstream)|
|Honda|Civic 2016-18|Honda Sensing|[Upstream](#upstream)|
|Honda|Civic 2019-21|All|[Upstream](#upstream)|
|Honda|Civic 2022-24|All|[Upstream](#upstream)|
@@ -96,9 +96,9 @@
|Honda|Clarity 2018-21|All|[Community](#community)|
|Honda|CR-V 2015-16|Touring Trim|[Upstream](#upstream)|
|Honda|CR-V 2017-22|Honda Sensing|[Upstream](#upstream)|
|Honda|CR-V 2023-25|All|[Community](#community)|
|Honda|CR-V 2023-25|All|[Upstream](#upstream)|
|Honda|CR-V Hybrid 2017-22|Honda Sensing|[Upstream](#upstream)|
|Honda|CR-V Hybrid 2023-25|All|[Community](#community)|
|Honda|CR-V Hybrid 2023-25|All|[Upstream](#upstream)|
|Honda|e 2020|All|[Upstream](#upstream)|
|Honda|Fit 2018-20|Honda Sensing|[Upstream](#upstream)|
|Honda|Freed 2020|Honda Sensing|[Upstream](#upstream)|
@@ -111,8 +111,7 @@
|Honda|Passport 2019-25|All|[Upstream](#upstream)|
|Honda|Passport 2026|All|[Community](#community)|
|Honda|Pilot 2016-22|Honda Sensing|[Upstream](#upstream)|
|Honda|Pilot 2023|All|[Dashcam mode](#dashcam)|
|Honda|Pilot 2023-25|All|[Community](#community)|
|Honda|Pilot 2023-25|All|[Upstream](#upstream)|
|Honda|Prologue 2024-25|All|[Not compatible](#can-bus-security)|
|Honda|Ridgeline 2017-25|Honda Sensing|[Upstream](#upstream)|
|Hyundai|Azera 2022|All|[Upstream](#upstream)|
@@ -137,7 +136,7 @@
|Hyundai|Ioniq Plug-in Hybrid 2019|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|Hyundai|Ioniq Plug-in Hybrid 2020-22|All|[Upstream](#upstream)|
|Hyundai|Kona 2020|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|Hyundai|Kona 2022|Smart Cruise Control (SCC)|[Dashcam mode](#dashcam)|
|Hyundai|Kona 2022-23|Smart Cruise Control (SCC)|[Dashcam mode](#dashcam)|
|Hyundai|Kona Electric 2018-21|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|Hyundai|Kona Electric 2022-23|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|Hyundai|Kona Electric (with HDA II, Korea only) 2023|Smart Cruise Control (SCC)|[Upstream](#upstream)|
@@ -241,6 +240,7 @@
|Nissan|Leaf 2018-23|ProPILOT Assist|[Upstream](#upstream)|
|Nissan|Rogue 2018-20|ProPILOT Assist|[Upstream](#upstream)|
|Nissan|X-Trail 2017|ProPILOT Assist|[Upstream](#upstream)|
|Peugeot|208 2019-25|Adaptive Cruise Control (ACC) & Lane Assist|[Dashcam mode](#dashcam)|
|Ram|1500 2019-24|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|Ram|2500 2020-24|Adaptive Cruise Control (ACC)|[Dashcam mode](#dashcam)|
|Ram|3500 2019-22|Adaptive Cruise Control (ACC)|[Dashcam mode](#dashcam)|
@@ -339,7 +339,7 @@
|Toyota|Sienna 2024-25|Any|[Not compatible](#can-bus-security)|
|Toyota|Tundra 2022-25|Any|[Not compatible](#can-bus-security)|
|Toyota|Venza 2021-25|Any|[Not compatible](#can-bus-security)|
|Toyota|Yaris (Non-US only) 2023|All|[Community](#community)|
|Toyota|Yaris (Non-US only) 2020, 2023|All|[Community](#community)|
|Volkswagen|Arteon 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|Volkswagen|Arteon eHybrid 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|Volkswagen|Arteon R 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
+4
View File
@@ -14,6 +14,7 @@ from opendbc.car.hyundai.hyundaicanfd import hkg_can_fd_checksum
from opendbc.car.volkswagen.mqbcan import volkswagen_mqb_meb_checksum, xor_checksum
from opendbc.car.tesla.teslacan import tesla_checksum
from opendbc.car.body.bodycan import body_checksum
from opendbc.car.psa.psacan import psa_checksum
class SignalType:
@@ -29,6 +30,7 @@ class SignalType:
HKG_CAN_FD_CHECKSUM = 9
FCA_GIORGIO_CHECKSUM = 10
TESLA_CHECKSUM = 11
PSA_CHECKSUM = 12
@dataclass
@@ -196,6 +198,8 @@ def get_checksum_state(dbc_name: str) -> ChecksumState | None:
return ChecksumState(8, 4, 7, 3, False, SignalType.BODY_CHECKSUM, body_checksum)
elif dbc_name.startswith("tesla_model3_party"):
return ChecksumState(8, -1, 0, -1, True, SignalType.TESLA_CHECKSUM, tesla_checksum, tesla_setup_signal)
elif dbc_name.startswith("psa_"):
return ChecksumState(4, 4, 7, 3, False, SignalType.PSA_CHECKSUM, psa_checksum)
return None
+17 -12
View File
@@ -142,10 +142,9 @@ class CANParser:
self._add_message(name_or_addr, freq)
self.can_valid: bool = False
self.bus_timeout: bool = False
self.can_invalid_cnt: int = CAN_INVALID_CNT
self.last_nonempty_nanos: int = 0
self._last_update_nanos: int = 0
def _add_message(self, name_or_addr: str | int, freq: int = None) -> None:
if isinstance(name_or_addr, numbers.Number):
@@ -181,17 +180,29 @@ class CANParser:
self.message_states[msg.address] = state
def update_valid(self, nanos: int) -> None:
@property
def bus_timeout(self) -> bool:
ignore_alive = all(s.ignore_alive for s in self.message_states.values())
bus_timeout_threshold = 500 * 1_000_000
for st in self.message_states.values():
if st.timeout_threshold > 0:
bus_timeout_threshold = min(bus_timeout_threshold, st.timeout_threshold)
return ((self._last_update_nanos - self.last_nonempty_nanos) > bus_timeout_threshold) and not ignore_alive
@property
def can_valid(self) -> bool:
valid = True
counters_valid = True
bus_timeout = self.bus_timeout
for state in self.message_states.values():
if state.counter_fail >= MAX_BAD_COUNTER:
counters_valid = False
if not state.valid(nanos, self.bus_timeout):
if not state.valid(self._last_update_nanos, bus_timeout):
valid = False
# TODO: probably only want to increment this once per update() call
self.can_invalid_cnt = 0 if valid else min(self.can_invalid_cnt + 1, CAN_INVALID_CNT)
self.can_valid = self.can_invalid_cnt < CAN_INVALID_CNT and counters_valid
return self.can_invalid_cnt < CAN_INVALID_CNT and counters_valid
def update(self, strings, sendcan: bool = False):
if strings and not isinstance(strings[0], list | tuple):
@@ -228,13 +239,7 @@ class CANParser:
if not bus_empty:
self.last_nonempty_nanos = t
ignore_alive = all(s.ignore_alive for s in self.message_states.values())
bus_timeout_threshold = 500 * 1_000_000
for st in self.message_states.values():
if st.timeout_threshold > 0:
bus_timeout_threshold = min(bus_timeout_threshold, st.timeout_threshold)
self.bus_timeout = ((t - self.last_nonempty_nanos) > bus_timeout_threshold) and not ignore_alive
self.update_valid(t)
self._last_update_nanos = t
return updated_addrs
+5
View File
@@ -182,6 +182,7 @@ class PlatformConfigBase(Freezable):
dbc_dict: DbcDict
flags: int = 0
sp_flags: int = 0
platform_str: str | None = None
@@ -246,3 +247,7 @@ class Platforms(str, ReprEnum, metaclass=PlatformsType):
@classmethod
def with_flags(cls, flags: IntFlag) -> set['Platforms']:
return {p for p in cls if p.config.flags & flags}
@classmethod
def with_sp_flags(cls, sp_flags: IntFlag) -> set['Platforms']:
return {p for p in cls if p.config.sp_flags & sp_flags}
+3 -2
View File
@@ -152,7 +152,8 @@ def fingerprint(can_recv: CanRecvCallable, can_send: CanSendCallable, set_obd_mu
def get_car(can_recv: CanRecvCallable, can_send: CanSendCallable, set_obd_multiplexing: ObdCallback, alpha_long_allowed: bool,
is_release: bool, num_pandas: int = 1, cached_params: CarParamsT | None = None, fixed_fingerprint: str | None = None):
is_release: bool, num_pandas: int = 1, cached_params: CarParamsT | None = None,
fixed_fingerprint: str | None = None, init_params_list_sp: list[dict[str, str]] = None):
candidate, fingerprints, vin, car_fw, source, exact_match = fingerprint(can_recv, can_send, set_obd_multiplexing, num_pandas, cached_params,
fixed_fingerprint)
@@ -168,7 +169,7 @@ def get_car(can_recv: CanRecvCallable, can_send: CanSendCallable, set_obd_multip
CP.fuzzyFingerprint = not exact_match
CP_SP = CarInterface.get_params_sp(CP, candidate, fingerprints, car_fw, alpha_long_allowed, docs=False)
sunnypilot_interfaces(CP, CP_SP, can_recv, can_send)
sunnypilot_interfaces(CarInterface, CP, CP_SP, init_params_list_sp, can_recv, can_send)
return interfaces[CP.carFingerprint](CP, CP_SP)
@@ -13,7 +13,7 @@ class CarController(CarControllerBase, MadsCarController, CarControllerExt):
def __init__(self, dbc_names, CP, CP_SP):
CarControllerBase.__init__(self, dbc_names, CP, CP_SP)
MadsCarController.__init__(self)
CarControllerExt.__init__(self, CP)
CarControllerExt.__init__(self, CP, CP_SP)
self.apply_torque_last = 0
self.hud_count = 0
@@ -65,7 +65,7 @@ class CarController(CarControllerBase, MadsCarController, CarControllerExt):
if CS.out.vEgo < (self.CP.minSteerSpeed - 0.5):
lkas_control_bit = False
lkas_control_bit = CarControllerExt.get_lkas_control_bit(self, CS, lkas_control_bit, self.lkas_control_bit_prev)
lkas_control_bit = CarControllerExt.get_lkas_control_bit(self, CS, CC, lkas_control_bit, self.lkas_control_bit_prev)
# EPS faults if LKAS re-enables too quickly
lkas_control_bit = lkas_control_bit and (self.frame - self.last_lkas_falling_edge > 200)
@@ -5,6 +5,7 @@ from opendbc.car.chrysler.carstate import CarState
from opendbc.car.chrysler.radar_interface import RadarInterface
from opendbc.car.chrysler.values import CAR, RAM_HD, RAM_DT, RAM_CARS, ChryslerFlags, ChryslerSafetyFlags
from opendbc.car.interfaces import CarInterfaceBase
from opendbc.sunnypilot.car.chrysler.values import ChryslerFlagsSP
class CarInterface(CarInterfaceBase):
@@ -88,4 +89,8 @@ class CarInterface(CarInterfaceBase):
if candidate == CAR.RAM_HD_5TH_GEN:
stock_cp.dashcamOnly = False
if 0x4FF in fingerprint[0]:
ret.flags |= ChryslerFlagsSP.NO_MIN_STEERING_SPEED.value
stock_cp.minSteerSpeed = 0.
return ret
+9 -1
View File
@@ -145,6 +145,10 @@ class CarHarness(EnumBase):
rivian = BaseCarHarness("Rivian A connector", parts=[Accessory.harness_box, Accessory.comma_power, Cable.long_obdc_cable, Cable.usbc_coupler])
tesla_a = BaseCarHarness("Tesla A connector", parts=[Accessory.harness_box, Accessory.comma_power, Cable.long_obdc_cable, Cable.usbc_coupler])
tesla_b = BaseCarHarness("Tesla B connector", parts=[Accessory.harness_box, Accessory.comma_power, Cable.long_obdc_cable, Cable.usbc_coupler])
psa_a = BaseCarHarness("PSA A connector", parts=[Accessory.harness_box, Cable.long_obdc_cable, Cable.usbc_coupler])
# custom harness
honda_clarity = BaseCarHarness("Honda Nidec connector + Honda Clarity Proxy Board")
class Device(EnumBase):
@@ -175,6 +179,7 @@ DEFAULT_CAR_PARTS: list[EnumBase] = [Device.threex]
@dataclass
class CarParts:
parts: list[EnumBase] = field(default_factory=list)
custom_parts_url: str | None = None
def __call__(self):
return copy.deepcopy(self)
@@ -304,7 +309,10 @@ class CarDocs:
# hardware column
hardware_col = "None"
if self.car_parts.parts:
buy_link = f'<a href="https://comma.ai/shop/comma-3x?harness={self.name}">Buy Here</a>'
if self.car_parts.custom_parts_url is not None:
buy_link = f'<a href="{self.car_parts.custom_parts_url}">Buy Here</a>'
else:
buy_link = f'<a href="https://comma.ai/shop/comma-3x?harness={self.name}">Buy Here</a>'
tools_docs = [part for part in self.car_parts.all_parts() if isinstance(part, Tool)]
parts_docs = [part for part in self.car_parts.all_parts() if not isinstance(part, Tool)]
+3 -2
View File
@@ -7,10 +7,11 @@ from opendbc.car.fw_query_definitions import EcuAddrBusType
def _is_tester_present_response(msg: CanData, subaddr: int = None) -> bool:
# ISO-TP messages are always padded to 8 bytes
# ISO-TP messages may use CAN frame optimization (not always 8 bytes)
# tester present response is always a single frame
dat_offset = 1 if subaddr is not None else 0
if len(msg.dat) == 8 and 1 <= msg.dat[dat_offset] <= 7:
min_length = 4 if subaddr is not None else 3 # bytes: frame len, (pos/neg) sid, (optional negative sid)/0x00 sub-function
if min_length <= len(msg.dat) <= 8 and 1 <= msg.dat[dat_offset] <= 7:
# success response
if msg.dat[dat_offset + 1] == (uds.SERVICE_TYPE.TESTER_PRESENT + 0x40):
return True
-5
View File
@@ -40,20 +40,15 @@ class CAR(Platforms):
CommunityCarDocs("Acura Integra 2023-25", "All"),
CommunityCarDocs("Acura MDX 2015-16", "Advance Package"),
CommunityCarDocs("Acura MDX 2017-20", "All"),
CommunityCarDocs("Acura MDX 2025", "All"),
CommunityCarDocs("Acura RDX 2022-25", "All"),
CommunityCarDocs("Acura RLX 2017", "Advance Package or Technology Package"),
CommunityCarDocs("Acura TLX 2015-17", "Advance Package"),
CommunityCarDocs("Acura TLX 2018-20", "All"),
GMSecurityCarDocs("Acura ZDX 2024", "All"),
CommunityCarDocs("Honda Accord 2016-17", "Honda Sensing"),
CommunityCarDocs("Honda Accord 2024-25", "All"),
CommunityCarDocs("Honda Clarity 2018-21", "All"),
CommunityCarDocs("Honda CR-V 2023-25", "All"),
CommunityCarDocs("Honda CR-V Hybrid 2023-25", "All"),
CommunityCarDocs("Honda Odyssey 2021-25", "All"),
CommunityCarDocs("Honda Passport 2026", "All"),
CommunityCarDocs("Honda Pilot 2023-25", "All"),
GMSecurityCarDocs("Honda Prologue 2024-25", "All"),
],
)
+41 -35
View File
@@ -1,15 +1,16 @@
#!/usr/bin/env python3
import os
from math import fabs, exp
import numpy as np
from opendbc.car import get_safety_config, structs
from opendbc.car.common.basedir import BASEDIR
from opendbc.car.common.conversions import Conversions as CV
from opendbc.car.gm.carcontroller import CarController
from opendbc.car.gm.carstate import CarState
from opendbc.car.gm.radar_interface import RadarInterface, RADAR_HEADER_MSG, CAMERA_DATA_HEADER_MSG
from opendbc.car.gm.values import CAR, CarControllerParams, EV_CAR, CAMERA_ACC_CAR, SDGM_CAR, ALT_ACCS, CanBus, GMSafetyFlags
from opendbc.car.interfaces import CarInterfaceBase, TorqueFromLateralAccelCallbackType, LatControlInputs, NanoFFModel
from opendbc.car.interfaces import CarInterfaceBase, TorqueFromLateralAccelCallbackType, LateralAccelFromTorqueCallbackType
from opendbc.sunnypilot.car.gm.interface_ext import CarInterfaceExt
TransmissionType = structs.CarParams.TransmissionType
NetworkLocation = structs.CarParams.NetworkLocation
@@ -20,14 +21,16 @@ NON_LINEAR_TORQUE_PARAMS = {
CAR.CHEVROLET_SILVERADO: [3.29974374, 1.0, 0.25571356, 0.0465122]
}
NEURAL_PARAMS_PATH = os.path.join(BASEDIR, 'torque_data/neural_ff_weights.json')
class CarInterface(CarInterfaceBase):
class CarInterface(CarInterfaceBase, CarInterfaceExt):
CarState = CarState
CarController = CarController
RadarInterface = RadarInterface
def __init__(self, CP, CP_SP):
CarInterfaceBase.__init__(self, CP, CP_SP)
CarInterfaceExt.__init__(self, CP, CarInterfaceBase)
@staticmethod
def get_pid_accel_limits(CP, current_speed, cruise_speed):
return CarControllerParams.ACCEL_MIN, CarControllerParams.ACCEL_MAX
@@ -45,42 +48,45 @@ class CarInterface(CarInterfaceBase):
else:
return CarInterfaceBase.get_steer_feedforward_default
def torque_from_lateral_accel_siglin(self, latcontrol_inputs: LatControlInputs, torque_params: structs.CarParams.LateralTorqueTuning,
gravity_adjusted: bool) -> float:
def sig(val):
# https://timvieira.github.io/blog/post/2014/02/11/exp-normalize-trick
if val >= 0:
return 1 / (1 + exp(-val)) - 0.5
else:
z = exp(val)
return z / (1 + z) - 0.5
def get_lataccel_torque_siglin(self) -> float:
# The "lat_accel vs torque" relationship is assumed to be the sum of "sigmoid + linear" curves
# An important thing to consider is that the slope at 0 should be > 0 (ideally >1)
# This has big effect on the stability about 0 (noise when going straight)
# ToDo: To generalize to other GMs, explore tanh function as the nonlinear
non_linear_torque_params = NON_LINEAR_TORQUE_PARAMS.get(self.CP.carFingerprint)
assert non_linear_torque_params, "The params are not defined"
a, b, c, _ = non_linear_torque_params
steer_torque = (sig(latcontrol_inputs.lateral_acceleration * a) * b) + (latcontrol_inputs.lateral_acceleration * c)
return float(steer_torque)
def torque_from_lateral_accel_siglin_func(lateral_acceleration: float) -> float:
# The "lat_accel vs torque" relationship is assumed to be the sum of "sigmoid + linear" curves
# An important thing to consider is that the slope at 0 should be > 0 (ideally >1)
# This has big effect on the stability about 0 (noise when going straight)
non_linear_torque_params = NON_LINEAR_TORQUE_PARAMS.get(self.CP.carFingerprint)
assert non_linear_torque_params, "The params are not defined"
a, b, c, _ = non_linear_torque_params
sig_input = a * lateral_acceleration
sig = np.sign(sig_input) * (1 / (1 + exp(-fabs(sig_input))) - 0.5)
steer_torque = (sig * b) + (lateral_acceleration * c)
return float(steer_torque)
def torque_from_lateral_accel_neural(self, latcontrol_inputs: LatControlInputs, torque_params: structs.CarParams.LateralTorqueTuning,
gravity_adjusted: bool) -> float:
inputs = list(latcontrol_inputs)
if gravity_adjusted:
inputs[0] += inputs[1]
return float(self.neural_ff_model.predict(inputs))
lataccel_values = np.arange(-5.0, 5.0, 0.01)
torque_values = [torque_from_lateral_accel_siglin_func(x) for x in lataccel_values]
assert min(torque_values) < -1 and max(torque_values) > 1, "The torque values should cover the range [-1, 1]"
return torque_values, lataccel_values
def torque_from_lateral_accel(self) -> TorqueFromLateralAccelCallbackType:
if self.CP.carFingerprint == CAR.CHEVROLET_BOLT_EUV:
self.neural_ff_model = NanoFFModel(NEURAL_PARAMS_PATH, self.CP.carFingerprint)
return self.torque_from_lateral_accel_neural
elif self.CP.carFingerprint in NON_LINEAR_TORQUE_PARAMS:
return self.torque_from_lateral_accel_siglin
if self.CP.carFingerprint in NON_LINEAR_TORQUE_PARAMS:
torque_values, lataccel_values = self.get_lataccel_torque_siglin()
def torque_from_lateral_accel_siglin(lateral_acceleration: float, torque_params: structs.CarParams.LateralTorqueTuning):
return np.interp(lateral_acceleration, lataccel_values, torque_values)
return torque_from_lateral_accel_siglin
else:
return self.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: structs.CarParams.LateralTorqueTuning):
return np.interp(torque, torque_values, lataccel_values)
return lateral_accel_from_torque_siglin
else:
return self.lateral_accel_from_torque_linear
@staticmethod
def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, is_release, docs) -> structs.CarParams:
ret.brand = "gm"
+7 -2
View File
@@ -10,6 +10,8 @@ from opendbc.car.honda.values import CAR, DBC, STEER_THRESHOLD, HONDA_BOSCH, HON
HondaFlags, CruiseButtons, CruiseSettings, GearShifter
from opendbc.car.interfaces import CarStateBase
from opendbc.sunnypilot.car.honda.carstate_ext import CarStateExt
TransmissionType = structs.CarParams.TransmissionType
ButtonType = structs.CarState.ButtonEvent.Type
@@ -18,9 +20,10 @@ BUTTONS_DICT = {CruiseButtons.RES_ACCEL: ButtonType.accelCruise, CruiseButtons.D
SETTINGS_BUTTONS_DICT = {CruiseSettings.DISTANCE: ButtonType.gapAdjustCruise, CruiseSettings.LKAS: ButtonType.lkas}
class CarState(CarStateBase):
class CarState(CarStateBase, CarStateExt):
def __init__(self, CP, CP_SP):
super().__init__(CP, CP_SP)
CarStateBase.__init__(self, CP, CP_SP)
CarStateExt.__init__(self, CP, CP_SP)
can_define = CANDefine(DBC[CP.carFingerprint][Bus.pt])
if CP.transmissionType != TransmissionType.manual:
@@ -206,6 +209,8 @@ class CarState(CarStateBase):
*create_button_events(self.cruise_setting, prev_cruise_setting, SETTINGS_BUTTONS_DICT),
]
CarStateExt.update(self, ret, can_parsers)
return ret, ret_sp
def get_can_parsers(self, CP, CP_SP):
+46 -15
View File
@@ -2,6 +2,9 @@
from opendbc.car.structs import CarParams
from opendbc.car.honda.values import CAR
from opendbc.sunnypilot.car.fw_versions_ext import merge_fw_versions
from opendbc.sunnypilot.car.honda.fingerprints_ext import FW_VERSIONS_EXT
Ecu = CarParams.Ecu
# Modified FW can be identified by the second dash being replaced by a comma
@@ -67,7 +70,6 @@ FW_VERSIONS = {
],
(Ecu.eps, 0x18da30f1, None): [
b'39990-TBX-H120\x00\x00',
b'39990-TVA,A150\x00\x00',
b'39990-TVA-A140\x00\x00',
b'39990-TVA-A150\x00\x00',
b'39990-TVA-A160\x00\x00',
@@ -147,7 +149,6 @@ FW_VERSIONS = {
b'57114-TEA-Q220\x00\x00',
],
(Ecu.eps, 0x18da30f1, None): [
b'39990-TBA,A030\x00\x00',
b'39990-TBA-A030\x00\x00',
b'39990-TBG-A030\x00\x00',
b'39990-TEA-T020\x00\x00',
@@ -220,8 +221,6 @@ FW_VERSIONS = {
b'39990-TEA-T330\x00\x00',
b'39990-TEA-T820\x00\x00',
b'39990-TEZ-T020\x00\x00',
b'39990-TGG,A020\x00\x00',
b'39990-TGG,A120\x00\x00',
b'39990-TGG-A020\x00\x00',
b'39990-TGG-A120\x00\x00',
b'39990-TGG-J510\x00\x00',
@@ -354,7 +353,6 @@ FW_VERSIONS = {
b'57114-TMC-Z050\x00\x00',
],
(Ecu.eps, 0x18da30f1, None): [
b'39990-TLA,A040\x00\x00',
b'39990-TLA-A040\x00\x00',
b'39990-TLA-A110\x00\x00',
b'39990-TLA-A220\x00\x00',
@@ -502,6 +500,14 @@ FW_VERSIONS = {
b'36161-TDK-J530\x00\x00',
],
},
CAR.ACURA_MDX_4G_MMR: {
(Ecu.fwdCamera, 0x18dab5f1, None): [
b'8S102-TYA-A020\x00\x00',
],
(Ecu.fwdRadar, 0x18dab0f1, None): [
b'8S302-TYA-A020\x00\x00',
],
},
CAR.HONDA_ODYSSEY: {
(Ecu.gateway, 0x18daeff1, None): [
b'38897-THR-A010\x00\x00',
@@ -804,6 +810,7 @@ FW_VERSIONS = {
(Ecu.fwdRadar, 0x18dab0f1, None): [
b'8S102-3M3-T050\x00\x00',
b'8S102-3M6-P030\x00\x00',
b'8S102-3M6-PA20\x00\x00',
b'8S102-3W0-A060\x00\x00',
b'8S102-3W0-AB10\x00\x00',
b'8S102-3W0-AB20\x00\x00',
@@ -938,21 +945,13 @@ FW_VERSIONS = {
(Ecu.fwdCamera, 0x18dab5f1, None): [
b'8S102-T90-A050\x00\x00',
b'8S102-T90-A060\x00\x00',
b'8S102-T90-A070\x00\x00',
],
(Ecu.fwdRadar, 0x18dab0f1, None): [
b'8S302-T90-A040\x00\x00',
],
},
CAR.HONDA_ACCORD_11G: {
(Ecu.eps, 0x18da30f1, None): [
b'39991-30B-A060\x00\x00',
],
(Ecu.gateway, 0x18daeff1, None): [
b'5J802-30B-AA10\x00\x00',
],
(Ecu.srs, 0x18da53f1, None): [
b'77959-30B-A750\x00\x00',
],
(Ecu.fwdRadar, 0x18dab0f1, None): [
b'8S302-30A-A040\x00\x00',
],
@@ -960,8 +959,40 @@ FW_VERSIONS = {
b'8S102-30A-A050\x00\x00',
b'8S102-30A-A060\x00\x00',
],
},
CAR.HONDA_CRV_6G: {
(Ecu.fwdRadar, 0x18dab0f1, None): [
b'8S302-3C0-Q050\x00\x00',
b'8S302-3D4-A050\x00\x00',
],
(Ecu.fwdCamera, 0x18dab5f1, None): [
b'8S102-3C0-Q060\x00\x00',
b'8S102-3D4-A060\x00\x00',
b'8S102-3D4-A070\x00\x00',
b'8S102-3D4-A080\x00\x00',
b'8S102-3D4-A090\x00\x00',
],
},
CAR.HONDA_CITY_7G: {
(Ecu.eps, 0x18da30f1, None): [
b'39990-T14-B030\x00\x00',
],
(Ecu.gateway, 0x18daeff1, None): [
b'38897-T14-M110\x00\x00',
],
(Ecu.srs, 0x18da53f1, None): [
b'77959-T00-B830\x00\x00',
],
(Ecu.fwdRadar, 0x18dab0f1, None): [
b'36161-T14-P050\x00\x00',
],
(Ecu.vsa, 0x18da28f1, None): [
b'57114-30B-A030\x00\x00',
b'57114-T14-B030\x00\x00',
],
(Ecu.transmission, 0x18da1ef1, None): [
b'28101-63B-M420\x00\x00',
],
},
}
FW_VERSIONS = merge_fw_versions(FW_VERSIONS, FW_VERSIONS_EXT)
+8 -2
View File
@@ -52,8 +52,6 @@ def create_brake_command(packer, CAN, apply_brake, pump_on, pcm_override, pcm_ca
pcm_fault_cmd = False
values = {
"COMPUTER_BRAKE": apply_brake,
"BRAKE_PUMP_REQUEST": pump_on,
"CRUISE_OVERRIDE": pcm_override,
"CRUISE_FAULT_CMD": pcm_fault_cmd,
"CRUISE_CANCEL_CMD": pcm_cancel_cmd,
@@ -66,6 +64,14 @@ def create_brake_command(packer, CAN, apply_brake, pump_on, pcm_override, pcm_ca
"AEB_REQ_2": 0,
"AEB_STATUS": 0,
}
if car_fingerprint == CAR.HONDA_CLARITY:
values["COMPUTER_BRAKE_ALT"] = apply_brake
values["BRAKE_PUMP_REQUEST_ALT"] = apply_brake > 0
else:
values["COMPUTER_BRAKE"] = apply_brake
values["BRAKE_PUMP_REQUEST"] = pump_on
return packer.make_can_msg("BRAKE_COMMAND", CAN.pt, values)
+94 -32
View File
@@ -11,6 +11,8 @@ from opendbc.car.honda.carstate import CarState
from opendbc.car.honda.radar_interface import RadarInterface
from opendbc.car.interfaces import CarInterfaceBase
from opendbc.sunnypilot.car.honda.values_ext import HondaFlagsSP, HondaSafetyFlagsSP
TransmissionType = structs.CarParams.TransmissionType
@@ -36,9 +38,6 @@ class CarInterface(CarInterfaceBase):
CAN = CanBus(ret, fingerprint)
# Pilot 4G needs a rescaled lateral actuator, switch to lat accel torque control, and an updated test route
ret.dashcamOnly = candidate in [CAR.HONDA_PILOT_4G]
if candidate in HONDA_BOSCH:
cfgs = [get_safety_config(structs.CarParams.SafetyModel.hondaBosch)]
if candidate in HONDA_BOSCH_CANFD and CAN.pt >= 4:
@@ -97,24 +96,14 @@ class CarInterface(CarInterfaceBase):
ret.longitudinalTuning.kiBP = [0., 5., 35.]
ret.longitudinalTuning.kiV = [1.2, 0.8, 0.5]
eps_modified = False
# Disable control if EPS mod detected
for fw in car_fw:
if fw.ecu == "eps" and b"," in fw.fwVersion:
eps_modified = True
ret.dashcamOnly = True
if candidate == CAR.HONDA_CIVIC:
if eps_modified:
# stock request input values: 0x0000, 0x00DE, 0x014D, 0x01EF, 0x0290, 0x0377, 0x0454, 0x0610, 0x06EE
# stock request output values: 0x0000, 0x0917, 0x0DC5, 0x1017, 0x119F, 0x140B, 0x1680, 0x1680, 0x1680
# modified request output values: 0x0000, 0x0917, 0x0DC5, 0x1017, 0x119F, 0x140B, 0x1680, 0x2880, 0x3180
# stock filter output values: 0x009F, 0x0108, 0x0108, 0x0108, 0x0108, 0x0108, 0x0108, 0x0108, 0x0108
# modified filter output values: 0x009F, 0x0108, 0x0108, 0x0108, 0x0108, 0x0108, 0x0108, 0x0400, 0x0480
# note: max request allowed is 4096, but request is capped at 3840 in firmware, so modifications result in 2x max
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 2560, 8000], [0, 2560, 3840]]
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.3], [0.1]]
else:
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 2560], [0, 2560]]
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[1.1], [0.33]]
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 2560], [0, 2560]]
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[1.1], [0.33]]
elif candidate in (CAR.HONDA_CIVIC_BOSCH, CAR.HONDA_CIVIC_BOSCH_DIESEL):
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]] # TODO: determine if there is a dead zone at the top end
@@ -127,11 +116,7 @@ class CarInterface(CarInterfaceBase):
elif candidate == CAR.HONDA_ACCORD:
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]] # TODO: determine if there is a dead zone at the top end
if eps_modified:
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.3], [0.09]]
else:
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.6], [0.18]]
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.6], [0.18]]
elif candidate == CAR.HONDA_ACCORD_11G:
ret.steerActuatorDelay = 0.22
@@ -142,21 +127,19 @@ class CarInterface(CarInterfaceBase):
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 3840], [0, 3840]] # TODO: determine if there is a dead zone at the top end
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.8], [0.24]]
elif candidate == CAR.HONDA_CITY_7G:
ret.steerActuatorDelay = 0.15
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 2560], [0, 2560]]
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
elif candidate in (CAR.HONDA_CRV, CAR.HONDA_CRV_EU):
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 1000], [0, 1000]] # TODO: determine if there is a dead zone at the top end
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.8], [0.24]]
ret.wheelSpeedFactor = 1.025
elif candidate == CAR.HONDA_CRV_5G:
if eps_modified:
# stock request input values: 0x0000, 0x00DB, 0x01BB, 0x0296, 0x0377, 0x0454, 0x0532, 0x0610, 0x067F
# stock request output values: 0x0000, 0x0500, 0x0A15, 0x0E6D, 0x1100, 0x1200, 0x129A, 0x134D, 0x1400
# modified request output values: 0x0000, 0x0500, 0x0A15, 0x0E6D, 0x1100, 0x1200, 0x1ACD, 0x239A, 0x2800
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 2560, 10000], [0, 2560, 3840]]
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.21], [0.07]]
else:
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 3840], [0, 3840]]
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.64], [0.192]]
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 3840], [0, 3840]]
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.64], [0.192]]
ret.wheelSpeedFactor = 1.025
elif candidate == CAR.HONDA_CRV_HYBRID:
@@ -164,6 +147,11 @@ class CarInterface(CarInterfaceBase):
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.6], [0.18]]
ret.wheelSpeedFactor = 1.025
elif candidate in (CAR.HONDA_CRV_6G):
ret.steerActuatorDelay = 0.15
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 2560], [0, 2560]]
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
elif candidate == CAR.HONDA_FIT:
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]] # TODO: determine if there is a dead zone at the top end
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.2], [0.05]]
@@ -192,10 +180,20 @@ class CarInterface(CarInterfaceBase):
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.28], [0.08]]
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]] # TODO: determine if there is a dead zone at the top end
elif candidate in (CAR.HONDA_PILOT, CAR.HONDA_PILOT_4G):
elif candidate == CAR.HONDA_PILOT:
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]] # TODO: determine if there is a dead zone at the top end
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.38], [0.11]]
elif candidate == CAR.HONDA_PILOT_4G:
ret.steerActuatorDelay = 0.15
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 2560], [0, 2560]]
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
elif candidate == CAR.ACURA_MDX_4G_MMR:
ret.steerActuatorDelay = 0.15
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 2560], [0, 2560]]
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
elif candidate == CAR.HONDA_RIDGELINE:
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]] # TODO: determine if there is a dead zone at the top end
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.38], [0.11]]
@@ -208,6 +206,10 @@ class CarInterface(CarInterfaceBase):
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]] # TODO: determine if there is a dead zone at the top end
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.6], [0.18]] # TODO: can probably use some tuning
# TODO-SP: remove when https://github.com/commaai/opendbc/pull/2687 is merged
elif candidate == CAR.HONDA_CLARITY:
pass
else:
raise ValueError(f"unsupported car {candidate}")
@@ -242,6 +244,66 @@ class CarInterface(CarInterfaceBase):
return ret
@staticmethod
def _get_params_sp(stock_cp: structs.CarParams, ret: structs.CarParamsSP, candidate, fingerprint: dict[int, dict[int, int]],
car_fw: list[structs.CarParams.CarFw], alpha_long: bool, docs: bool) -> structs.CarParamsSP:
for fw in car_fw:
if fw.ecu == "eps" and b"," in fw.fwVersion:
ret.flags |= HondaFlagsSP.EPS_MODIFIED.value
stock_cp.dashcamOnly = False
if candidate == CAR.HONDA_CIVIC:
if ret.flags & HondaFlagsSP.EPS_MODIFIED:
# stock request input values: 0x0000, 0x00DE, 0x014D, 0x01EF, 0x0290, 0x0377, 0x0454, 0x0610, 0x06EE
# stock request output values: 0x0000, 0x0917, 0x0DC5, 0x1017, 0x119F, 0x140B, 0x1680, 0x1680, 0x1680
# modified request output values: 0x0000, 0x0917, 0x0DC5, 0x1017, 0x119F, 0x140B, 0x1680, 0x2880, 0x3180
# stock filter output values: 0x009F, 0x0108, 0x0108, 0x0108, 0x0108, 0x0108, 0x0108, 0x0108, 0x0108
# modified filter output values: 0x009F, 0x0108, 0x0108, 0x0108, 0x0108, 0x0108, 0x0108, 0x0400, 0x0480
# note: max request allowed is 4096, but request is capped at 3840 in firmware, so modifications result in 2x max
stock_cp.lateralParams.torqueBP, stock_cp.lateralParams.torqueV = [[0, 2560, 8000], [0, 2560, 3840]]
stock_cp.lateralTuning.pid.kpV, stock_cp.lateralTuning.pid.kiV = [[0.3], [0.1]]
elif candidate in (CAR.HONDA_CIVIC_BOSCH, CAR.HONDA_CIVIC_BOSCH_DIESEL):
if ret.flags & HondaFlagsSP.EPS_MODIFIED:
stock_cp.lateralParams.torqueBP, stock_cp.lateralParams.torqueV = [[0, 2564, 8000], [0, 2564, 3840]]
stock_cp.lateralTuning.pid.kpV, stock_cp.lateralTuning.pid.kiV = [[0.3], [0.09]] # 2.5x Modded EPS
elif candidate == CAR.HONDA_CIVIC_2022:
if ret.flags & HondaFlagsSP.EPS_MODIFIED:
stock_cp.lateralParams.torqueBP, stock_cp.lateralParams.torqueV = [[0, 2564, 8000], [0, 2564, 3840]]
stock_cp.lateralTuning.pid.kpV, stock_cp.lateralTuning.pid.kiV = [[0.3], [0.09]] # 2.5x Modded EPS
elif candidate == CAR.HONDA_ACCORD:
if ret.flags & HondaFlagsSP.EPS_MODIFIED:
stock_cp.lateralTuning.pid.kpV, stock_cp.lateralTuning.pid.kiV = [[0.3], [0.09]]
elif candidate == CAR.HONDA_CRV_5G:
if ret.flags & HondaFlagsSP.EPS_MODIFIED:
# stock request input values: 0x0000, 0x00DB, 0x01BB, 0x0296, 0x0377, 0x0454, 0x0532, 0x0610, 0x067F
# stock request output values: 0x0000, 0x0500, 0x0A15, 0x0E6D, 0x1100, 0x1200, 0x129A, 0x134D, 0x1400
# modified request output values: 0x0000, 0x0500, 0x0A15, 0x0E6D, 0x1100, 0x1200, 0x1ACD, 0x239A, 0x2800
stock_cp.lateralParams.torqueBP, stock_cp.lateralParams.torqueV = [[0, 2560, 10000], [0, 2560, 3840]]
stock_cp.lateralTuning.pid.kpV, stock_cp.lateralTuning.pid.kiV = [[0.21], [0.07]]
elif candidate == CAR.HONDA_CLARITY:
ret.safetyParam |= HondaSafetyFlagsSP.CLARITY
stock_cp.autoResumeSng = True
stock_cp.minEnableSpeed = -1
if ret.flags & HondaFlagsSP.EPS_MODIFIED:
for fw in car_fw:
if fw.ecu == "eps" and b"-" not in fw.fwVersion and b"," in fw.fwVersion:
stock_cp.lateralTuning.pid.kf = 0.00004
stock_cp.lateralParams.torqueBP, stock_cp.lateralParams.torqueV = [[0, 5760, 15360], [0, 2560, 3840]]
stock_cp.lateralTuning.pid.kpV, stock_cp.lateralTuning.pid.kiV = [[0.1575], [0.05175]]
elif fw.ecu == "eps" and b"-" in fw.fwVersion and b"," in fw.fwVersion:
stock_cp.lateralParams.torqueBP, stock_cp.lateralParams.torqueV = [[0, 5760, 10240], [0, 2560, 3840]]
stock_cp.lateralTuning.pid.kpV, stock_cp.lateralTuning.pid.kiV = [[0.3], [0.1]]
else:
stock_cp.lateralParams.torqueBP, stock_cp.lateralParams.torqueV = [[0, 2560], [0, 2560]]
stock_cp.lateralTuning.pid.kpV, stock_cp.lateralTuning.pid.kiV = [[0.8], [0.24]]
return ret
@staticmethod
def init(CP, CP_SP, can_recv, can_send, communication_control=None):
if CP.carFingerprint in (HONDA_BOSCH - HONDA_BOSCH_RADARLESS) and CP.openpilotLongitudinalControl:
@@ -2,7 +2,7 @@ import re
from opendbc.car.honda.fingerprints import FW_VERSIONS
HONDA_FW_VERSION_RE = br"[A-Z0-9]{5}-[A-Z0-9]{3}(-|,)[A-Z0-9]{4}(\x00){2}$"
HONDA_FW_VERSION_RE = br"[A-Z0-9]{5}(-|,)[A-Z0-9]{3}(-|,)[A-Z0-9]{4}(\x00){2}$"
class TestHondaFingerprint:
+47 -7
View File
@@ -6,6 +6,8 @@ from opendbc.car.common.conversions import Conversions as CV
from opendbc.car.docs_definitions import CarFootnote, CarHarness, CarDocs, CarParts, Column, Device
from opendbc.car.fw_query_definitions import FwQueryConfig, Request, StdQueries, p16
from opendbc.sunnypilot.car.honda.values_ext import HondaFlagsSP
Ecu = structs.CarParams.Ecu
VisualAlert = structs.CarControl.HUDControl.VisualAlert
GearShifter = structs.CarState.GearShifter
@@ -124,6 +126,10 @@ class HondaCarDocs(CarDocs):
else:
self.car_parts = CarParts.common([harness])
if CP.carFingerprint in (CAR.HONDA_CLARITY,):
self.car_parts = CarParts.common([CarHarness.honda_clarity])
self.car_parts.custom_parts_url = "https://shop.retropilot.org/product/honda-clarity-proxy-board-kit"
class Footnote(Enum):
CIVIC_DIESEL = CarFootnote(
@@ -169,14 +175,18 @@ class CAR(Platforms):
{Bus.pt: 'honda_accord_2018_can_generated'},
)
HONDA_ACCORD_11G = HondaBoschCANFDPlatformConfig(
[HondaCarDocs("Honda Accord 2023", "All")],
[
HondaCarDocs("Honda Accord 2023-25", "All"),
HondaCarDocs("Honda Accord Hybrid 2023-25", "All"),
],
CarSpecs(mass=3477 * CV.LB_TO_KG, wheelbase=2.83, steerRatio=16.0, centerToFrontRatio=0.39),
)
HONDA_CIVIC_BOSCH = HondaBoschPlatformConfig(
[
HondaCarDocs("Honda Civic 2019-21", "All", video="https://www.youtube.com/watch?v=4Iz1Mz5LGF8",
footnotes=[Footnote.CIVIC_DIESEL], min_steer_speed=2. * CV.MPH_TO_MS),
HondaCarDocs("Honda Civic Hatchback 2017-21", min_steer_speed=12. * CV.MPH_TO_MS),
HondaCarDocs("Honda Civic Hatchback 2017-18", min_steer_speed=12. * CV.MPH_TO_MS),
HondaCarDocs("Honda Civic Hatchback 2019-21", "All", min_steer_speed=12. * CV.MPH_TO_MS),
],
CarSpecs(mass=1326, wheelbase=2.7, steerRatio=15.38, centerToFrontRatio=0.4), # steerRatio: 10.93 is end-to-end spec
{Bus.pt: 'honda_civic_hatchback_ex_2017_can_generated'},
@@ -206,6 +216,13 @@ class CAR(Platforms):
{Bus.pt: 'honda_crv_ex_2017_can_generated', Bus.body: 'honda_crv_ex_2017_body_generated'},
flags=HondaFlags.BOSCH_ALT_BRAKE,
)
HONDA_CRV_6G = HondaBoschCANFDPlatformConfig(
[
HondaCarDocs("Honda CR-V 2023-25", "All"),
HondaCarDocs("Honda CR-V Hybrid 2023-25", "All"),
],
CarSpecs(mass=1703, wheelbase=2.7, steerRatio=16.2, centerToFrontRatio=0.42),
)
HONDA_CRV_HYBRID = HondaBoschPlatformConfig(
[HondaCarDocs("Honda CR-V Hybrid 2017-22", min_steer_speed=12. * CV.MPH_TO_MS)],
# mass: mean of 4 models in kg, steerRatio: 12.3 is spec end-to-end
@@ -218,6 +235,12 @@ class CAR(Platforms):
{Bus.pt: 'honda_civic_ex_2022_can_generated'},
flags=HondaFlags.BOSCH_RADARLESS,
)
HONDA_CITY_7G = HondaBoschPlatformConfig(
[HondaCarDocs("Honda City (Brazil only) 2023", "All")],
CarSpecs(mass=3125 * CV.LB_TO_KG, wheelbase=2.6, steerRatio=19.0, centerToFrontRatio=0.41, minSteerSpeed=23. * CV.KPH_TO_MS),
{Bus.pt: 'honda_civic_ex_2022_can_generated'},
flags=HondaFlags.BOSCH_RADARLESS,
)
ACURA_RDX_3G = HondaBoschPlatformConfig(
[HondaCarDocs("Acura RDX 2019-21", "All", min_steer_speed=3. * CV.MPH_TO_MS)],
CarSpecs(mass=4068 * CV.LB_TO_KG, wheelbase=2.75, steerRatio=11.95, centerToFrontRatio=0.41, tireStiffnessFactor=0.677), # as spec
@@ -235,9 +258,13 @@ class CAR(Platforms):
{Bus.pt: 'acura_rdx_2020_can_generated'},
)
HONDA_PILOT_4G = HondaBoschCANFDPlatformConfig(
[HondaCarDocs("Honda Pilot 2023", "All")],
CarSpecs(mass=4278 * CV.LB_TO_KG, wheelbase=2.86, centerToFrontRatio=0.428, steerRatio=16.0, tireStiffnessFactor=0.444), # as spec
flags=HondaFlags.BOSCH_ALT_BRAKE,
[HondaCarDocs("Honda Pilot 2023-25", "All")],
CarSpecs(mass=4660 * CV.LB_TO_KG, wheelbase=2.89, centerToFrontRatio=0.442, steerRatio=17.5),
)
# mid-model refresh
ACURA_MDX_4G_MMR = HondaBoschCANFDPlatformConfig(
[HondaCarDocs("Acura MDX 2025", "All except Type S")],
CarSpecs(mass=4544 * CV.LB_TO_KG, wheelbase=2.89, centerToFrontRatio=0.428, steerRatio=16.2),
)
# Nidec Cars
@@ -314,6 +341,15 @@ class CAR(Platforms):
flags=HondaFlags.HAS_ALL_DOOR_STATES
)
# port extensions
HONDA_CLARITY = HondaNidecPlatformConfig(
[HondaCarDocs("Honda Clarity 2018-21", min_steer_speed=12. * CV.MPH_TO_MS)],
CarSpecs(mass=1834, wheelbase=2.75, centerToFrontRatio=0.4, steerRatio=16.5),
radar_dbc_dict('honda_clarity_hybrid_2018_can_generated'),
flags=HondaFlags.HAS_ALL_DOOR_STATES,
sp_flags=HondaFlagsSP.CLARITY,
)
HONDA_NIDEC_ALT_PCM_ACCEL = CAR.with_flags(HondaFlags.NIDEC_ALT_PCM_ACCEL)
HONDA_NIDEC_ALT_SCM_MESSAGES = CAR.with_flags(HondaFlags.NIDEC_ALT_SCM_MESSAGES)
@@ -330,6 +366,10 @@ STEER_THRESHOLD = {
CAR.ACURA_RDX: 400,
CAR.HONDA_CRV_EU: 400,
CAR.HONDA_ACCORD_11G: 600,
CAR.HONDA_PILOT_4G: 600,
CAR.ACURA_MDX_4G_MMR: 600,
CAR.HONDA_CRV_6G: 600,
CAR.HONDA_CITY_7G: 600,
}
@@ -374,9 +414,9 @@ FW_QUERY_CONFIG = FwQueryConfig(
# Note that we still attempt to match with them when they are present
# This is or'd with (ALL_ECUS - ESSENTIAL_ECUS) from fw_versions.py
non_essential_ecus={
Ecu.eps: [CAR.ACURA_RDX_3G, CAR.HONDA_ACCORD, CAR.HONDA_CIVIC_2022, CAR.HONDA_E, CAR.HONDA_HRV_3G, *HONDA_BOSCH_CANFD],
Ecu.eps: [CAR.ACURA_RDX_3G, CAR.HONDA_ACCORD, CAR.HONDA_CIVIC_2022, CAR.HONDA_E, CAR.HONDA_HRV_3G, CAR.HONDA_CITY_7G, *HONDA_BOSCH_CANFD],
Ecu.vsa: [CAR.ACURA_RDX_3G, CAR.HONDA_ACCORD, CAR.HONDA_CIVIC, CAR.HONDA_CIVIC_BOSCH, CAR.HONDA_CIVIC_2022, CAR.HONDA_CRV_5G, CAR.HONDA_CRV_HYBRID,
CAR.HONDA_E, CAR.HONDA_HRV_3G, CAR.HONDA_INSIGHT, *HONDA_BOSCH_CANFD],
CAR.HONDA_E, CAR.HONDA_HRV_3G, CAR.HONDA_INSIGHT, CAR.HONDA_CITY_7G, *HONDA_BOSCH_CANFD],
},
extra_ecus=[
(Ecu.combinationMeter, 0x18da60f1, None),
@@ -10,6 +10,7 @@ from opendbc.car.interfaces import CarControllerBase
from opendbc.sunnypilot.car.hyundai.escc import EsccCarController
from opendbc.sunnypilot.car.hyundai.longitudinal.controller import LongitudinalController
from opendbc.sunnypilot.car.hyundai.lead_data_ext import LeadDataCarController
from opendbc.sunnypilot.car.hyundai.mads import MadsCarController
VisualAlert = structs.CarControl.HUDControl.VisualAlert
@@ -46,11 +47,12 @@ def process_hud_alert(enabled, fingerprint, hud_control):
return sys_warning, sys_state, left_lane_warning, right_lane_warning
class CarController(CarControllerBase, EsccCarController, LongitudinalController, MadsCarController):
class CarController(CarControllerBase, EsccCarController, LeadDataCarController, LongitudinalController, MadsCarController):
def __init__(self, dbc_names, CP, CP_SP):
CarControllerBase.__init__(self, dbc_names, CP, CP_SP)
EsccCarController.__init__(self, CP, CP_SP)
MadsCarController.__init__(self)
LeadDataCarController.__init__(self, CP)
LongitudinalController.__init__(self, CP, CP_SP)
self.CAN = CanBus(CP)
self.params = CarControllerParams(CP)
@@ -64,6 +66,7 @@ class CarController(CarControllerBase, EsccCarController, LongitudinalController
def update(self, CC, CC_SP, CS, now_nanos):
EsccCarController.update(self, CS)
LeadDataCarController.update(self, CC_SP)
MadsCarController.update(self, self.CP, CC, CC_SP, self.frame)
if self.frame % 2 == 0:
LongitudinalController.update(self, CC, CS)
@@ -157,7 +160,7 @@ class CarController(CarControllerBase, EsccCarController, LongitudinalController
jerk = 3.0 if actuators.longControlState == LongCtrlState.pid else 1.0
use_fca = self.CP.flags & HyundaiFlags.USE_FCA.value
can_sends.extend(hyundaican.create_acc_commands(self.packer, CC.enabled, accel, jerk, int(self.frame / 2),
hud_control, set_speed_in_units, stopping,
self.lead_data, hud_control, set_speed_in_units, stopping,
CC.cruiseControl.override, use_fca, self.CP,
CS.main_cruise_enabled, self.tuning, self.ESCC))
@@ -204,7 +207,7 @@ class CarController(CarControllerBase, EsccCarController, LongitudinalController
can_sends.extend(hyundaicanfd.create_fca_warning_light(self.packer, self.CAN, self.frame))
if self.frame % 2 == 0:
can_sends.append(hyundaicanfd.create_acc_control(self.packer, self.CAN, CC.enabled, self.accel_last, accel, stopping, CC.cruiseControl.override,
set_speed_in_units, hud_control, CS.main_cruise_enabled, self.tuning))
set_speed_in_units, hud_control, self.lead_data, CS.main_cruise_enabled, self.tuning))
self.accel_last = accel
else:
# button presses
+7 -5
View File
@@ -12,6 +12,7 @@ from opendbc.car.interfaces import CarStateBase
from opendbc.sunnypilot.car.hyundai.carstate_ext import CarStateExt
from opendbc.sunnypilot.car.hyundai.escc import EsccCarStateBase
from opendbc.sunnypilot.car.hyundai.mads import MadsCarState
from opendbc.sunnypilot.car.hyundai.values import HyundaiFlagsSP
ButtonType = structs.CarState.ButtonEvent.Type
@@ -30,7 +31,7 @@ class CarState(CarStateBase, EsccCarStateBase, MadsCarState, CarStateExt):
CarStateBase.__init__(self, CP, CP_SP)
EsccCarStateBase.__init__(self)
MadsCarState.__init__(self, CP, CP_SP)
CarStateExt.__init__(self)
CarStateExt.__init__(self, CP, CP_SP)
can_define = CANDefine(DBC[CP.carFingerprint][Bus.pt])
self.cruise_buttons: deque = deque([Buttons.NONE] * PREV_BUTTON_SAMPLES, maxlen=PREV_BUTTON_SAMPLES)
@@ -131,7 +132,7 @@ class CarState(CarStateBase, EsccCarStateBase, MadsCarState, CarStateExt):
ret.cruiseState.enabled = cp.vl["TCS13"]["ACC_REQ"] == 1
ret.cruiseState.standstill = False
ret.cruiseState.nonAdaptive = False
else:
elif not self.CP_SP.flags & HyundaiFlagsSP.NON_SCC:
ret.cruiseState.available = cp_cruise.vl["SCC11"]["MainMode_ACC"] == 1
ret.cruiseState.enabled = cp_cruise.vl["SCC12"]["ACCMode"] != 0
ret.cruiseState.standstill = cp_cruise.vl["SCC11"]["SCCInfoDisplay"] == 4.
@@ -172,7 +173,7 @@ class CarState(CarStateBase, EsccCarStateBase, MadsCarState, CarStateExt):
ret.gearShifter = self.parse_gear_shifter(self.shifter_values.get(gear))
if not self.CP.openpilotLongitudinalControl or self.CP.flags & HyundaiFlags.CAMERA_SCC:
if (not self.CP.openpilotLongitudinalControl or self.CP.flags & HyundaiFlags.CAMERA_SCC) and not self.CP_SP.flags & HyundaiFlagsSP.NON_SCC:
aeb_src = "FCA11" if self.CP.flags & HyundaiFlags.USE_FCA.value else "SCC12"
aeb_sig = "FCA_CmdAct" if self.CP.flags & HyundaiFlags.USE_FCA.value else "AEB_CmdAct"
aeb_warning = cp_cruise.vl[aeb_src]["CF_VSM_Warn"] != 0
@@ -204,7 +205,7 @@ class CarState(CarStateBase, EsccCarStateBase, MadsCarState, CarStateExt):
if self.CP.openpilotLongitudinalControl:
ret.cruiseState.available = self.get_main_cruise(ret)
CarStateExt.update(self, ret, can_parsers)
CarStateExt.update(self, ret, can_parsers, speed_conv)
ret.blockPcmEnable = not self.recent_button_interaction()
@@ -321,7 +322,8 @@ class CarState(CarStateBase, EsccCarStateBase, MadsCarState, CarStateExt):
if not (CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS):
# TODO: this can be removed once we add dynamic support to vl_all
msgs += [
("CRUISE_BUTTONS", 50)
# this message is 50Hz but the ECU frequently stops transmitting for ~0.5s
("CRUISE_BUTTONS", 1)
]
return {
Bus.pt: CANParser(DBC[CP.carFingerprint][Bus.pt], msgs, CanBus(CP).ECAN),
@@ -731,6 +731,7 @@ FW_VERSIONS = {
b'\xf1\x00DE MDPS C 1.00 1.04 56310Q4100\x00 4DEEC104',
b'\xf1\x00DE MDPS C 1.00 1.05 56310Q4000\x00 4DEEC105',
b'\xf1\x00DE MDPS C 1.00 1.05 56310Q4100\x00 4DEEC105',
b'\xf1\x00DE MDPS C 1.00 1.05 56310Q4200\x00 4DEEC105',
],
(Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00DEE MFC AT EUR LHD 1.00 1.00 99211-Q4000 191211',
@@ -986,6 +987,7 @@ FW_VERSIONS = {
},
CAR.KIA_SORENTO: {
(Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00UMP LKAS AT AUS RHD 1.00 1.00 96400-C6550 S30',
b'\xf1\x00UMP LKAS AT KOR LHD 1.00 1.00 95740-C5550 S30',
b'\xf1\x00UMP LKAS AT USA LHD 1.00 1.00 95740-C6550 d00',
b'\xf1\x00UMP LKAS AT USA LHD 1.01 1.01 95740-C6550 d01',
@@ -1249,16 +1251,19 @@ FW_VERSIONS = {
},
CAR.HYUNDAI_KONA_2022: {
(Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00OSP LKA AT CND LHD 1.00 1.04 99211-J9200 904',
b'\xf1\x00OSP LKA AT USA LHD 1.00 1.04 99211-J9200 904',
],
(Ecu.eps, 0x7d4, None): [
b'\xf1\x00OSP MDPS C 1.00 1.04 56310/J9290 4OPCC104',
b'\xf1\x00OSP MDPS C 1.00 1.04 56310/J9291 4OPCC104',
b'\xf1\x00OSP MDPS C 1.00 1.04 56310J9291\x00 4OPCC104',
],
(Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00YB__ FCA ----- 1.00 1.01 99110-J9000 \x00\x00\x00',
],
(Ecu.transmission, 0x7e1, None): [
b'\xf1\x00HT6WA280BLHT6VA650A1COS4N20NS1\x00\x00\x00\x00\x00\x00\x15\xf5\x87~',
b'\xf1\x00T01960BL T01E60A1 DOS2T16X4XE60NS4N\x90\xe6\xcb',
b'\xf1\x00T01G00BL T01I00A1 DOS2T16X2XI00NS0\x8c`\xff\xe7',
b'\xf1\x00T01G00BL T01I00A1 DOS2T16X4XI00NS0\x99L\xeeq',
+13 -8
View File
@@ -2,6 +2,7 @@ import crcmod
from opendbc.car.hyundai.values import CAR, HyundaiFlags
from opendbc.sunnypilot.car.hyundai.escc import EnhancedSmartCruiseControl
from opendbc.sunnypilot.car.hyundai.lead_data_ext import CanLeadData
hyundai_checksum = crcmod.mkCrcFun(0x11D, initCrc=0xFD, rev=False, xorOut=0xdf)
@@ -42,7 +43,9 @@ def create_lkas11(packer, frame, CP, apply_torque, steer_req,
CAR.HYUNDAI_ELANTRA_HEV_2021, CAR.HYUNDAI_SONATA_HYBRID, CAR.HYUNDAI_KONA_EV, CAR.HYUNDAI_KONA_HEV, CAR.HYUNDAI_KONA_EV_2022,
CAR.HYUNDAI_SANTA_FE_2022, CAR.KIA_K5_2021, CAR.HYUNDAI_IONIQ_HEV_2022, CAR.HYUNDAI_SANTA_FE_HEV_2022,
CAR.HYUNDAI_SANTA_FE_PHEV_2022, CAR.KIA_STINGER_2022, CAR.KIA_K5_HEV_2020, CAR.KIA_CEED,
CAR.HYUNDAI_AZERA_6TH_GEN, CAR.HYUNDAI_AZERA_HEV_6TH_GEN, CAR.HYUNDAI_CUSTIN_1ST_GEN, CAR.HYUNDAI_KONA_2022):
CAR.HYUNDAI_AZERA_6TH_GEN, CAR.HYUNDAI_AZERA_HEV_6TH_GEN, CAR.HYUNDAI_CUSTIN_1ST_GEN, CAR.HYUNDAI_KONA_2022,
CAR.KIA_CEED_PHEV_2022_NON_SCC, CAR.HYUNDAI_KONA_EV_NON_SCC, CAR.HYUNDAI_ELANTRA_2022_NON_SCC,
CAR.GENESIS_G70_2021_NON_SCC, CAR.KIA_SELTOS_2023_NON_SCC, CAR.HYUNDAI_BAYON_1ST_GEN_NON_SCC):
values["CF_Lkas_LdwsActivemode"] = int(left_lane) + (int(right_lane) << 1)
values["CF_Lkas_LdwsOpt_USM"] = 2
@@ -61,7 +64,7 @@ def create_lkas11(packer, frame, CP, apply_torque, steer_req,
values["CF_Lkas_SysWarning"] = 4 if sys_warning else 0
# Likely cars lacking the ability to show individual lane lines in the dash
elif CP.carFingerprint in (CAR.KIA_OPTIMA_G4, CAR.KIA_OPTIMA_G4_FL):
elif CP.carFingerprint in (CAR.KIA_OPTIMA_G4, CAR.KIA_OPTIMA_G4_FL, CAR.HYUNDAI_KONA_NON_SCC):
# SysWarning 4 = keep hands on wheel + beep
values["CF_Lkas_SysWarning"] = 4 if sys_warning else 0
@@ -128,7 +131,8 @@ def create_lfahda_mfc(packer, enabled, lfa_icon):
return packer.make_can_msg("LFAHDA_MFC", 0, values)
def create_acc_commands(packer, enabled, accel, upper_jerk, idx, hud_control, set_speed, stopping, long_override, use_fca, CP,
def create_acc_commands(packer, enabled, accel, upper_jerk, idx, lead_data: CanLeadData,
hud_control, set_speed, stopping, long_override, use_fca, CP,
main_cruise_enabled, tuning, ESCC: EnhancedSmartCruiseControl = None):
commands = []
@@ -138,11 +142,11 @@ def create_acc_commands(packer, enabled, accel, upper_jerk, idx, hud_control, se
"TauGapSet": hud_control.leadDistanceBars,
"VSetDis": set_speed if enabled else 0,
"AliveCounterACC": idx % 0x10,
"ObjValid": 1, # close lead makes controls tighter
"ACC_ObjStatus": 1, # close lead makes controls tighter
"ObjValid": int(lead_data.lead_visible), # close lead makes controls tighter
"ACC_ObjStatus": int(lead_data.lead_visible), # close lead makes controls tighter
"ACC_ObjLatPos": 0,
"ACC_ObjRelSpd": 0,
"ACC_ObjDist": 1, # close lead makes controls tighter
"ACC_ObjRelSpd": lead_data.lead_rel_speed,
"ACC_ObjDist": int(lead_data.lead_distance), # close lead makes controls tighter
}
def get_scc12_values():
@@ -178,7 +182,8 @@ def create_acc_commands(packer, enabled, accel, upper_jerk, idx, hud_control, se
"JerkUpperLimit": tuning.jerk_upper, # stock usually is 1.0 but sometimes uses higher values
"JerkLowerLimit": tuning.jerk_lower, # stock usually is 0.5 but sometimes uses higher values
"ACCMode": 2 if enabled and long_override else 1 if enabled else 4, # stock will always be 4 instead of 0 after first disengage
"ObjGap": 2 if hud_control.leadVisible else 0, # 5: >30, m, 4: 25-30 m, 3: 20-25 m, 2: < 20 m, 0: no lead
"ObjGap": lead_data.object_gap, # 5: >30, m, 4: 25-30 m, 3: 20-25 m, 2: < 20 m, 0: no lead
"ObjDistStat": lead_data.object_rel_gap,
}
def get_fca11_values():
@@ -3,6 +3,7 @@ import numpy as np
from opendbc.car import CanBusBase
from opendbc.car.crc import CRC16_XMODEM
from opendbc.car.hyundai.values import HyundaiFlags
from opendbc.sunnypilot.car.hyundai.lead_data_ext import CanFdLeadData
class CanBus(CanBusBase):
@@ -131,7 +132,7 @@ def create_lfahda_cluster(packer, CAN, enabled, lfa_icon):
def create_acc_control(packer, CAN, enabled, accel_last, accel, stopping, gas_override, set_speed, hud_control,
main_cruise_enabled, tuning):
lead_data: CanFdLeadData, main_cruise_enabled, tuning):
jerk = 5
jn = jerk / 50
if not enabled or gas_override:
@@ -150,9 +151,10 @@ def create_acc_control(packer, CAN, enabled, accel_last, accel, stopping, gas_ov
"JerkLowerLimit": tuning.jerk_lower,
"JerkUpperLimit": tuning.jerk_upper,
"ACC_ObjDist": 1,
"ObjValid": 0,
"OBJ_STATUS": 2,
"ACC_ObjDist": int(lead_data.lead_distance),
"ACC_ObjRelSpd": lead_data.lead_rel_speed,
"ObjValid": int(not lead_data.lead_visible),
"SCC_ObjSta": 0 if not (enabled and lead_data.lead_visible) else (1 if gas_override else 2),
"SET_ME_2": 0x4,
"SET_ME_3": 0x3,
"SET_ME_TMP_64": 0x64,
@@ -179,6 +179,22 @@ class CarInterface(CarInterfaceBase):
if stock_cp.flags & HyundaiFlags.ALT_LIMITS_2:
stock_cp.dashcamOnly = False
if ret.flags & HyundaiFlagsSP.NON_SCC:
stock_cp.alphaLongitudinalAvailable = False
stock_cp.openpilotLongitudinalControl = False
stock_cp.pcmCruise = True
ret.safetyParam |= HyundaiSafetyFlagsSP.NON_SCC
# untested non-SCC platforms, need user validations
if stock_cp.carFingerprint in (CAR.HYUNDAI_BAYON_1ST_GEN_NON_SCC, CAR.KIA_FORTE_2019_NON_SCC, CAR.KIA_FORTE_2021_NON_SCC,
CAR.KIA_SELTOS_2023_NON_SCC, CAR.GENESIS_G70_2021_NON_SCC):
stock_cp.dashcamOnly = True
# Detect smartMDPS, which bypasses EPS low-speed lockout, allowing sunnypilot to send steering commands down to 0
if 0x2AA in fingerprint[0]:
stock_cp.minSteerSpeed = 0.0
stock_cp.flags &= ~HyundaiFlags.MIN_STEER_32_MPH.value
return ret
@staticmethod
@@ -11,7 +11,8 @@ from opendbc.car.hyundai.radar_interface import RADAR_START_ADDR
from opendbc.car.hyundai.values import CAMERA_SCC_CAR, CANFD_CAR, CAN_GEARS, CAR, CHECKSUM, DATE_FW_ECUS, \
HYBRID_CAR, EV_CAR, FW_QUERY_CONFIG, LEGACY_SAFETY_MODE_CAR, CANFD_FUZZY_WHITELIST, \
UNSUPPORTED_LONGITUDINAL_CAR, PLATFORM_CODE_ECUS, HYUNDAI_VERSION_REQUEST_LONG, \
HyundaiFlags, get_platform_codes, HyundaiSafetyFlags
HyundaiFlags, get_platform_codes, HyundaiSafetyFlags, \
NON_SCC_CAR
from opendbc.car.hyundai.fingerprints import FW_VERSIONS
Ecu = CarParams.Ecu
@@ -157,6 +158,8 @@ class TestHyundaiFingerprint:
continue
if platform_code_ecu == Ecu.eps and car_model in no_eps_platforms:
continue
if car_model in NON_SCC_CAR:
continue
assert platform_code_ecu in [e[0] for e in ecus]
def test_fw_format(self, subtests):
@@ -171,6 +174,9 @@ class TestHyundaiFingerprint:
if ecu[0] not in PLATFORM_CODE_ECUS:
continue
if car_model in NON_SCC_CAR:
continue
codes = set()
for fw in fws:
result = get_platform_codes([fw])
@@ -237,6 +243,9 @@ class TestHyundaiFingerprint:
car_fw.append(CarParams.CarFw(ecu=ecu_name, fwVersion=fw, address=addr,
subAddress=0 if sub_addr is None else sub_addr))
if platform in NON_SCC_CAR:
continue
CP = CarParams(carFw=car_fw)
matches = FW_QUERY_CONFIG.match_fw_to_car_fuzzy(build_fw_dict(CP.carFw), CP.carVin, FW_VERSIONS)
if len(matches) == 1:
+60 -1
View File
@@ -8,6 +8,8 @@ from opendbc.car.structs import CarParams
from opendbc.car.docs_definitions import CarFootnote, CarHarness, CarDocs, CarParts, Column, Device
from opendbc.car.fw_query_definitions import FwQueryConfig, Request, p16
from opendbc.sunnypilot.car.hyundai.values import HyundaiFlagsSP
Ecu = CarParams.Ecu
@@ -251,7 +253,7 @@ class CAR(Platforms):
flags=HyundaiFlags.CLUSTER_GEARS | HyundaiFlags.ALT_LIMITS,
)
HYUNDAI_KONA_2022 = HyundaiPlatformConfig(
[HyundaiCarDocs("Hyundai Kona 2022", car_parts=CarParts.common([CarHarness.hyundai_o]))],
[HyundaiCarDocs("Hyundai Kona 2022-23", car_parts=CarParts.common([CarHarness.hyundai_o]))],
CarSpecs(mass=1491, wheelbase=2.6, steerRatio=13.42, tireStiffnessFactor=0.385),
flags=HyundaiFlags.CAMERA_SCC | HyundaiFlags.ALT_LIMITS_2,
)
@@ -597,6 +599,60 @@ class CAR(Platforms):
flags=HyundaiFlags.RADAR_SCC,
)
# port extensions
HYUNDAI_BAYON_1ST_GEN_NON_SCC = HyundaiPlatformConfig(
[HyundaiCarDocs("Hyundai Bayon Non-SCC 2021", "No Smart Cruise Control (Non-SCC)", car_parts=CarParts.common([CarHarness.hyundai_n]))],
CarSpecs(mass=1150, wheelbase=2.58, steerRatio=13.27 * 1.15),
flags=HyundaiFlags.CHECKSUM_CRC8,
sp_flags=HyundaiFlagsSP.NON_SCC,
)
HYUNDAI_ELANTRA_2022_NON_SCC = HyundaiPlatformConfig(
[HyundaiCarDocs("Hyundai Elantra Non-SCC 2022", "No Smart Cruise Control (Non-SCC)", car_parts=CarParts.common([CarHarness.hyundai_k]))],
HYUNDAI_ELANTRA_2021.specs,
flags=HyundaiFlags.CHECKSUM_CRC8,
sp_flags=HyundaiFlagsSP.NON_SCC,
)
HYUNDAI_KONA_NON_SCC = HyundaiPlatformConfig(
[HyundaiCarDocs("Hyundai Kona Non-SCC 2019", "No Smart Cruise Control (Non-SCC)", car_parts=CarParts.common([CarHarness.hyundai_b]))],
HYUNDAI_KONA.specs,
flags=HyundaiFlags.ALT_LIMITS,
sp_flags=HyundaiFlagsSP.NON_SCC,
)
HYUNDAI_KONA_EV_NON_SCC = HyundaiPlatformConfig(
[HyundaiCarDocs("Hyundai Kona Electric Non-SCC 2019", "No Smart Cruise Control (Non-SCC)", car_parts=CarParts.common([CarHarness.hyundai_g]))],
HYUNDAI_KONA_EV.specs,
flags=HyundaiFlags.EV | HyundaiFlags.ALT_LIMITS,
sp_flags=HyundaiFlagsSP.NON_SCC,
)
KIA_CEED_PHEV_2022_NON_SCC = HyundaiPlatformConfig(
[HyundaiCarDocs("Kia Ceed Plug-in Hybrid Non-SCC 2022", "No Smart Cruise Control (Non-SCC)", car_parts=CarParts.common([CarHarness.hyundai_i]))],
CarSpecs(mass=1650, wheelbase=2.65, steerRatio=13.75, tireStiffnessFactor=0.5),
flags=HyundaiFlags.HYBRID,
sp_flags=HyundaiFlagsSP.NON_SCC,
)
KIA_FORTE_2019_NON_SCC = HyundaiPlatformConfig(
[HyundaiCarDocs("Kia Forte Non-SCC 2019", "No Smart Cruise Control (Non-SCC)", car_parts=CarParts.common([CarHarness.hyundai_g]))],
KIA_FORTE.specs,
sp_flags=HyundaiFlagsSP.NON_SCC | HyundaiFlagsSP.NON_SCC_NO_FCA,
)
KIA_FORTE_2021_NON_SCC = HyundaiPlatformConfig(
[HyundaiCarDocs("Kia Forte Non-SCC 2021", "No Smart Cruise Control (Non-SCC)", car_parts=CarParts.common([CarHarness.hyundai_g]))],
KIA_FORTE.specs,
sp_flags=HyundaiFlagsSP.NON_SCC,
)
KIA_SELTOS_2023_NON_SCC = HyundaiPlatformConfig(
[HyundaiCarDocs("Kia Seltos Non-SCC 2023-24", "No Smart Cruise Control (Non-SCC)", car_parts=CarParts.common([CarHarness.hyundai_l]))],
KIA_SELTOS.specs,
flags=HyundaiFlags.CHECKSUM_CRC8,
sp_flags=HyundaiFlagsSP.NON_SCC,
)
GENESIS_G70_2021_NON_SCC = HyundaiPlatformConfig(
[HyundaiCarDocs("Genesis G70 Non-SCC 2021", "No Smart Cruise Control (Non-SCC)", car_parts=CarParts.common([CarHarness.hyundai_f]))],
GENESIS_G70_2020.specs,
flags=HyundaiFlags.CHECKSUM_CRC8,
sp_flags=HyundaiFlagsSP.NON_SCC | HyundaiFlagsSP.NON_SCC_RADAR_FCA,
)
class Buttons:
NONE = 0
@@ -803,4 +859,7 @@ LEGACY_SAFETY_MODE_CAR = CAR.with_flags(HyundaiFlags.LEGACY)
# HyundaiFlags.CANFD_RADAR_SCC | HyundaiFlags.CANFD_NO_RADAR_DISABLE | )
UNSUPPORTED_LONGITUDINAL_CAR = CAR.with_flags(HyundaiFlags.LEGACY) | CAR.with_flags(HyundaiFlags.UNSUPPORTED_LONGITUDINAL)
# port extensions
NON_SCC_CAR = CAR.with_sp_flags(HyundaiFlagsSP.NON_SCC)
DBC = CAR.create_dbc_map()
+18 -48
View File
@@ -1,11 +1,10 @@
import json
import os
import numpy as np
import time
import tomllib
from abc import abstractmethod, ABC
from enum import StrEnum
from typing import Any, NamedTuple
from typing import Any
from collections.abc import Callable
from functools import cache
@@ -19,6 +18,8 @@ from opendbc.car.values import PLATFORMS
from opendbc.can import CANParser
from opendbc.car.carlog import carlog
from opendbc.sunnypilot.car.interfaces import CarInterfaceBaseSP
GearShifter = structs.CarState.GearShifter
ButtonType = structs.CarState.ButtonEvent.Type
@@ -43,15 +44,8 @@ GEAR_SHIFTER_MAP: dict[str, structs.CarState.GearShifter] = {
'B': GearShifter.brake, 'BRAKE': GearShifter.brake,
}
class LatControlInputs(NamedTuple):
lateral_acceleration: float
roll_compensation: float
vego: float
aego: float
TorqueFromLateralAccelCallbackType = Callable[[LatControlInputs, structs.CarParams.LateralTorqueTuning, bool], float]
TorqueFromLateralAccelCallbackType = Callable[[float, structs.CarParams.LateralTorqueTuning, bool], float]
LateralAccelFromTorqueCallbackType = Callable[[float, structs.CarParams.LateralTorqueTuning, bool], float]
@cache
@@ -101,7 +95,7 @@ class RadarInterfaceBase(ABC):
return None
class CarInterfaceBase(ABC):
class CarInterfaceBase(ABC, CarInterfaceBaseSP):
CarState: 'CarStateBase'
CarController: 'CarControllerBase'
RadarInterface: 'RadarInterfaceBase' = RadarInterfaceBase
@@ -171,6 +165,9 @@ class CarInterfaceBase(ABC):
docs: bool) -> structs.CarParamsSP:
car_params_sp = structs.CarParamsSP()
platform = PLATFORMS[candidate]
car_params_sp.flags |= int(platform.config.sp_flags)
return cls._get_params_sp(car_params, car_params_sp, candidate, fingerprint, car_fw, alpha_long, docs)
@staticmethod
@@ -211,14 +208,19 @@ class CarInterfaceBase(ABC):
def get_steer_feedforward_function(self):
return self.get_steer_feedforward_default
def torque_from_lateral_accel_linear(self, latcontrol_inputs: LatControlInputs, torque_params: structs.CarParams.LateralTorqueTuning,
gravity_adjusted: bool) -> float:
def torque_from_lateral_accel_linear(self, lateral_acceleration: float, torque_params: structs.CarParams.LateralTorqueTuning) -> float:
# The default is a linear relationship between torque and lateral acceleration (accounting for road roll and steering friction)
return latcontrol_inputs.lateral_acceleration / float(torque_params.latAccelFactor)
return lateral_acceleration / float(torque_params.latAccelFactor)
def torque_from_lateral_accel(self) -> TorqueFromLateralAccelCallbackType:
return self.torque_from_lateral_accel_linear
def lateral_accel_from_torque_linear(self, torque: float, torque_params: structs.CarParams.LateralTorqueTuning) -> float:
return torque * float(torque_params.latAccelFactor)
def lateral_accel_from_torque(self) -> LateralAccelFromTorqueCallbackType:
return self.lateral_accel_from_torque_linear
# returns a set of default params to avoid repetition in car specific params
@staticmethod
def get_std_params(candidate: str) -> structs.CarParams:
@@ -258,8 +260,8 @@ class CarInterfaceBase(ABC):
params = get_torque_params()[candidate]
tune.init('torque')
tune.torque.kp = 1.0
tune.torque.kf = 1.0
tune.torque.kp = 1.0
tune.torque.ki = 0.3
tune.torque.friction = params['FRICTION']
tune.torque.latAccelFactor = params['LAT_ACCEL_FACTOR']
@@ -442,35 +444,3 @@ def get_interface_attr(attr: str, combine_brands: bool = False, ignore_none: boo
pass
return result
class NanoFFModel:
def __init__(self, weights_loc: str, platform: str):
self.weights_loc = weights_loc
self.platform = platform
self.load_weights(platform)
def load_weights(self, platform: str):
with open(self.weights_loc) as fob:
self.weights = {k: np.array(v) for k, v in json.load(fob)[platform].items()}
def relu(self, x: np.ndarray):
return np.maximum(0.0, x)
def forward(self, x: np.ndarray):
assert x.ndim == 1
x = (x - self.weights['input_norm_mat'][:, 0]) / (self.weights['input_norm_mat'][:, 1] - self.weights['input_norm_mat'][:, 0])
x = self.relu(np.dot(x, self.weights['w_1']) + self.weights['b_1'])
x = self.relu(np.dot(x, self.weights['w_2']) + self.weights['b_2'])
x = self.relu(np.dot(x, self.weights['w_3']) + self.weights['b_3'])
x = np.dot(x, self.weights['w_4']) + self.weights['b_4']
return x
def predict(self, x: list[float], do_sample: bool = False):
x = self.forward(np.array(x))
if do_sample:
pred = np.random.laplace(x[0], np.exp(x[1]) / self.weights['temperature'])
else:
pred = x[0]
pred = pred * (self.weights['output_norm_mat'][1] - self.weights['output_norm_mat'][0]) + self.weights['output_norm_mat'][0]
return pred
+2 -1
View File
@@ -160,9 +160,10 @@ def apply_center_deadzone(error, deadzone):
def get_friction(lateral_accel_error: float, lateral_accel_deadzone: float, friction_threshold: float,
torque_params: structs.CarParams.LateralTorqueTuning) -> float:
# TODO torque params' friction should be in lataxel space, not torque space
friction_interp = np.interp(
apply_center_deadzone(lateral_accel_error, lateral_accel_deadzone),
[-friction_threshold, friction_threshold],
[-torque_params.friction, torque_params.friction]
[-torque_params.friction * torque_params.latAccelFactor, torque_params.friction * torque_params.latAccelFactor]
)
return float(friction_interp)
@@ -59,6 +59,7 @@ FW_VERSIONS = {
b'476605SD2E',
b'476605SH1D',
b'476605SH7D',
b'476605SH7E',
b'476605SK2A',
],
(Ecu.eps, 0x742, None): [
@@ -0,0 +1,41 @@
from opendbc.can.packer import CANPacker
from opendbc.car import Bus
from opendbc.car.lateral import apply_std_steer_angle_limits
from opendbc.car.interfaces import CarControllerBase
from opendbc.car.psa.psacan import create_lka_steering
from opendbc.car.psa.values import CarControllerParams
class CarController(CarControllerBase):
def __init__(self, dbc_names, CP, CP_SP):
super().__init__(dbc_names, CP, CP_SP)
self.packer = CANPacker(dbc_names[Bus.main])
self.apply_angle_last = 0
self.status = 2
def update(self, CC, CC_SP, CS, now_nanos):
can_sends = []
actuators = CC.actuators
# lateral control
if self.frame % 5 == 0:
apply_angle = apply_std_steer_angle_limits(actuators.steeringAngleDeg, self.apply_angle_last, CS.out.vEgoRaw,
CS.out.steeringAngleDeg, CC.latActive, CarControllerParams.ANGLE_LIMITS)
# EPS disengages on steering override, activation sequence 2->3->4 to re-engage
# STATUS - 0: UNAVAILABLE, 1: UNSELECTED, 2: READY, 3: AUTHORIZED, 4: ACTIVE
if not CC.latActive:
self.status = 2
elif not CS.eps_active and not CS.out.steeringPressed:
self.status = 2 if self.status == 4 else self.status + 1
else:
self.status = 4
can_sends.append(create_lka_steering(self.packer, CC.latActive, apply_angle, self.status))
self.apply_angle_last = apply_angle
new_actuators = actuators.as_builder()
new_actuators.steeringAngleDeg = self.apply_angle_last
self.frame += 1
return new_actuators, can_sends
+74
View File
@@ -0,0 +1,74 @@
from opendbc.car import structs, Bus
from opendbc.can.parser import CANParser
from opendbc.car.common.conversions import Conversions as CV
from opendbc.car.psa.values import DBC, CarControllerParams
from opendbc.car.interfaces import CarStateBase
GearShifter = structs.CarState.GearShifter
TransmissionType = structs.CarParams.TransmissionType
class CarState(CarStateBase):
def update(self, can_parsers) -> structs.CarState:
cp = can_parsers[Bus.main]
cp_adas = can_parsers[Bus.adas]
cp_cam = can_parsers[Bus.cam]
ret = structs.CarState()
ret_sp = structs.CarStateSP()
# car speed
self.parse_wheel_speeds(ret,
cp.vl['Dyn4_FRE']['P263_VehV_VPsvValWhlFrtL'],
cp.vl['Dyn4_FRE']['P264_VehV_VPsvValWhlFrtR'],
cp.vl['Dyn4_FRE']['P265_VehV_VPsvValWhlBckL'],
cp.vl['Dyn4_FRE']['P266_VehV_VPsvValWhlBckR'],
)
ret.yawRate = cp_adas.vl['HS2_DYN_UCF_MDD_32D']['VITESSE_LACET_BRUTE'] * CV.DEG_TO_RAD
ret.standstill = bool(cp_adas.vl['HS2_DYN_UCF_MDD_32D']['VEHICLE_STANDSTILL'])
# gas
ret.gasPressed = cp.vl['Dyn_CMM']['P002_Com_rAPP'] > 0
# brake
ret.brakePressed = bool(cp_cam.vl['Dat_BSI']['P013_MainBrake'])
ret.parkingBrake = cp.vl['Dyn_EasyMove']['P337_Com_stPrkBrk'] == 1 # 0: disengaged, 1: engaged, 3: brake actuator moving
# steering wheel
ret.steeringAngleDeg = cp.vl['STEERING_ALT']['ANGLE'] # EPS
ret.steeringRateDeg = cp.vl['STEERING_ALT']['RATE'] * (2 * cp.vl['STEERING_ALT']['RATE_SIGN'] - 1) # convert [0,1] to [-1,1] EPS: rot. speed * rot. sign
ret.steeringTorque = cp.vl['STEERING']['DRIVER_TORQUE']
ret.steeringTorqueEps = cp.vl['IS_DAT_DIRA']['EPS_TORQUE']
ret.steeringPressed = self.update_steering_pressed(abs(ret.steeringTorque) > CarControllerParams.STEER_DRIVER_ALLOWANCE, 5)
self.eps_active = cp.vl['IS_DAT_DIRA']['EPS_STATE_LKA'] == 3 # 0: Unauthorized, 1: Authorized, 2: Available, 3: Active, 4: Defect
# cruise
ret.cruiseState.speed = cp_adas.vl['HS2_DAT_MDD_CMD_452']['SPEED_SETPOINT'] * CV.KPH_TO_MS # set to 255 when ACC is off, -2 kph offset from dash speed
ret.cruiseState.enabled = cp_adas.vl['HS2_DAT_MDD_CMD_452']['RVV_ACC_ACTIVATION_REQ'] == 1
ret.cruiseState.available = cp_adas.vl['HS2_DYN1_MDD_ETAT_2B6']['ACC_STATUS'] > 2
ret.cruiseState.nonAdaptive = cp_adas.vl['HS2_DAT_MDD_CMD_452']['LONGITUDINAL_REGULATION_TYPE'] != 3 # 0: None, 1: CC, 2: Limiter, 3: ACC
ret.cruiseState.standstill = bool(cp_adas.vl['HS2_DYN_UCF_MDD_32D']['VEHICLE_STANDSTILL'])
ret.accFaulted = cp_adas.vl['HS2_DYN_UCF_MDD_32D']['ACC_ETAT_DECEL_OR_ESP_STATUS'] == 3 # 0: Inhibited, 1: Waiting, 2: Active, 3: Fault
# gear
if bool(cp_cam.vl['Dat_BSI']['P103_Com_bRevGear']):
ret.gearShifter = GearShifter.reverse
else:
ret.gearShifter = GearShifter.drive
# blinkers
blinker = cp_cam.vl['HS2_DAT7_BSI_612']['CDE_CLG_ET_HDC']
ret.leftBlinker = blinker == 1
ret.rightBlinker = blinker == 2
# lock info
ret.doorOpen = any((cp_cam.vl['Dat_BSI']['DRIVER_DOOR'], cp_cam.vl['Dat_BSI']['PASSENGER_DOOR']))
ret.seatbeltUnlatched = cp_cam.vl['RESTRAINTS']['DRIVER_SEATBELT'] != 2
return ret, ret_sp
@staticmethod
def get_can_parsers(CP, CP_SP):
return {
Bus.main: CANParser(DBC[CP.carFingerprint][Bus.pt], [], 0),
Bus.adas: CANParser(DBC[CP.carFingerprint][Bus.pt], [], 1),
Bus.cam: CANParser(DBC[CP.carFingerprint][Bus.pt], [], 2),
}
@@ -0,0 +1,13 @@
""" AUTO-FORMATTED USING opendbc/car/debug/format_fingerprints.py, EDIT STRUCTURE THERE."""
from opendbc.car.structs import CarParams
from opendbc.car.psa.values import CAR
Ecu = CarParams.Ecu
FW_VERSIONS = {
CAR.PSA_PEUGEOT_208: {
(Ecu.fwdRadar, 0x6b6, None): [
b'212053276',
],
},
}
+30
View File
@@ -0,0 +1,30 @@
from opendbc.car import structs, get_safety_config
from opendbc.car.interfaces import CarInterfaceBase
from opendbc.car.psa.carcontroller import CarController
from opendbc.car.psa.carstate import CarState
TransmissionType = structs.CarParams.TransmissionType
class CarInterface(CarInterfaceBase):
CarState = CarState
CarController = CarController
@staticmethod
def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, is_release, docs) -> structs.CarParams:
ret.brand = 'psa'
ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.psa)]
ret.dashcamOnly = True
ret.steerActuatorDelay = 0.3
ret.steerLimitTimer = 0.1
ret.steerAtStandstill = True
ret.steerControlType = structs.CarParams.SteerControlType.angle
ret.radarUnavailable = True
ret.alphaLongitudinalAvailable = False
return ret
+18
View File
@@ -0,0 +1,18 @@
def psa_checksum(address: int, sig, d: bytearray) -> int:
chk_ini = {0x452: 0x4, 0x38D: 0x7, 0x42D: 0xC}.get(address, 0xB)
byte = sig.start_bit // 8
d[byte] &= 0x0F if sig.start_bit % 8 >= 4 else 0xF0
checksum = sum((b >> 4) + (b & 0xF) for b in d)
return (chk_ini - checksum) & 0xF
def create_lka_steering(packer, lat_active: bool, apply_angle: float, status: int):
values = {
'DRIVE': 1,
'STATUS': status,
'LXA_ACTIVATION': 1,
'TORQUE_FACTOR': lat_active * 100,
'SET_ANGLE': apply_angle,
}
return packer.make_can_msg('LANE_KEEP_ASSIST', 0, values)
+54
View File
@@ -0,0 +1,54 @@
from dataclasses import dataclass, field
from opendbc.car.structs import CarParams
from opendbc.car import Bus, CarSpecs, DbcDict, PlatformConfig, Platforms
from opendbc.car.lateral import AngleSteeringLimits
from opendbc.car.docs_definitions import CarDocs, CarHarness, CarParts
from opendbc.car.fw_query_definitions import FwQueryConfig, Request, StdQueries
Ecu = CarParams.Ecu
class CarControllerParams:
STEER_STEP = 1
ANGLE_LIMITS: AngleSteeringLimits = AngleSteeringLimits(
390, # deg
([0., 5., 25.], [2.5, 1.5, .2]),
([0., 5., 25.], [5., 2., .3]),
)
STEER_DRIVER_ALLOWANCE = 5 # Driver intervention threshold, 0.5 Nm
@dataclass
class PSACarDocs(CarDocs):
package: str = "Adaptive Cruise Control (ACC) & Lane Assist"
car_parts: CarParts = field(default_factory=CarParts.common([CarHarness.psa_a]))
@dataclass
class PSAPlatformConfig(PlatformConfig):
dbc_dict: DbcDict = field(default_factory=lambda: {
Bus.pt: 'psa_aee2010_r3',
})
class CAR(Platforms):
PSA_PEUGEOT_208 = PSAPlatformConfig(
[PSACarDocs("Peugeot 208 2019-25")],
CarSpecs(mass=1530, wheelbase=2.54, steerRatio=17.6),
)
# Placeholder, FW Query will be added in separate PR
FW_QUERY_CONFIG = FwQueryConfig(
requests=[
Request(
[StdQueries.TESTER_PRESENT_REQUEST, StdQueries.UDS_VERSION_REQUEST],
[StdQueries.TESTER_PRESENT_RESPONSE, StdQueries.UDS_VERSION_RESPONSE],
bus=0,
),
],
)
DBC = CAR.create_dbc_map()
@@ -6,8 +6,6 @@ from opendbc.car.interfaces import CarControllerBase
from opendbc.car.tesla.teslacan import TeslaCAN
from opendbc.car.tesla.values import CarControllerParams
from opendbc.car.vehicle_model import VehicleModel
from opendbc.sunnypilot.car.tesla.virtual_torque_blending import TorqueBlendingCarController
from opendbc.sunnypilot.car.tesla.mads import MadsCarController
@@ -18,11 +16,10 @@ def get_safety_CP():
return CarInterface.get_non_essential_params("TESLA_MODEL_Y")
class CarController(CarControllerBase, MadsCarController, TorqueBlendingCarController):
class CarController(CarControllerBase, MadsCarController):
def __init__(self, dbc_names, CP, CP_SP):
CarControllerBase.__init__(self, dbc_names, CP, CP_SP)
MadsCarController.__init__(self)
TorqueBlendingCarController.__init__(self)
self.apply_angle_last = 0
self.packer = CANPacker(dbc_names[Bus.party])
self.tesla_can = TeslaCAN(self.packer)
@@ -41,11 +38,8 @@ class CarController(CarControllerBase, MadsCarController, TorqueBlendingCarContr
lat_active = CC.latActive and CS.hands_on_level < 3
if self.frame % 2 == 0:
# Virtual torque blending
lat_active, apply_angle = self.update_torque_blending(CS, CC, lat_active, actuators.steeringAngleDeg)
# Angular rate limit based on speed
self.apply_angle_last = apply_steer_angle_limits_vm(apply_angle, self.apply_angle_last, CS.out.vEgoRaw, CS.out.steeringAngleDeg,
self.apply_angle_last = apply_steer_angle_limits_vm(actuators.steeringAngleDeg, self.apply_angle_last, CS.out.vEgoRaw, CS.out.steeringAngleDeg,
lat_active, CarControllerParams, self.VM)
can_sends.append(self.tesla_can.create_steering_control(self.apply_angle_last, lat_active, self.mads.control_type))
+2 -7
View File
@@ -5,15 +5,12 @@ from opendbc.car.common.conversions import Conversions as CV
from opendbc.car.interfaces import CarStateBase
from opendbc.car.tesla.values import DBC, CANBUS, GEAR_MAP, STEER_THRESHOLD, CAR
from opendbc.sunnypilot.car.tesla.virtual_torque_blending import TorqueBlendingCarState
ButtonType = structs.CarState.ButtonEvent.Type
class CarState(CarStateBase, TorqueBlendingCarState):
class CarState(CarStateBase):
def __init__(self, CP, CP_SP):
CarStateBase.__init__(self, CP, CP_SP)
TorqueBlendingCarState.__init__(self)
super().__init__(CP, CP_SP)
self.can_define = CANDefine(DBC[CP.carFingerprint][Bus.party])
self.shifter_values = self.can_define.dv["DI_systemStatus"]["DI_gear"]
@@ -121,8 +118,6 @@ class CarState(CarStateBase, TorqueBlendingCarState):
# Messages needed by carcontroller
self.das_control = copy.copy(cp_ap_party.vl["DAS_control"])
TorqueBlendingCarState.update_torque_blending(self, ret, eac_status, eac_error_code)
return ret, ret_sp
@staticmethod
@@ -14,6 +14,7 @@ FW_VERSIONS = {
b'TeMYG4_DCS_Update_0.0.0 (9),E4014.26.0',
b'TeMYG4_Legacy3Y_0.0.0 (2),E4015.02.0',
b'TeMYG4_Legacy3Y_0.0.0 (5),E4015.03.2',
b'TeMYG4_Legacy3Y_0.0.0 (5),E4L015.03.2',
b'TeMYG4_Main_0.0.0 (59),E4H014.29.0',
b'TeMYG4_Main_0.0.0 (65),E4H015.01.0',
b'TeMYG4_Main_0.0.0 (67),E4H015.02.1',
@@ -3,7 +3,6 @@ from opendbc.car.interfaces import CarInterfaceBase
from opendbc.car.tesla.carcontroller import CarController
from opendbc.car.tesla.carstate import CarState
from opendbc.car.tesla.values import TeslaSafetyFlags, CAR
from opendbc.sunnypilot.car.tesla.values import TeslaFlagsSP, TeslaSafetyFlagsSP
class CarInterface(CarInterfaceBase):
@@ -42,9 +41,4 @@ class CarInterface(CarInterfaceBase):
stock_cp.enableBsm = True
ret.flags |= TeslaFlagsSP.VIRTUAL_TORQUE_BLENDING.value
if ret.flags & TeslaFlagsSP.VIRTUAL_TORQUE_BLENDING:
ret.safetyParam |= TeslaSafetyFlagsSP.VIRTUAL_TORQUE_BLENDING
return ret
+20 -1
View File
@@ -15,6 +15,7 @@ from opendbc.car.toyota.values import CAR as TOYOTA
from opendbc.car.values import Platform
from opendbc.car.volkswagen.values import CAR as VOLKSWAGEN
from opendbc.car.body.values import CAR as COMMA
from opendbc.car.psa.values import CAR as PSA
# FIXME: add routes for these cars
non_tested_cars = [
@@ -25,6 +26,19 @@ non_tested_cars = [
HYUNDAI.GENESIS_G90,
VOLKSWAGEN.VOLKSWAGEN_CRAFTER_MK2, # need a route from an ACC-equipped Crafter
SUBARU.SUBARU_FORESTER_HYBRID,
# port extensions
HYUNDAI.KIA_CEED_PHEV_2022_NON_SCC,
HYUNDAI.HYUNDAI_KONA_EV_NON_SCC,
HYUNDAI.HYUNDAI_BAYON_1ST_GEN_NON_SCC,
HYUNDAI.HYUNDAI_ELANTRA_2022_NON_SCC,
HYUNDAI.HYUNDAI_KONA_NON_SCC,
HYUNDAI.KIA_FORTE_2019_NON_SCC,
HYUNDAI.KIA_FORTE_2021_NON_SCC,
HYUNDAI.KIA_SELTOS_2023_NON_SCC,
HYUNDAI.GENESIS_G70_2021_NON_SCC,
HONDA.HONDA_CLARITY,
TOYOTA.TOYOTA_WILDLANDER,
]
@@ -110,6 +124,9 @@ routes = [
CarTestRoute("b1c832ad56b6bc9d/00000010--debfcf5867", HONDA.HONDA_CIVIC_2022), # 2025 Civic Hatch Hybrid with new eCVT transmission
CarTestRoute("f9c43864cf057d05/2024-01-15--23-01-20", HONDA.HONDA_PILOT_4G), # TODO: Replace with a newer route
CarTestRoute("f39cf149898833ff/0000002b--54f3fae045", HONDA.HONDA_ACCORD_11G),
CarTestRoute("ad9840558640c31d/0000001a--d6cd4871c2", HONDA.ACURA_MDX_4G_MMR), # 2025 MDX
CarTestRoute("63568e3e2f56c8ad/0000000a--a254e90429", HONDA.HONDA_CRV_6G),
CarTestRoute("56b2cf1dacdcd033/00000048--3267801001", HONDA.HONDA_CITY_7G), # Brazilian model
CarTestRoute("87d7f06ade479c2e/2023-09-11--23-30-11", HYUNDAI.HYUNDAI_AZERA_6TH_GEN),
CarTestRoute("66189dd8ec7b50e6/2023-09-20--07-02-12", HYUNDAI.HYUNDAI_AZERA_HEV_6TH_GEN),
@@ -182,7 +199,7 @@ routes = [
CarTestRoute("db04d2c63990e3ba/2023-02-08--16-52-39", HYUNDAI.KIA_NIRO_HEV_2ND_GEN),
CarTestRoute("50a2212c41f65c7b/2021-05-24--16-22-06", HYUNDAI.KIA_FORTE),
CarTestRoute("192283cdbb7a58c2/2022-10-15--01-43-18", HYUNDAI.KIA_SPORTAGE_5TH_GEN),
CarTestRoute("09559f1fcaed4704/2023-11-16--02-24-57", HYUNDAI.KIA_SPORTAGE_5TH_GEN), # openpilot longitudinal
CarTestRoute("09559f1fcaed4704/2023-11-16--02-24-57", HYUNDAI.KIA_SPORTAGE_5TH_GEN, segment=0), # openpilot longitudinal
CarTestRoute("b3537035ffe6a7d6/2022-10-17--15-23-49", HYUNDAI.KIA_SPORTAGE_5TH_GEN), # hybrid
CarTestRoute("c5ac319aa9583f83/2021-06-01--18-18-31", HYUNDAI.HYUNDAI_ELANTRA),
CarTestRoute("734ef96182ddf940/2022-10-02--16-41-44", HYUNDAI.HYUNDAI_ELANTRA_GT_I30),
@@ -312,6 +329,8 @@ routes = [
CarTestRoute("f6d5b1a9d7a1c92e/2021-07-08--06-56-59", MAZDA.MAZDA_CX9_2021),
CarTestRoute("a4af1602d8e668ac/2022-02-03--12-17-07", MAZDA.MAZDA_CX5_2022),
CarTestRoute("6a7075a4fdd765ee/0000004e--1f612006dd", PSA.PSA_PEUGEOT_208),
CarTestRoute("bc095dc92e101734/000000db--ee9fe46e57", RIVIAN.RIVIAN_R1_GEN1),
CarTestRoute("7dc058789994da80/00000112--adb970f6a8", TESLA.TESLA_MODEL_3),
@@ -260,7 +260,7 @@ class TestFwFingerprintTiming:
print(f'get_vin {name} case, query time={self.total_time / self.N} seconds')
def test_fw_query_timing(self, subtests, mocker):
total_ref_time = {1: 7.3, 2: 7.9}
total_ref_time = {1: 7.4, 2: 8.0}
brand_ref_times = {
1: {
'gm': 1.0,
@@ -276,6 +276,7 @@ class TestFwFingerprintTiming:
'toyota': 0.7,
'volkswagen': 0.65,
'rivian': 0.3,
'psa': 0.1,
},
2: {
'ford': 1.6,
@@ -28,6 +28,7 @@ class TestLateralLimits:
def setup_class(cls):
CarInterface = interfaces[cls.car_model]
CP = CarInterface.get_non_essential_params(cls.car_model)
_ = CarInterface.get_non_essential_params_sp(CP, cls.car_model)
if cls.car_model == 'MOCK':
pytest.skip('Mock car')
@@ -7,6 +7,9 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"]
"NISSAN_LEAF" = [nan, 1.5, nan]
"NISSAN_ROGUE" = [nan, 1.5, nan]
# PSA angle based controllers
"PSA_PEUGEOT_208" = [nan, 2.0, nan]
# New subarus angle based controllers
"SUBARU_FORESTER_2022" = [nan, 3.0, nan]
"SUBARU_OUTBACK_2023" = [nan, 3.0, nan]
@@ -80,6 +83,10 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"]
"RIVIAN_R1_GEN1" = [2.8, 2.5, 0.07]
"HYUNDAI_NEXO_1ST_GEN" = [2.5, 2.5, 0.1]
"HONDA_ACCORD_11G" = [1.35, 1.35, 0.17]
"HONDA_PILOT_4G" = [1.25, 1.25, 0.21]
"ACURA_MDX_4G_MMR" = [1.25, 1.25, 0.15]
"HONDA_CRV_6G" = [1.3, 1.3, 0.2]
"HONDA_CITY_7G" = [1.2, 1.2, 0.23]
# Dashcam or fallback configured as ideal car
"MOCK" = [10.0, 10, 0.0]
@@ -87,4 +94,3 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"]
# Manually checked
"HONDA_CIVIC_2022" = [2.5, 1.2, 0.15]
"HONDA_HRV_3G" = [2.5, 1.2, 0.2]
"HONDA_PILOT_4G" = [1.0, 1.0, 0.2]
@@ -85,3 +85,16 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"]
"SUBARU_FORESTER_PREGLOBAL" = "SUBARU_IMPREZA"
"SUBARU_LEGACY_PREGLOBAL" = "SUBARU_IMPREZA"
"SUBARU_ASCENT" = "SUBARU_FORESTER"
# port extensions
"KIA_CEED_PHEV_2022_NON_SCC" = "HYUNDAI_SONATA"
"HYUNDAI_KONA_EV_NON_SCC" = "HYUNDAI_KONA_EV"
"KIA_FORTE_2019_NON_SCC" = "HYUNDAI_SONATA"
"KIA_FORTE_2021_NON_SCC" = "HYUNDAI_SONATA"
"KIA_SELTOS_2023_NON_SCC" = "HYUNDAI_SONATA"
"HYUNDAI_KONA_NON_SCC" = "HYUNDAI_KONA_EV"
"HYUNDAI_ELANTRA_2022_NON_SCC" = "HYUNDAI_ELANTRA_2021"
"GENESIS_G70_2021_NON_SCC" = "HYUNDAI_SONATA"
"HYUNDAI_BAYON_1ST_GEN_NON_SCC" = "HYUNDAI_SONATA"
"HONDA_CLARITY" = "HONDA_CIVIC"
"TOYOTA_WILDLANDER" = "TOYOTA_RAV4_TSS2"
@@ -2,6 +2,9 @@
from opendbc.car.structs import CarParams
from opendbc.car.toyota.values import CAR
from opendbc.sunnypilot.car.fw_versions_ext import merge_fw_versions
from opendbc.sunnypilot.car.toyota.fingerprints_ext import FW_VERSIONS_EXT
Ecu = CarParams.Ecu
FW_VERSIONS = {
@@ -500,6 +503,7 @@ FW_VERSIONS = {
b'\x02896630ZZ0000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00',
b'\x028966312K6000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00',
b'\x028966312L0000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00',
b'\x028966312L0100\x00\x00\x00\x008966A4703000\x00\x00\x00\x00',
b'\x028966312Q3000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00',
b'\x028966312Q3100\x00\x00\x00\x008966A4703000\x00\x00\x00\x00',
b'\x028966312Q4000\x00\x00\x00\x008966A4703000\x00\x00\x00\x00',
@@ -1187,6 +1191,7 @@ FW_VERSIONS = {
b'\x01F15264283200\x00\x00\x00\x00',
b'\x01F15264286100\x00\x00\x00\x00',
b'\x01F15264286200\x00\x00\x00\x00',
b'\x01F152642870\x00\x00\x00\x00\x00\x00',
],
(Ecu.eps, 0x7a1, None): [
b'\x028965B0R01500\x00\x00\x00\x008965B0R02500\x00\x00\x00\x00',
@@ -1837,18 +1842,25 @@ FW_VERSIONS = {
CAR.TOYOTA_YARIS: {
(Ecu.engine, 0x700, None): [
b'\x0189663K015300\x00\x00\x00\x00',
b'\x0189663K023000\x00\x00\x00\x00',
],
(Ecu.eps, 0x7a1, None): [
b'\x018965BK002100\x00\x00\x00\x00',
b'\x018965BK003200\x00\x00\x00\x00',
],
(Ecu.abs, 0x7b0, None): [
b'\x01F1526K005600\x00\x00\x00\x00',
b'\x01F1526K007500\x00\x00\x00\x00',
],
(Ecu.fwdRadar, 0x750, 0xf): [
b'\x018821F0D04100\x00\x00\x00\x00',
b'\x018821F0D05300\x00\x00\x00\x00',
],
(Ecu.fwdCamera, 0x750, 0x6d): [
b'\x028646F0W04100\x00\x00\x00\x008646G0W04100\x00\x00\x00\x00',
b'\x028646F5205200\x00\x00\x00\x008646G5202200\x00\x00\x00\x00',
],
},
}
FW_VERSIONS = merge_fw_versions(FW_VERSIONS, FW_VERSIONS_EXT)
@@ -157,6 +157,14 @@ class CarInterface(CarInterfaceBase):
if candidate in UNSUPPORTED_DSU_CAR:
ret.safetyParam |= ToyotaSafetyFlagsSP.UNSUPPORTED_DSU
if candidate in (CAR.TOYOTA_WILDLANDER, ):
stock_cp.lateralTuning.init('pid')
stock_cp.lateralTuning.pid.kiBP = [0.0]
stock_cp.lateralTuning.pid.kpBP = [0.0]
stock_cp.lateralTuning.pid.kpV = [0.6]
stock_cp.lateralTuning.pid.kiV = [0.1]
stock_cp.lateralTuning.pid.kf = 0.00007818594
return ret
@staticmethod
+7 -1
View File
@@ -290,7 +290,7 @@ class CAR(Platforms):
CarSpecs(mass=4372. * CV.LB_TO_KG, wheelbase=2.68, steerRatio=16.88, tireStiffnessFactor=0.5533),
)
TOYOTA_YARIS = ToyotaSecOCPlatformConfig(
[ToyotaCommunityCarDocs("Toyota Yaris (Non-US only) 2023", min_enable_speed=MIN_ACC_SPEED)],
[ToyotaCommunityCarDocs("Toyota Yaris (Non-US only) 2020, 2023", min_enable_speed=MIN_ACC_SPEED)],
CarSpecs(mass=1170, wheelbase=2.55, steerRatio=14.80, tireStiffnessFactor=0.5533),
flags=ToyotaFlags.RADAR_ACC,
)
@@ -396,6 +396,12 @@ class CAR(Platforms):
flags=ToyotaFlags.UNSUPPORTED_DSU,
)
# port extensions
TOYOTA_WILDLANDER = ToyotaSecOCPlatformConfig(
[ToyotaCarDocs("Toyota Wildlander PHEV 2021", min_enable_speed=MIN_ACC_SPEED)],
CarSpecs(mass=4155. * CV.LB_TO_KG, wheelbase=2.69, steerRatio=16.88, tireStiffnessFactor=0.5533),
)
# (addr, cars, bus, 1/freq*100, vl)
STATIC_DSU_MSGS = [
+2 -1
View File
@@ -8,13 +8,14 @@ from opendbc.car.hyundai.values import CAR as HYUNDAI
from opendbc.car.mazda.values import CAR as MAZDA
from opendbc.car.mock.values import CAR as MOCK
from opendbc.car.nissan.values import CAR as NISSAN
from opendbc.car.psa.values import CAR as PSA
from opendbc.car.rivian.values import CAR as RIVIAN
from opendbc.car.subaru.values import CAR as SUBARU
from opendbc.car.tesla.values import CAR as TESLA
from opendbc.car.toyota.values import CAR as TOYOTA
from opendbc.car.volkswagen.values import CAR as VOLKSWAGEN
Platform = BODY | CHRYSLER | FORD | GM | HONDA | HYUNDAI | MAZDA | MOCK | NISSAN | RIVIAN | SUBARU | TESLA | TOYOTA | VOLKSWAGEN
Platform = BODY | CHRYSLER | FORD | GM | HONDA | HYUNDAI | MAZDA | MOCK | NISSAN | PSA | RIVIAN | SUBARU | TESLA | TOYOTA | VOLKSWAGEN
BRANDS = get_args(Platform)
PLATFORMS: dict[str, Platform] = {str(platform): platform for brand in BRANDS for platform in brand}
@@ -441,6 +441,7 @@ FW_VERSIONS = {
(Ecu.engine, 0x7e0, None): [
b'\xf1\x8703N906026E \xf1\x892114',
b'\xf1\x8704E906023AH\xf1\x893379',
b'\xf1\x8704E906023BF\xf1\x893842',
b'\xf1\x8704E906023BM\xf1\x894522',
b'\xf1\x8704L906026DP\xf1\x891538',
b'\xf1\x8704L906026ET\xf1\x891990',
@@ -465,6 +466,7 @@ FW_VERSIONS = {
b'\xf1\x870D9300041A \xf1\x894801',
b'\xf1\x870D9300042H \xf1\x894901',
b'\xf1\x870DD300045T \xf1\x891601',
b'\xf1\x870DD300046B \xf1\x891601',
b'\xf1\x870DD300046H \xf1\x891601',
b'\xf1\x870DL300011H \xf1\x895201',
b'\xf1\x870GC300042H \xf1\x891404',
@@ -327,7 +327,7 @@ BO_ 416 SCC_CONTROL: 32 ADRV
SG_ VSetDis : 103|8@0+ (1,0) [0|255] "km/h or mph" XXX
SG_ NEW_SIGNAL_6 : 104|1@0+ (1,0) [0|1] "" XXX
SG_ SET_ME_2 : 105|3@1+ (1,0) [0|7] "" XXX
SG_ NEW_SIGNAL_3 : 109|2@0+ (1,0) [0|1] "" XXX
SG_ SCC_ObjSta : 108|3@1+ (1,0) [0|7] "" CLU,CGW
SG_ ZEROS_10 : 111|2@0+ (1,0) [0|3] "" XXX
SG_ ZEROS_6 : 119|16@0+ (1,0) [0|65535] "" XXX
SG_ aReqValue : 128|11@1+ (0.01,-10.23) [-10.23|10.24] "m/s^2" XXX
@@ -384,8 +384,8 @@ BO_ 437 FR_CMR_03_50ms: 32 FR_CMR
SG_ Info_RtLnDptSta : 99|2@1+ (1,0) [0|3] "" RR_C_RDR,CGW
SG_ Info_RtLnPosVal : 101|14@1- (0.0039625,0) [-32.4608|32.4568375] "m" RR_C_RDR,CGW
SG_ Info_RtLnHdingAnglVal : 115|10@1- (0.000976563,0) [-0.500000256|0.499023693] "rad" RR_C_RDR,CGW
SG_ Info_RtLnCvtrVal : 128|16@1- (1,0) [0|65535] "" CGW
SG_ Info_RtLnCrvtrDrvtvVal : 144|16@1- (1,0) [0|65535] "" CGW
SG_ Info_RtLnCvtrVal : 128|16@1- (1e-06,0) [-0.032768|0.032767] "1/m" CGW
SG_ Info_RtLnCrvtrDrvtvVal : 144|16@1- (4e-09,0) [-0.000131072|0.000131068] "1/m2" CGW
SG_ ID_CIPV : 192|8@1+ (1,0) [0|255] "" XXX
SG_ Relative_Velocity : 200|12@1+ (0.05,-100) [-100|104.75] "m/s" XXX
SG_ Longitudinal_Distance : 212|12@1+ (0.05,0) [0|204.75] "m" XXX
@@ -727,6 +727,7 @@ CM_ SG_ 437 Info_RtLnHdingAnglVal "This signal outputs the heading angle of righ
CM_ SG_ 437 Info_RtLnCvtrVal "This signal outputs the curvature of right line.";
CM_ SG_ 437 ID_CIPV "Valid Object = 1 to 255 - ID detected by front camera can vary depending on vehicle environment. - Additional logic would be required to apply this signal for ISG.";
CM_ SG_ 437 Relative_Velocity "+ : Preceding, - : Oncoming - Velocity detected by front camera can vary depending on vehicle environment. - Additional logic would be required to apply this signal for ISG. - Confirmaiton by Autonomous Driving Engineering Team is required to use ID_C";
CM_ SG_ 416 SCC_ObjSta "state of in-path object and information of controllable state.";
CM_ SG_ 480 NEW_SIGNAL_5 "todo: figure out why always set to 1";
CM_ BO_ 506 "Sent by the camera containing speed limit information. ISLW stands for Intelligent Speed Limit Warning, and ISLA is Intelligent Speed Limit Assist. it also contains road sign information.";
CM_ SG_ 506 FR_CMR_Crc2Val "The data area for CRC calculation is based on the data length (DLC) of the message DB.The CRC shall be calculated over the entire data block (excluding the CRC bytes) including the user data, alive counter and Data ID - CRC Polynomial (0x1021) , In";
@@ -904,6 +905,7 @@ VAL_ 354 FAULT_ESS 0 "HIDDEN" 1 "CHECK_EMERGENCY_STOPPING_FUNCTION" 2 "EMERGENCY
VAL_ 362 BLINKER_CONTROL 1 "hazards" 2 "hazards button backlight" 3 "left blinkers" 4 "right blinkers";
VAL_ 373 ACCEnable 0 "SCC ready" 1 "SCC temp fault" 2 "SCC permanent fault" 3 "SCC permanent fault, communication issue";
VAL_ 416 ACCMode 0 "off" 1 "enabled" 2 "driver_override" 3 "off_maybe_fault" 4 "cancelled";
VAL_ 416 SCC_ObjSta 0 "No in-path object detected" 1 "In-path object detected (uncontrollable)" 2 "In-path object detected (controllable:longitudinal)" 3 "Reserved" 4 "Reserved" 5 "Reserved" 6 "Reserved" 7 "Reserved";
VAL_ 426 CRUISE_BUTTONS 0 "none" 1 "res_accel" 2 "set_decel" 3 "gap_distance" 4 "pause_resume";
VAL_ 437 Info_LftLnQualSta 0 "Very Low Quality" 1 "Low Quality" 2 "High Quality" 3 "Very High Quality" 4 "Reserved" 5 "Reserved" 6 "Reserved" 7 "Error indicator";
VAL_ 437 Info_LftLnDptSta 0 "No Left Line Departure" 1 "Left Line Departure" 2 "Reserved" 3 "Error Indicator";
@@ -564,7 +564,7 @@ BO_ 416 SCC_CONTROL: 32 ADRV
SG_ VSetDis : 103|8@0+ (1,0) [0|255] "km/h or mph" XXX
SG_ NEW_SIGNAL_6 : 104|1@0+ (1,0) [0|1] "" XXX
SG_ SET_ME_2 : 105|3@1+ (1,0) [0|7] "" XXX
SG_ NEW_SIGNAL_3 : 109|2@0+ (1,0) [0|1] "" XXX
SG_ SCC_ObjSta : 108|3@1+ (1,0) [0|7] "" CLU,CGW
SG_ ZEROS_10 : 111|2@0+ (1,0) [0|3] "" XXX
SG_ ZEROS_6 : 119|16@0+ (1,0) [0|65535] "" XXX
SG_ aReqValue : 128|11@1+ (0.01,-10.23) [-10.23|10.24] "m/s^2" XXX
@@ -621,8 +621,8 @@ BO_ 437 FR_CMR_03_50ms: 32 FR_CMR
SG_ Info_RtLnDptSta : 99|2@1+ (1,0) [0|3] "" RR_C_RDR,CGW
SG_ Info_RtLnPosVal : 101|14@1- (0.0039625,0) [-32.4608|32.4568375] "m" RR_C_RDR,CGW
SG_ Info_RtLnHdingAnglVal : 115|10@1- (0.000976563,0) [-0.500000256|0.499023693] "rad" RR_C_RDR,CGW
SG_ Info_RtLnCvtrVal : 128|16@1- (1,0) [0|65535] "" CGW
SG_ Info_RtLnCrvtrDrvtvVal : 144|16@1- (1,0) [0|65535] "" CGW
SG_ Info_RtLnCvtrVal : 128|16@1- (1e-06,0) [-0.032768|0.032767] "1/m" CGW
SG_ Info_RtLnCrvtrDrvtvVal : 144|16@1- (4e-09,0) [-0.000131072|0.000131068] "1/m2" CGW
SG_ ID_CIPV : 192|8@1+ (1,0) [0|255] "" XXX
SG_ Relative_Velocity : 200|12@1+ (0.05,-100) [-100|104.75] "m/s" XXX
SG_ Longitudinal_Distance : 212|12@1+ (0.05,0) [0|204.75] "m" XXX
@@ -964,6 +964,7 @@ CM_ SG_ 437 Info_RtLnHdingAnglVal "This signal outputs the heading angle of righ
CM_ SG_ 437 Info_RtLnCvtrVal "This signal outputs the curvature of right line.";
CM_ SG_ 437 ID_CIPV "Valid Object = 1 to 255 - ID detected by front camera can vary depending on vehicle environment. - Additional logic would be required to apply this signal for ISG.";
CM_ SG_ 437 Relative_Velocity "+ : Preceding, - : Oncoming - Velocity detected by front camera can vary depending on vehicle environment. - Additional logic would be required to apply this signal for ISG. - Confirmaiton by Autonomous Driving Engineering Team is required to use ID_C";
CM_ SG_ 416 SCC_ObjSta "state of in-path object and information of controllable state.";
CM_ SG_ 480 NEW_SIGNAL_5 "todo: figure out why always set to 1";
CM_ BO_ 506 "Sent by the camera containing speed limit information. ISLW stands for Intelligent Speed Limit Warning, and ISLA is Intelligent Speed Limit Assist. it also contains road sign information.";
CM_ SG_ 506 FR_CMR_Crc2Val "The data area for CRC calculation is based on the data length (DLC) of the message DB.The CRC shall be calculated over the entire data block (excluding the CRC bytes) including the user data, alive counter and Data ID - CRC Polynomial (0x1021) , In";
@@ -1141,6 +1142,7 @@ VAL_ 354 FAULT_ESS 0 "HIDDEN" 1 "CHECK_EMERGENCY_STOPPING_FUNCTION" 2 "EMERGENCY
VAL_ 362 BLINKER_CONTROL 1 "hazards" 2 "hazards button backlight" 3 "left blinkers" 4 "right blinkers";
VAL_ 373 ACCEnable 0 "SCC ready" 1 "SCC temp fault" 2 "SCC permanent fault" 3 "SCC permanent fault, communication issue";
VAL_ 416 ACCMode 0 "off" 1 "enabled" 2 "driver_override" 3 "off_maybe_fault" 4 "cancelled";
VAL_ 416 SCC_ObjSta 0 "No in-path object detected" 1 "In-path object detected (uncontrollable)" 2 "In-path object detected (controllable:longitudinal)" 3 "Reserved" 4 "Reserved" 5 "Reserved" 6 "Reserved" 7 "Reserved";
VAL_ 426 CRUISE_BUTTONS 0 "none" 1 "res_accel" 2 "set_decel" 3 "gap_distance" 4 "pause_resume";
VAL_ 437 Info_LftLnQualSta 0 "Very Low Quality" 1 "Low Quality" 2 "High Quality" 3 "Very High Quality" 4 "Reserved" 5 "Reserved" 6 "Reserved" 7 "Error indicator";
VAL_ 437 Info_LftLnDptSta 0 "No Left Line Departure" 1 "Left Line Departure" 2 "Reserved" 3 "Error Indicator";
@@ -1480,6 +1480,7 @@ BO_ 905 SCC14: 8 SCC
SG_ JerkLowerLimit : 19|7@1+ (0.1,0) [0|12.7] "m/s^3" ESC
SG_ ACCMode : 32|3@1+ (1,0) [0|7] "" CLU,HUD,LDWS_LKAS,ESC
SG_ ObjGap : 56|8@1+ (1,0) [0|255] "" CLU,HUD,ESC
SG_ ObjDistStat : 42|2@1+ (1,0) [0|3] "" XXX
BO_ 1157 LFAHDA_MFC: 4 XXX
SG_ HDA_USM : 0|2@1+ (1,0) [0|3] "" XXX
@@ -1500,6 +1501,7 @@ BO_ 913 BCM_PO_11: 8 Vector__XXX
BO_ 1426 LABEL11: 8 XXX
SG_ CC_React : 34|1@1+ (1,0) [0|1] "" XXX
SG_ CC_ACT : 35|1@1+ (1,0) [0|1] "" XXX
BO_ 910 WHL_SPD12_FS: 5 iBAU
SG_ CRC : 0|8@1+ (1,0) [0|0] "" Vector__XXX
@@ -1536,6 +1538,10 @@ BO_ 881 E_EMS11: 8 XXX
BO_ 1355 EV_PC6: 8 CGW
SG_ CF_Vcu_SbwWarnMsg : 16|3@1+ (1,0) [0|7] "" Vector__XXX
BO_ 1429 E_CRUISE_CONTROL: 8 XXX
SG_ CRUISE_LAMP_M : 50|1@0+ (1,0) [0|1] "" XXX
SG_ CRUISE_LAMP_S : 51|1@0+ (1,0) [0|1] "" XXX
BO_ 1430 EV_PC2: 8 CGW
SG_ CR_Ldc_ActVol_LS_V : 32|8@1+ (0.1,0) [0|0] "V" Vector__XXX
@@ -1680,6 +1686,7 @@ VAL_ 871 CF_Lvr_IsgState 0 "enabled" 1 "activated" 2 "unknown" 3 "disabled";
VAL_ 871 CF_Lvr_Gear 12 "T" 5 "D" 8 "S" 6 "N" 7 "R" 0 "P";
VAL_ 882 Elect_Gear_Shifter 4 "S" 5 "D" 8 "S" 6 "N" 7 "R" 0 "P";
VAL_ 905 ACCMode 0 "off" 1 "enabled" 2 "driver_override" 3 "off_maybe_fault" 4 "cancelled";
VAL_ 905 ObjDistStat 0 "no_object" 1 "receding" 2 "approaching";
VAL_ 909 CF_VSM_Warn 2 "FCW" 3 "AEB";
VAL_ 916 ACCEnable 0 "SCC ready" 1 "SCC temp fault" 2 "SCC permanent fault" 3 "SCC permanent fault, communication issue";
VAL_ 1056 SCCInfoDisplay 0 "No Message" 2 "Cruise Control" 3 "Lost Lead" 4 "Standstill";
+3 -2
View File
@@ -162,8 +162,8 @@ BO_ 773 STEERING_ALT: 7 XXX
SG_ ANGLE : 7|16@0- (0.1,0) [-3276.8|3276.7] "degrees" XXX
SG_ RATE : 23|8@0+ (1,0) [0|255] "" XXX
SG_ RATE_SIGN : 31|1@0+ (1,0) [0|1] "" XXX
SG_ COUNTER : 35|4@0+ (1,0) [0|255] "" XXX
SG_ CHECKSUM : 39|4@0+ (1,0) [0|15] "" XXX
SG_ 0_COUNTER : 35|4@0+ (1,0) [0|255] "" XXX
SG_ 0_CHECKSUM : 39|4@0+ (1,0) [0|15] "" XXX
SG_ RATE_ALT : 47|8@0+ (1,0) [0|255] "" XXX
BO_ 781 Dyn4_FRE: 8 CDS___Fahrdynamikregelung
@@ -833,6 +833,7 @@ CM_ SG_ 758 CHECKSUM_TRANSM_DYN_ACC2 "CHK_INI = 0x7";
CM_ SG_ 758 PROCESS_COUNTER_4B_ACC2 "This counter increments from 0 to 15 at each activation of the calculation process.";
CM_ SG_ 773 ANGLE "-565 to 560, seems like estimate and not init";
CM_ SG_ 773 RATE_SIGN "1=moving clockwise, 0=moving anticlockwise";
CM_ SG_ 773 0_CHECKSUM "TODO: find checksum";
CM_ BO_ 840 "ID 348: Engine Dynamic Frame 2 (Period time 20 ms)";
CM_ SG_ 840 P165_FlFCD_stWtLvlSensDebVal "P165: Water in fuel indication (1 = water in fuel detected / 0 = no water in fuel)";
CM_ SG_ 840 P152_Gearbx_stGear "P152: Gear detected by ratio vehicule speed to engine speed";
+14
View File
@@ -32,6 +32,7 @@ static bool honda_fwd_brake = false;
static bool honda_bosch_long = false;
static bool honda_bosch_radarless = false;
static bool honda_bosch_canfd = false;
static bool honda_clarity = false;
typedef enum {HONDA_NIDEC, HONDA_BOSCH} HondaHw;
static HondaHw honda_hw = HONDA_NIDEC;
@@ -157,6 +158,10 @@ static void honda_rx_hook(const CANPacket_t *msg) {
bool honda_stock_aeb = GET_BIT(msg, 29U);
int honda_stock_brake = (msg->data[0] << 2) | (msg->data[1] >> 6);
if (honda_clarity) {
honda_stock_brake = (msg->data[6] << 2) | (msg->data[7] >> 6);
}
// Forward AEB when stock braking is higher than openpilot braking
// only stop forwarding when AEB event is over
if (!honda_stock_aeb) {
@@ -208,6 +213,11 @@ static bool honda_tx_hook(const CANPacket_t *msg) {
// BRAKE: safety check (nidec)
if ((msg->addr == 0x1FAU) && (msg->bus == bus_pt)) {
honda_brake = (msg->data[0] << 2) + ((msg->data[1] >> 6) & 0x3U);
if (honda_clarity) {
honda_brake = (msg->data[6] << 2) + ((msg->data[7] >> 6) & 0x3U);
}
if (longitudinal_brake_checks(honda_brake, HONDA_NIDEC_LONG_LIMITS)) {
tx = false;
}
@@ -289,6 +299,8 @@ static safety_config honda_nidec_init(uint16_t param) {
const uint16_t HONDA_PARAM_NIDEC_ALT = 4;
const uint16_t HONDA_PARAM_SP_CLARITY = 1;
honda_hw = HONDA_NIDEC;
honda_brake = 0;
honda_brake_switch_prev = false;
@@ -302,6 +314,8 @@ static safety_config honda_nidec_init(uint16_t param) {
bool enable_nidec_alt = GET_FLAG(param, HONDA_PARAM_NIDEC_ALT);
honda_clarity = GET_FLAG(current_safety_param_sp, HONDA_PARAM_SP_CLARITY);
if (enable_nidec_alt) {
// For Nidecs with main on signal on an alternate msg (missing 0x326)
static RxCheck honda_nidec_alt_rx_checks[] = {
@@ -58,6 +58,12 @@ const LongitudinalLimits HYUNDAI_LONG_LIMITS = {
#define HYUNDAI_LDA_BUTTON_ADDR_CHECK \
{.msg = {{0x391, 0, 8, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true, .frequency = 50U}, { 0 }, { 0 }}}, \
#define HYUNDAI_NON_SCC_HEV_ADDR_CHECK \
{.msg = {{0x595U, 0, 8, 10U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}}, \
#define HYUNDAI_NON_SCC_EV_ADDR_CHECK \
{.msg = {{0x592U, 0, 8, 10U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}}, \
static const CanMsg HYUNDAI_TX_MSGS[] = {
HYUNDAI_COMMON_TX_MSGS(0)
};
@@ -191,6 +197,24 @@ static void hyundai_rx_hook(const CANPacket_t *msg) {
if (msg->addr == 0x394U) {
brake_pressed = ((msg->data[5] >> 5U) & 0x3U) == 0x2U;
}
if (msg->addr == 0x592U) {
acc_main_on = GET_BIT(msg, 34U);
bool cruise_engaged = GET_BIT(msg, 35U);
hyundai_common_cruise_state_check(cruise_engaged);
}
if (msg->addr == 0x595U) {
acc_main_on = GET_BIT(msg, 50U);
bool cruise_engaged = GET_BIT(msg, 51U);
hyundai_common_cruise_state_check(cruise_engaged);
}
if ((msg->addr == 0x260U) && hyundai_non_scc && !hyundai_ev_gas_signal && !hyundai_hybrid_gas_signal) {
acc_main_on = GET_BIT(msg, 25U);
bool cruise_engaged = GET_BIT(msg, 26U);
hyundai_common_cruise_state_check(cruise_engaged);
}
}
hyundai_common_reset_acc_main_on_mismatches();
@@ -380,6 +404,37 @@ static safety_config hyundai_init(uint16_t param) {
HYUNDAI_LDA_BUTTON_ADDR_CHECK
};
static RxCheck hyundai_non_scc_addr_checks[] = {
HYUNDAI_COMMON_RX_CHECKS(false)
};
static RxCheck hyundai_non_scc_lda_button_addr_checks[] = {
HYUNDAI_COMMON_RX_CHECKS(false)
HYUNDAI_LDA_BUTTON_ADDR_CHECK
};
static RxCheck hyundai_hev_non_scc_addr_checks[] = {
HYUNDAI_COMMON_RX_CHECKS(false)
HYUNDAI_NON_SCC_HEV_ADDR_CHECK
};
static RxCheck hyundai_hev_non_scc_lda_button_addr_checks[] = {
HYUNDAI_COMMON_RX_CHECKS(false)
HYUNDAI_NON_SCC_HEV_ADDR_CHECK
HYUNDAI_LDA_BUTTON_ADDR_CHECK
};
static RxCheck hyundai_ev_non_scc_addr_checks[] = {
HYUNDAI_COMMON_RX_CHECKS(false)
HYUNDAI_NON_SCC_EV_ADDR_CHECK
};
static RxCheck hyundai_ev_non_scc_lda_button_addr_checks[] = {
HYUNDAI_COMMON_RX_CHECKS(false)
HYUNDAI_NON_SCC_EV_ADDR_CHECK
HYUNDAI_LDA_BUTTON_ADDR_CHECK
};
SET_TX_MSGS(HYUNDAI_TX_MSGS, ret);
if (hyundai_fcev_gas_signal) {
if (hyundai_has_lda_button) {
@@ -387,6 +442,26 @@ static safety_config hyundai_init(uint16_t param) {
} else {
SET_RX_CHECKS(hyundai_fcev_rx_checks, ret);
}
} else if (hyundai_non_scc) {
if (hyundai_ev_gas_signal) {
if (hyundai_has_lda_button) {
SET_RX_CHECKS(hyundai_ev_non_scc_lda_button_addr_checks, ret);
} else {
SET_RX_CHECKS(hyundai_ev_non_scc_addr_checks, ret);
}
} else if (hyundai_hybrid_gas_signal) {
if (hyundai_has_lda_button) {
SET_RX_CHECKS(hyundai_hev_non_scc_lda_button_addr_checks, ret);
} else {
SET_RX_CHECKS(hyundai_hev_non_scc_addr_checks, ret);
}
} else {
if (hyundai_has_lda_button) {
SET_RX_CHECKS(hyundai_non_scc_lda_button_addr_checks, ret);
} else {
SET_RX_CHECKS(hyundai_non_scc_addr_checks, ret);
}
}
} else {
if (hyundai_has_lda_button) {
SET_RX_CHECKS(hyundai_lda_button_rx_checks, ret);
@@ -21,6 +21,7 @@ enum {
HYUNDAI_PARAM_SP_ESCC = 1,
HYUNDAI_PARAM_SP_LONGITUDINAL_MAIN_CRUISE_TOGGLEABLE = 2,
HYUNDAI_PARAM_SP_HAS_LDA_BUTTON = 4,
HYUNDAI_PARAM_SP_NON_SCC = 8,
};
// common state
@@ -58,6 +59,9 @@ bool hyundai_longitudinal_main_cruise_toggleable = false;
extern bool hyundai_has_lda_button;
bool hyundai_has_lda_button = false;
extern bool hyundai_non_scc;
bool hyundai_non_scc = false;
static uint8_t hyundai_last_button_interaction; // button messages since the user pressed an enable button
static bool main_button_prev;
@@ -85,6 +89,7 @@ void hyundai_common_init(uint16_t param) {
hyundai_escc = GET_FLAG(current_safety_param_sp, HYUNDAI_PARAM_SP_ESCC);
hyundai_longitudinal_main_cruise_toggleable = GET_FLAG(current_safety_param_sp, HYUNDAI_PARAM_SP_LONGITUDINAL_MAIN_CRUISE_TOGGLEABLE);
hyundai_has_lda_button = GET_FLAG(current_safety_param_sp, HYUNDAI_PARAM_SP_HAS_LDA_BUTTON);
hyundai_non_scc = GET_FLAG(current_safety_param_sp, HYUNDAI_PARAM_SP_NON_SCC);
hyundai_last_button_interaction = HYUNDAI_PREV_BUTTON_SAMPLES;
+151
View File
@@ -0,0 +1,151 @@
#pragma once
#include "opendbc/safety/safety_declarations.h"
#define PSA_STEERING 757U // RX from XXX, driver torque
#define PSA_STEERING_ALT 773U // RX from EPS, steering angle
#define PSA_DYN_CMM 520U // RX from CMM, gas pedal
#define PSA_HS2_DYN_ABR_38D 909U // RX from UC_FREIN, speed
#define PSA_HS2_DAT_MDD_CMD_452 1106U // RX from BSI, cruise state
#define PSA_DAT_BSI 1042U // RX from BSI, brake
#define PSA_LANE_KEEP_ASSIST 1010U // TX from OP, EPS
// CAN bus
#define PSA_MAIN_BUS 0U
#define PSA_ADAS_BUS 1U
#define PSA_CAM_BUS 2U
static uint8_t psa_get_counter(const CANPacket_t *msg) {
uint8_t cnt = 0;
if (msg->addr == PSA_HS2_DAT_MDD_CMD_452) {
cnt = (msg->data[3] >> 4) & 0xFU;
} else if (msg->addr == PSA_HS2_DYN_ABR_38D) {
cnt = (msg->data[5] >> 4) & 0xFU;
} else {
}
return cnt;
}
static uint32_t psa_get_checksum(const CANPacket_t *msg) {
uint8_t chksum = 0;
if (msg->addr == PSA_HS2_DAT_MDD_CMD_452) {
chksum = msg->data[5] & 0xFU;
} else if (msg->addr == PSA_HS2_DYN_ABR_38D) {
chksum = msg->data[5] & 0xFU;
} else {
}
return chksum;
}
static uint8_t _psa_compute_checksum(const CANPacket_t *msg, uint8_t chk_ini, int chk_pos) {
int len = GET_LEN(msg);
uint8_t sum = 0;
for (int i = 0; i < len; i++) {
uint8_t b = msg->data[i];
if (i == chk_pos) {
// set checksum in low nibble to 0
b &= 0xF0U;
}
sum += (b >> 4) + (b & 0xFU);
}
return (chk_ini - sum) & 0xFU;
}
static uint32_t psa_compute_checksum(const CANPacket_t *msg) {
uint8_t chk = 0;
if (msg->addr == PSA_HS2_DAT_MDD_CMD_452) {
chk = _psa_compute_checksum(msg, 0x4, 5);
} else if (msg->addr == PSA_HS2_DYN_ABR_38D) {
chk = _psa_compute_checksum(msg, 0x7, 5);
} else {
}
return chk;
}
static void psa_rx_hook(const CANPacket_t *msg) {
if (msg->bus == PSA_MAIN_BUS) {
if (msg->addr == PSA_DYN_CMM) {
gas_pressed = msg->data[3] > 0U; // P002_Com_rAPP
}
if (msg->addr == PSA_STEERING_ALT) {
int angle_meas_new = to_signed((msg->data[0] << 8) | msg->data[1], 16); // ANGLE
update_sample(&angle_meas, angle_meas_new);
}
if (msg->addr == PSA_HS2_DYN_ABR_38D) {
int speed = (msg->data[0] << 8) | msg->data[1];
vehicle_moving = speed > 0;
UPDATE_VEHICLE_SPEED(speed * 0.01 * KPH_TO_MS); // VITESSE_VEHICULE_ROUES
}
}
if (msg->bus == PSA_ADAS_BUS) {
if (msg->addr == PSA_HS2_DAT_MDD_CMD_452) {
pcm_cruise_check((msg->data[2U] >> 7U) & 1U); // RVV_ACC_ACTIVATION_REQ
}
}
if (msg->bus == PSA_CAM_BUS) {
if (msg->addr == PSA_DAT_BSI) {
brake_pressed = (msg->data[0U] >> 5U) & 1U; // P013_MainBrake
}
}
}
static bool psa_tx_hook(const CANPacket_t *msg) {
bool tx = true;
static const AngleSteeringLimits PSA_STEERING_LIMITS = {
.max_angle = 3900,
.angle_deg_to_can = 10,
.angle_rate_up_lookup = {
{0., 5., 25.},
{2.5, 1.5, .2},
},
.angle_rate_down_lookup = {
{0., 5., 25.},
{5., 2., .3},
},
};
// Safety check for LKA
if (msg->addr == PSA_LANE_KEEP_ASSIST) {
// SET_ANGLE
int desired_angle = to_signed((msg->data[6] << 6) | ((msg->data[7] & 0xFCU) >> 2), 14);
// TORQUE_FACTOR
bool lka_active = ((msg->data[5] & 0xFEU) >> 1) == 100U;
if (steer_angle_cmd_checks(desired_angle, lka_active, PSA_STEERING_LIMITS)) {
tx = false;
}
}
return tx;
}
static safety_config psa_init(uint16_t param) {
UNUSED(param);
static const CanMsg PSA_TX_MSGS[] = {
{PSA_LANE_KEEP_ASSIST, PSA_MAIN_BUS, 8, .check_relay = true}, // EPS steering
};
static RxCheck psa_rx_checks[] = {
{.msg = {{PSA_HS2_DAT_MDD_CMD_452, PSA_ADAS_BUS, 6, 20U, .max_counter = 15U, .ignore_quality_flag = true}, { 0 }, { 0 }}}, // cruise state
{.msg = {{PSA_HS2_DYN_ABR_38D, PSA_MAIN_BUS, 8, 25U, .max_counter = 15U, .ignore_quality_flag = true}, { 0 }, { 0 }}}, // speed
{.msg = {{PSA_STEERING_ALT, PSA_MAIN_BUS, 7, 100U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}}, // steering angle
{.msg = {{PSA_STEERING, PSA_MAIN_BUS, 7, 100U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}}, // driver torque
{.msg = {{PSA_DYN_CMM, PSA_MAIN_BUS, 8, 100U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}}, // gas pedal
{.msg = {{PSA_DAT_BSI, PSA_CAM_BUS, 8, 20U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}}, // brake
};
return BUILD_SAFETY_CFG(psa_rx_checks, PSA_TX_MSGS);
}
const safety_hooks psa_hooks = {
.init = psa_init,
.rx = psa_rx_hook,
.tx = psa_tx_hook,
.get_counter = psa_get_counter,
.get_checksum = psa_get_checksum,
.compute_checksum = psa_compute_checksum,
};
+1 -10
View File
@@ -2,12 +2,6 @@
#include "opendbc/safety/safety_declarations.h"
enum {
TESLA_PARAM_SP_VIRTUAL_TORQUE_BLENDING = 1,
};
static bool tesla_virtual_torque_blending;
static bool tesla_longitudinal = false;
static bool tesla_stock_aeb = false;
@@ -111,8 +105,7 @@ static void tesla_rx_hook(const CANPacket_t *msg) {
const int eac_error_code = msg->data[2] >> 4; // EPAS3S_eacErrorCode
// Disengage on normal user override, or if high angle rate fault from user overriding extremely quickly
const bool hands_on_level_check = (!tesla_virtual_torque_blending && (hands_on_level >= 3));
steering_disengage = hands_on_level_check || ((eac_status == 0) && (eac_error_code == 9));
steering_disengage = (hands_on_level >= 3) || ((eac_status == 0) && (eac_error_code == 9));
}
// Vehicle speed (DI_speed)
@@ -340,8 +333,6 @@ static safety_config tesla_init(uint16_t param) {
tesla_longitudinal = GET_FLAG(param, TESLA_FLAG_LONGITUDINAL_CONTROL);
#endif
tesla_virtual_torque_blending = GET_FLAG(current_safety_param_sp, TESLA_PARAM_SP_VIRTUAL_TORQUE_BLENDING);
tesla_stock_aeb = false;
tesla_stock_lkas = false;
tesla_stock_lkas_prev = false;
+2
View File
@@ -24,6 +24,7 @@
#include "opendbc/safety/modes/volkswagen_pq.h"
#include "opendbc/safety/modes/elm327.h"
#include "opendbc/safety/modes/body.h"
#include "opendbc/safety/modes/psa.h"
// CAN-FD only safety modes
#ifdef CANFD
@@ -415,6 +416,7 @@ int set_safety_hooks(uint16_t mode, uint16_t param) {
{SAFETY_HYUNDAI_CANFD, &hyundai_canfd_hooks},
#endif
#ifdef ALLOW_DEBUG
{SAFETY_PSA, &psa_hooks},
{SAFETY_SUBARU_PREGLOBAL, &subaru_preglobal_hooks},
{SAFETY_VOLKSWAGEN_PQ, &volkswagen_pq_hooks},
{SAFETY_ALLOUTPUT, &alloutput_hooks},
@@ -30,6 +30,7 @@
#define SAFETY_FAW 26U
#define SAFETY_BODY 27U
#define SAFETY_HYUNDAI_CANFD 28U
#define SAFETY_PSA 31U
#define SAFETY_RIVIAN 33U
#define SAFETY_VOLKSWAGEN_MEB 34U
@@ -341,3 +342,4 @@ extern const safety_hooks toyota_hooks;
extern const safety_hooks volkswagen_mqb_hooks;
extern const safety_hooks volkswagen_pq_hooks;
extern const safety_hooks rivian_hooks;
extern const safety_hooks psa_hooks;
@@ -266,7 +266,6 @@ class TorqueSteeringSafetyTestBase(PandaSafetyTestBase, abc.ABC):
max_torque = self._get_max_torque(speed)
for enabled in [0, 1]:
for t in range(int(-max_torque * 1.5), int(max_torque * 1.5)):
self._mads_states_cleanup()
self.safety.set_controls_allowed(enabled)
self._set_prev_torque(t)
if abs(t) > max_torque or (not enabled and abs(t) > 0):
@@ -543,7 +542,6 @@ class MotorTorqueSteeringSafetyTest(TorqueSteeringSafetyTestBase, abc.ABC):
max_torque = self._get_max_torque(speed)
for controls_allowed in [True, False]:
for torque in np.arange(-max_torque - 1000, max_torque + 1000, self.MAX_RATE_UP):
self._mads_states_cleanup()
self.safety.set_controls_allowed(controls_allowed)
self.safety.set_rt_torque_last(torque)
self.safety.set_torque_meas(torque, torque)
@@ -767,7 +765,6 @@ class AngleSteeringSafetyTest(VehicleSpeedSafetyTest):
self._reset_angle_measurement(angle_meas)
for angle_cmd in np.arange(-90, 91, 10):
self._mads_states_cleanup()
self._set_prev_desired_angle(angle_cmd)
# controls_allowed is checked if actuation bit is 1, else the angle must be close to meas (inactive)
@@ -155,7 +155,6 @@ class HyundaiLongitudinalBase(common.LongitudinalAccelSafetyTest):
self.safety.set_safety_hooks(default_safety_mode, default_safety_param)
# Test initial state
self._mads_states_cleanup()
self.safety.set_mads_params(enable_mads, False, False)
self.assertFalse(self.safety.get_acc_main_on())
@@ -173,7 +172,6 @@ class HyundaiLongitudinalBase(common.LongitudinalAccelSafetyTest):
for _ in range(10):
self._rx(self._main_cruise_button_msg(1))
self.assertFalse(self.safety.get_controls_allowed_lat())
self._mads_states_cleanup()
self.safety.set_current_safety_param_sp(default_safety_param_sp)
def test_acc_main_sync_mismatches_reset(self):
@@ -188,7 +186,6 @@ class HyundaiLongitudinalBase(common.LongitudinalAccelSafetyTest):
self.safety.set_current_safety_param_sp(default_safety_param_sp | main_cruise_toggleable_flag)
self.safety.set_safety_hooks(default_safety_mode, default_safety_param)
self._mads_states_cleanup()
self.safety.set_mads_params(enable_mads, False, False)
# Initial state
@@ -208,7 +205,6 @@ class HyundaiLongitudinalBase(common.LongitudinalAccelSafetyTest):
self._tx(self._tx_acc_state_msg(False)) # acc_main_on_tx = False
self.assertFalse(self.safety.get_acc_main_on())
self.assertEqual(0, self.safety.get_acc_main_on_mismatches())
self._mads_states_cleanup()
self.safety.set_current_safety_param_sp(default_safety_param_sp)
def test_acc_main_sync_mismatch_counter(self):
@@ -223,7 +219,6 @@ class HyundaiLongitudinalBase(common.LongitudinalAccelSafetyTest):
self.safety.set_current_safety_param_sp(default_safety_param_sp | main_cruise_toggleable_flag)
self.safety.set_safety_hooks(default_safety_mode, default_safety_param)
self._mads_states_cleanup()
self.safety.set_mads_params(enable_mads, False, False)
self.safety.set_controls_allowed_lat(True)
@@ -251,7 +246,6 @@ class HyundaiLongitudinalBase(common.LongitudinalAccelSafetyTest):
# Counter should reset after disengagement
self._tx(self._tx_acc_state_msg(False))
self.assertEqual(0, self.safety.get_acc_main_on_mismatches())
self._mads_states_cleanup()
self.safety.set_current_safety_param_sp(default_safety_param_sp)
def test_acc_main_sync_mismatch_recovery(self):
@@ -266,7 +260,6 @@ class HyundaiLongitudinalBase(common.LongitudinalAccelSafetyTest):
self.safety.set_current_safety_param_sp(default_safety_param_sp | main_cruise_toggleable_flag)
self.safety.set_safety_hooks(default_safety_mode, default_safety_param)
self._mads_states_cleanup()
self.safety.set_mads_params(enable_mads, False, False)
# Create initial mismatch
@@ -278,7 +271,6 @@ class HyundaiLongitudinalBase(common.LongitudinalAccelSafetyTest):
# Sync states
self._tx(self._tx_acc_state_msg(True)) # Match acc_main_on_tx to acc_main_on
self.assertEqual(0, self.safety.get_acc_main_on_mismatches())
self._mads_states_cleanup()
self.safety.set_current_safety_param_sp(default_safety_param_sp)
def test_tester_present_allowed(self, ecu_disable: bool = True):
+226 -314
View File
@@ -1,3 +1,4 @@
from parameterized import parameterized
import abc
import unittest
@@ -15,7 +16,7 @@ class MadsSafetyTestBase(unittest.TestCase):
def _acc_state_msg(self, enabled):
raise NotImplementedError
def _mads_states_cleanup(self):
def teardown_method(self, method):
self.safety.set_mads_button_press(-1)
self.safety.set_controls_allowed_lat(False)
self.safety.set_controls_requested_lat(False)
@@ -29,7 +30,6 @@ class MadsSafetyTestBase(unittest.TestCase):
# If boolean is True, the heartbeat is engaged and should remain engaged, otherwise it should disengage.
with self.subTest(heartbeat_engaged=boolean, should_remain_engaged=boolean):
# Setup initial conditions
self._mads_states_cleanup()
self.safety.set_mads_params(True, False, False) # Enable MADS
self.safety.set_controls_allowed_lat(True)
self.assertTrue(self.safety.get_controls_allowed_lat())
@@ -53,257 +53,200 @@ class MadsSafetyTestBase(unittest.TestCase):
except NotImplementedError as err:
raise unittest.SkipTest("Skipping test because MADS button is not supported") from err
try:
for enable_mads in (True, False):
with self.subTest("enable_mads", mads_enabled=enable_mads):
self._mads_states_cleanup()
self.safety.set_mads_params(enable_mads, False, False)
self.assertEqual(enable_mads, self.safety.get_enable_mads())
for enable_mads in (True, False):
with self.subTest("enable_mads", mads_enabled=enable_mads):
self.safety.set_mads_params(enable_mads, False, False)
self.assertEqual(enable_mads, self.safety.get_enable_mads())
self._rx(self._lkas_button_msg(True))
self._rx(self._speed_msg(0))
self._rx(self._lkas_button_msg(False))
self._rx(self._speed_msg(0))
self.assertEqual(enable_mads, self.safety.get_controls_allowed_lat())
finally:
self._mads_states_cleanup()
self._rx(self._lkas_button_msg(True))
self._rx(self._lkas_button_msg(False))
self.assertEqual(enable_mads, self.safety.get_controls_allowed_lat())
def test_enable_control_allowed_with_manual_acc_main_on_state(self):
try:
self._acc_state_msg(False)
except NotImplementedError as err:
self._mads_states_cleanup()
raise unittest.SkipTest("Skipping test because _acc_state_msg is not implemented for this car") from err
try:
for enable_mads in (True, False):
with self.subTest("enable_mads", mads_enabled=enable_mads):
self._mads_states_cleanup()
self.safety.set_mads_params(enable_mads, False, False)
self._rx(self._acc_state_msg(True))
self._rx(self._speed_msg(0))
self.assertEqual(enable_mads, self.safety.get_controls_allowed_lat())
finally:
self._mads_states_cleanup()
for enable_mads in (True, False):
with self.subTest("enable_mads", mads_enabled=enable_mads):
self.safety.set_mads_params(enable_mads, False, False)
self._rx(self._acc_state_msg(True))
self.assertEqual(enable_mads, self.safety.get_controls_allowed_lat())
def test_enable_control_allowed_with_manual_mads_button_state(self):
try:
for enable_mads in (True, False):
with self.subTest("enable_mads", mads_enabled=enable_mads):
for mads_button_press in (-1, 0, 1):
with self.subTest("mads_button_press", button_state=mads_button_press):
self._mads_states_cleanup()
self.safety.set_mads_params(enable_mads, False, False)
for enable_mads in (True, False):
with self.subTest("enable_mads", mads_enabled=enable_mads):
for mads_button_press in (-1, 0, 1):
with self.subTest("mads_button_press", button_state=mads_button_press):
self.safety.set_mads_params(enable_mads, False, False)
self.safety.set_mads_button_press(mads_button_press)
self._rx(self._speed_msg(0))
self.assertEqual(enable_mads and mads_button_press == 1, self.safety.get_controls_allowed_lat())
finally:
self._mads_states_cleanup()
self.safety.set_mads_button_press(mads_button_press)
self._rx(self._speed_msg(0))
self.assertEqual(enable_mads and mads_button_press == 1, self.safety.get_controls_allowed_lat())
def test_enable_control_allowed_from_acc_main_on(self):
"""Test that lateral controls are allowed when ACC main is enabled and disabled when ACC main is disabled"""
try:
for enable_mads in (True, False):
with self.subTest("enable_mads", mads_enabled=enable_mads):
for acc_main_on in (True, False):
with self.subTest("initial_acc_main", initial_acc_main=acc_main_on):
self._mads_states_cleanup()
self.safety.set_mads_params(enable_mads, False, False)
for enable_mads in (True, False):
with self.subTest("enable_mads", mads_enabled=enable_mads):
for acc_main_on in (True, False):
with self.subTest("initial_acc_main", initial_acc_main=acc_main_on):
self.safety.set_mads_params(enable_mads, False, False)
# Set initial state
self.safety.set_acc_main_on(acc_main_on)
self._rx(self._speed_msg(0))
expected_lat = enable_mads and acc_main_on
self.assertEqual(expected_lat, self.safety.get_controls_allowed_lat(),
f"Expected lat: [{expected_lat}] when acc_main_on goes to [{acc_main_on}]")
# Set initial state
self.safety.set_acc_main_on(acc_main_on)
self._rx(self._speed_msg(0))
expected_lat = enable_mads and acc_main_on
self.assertEqual(expected_lat, self.safety.get_controls_allowed_lat(),
f"Expected lat: [{expected_lat}] when acc_main_on goes to [{acc_main_on}]")
# Test transition to opposite state
self.safety.set_acc_main_on(not acc_main_on)
self._rx(self._speed_msg(0))
expected_lat = enable_mads and not acc_main_on
self.assertEqual(expected_lat, self.safety.get_controls_allowed_lat(),
f"Expected lat: [{expected_lat}] when acc_main_on goes from [{acc_main_on}] to [{not acc_main_on}]")
# Test transition to opposite state
self.safety.set_acc_main_on(not acc_main_on)
self._rx(self._speed_msg(0))
expected_lat = enable_mads and not acc_main_on
self.assertEqual(expected_lat, self.safety.get_controls_allowed_lat(),
f"Expected lat: [{expected_lat}] when acc_main_on goes from [{acc_main_on}] to [{not acc_main_on}]")
# Test transition back to initial state
self.safety.set_acc_main_on(acc_main_on)
self._rx(self._speed_msg(0))
expected_lat = enable_mads and acc_main_on
self.assertEqual(expected_lat, self.safety.get_controls_allowed_lat(),
f"Expected lat: [{expected_lat}] when acc_main_on goes from [{not acc_main_on}] to [{acc_main_on}]")
finally:
self._mads_states_cleanup()
# Test transition back to initial state
self.safety.set_acc_main_on(acc_main_on)
self._rx(self._speed_msg(0))
expected_lat = enable_mads and acc_main_on
self.assertEqual(expected_lat, self.safety.get_controls_allowed_lat(),
f"Expected lat: [{expected_lat}] when acc_main_on goes from [{not acc_main_on}] to [{acc_main_on}]")
def test_mads_with_acc_main_on(self):
try:
for enable_mads in (True, False):
with self.subTest("enable_mads", mads_enabled=enable_mads):
self._mads_states_cleanup()
self.safety.set_mads_params(enable_mads, False, False)
for enable_mads in (True, False):
with self.subTest("enable_mads", mads_enabled=enable_mads):
self.safety.set_mads_params(enable_mads, False, False)
self.safety.set_acc_main_on(True)
self._rx(self._speed_msg(0))
self.assertEqual(enable_mads, self.safety.get_controls_allowed_lat())
self.safety.set_acc_main_on(True)
self._rx(self._speed_msg(0))
self.assertEqual(enable_mads, self.safety.get_controls_allowed_lat())
self.safety.set_acc_main_on(False)
self._rx(self._speed_msg(0))
self.assertFalse(self.safety.get_controls_allowed_lat())
finally:
self._mads_states_cleanup()
def test_pause_lateral_on_brake_setup(self):
try:
for enable_mads in (True, False):
with self.subTest("enable_mads", enable_mads=enable_mads):
for pause_lateral_on_brake in (True, False):
with self.subTest("pause_lateral_on_brake", pause_lateral_on_brake=pause_lateral_on_brake):
self._mads_states_cleanup()
self.safety.set_mads_params(enable_mads, False, pause_lateral_on_brake)
self.assertEqual(enable_mads and pause_lateral_on_brake, self.safety.get_pause_lateral_on_brake())
finally:
self._mads_states_cleanup()
def test_pause_lateral_on_brake(self):
try:
self._mads_states_cleanup()
self.safety.set_mads_params(True, False, True)
self._rx(self._user_brake_msg(False))
self.safety.set_controls_requested_lat(True)
self.safety.set_controls_allowed_lat(True)
self._rx(self._user_brake_msg(True))
# Test we pause lateral
self.assertFalse(self.safety.get_controls_allowed_lat())
# Make sure we can re-gain lateral actuation
self._rx(self._user_brake_msg(False))
self.assertTrue(self.safety.get_controls_allowed_lat())
finally:
self._mads_states_cleanup()
def test_no_pause_lateral_on_brake(self):
try:
self._mads_states_cleanup()
self.safety.set_mads_params(True, False, False)
self._rx(self._user_brake_msg(False))
self.safety.set_controls_requested_lat(True)
self.safety.set_controls_allowed_lat(True)
self._rx(self._user_brake_msg(True))
self.assertTrue(self.safety.get_controls_allowed_lat())
finally:
self._mads_states_cleanup()
def test_engage_with_brake_pressed(self):
try:
self._lkas_button_msg(False)
except NotImplementedError as err:
raise unittest.SkipTest("Skipping test because MADS button is not supported") from err
try:
for enable_mads in (True, False):
with self.subTest("enable_mads", enable_mads=enable_mads):
for pause_lateral_on_brake in (True, False):
with self.subTest("pause_lateral_on_brake", pause_lateral_on_brake=pause_lateral_on_brake):
with self.subTest("mads_button"):
self._mads_states_cleanup()
self.safety.set_mads_params(enable_mads, False, pause_lateral_on_brake)
# Brake press rising edge
self._rx(self._user_brake_msg(True))
self._rx(self._lkas_button_msg(True))
self._rx(self._speed_msg(0))
self.assertEqual(enable_mads and not pause_lateral_on_brake, self.safety.get_controls_allowed_lat())
# Continuous braking after the first frame of brake press rising edge
self.assertEqual(enable_mads and not pause_lateral_on_brake, self.safety.get_controls_allowed_lat())
for _ in range(400):
self._rx(self._user_brake_msg(True))
self.assertEqual(enable_mads and not pause_lateral_on_brake, self.safety.get_controls_allowed_lat())
with self.subTest("acc_main_on"):
self._mads_states_cleanup()
self.safety.set_mads_params(enable_mads, False, pause_lateral_on_brake)
# Brake press rising edge
self._rx(self._user_brake_msg(True))
self.safety.set_acc_main_on(True)
self._rx(self._speed_msg(0))
self.assertEqual(enable_mads and not pause_lateral_on_brake, self.safety.get_controls_allowed_lat())
# Continuous braking after the first frame of brake press rising edge
self.assertEqual(enable_mads and not pause_lateral_on_brake, self.safety.get_controls_allowed_lat())
for _ in range(400):
self._rx(self._user_brake_msg(True))
self.assertEqual(enable_mads and not pause_lateral_on_brake, self.safety.get_controls_allowed_lat())
finally:
self._mads_states_cleanup()
def test_pause_lateral_on_brake_with_pressed_and_released(self):
try:
for enable_mads in (True, False):
with self.subTest("enable_mads", enable_mads=enable_mads):
for pause_lateral_on_brake in (True, False):
with self.subTest("pause_lateral_on_brake", pause_lateral_on_brake=pause_lateral_on_brake):
self._mads_states_cleanup()
self.safety.set_mads_params(enable_mads, False, pause_lateral_on_brake)
# Set controls_allowed_lat rising edge
self.safety.set_controls_requested_lat(True)
self._rx(self._speed_msg(0))
self.assertEqual(enable_mads, self.safety.get_controls_allowed_lat())
# User brake press, validate controls_allowed_lat is false
self._rx(self._user_brake_msg(True))
self._rx(self._speed_msg(0))
self.assertEqual(enable_mads and not pause_lateral_on_brake, self.safety.get_controls_allowed_lat())
# User brake release, validate controls_allowed_lat is true
self._rx(self._user_brake_msg(False))
self._rx(self._speed_msg(0))
self.assertEqual(enable_mads, self.safety.get_controls_allowed_lat())
finally:
self._mads_states_cleanup()
def test_pause_lateral_on_brake_persistent_control_allowed_off(self):
try:
self._mads_states_cleanup()
self.safety.set_mads_params(True, False, True)
self.safety.set_controls_requested_lat(True)
# Vehicle moving, validate controls_allowed_lat is true
for _ in range(10):
self._rx(self._speed_msg(10))
self.assertTrue(self.safety.get_controls_allowed_lat())
# User braked, vehicle slowed down in 10 frames, then stopped for 10 frames
# Validate controls_allowed_lat is false
self._rx(self._user_brake_msg(True))
for _ in range(10):
self._rx(self._speed_msg(5))
self.assertFalse(self.safety.get_controls_allowed_lat())
for _ in range(10):
self.safety.set_acc_main_on(False)
self._rx(self._speed_msg(0))
self.assertFalse(self.safety.get_controls_allowed_lat())
finally:
self._mads_states_cleanup()
def test_pause_lateral_on_brake_setup(self):
for enable_mads in (True, False):
with self.subTest("enable_mads", enable_mads=enable_mads):
for pause_lateral_on_brake in (True, False):
with self.subTest("pause_lateral_on_brake", pause_lateral_on_brake=pause_lateral_on_brake):
self.safety.set_mads_params(enable_mads, False, pause_lateral_on_brake)
self.assertEqual(enable_mads and pause_lateral_on_brake, self.safety.get_pause_lateral_on_brake())
def test_pause_lateral_on_brake(self):
self.safety.set_mads_params(True, False, True)
self._rx(self._user_brake_msg(False))
self.safety.set_controls_requested_lat(True)
self.safety.set_controls_allowed_lat(True)
self._rx(self._user_brake_msg(True))
# Test we pause lateral
self.assertFalse(self.safety.get_controls_allowed_lat())
# Make sure we can re-gain lateral actuation
self._rx(self._user_brake_msg(False))
self.assertTrue(self.safety.get_controls_allowed_lat())
def test_no_pause_lateral_on_brake(self):
self.safety.set_mads_params(True, False, False)
self._rx(self._user_brake_msg(False))
self.safety.set_controls_requested_lat(True)
self.safety.set_controls_allowed_lat(True)
self._rx(self._user_brake_msg(True))
self.assertTrue(self.safety.get_controls_allowed_lat())
@parameterized.expand(["mads_button", "acc_main_on"])
def test_engage_with_brake_pressed(self, engage_method):
if engage_method == "mads_button":
try:
self._lkas_button_msg(False)
except NotImplementedError as err:
raise unittest.SkipTest("Skipping test because MADS button is not supported") from err
elif engage_method == "acc_main_on":
try:
self._acc_state_msg(False)
except NotImplementedError as err:
raise unittest.SkipTest("Skipping test because ACC main is not supported") from err
for enable_mads in (True, False):
with self.subTest("enable_mads", enable_mads=enable_mads):
for pause_lateral_on_brake in (True, False):
with self.subTest("pause_lateral_on_brake", pause_lateral_on_brake=pause_lateral_on_brake):
with self.subTest(engage_method):
self.safety.set_mads_params(enable_mads, False, pause_lateral_on_brake)
# Brake press rising edge
self._rx(self._user_brake_msg(True))
if engage_method == "mads_button":
self._rx(self._lkas_button_msg(True))
elif engage_method == "acc_main_on":
self.safety.set_acc_main_on(True)
self.assertTrue(self.safety.get_acc_main_on())
else:
raise ValueError(f"Invalid engage_method: {engage_method}")
self._rx(self._speed_msg(0))
self.assertEqual(enable_mads and not pause_lateral_on_brake, self.safety.get_controls_allowed_lat())
# Continuous braking after the first frame of brake press rising edge
for _ in range(400):
self.assertEqual(enable_mads and not pause_lateral_on_brake, self.safety.get_controls_allowed_lat())
def test_pause_lateral_on_brake_with_pressed_and_released(self):
for enable_mads in (True, False):
with self.subTest("enable_mads", enable_mads=enable_mads):
for pause_lateral_on_brake in (True, False):
with self.subTest("pause_lateral_on_brake", pause_lateral_on_brake=pause_lateral_on_brake):
self.safety.set_mads_params(enable_mads, False, pause_lateral_on_brake)
# Set controls_allowed_lat rising edge
self.safety.set_controls_requested_lat(True)
self._rx(self._speed_msg(0))
self.assertEqual(enable_mads, self.safety.get_controls_allowed_lat())
# User brake press, validate controls_allowed_lat is false
self._rx(self._user_brake_msg(True))
self.assertEqual(enable_mads and not pause_lateral_on_brake, self.safety.get_controls_allowed_lat())
# User brake release, validate controls_allowed_lat is true
self._rx(self._user_brake_msg(False))
self.assertEqual(enable_mads, self.safety.get_controls_allowed_lat())
def test_pause_lateral_on_brake_persistent_control_allowed_off(self):
self.safety.set_mads_params(True, False, True)
self.safety.set_controls_requested_lat(True)
# Vehicle moving, validate controls_allowed_lat is true
for _ in range(10):
self._rx(self._speed_msg(10))
self.assertTrue(self.safety.get_controls_allowed_lat())
# User braked, vehicle slowed down in 10 frames, then stopped for 10 frames
# Validate controls_allowed_lat is false
self._rx(self._user_brake_msg(True))
for _ in range(10):
self._rx(self._speed_msg(5))
self.assertFalse(self.safety.get_controls_allowed_lat())
for _ in range(10):
self._rx(self._speed_msg(0))
self.assertFalse(self.safety.get_controls_allowed_lat())
def test_enable_lateral_control_with_controls_allowed_rising_edge(self):
try:
for enable_mads in (True, False):
with self.subTest("enable_mads", enable_mads=enable_mads):
self._mads_states_cleanup()
self.safety.set_mads_params(enable_mads, False, False)
for enable_mads in (True, False):
with self.subTest("enable_mads", enable_mads=enable_mads):
self.safety.set_mads_params(enable_mads, False, False)
self.safety.set_controls_allowed(False)
self._rx(self._speed_msg(0))
self.safety.set_controls_allowed(True)
self._rx(self._speed_msg(0))
self.assertTrue(self.safety.get_controls_allowed())
finally:
self._mads_states_cleanup()
self.safety.set_controls_allowed(False)
self._rx(self._speed_msg(0))
self.safety.set_controls_allowed(True)
self._rx(self._speed_msg(0))
self.assertTrue(self.safety.get_controls_allowed())
def test_enable_control_allowed_with_mads_button_and_disable_with_main_cruise(self):
"""Tests main cruise and MADS button state transitions.
@@ -324,27 +267,19 @@ class MadsSafetyTestBase(unittest.TestCase):
except NotImplementedError as err:
raise unittest.SkipTest("Skipping test because _acc_state_msg is not implemented for this car") from err
try:
for enable_mads in (True, False):
with self.subTest("enable_mads", enable_mads=enable_mads):
self._mads_states_cleanup()
self.safety.set_mads_params(enable_mads, False, False)
for enable_mads in (True, False):
with self.subTest("enable_mads", enable_mads=enable_mads):
self.safety.set_mads_params(enable_mads, False, False)
self._rx(self._lkas_button_msg(True))
self._rx(self._speed_msg(0))
self._rx(self._lkas_button_msg(False))
self._rx(self._speed_msg(0))
self.assertEqual(enable_mads, self.safety.get_controls_allowed_lat())
self._rx(self._lkas_button_msg(True))
self._rx(self._lkas_button_msg(False))
self.assertEqual(enable_mads, self.safety.get_controls_allowed_lat())
self._rx(self._acc_state_msg(True))
self._rx(self._speed_msg(0))
self.assertEqual(enable_mads, self.safety.get_controls_allowed_lat())
self._rx(self._acc_state_msg(True))
self.assertEqual(enable_mads, self.safety.get_controls_allowed_lat())
self._rx(self._acc_state_msg(False))
self._rx(self._speed_msg(0))
self.assertFalse(self.safety.get_controls_allowed_lat())
finally:
self._mads_states_cleanup()
self._rx(self._acc_state_msg(False))
self.assertFalse(self.safety.get_controls_allowed_lat())
def test_brake_disengage_with_control_request(self):
"""Tests behavior when controls are requested while brake is engaged
@@ -356,30 +291,24 @@ class MadsSafetyTestBase(unittest.TestCase):
4. Release brake
5. Verify controls become allowed
"""
try:
self._mads_states_cleanup()
self.safety.set_mads_params(True, False, True) # enable MADS with pause lateral on brake
self.safety.set_mads_params(True, False, True) # enable MADS with pause lateral on brake
# Initial state
self.safety.set_controls_allowed_lat(True)
self._rx(self._speed_msg(0))
self.assertTrue(self.safety.get_controls_allowed_lat())
# Initial state
self.safety.set_controls_allowed_lat(True)
self._rx(self._speed_msg(0))
self.assertTrue(self.safety.get_controls_allowed_lat())
# Brake press disengages lateral
self._rx(self._user_brake_msg(True))
self.assertFalse(self.safety.get_controls_allowed_lat())
# Brake press disengages lateral
self._rx(self._user_brake_msg(True))
self.assertFalse(self.safety.get_controls_allowed_lat())
# Request controls while braking
self.safety.set_controls_requested_lat(True)
self.assertFalse(self.safety.get_controls_allowed_lat())
# Request controls while braking
self.safety.set_controls_requested_lat(True)
self.assertFalse(self.safety.get_controls_allowed_lat())
# Release brake - should enable since controls were requested
self._rx(self._user_brake_msg(False))
self._rx(self._speed_msg(0))
self.assertTrue(self.safety.get_controls_allowed_lat())
finally:
self._mads_states_cleanup()
# Release brake - should enable since controls were requested
self._rx(self._user_brake_msg(False))
self.assertTrue(self.safety.get_controls_allowed_lat())
def test_brake_disengage_with_acc_main_off(self):
"""Tests behavior when ACC main is turned off while brake is engaged
@@ -391,66 +320,49 @@ class MadsSafetyTestBase(unittest.TestCase):
4. Release brake
5. Verify controls remain disengaged
"""
try:
self._mads_states_cleanup()
self.safety.set_mads_params(True, False, True) # enable MADS with pause lateral on brake
self.safety.set_mads_params(True, False, True) # enable MADS with pause lateral on brake
# Initial state - enable with ACC main
self.safety.set_acc_main_on(True)
self._rx(self._speed_msg(0))
self.assertTrue(self.safety.get_controls_allowed_lat())
# Initial state - enable with ACC main
self.safety.set_acc_main_on(True)
self._rx(self._speed_msg(0))
self.assertTrue(self.safety.get_controls_allowed_lat())
# Brake press disengages lateral
self._rx(self._user_brake_msg(True))
self.assertFalse(self.safety.get_controls_allowed_lat())
# Brake press disengages lateral
self._rx(self._user_brake_msg(True))
self.assertFalse(self.safety.get_controls_allowed_lat())
# Turn ACC main off while braking
self.safety.set_acc_main_on(False)
self._rx(self._speed_msg(0))
self.assertFalse(self.safety.get_controls_allowed_lat())
# Turn ACC main off while braking
self.safety.set_acc_main_on(False)
self._rx(self._speed_msg(0))
self.assertFalse(self.safety.get_controls_allowed_lat())
# Release brake - should remain disabled since ACC main is off
self._rx(self._user_brake_msg(False))
self._rx(self._speed_msg(0))
self.assertFalse(self.safety.get_controls_allowed_lat())
finally:
self._mads_states_cleanup()
# Release brake - should remain disabled since ACC main is off
self._rx(self._user_brake_msg(False))
self.assertFalse(self.safety.get_controls_allowed_lat())
def test_steering_disengage_with_control_request(self):
try:
self._mads_states_cleanup()
self.safety.set_mads_params(True, False, False)
self.safety.set_mads_params(True, False, False)
self.safety.set_controls_allowed_lat(True)
self._rx(self._speed_msg(0))
self.assertTrue(self.safety.get_controls_allowed_lat())
self.safety.set_steering_disengage(True)
self._rx(self._speed_msg(0))
self.assertFalse(self.safety.get_controls_allowed_lat())
def test_disengage_on_brake(self):
for disengage_on_brake in (True, False):
self.safety.set_mads_params(True, disengage_on_brake, False)
self.safety.set_controls_allowed_lat(True)
self._rx(self._speed_msg(0))
self.assertTrue(self.safety.get_controls_allowed_lat())
self.safety.set_steering_disengage(True)
self._rx(self._speed_msg(0))
self.assertFalse(self.safety.get_controls_allowed_lat())
self._rx(self._user_brake_msg(True))
self.assertEqual(not disengage_on_brake, self.safety.get_controls_allowed_lat())
finally:
self._mads_states_cleanup()
def test_disengage_on_brake(self):
try:
for disengage_on_brake in (True, False):
self._mads_states_cleanup()
self.safety.set_mads_params(True, disengage_on_brake, False)
self.safety.set_controls_allowed_lat(True)
self._rx(self._speed_msg(0))
self.assertTrue(self.safety.get_controls_allowed_lat())
self._rx(self._user_brake_msg(True))
self._rx(self._speed_msg(0))
self.assertEqual(not disengage_on_brake, self.safety.get_controls_allowed_lat())
self._rx(self._user_brake_msg(False))
self._rx(self._speed_msg(0))
self.assertEqual(not disengage_on_brake, self.safety.get_controls_allowed_lat())
finally:
self._mads_states_cleanup()
self._rx(self._user_brake_msg(False))
self.assertEqual(not disengage_on_brake, self.safety.get_controls_allowed_lat())
# TODO-SP: controls_allowed and controls_allowed_lat check for steering safety tests
@@ -4,6 +4,7 @@ set -e
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null && pwd)"
cd $DIR
source $DIR/../../../setup.sh
$DIR/install_mull.sh
GIT_REF="${GIT_REF:-origin/master}"
@@ -11,6 +12,6 @@ GIT_ROOT=$(git rev-parse --show-toplevel)
MULL_OPS="mutators: [cxx_increment, cxx_decrement, cxx_comparison, cxx_boundary, cxx_bitwise_assignment, cxx_bitwise, cxx_arithmetic_assignment, cxx_arithmetic, cxx_remove_negation]"
echo -e "$MULL_OPS" > $GIT_ROOT/mull.yml
scons --mutation -j$(nproc) -D
echo -e "timeout: 100000\ngitDiffRef: $GIT_REF\ngitProjectRoot: $GIT_ROOT" >> $GIT_ROOT/mull.yml
echo -e "timeout: 1000000\ngitDiffRef: $GIT_REF\ngitProjectRoot: $GIT_ROOT" >> $GIT_ROOT/mull.yml
mull-runner-17 --ld-search-path /lib/x86_64-linux-gnu/ ./libsafety/libsafety.so -test-program=pytest -- -n8 --ignore-glob=misra/*
@@ -66,8 +66,8 @@ def replay_drive(msgs, safety_mode, param, alternative_experience, param_sp):
if msg.which() == 'sendcan':
for canmsg in msg.sendcan:
msg = package_can_msg(canmsg)
sent = safety.safety_tx_hook(msg)
_msg = package_can_msg(canmsg)
sent = safety.safety_tx_hook(_msg)
# mismatched
if safety.get_controls_allowed() and not safety.get_controls_allowed_lat():
@@ -112,8 +112,8 @@ def replay_drive(msgs, safety_mode, param, alternative_experience, param_sp):
# ignore msgs we sent
for canmsg in filter(lambda m: m.src < 128, msg.can):
safety.safety_fwd_hook(canmsg.src, canmsg.address)
msg = package_can_msg(canmsg)
recv = safety.safety_rx_hook(msg)
_msg = package_can_msg(canmsg)
recv = safety.safety_rx_hook(_msg)
if not recv:
rx_invalid += 1
invalid_addrs.add(canmsg.address)
+7 -12
View File
@@ -273,7 +273,6 @@ class TestFordSafetyBase(common.PandaCarSafetyTest):
for path_angle in path_angles:
for curvature_rate in curvature_rates:
for curvature in curvatures:
self._mads_states_cleanup()
self.safety.set_controls_allowed(controls_allowed)
self._set_prev_desired_angle(curvature)
self._reset_curvature_measurement(curvature, speed)
@@ -380,17 +379,13 @@ class TestFordSafetyBase(common.PandaCarSafetyTest):
self.assertEqual(enabled, self._tx(self._acc_button_msg(Buttons.CANCEL, bus)))
def test_enable_control_allowed_from_acc_main_on(self):
try:
for enable_mads in (True, False):
with self.subTest("enable_mads", mads_enabled=enable_mads):
for main_button_msg_valid in (True, False):
with self.subTest("main_button_msg_valid", state_valid=main_button_msg_valid):
self._mads_states_cleanup()
self.safety.set_mads_params(enable_mads, False, False)
self._rx(self._pcm_status_msg(main_button_msg_valid))
self.assertEqual(enable_mads and main_button_msg_valid, self.safety.get_controls_allowed_lat())
finally:
self._mads_states_cleanup()
for enable_mads in (True, False):
with self.subTest("enable_mads", mads_enabled=enable_mads):
for main_button_msg_valid in (True, False):
with self.subTest("main_button_msg_valid", state_valid=main_button_msg_valid):
self.safety.set_mads_params(enable_mads, False, False)
self._rx(self._pcm_status_msg(main_button_msg_valid))
self.assertEqual(enable_mads and main_button_msg_valid, self.safety.get_controls_allowed_lat())
class TestFordCANFDStockSafety(TestFordSafetyBase):
+43 -33
View File
@@ -8,6 +8,8 @@ import opendbc.safety.tests.common as common
from opendbc.car.structs import CarParams
from opendbc.safety.tests.common import CANPackerPanda, MAX_WRONG_COUNTERS
from opendbc.sunnypilot.car.honda.values_ext import HondaSafetyFlagsSP
HONDA_N_COMMON_TX_MSGS = [[0xE4, 0], [0x194, 0], [0x1FA, 0], [0x30C, 0], [0x33D, 0]]
@@ -233,7 +235,6 @@ class HondaBase(common.PandaCarSafetyTest):
self.assertFalse(self.safety.get_controls_allowed())
def test_steer_safety_check(self):
self._mads_states_cleanup()
self.safety.set_controls_allowed(0)
self.assertTrue(self._tx(self._send_steer_msg(0x0000)))
self.assertFalse(self._tx(self._send_steer_msg(0x1000)))
@@ -245,41 +246,36 @@ class HondaBase(common.PandaCarSafetyTest):
def test_enable_control_allowed_with_mads_button(self):
"""Tests MADS button state transitions and internal button press state."""
try:
for enable_mads in (True, False):
with self.subTest("enable_mads", mads_enabled=enable_mads):
self._mads_states_cleanup()
self.safety.set_mads_params(enable_mads, False, False)
for enable_mads in (True, False):
with self.subTest("enable_mads", mads_enabled=enable_mads):
self.safety.set_mads_params(enable_mads, False, False)
# Verify initial state
self._rx(self._lkas_button_msg(False, 0))
self.assertEqual(0, self.safety.get_mads_button_press()) # NOT_PRESSED
self.assertFalse(self.safety.get_controls_allowed_lat())
# Verify initial state
self._rx(self._lkas_button_msg(False, 0))
self.assertEqual(0, self.safety.get_mads_button_press()) # NOT_PRESSED
self.assertFalse(self.safety.get_controls_allowed_lat())
# Verify press sets correct internal state
self._rx(self._lkas_button_msg(False, 1))
self.assertEqual(1, self.safety.get_mads_button_press()) # PRESSED
# Verify press sets correct internal state
self._rx(self._lkas_button_msg(False, 1))
self.assertEqual(1, self.safety.get_mads_button_press()) # PRESSED
self.assertEqual(enable_mads, self.safety.get_controls_allowed_lat())
# Verify release sets correct internal state
self._rx(self._lkas_button_msg(False, 0))
self.assertEqual(0, self.safety.get_mads_button_press()) # NOT_PRESSED
self.assertEqual(enable_mads, self.safety.get_controls_allowed_lat())
# Test invalid values - should not change button press state
for invalid_setting in (2, 3):
self._rx(self._lkas_button_msg(False, invalid_setting))
self.assertEqual(0, self.safety.get_mads_button_press()) # Should remain NOT_PRESSED
self.assertEqual(enable_mads, self.safety.get_controls_allowed_lat())
# Verify release sets correct internal state
self._rx(self._lkas_button_msg(False, 0))
self.assertEqual(0, self.safety.get_mads_button_press()) # NOT_PRESSED
self.assertEqual(enable_mads, self.safety.get_controls_allowed_lat())
# Test invalid values - should not change button press state
for invalid_setting in (2, 3):
self._rx(self._lkas_button_msg(False, invalid_setting))
self.assertEqual(0, self.safety.get_mads_button_press()) # Should remain NOT_PRESSED
self.assertEqual(enable_mads, self.safety.get_controls_allowed_lat())
# Verify we can still transition after invalid values
self._rx(self._lkas_button_msg(False, 1))
self.assertEqual(1, self.safety.get_mads_button_press())
self._rx(self._lkas_button_msg(False, 0))
self.assertEqual(0, self.safety.get_mads_button_press())
finally:
self._mads_states_cleanup()
# Verify we can still transition after invalid values
self._rx(self._lkas_button_msg(False, 1))
self.assertEqual(1, self.safety.get_mads_button_press())
self._rx(self._lkas_button_msg(False, 0))
self.assertEqual(0, self.safety.get_mads_button_press())
# ********************* Honda Nidec **********************
@@ -296,6 +292,8 @@ class TestHondaNidecSafetyBase(HondaBase):
MAX_GAS = 198
BRAKE_SIG = "COMPUTER_BRAKE"
def setUp(self):
self.packer = CANPackerPanda("honda_civic_touring_2016_can_generated")
self.safety = libsafety_py.libsafety
@@ -303,7 +301,7 @@ class TestHondaNidecSafetyBase(HondaBase):
self.safety.init_tests()
def _send_brake_msg(self, brake, aeb_req=0, bus=0):
values = {"COMPUTER_BRAKE": brake, "AEB_REQ_1": aeb_req}
values = {self.BRAKE_SIG: brake, "AEB_REQ_1": aeb_req}
return self.packer.make_can_msg_panda("BRAKE_COMMAND", bus, values)
def _rx_brake_msg(self, brake, aeb_req=0):
@@ -642,5 +640,17 @@ class TestHondaBoschCANFDAltBrakeSafety(HondaPcmEnableBase, TestHondaBoschCANFDS
self.safety.init_tests()
class TestHondaNidecClaritySafety(TestHondaNidecPcmSafety):
BRAKE_SIG = "COMPUTER_BRAKE_ALT"
def setUp(self):
self.packer = CANPackerPanda("honda_clarity_hybrid_2018_can_generated")
self.safety = libsafety_py.libsafety
self.safety.set_current_safety_param_sp(HondaSafetyFlagsSP.CLARITY)
self.safety.set_safety_hooks(CarParams.SafetyModel.hondaNidec, 0)
self.safety.init_tests()
if __name__ == "__main__":
unittest.main()
@@ -18,6 +18,21 @@ LDA_BUTTON = [
{"SAFETY_PARAM_SP": HyundaiSafetyFlagsSP.HAS_LDA_BUTTON},
]
# All combinations of non-SCC HEV/PHEV/EV cars
_ALL_NON_SCC_HEV_EV_COMBOS = [
# Hybrid
{"PCM_STATUS_MSG": ("E_CRUISE_CONTROL", "CRUISE_LAMP_S"),
"ACC_STATE_MSG": ("E_CRUISE_CONTROL", "CRUISE_LAMP_M"),
"GAS_MSG": ("E_EMS11", "CR_Vcu_AccPedDep_Pos"),
"SAFETY_PARAM": HyundaiSafetyFlags.HYBRID_GAS},
# EV
{"PCM_STATUS_MSG": ("LABEL11", "CC_ACT"),
"ACC_STATE_MSG": ("LABEL11", "CC_React"),
"GAS_MSG": ("E_EMS11", "Accel_Pedal_Pos"),
"SAFETY_PARAM": HyundaiSafetyFlags.EV_GAS},
]
ALL_NON_SCC_HEV_EV_COMBOS = [{**p, **lda} for lda in LDA_BUTTON for p in _ALL_NON_SCC_HEV_EV_COMBOS]
# 4 bit checkusm used in some hyundai messages
# lives outside the can packer because we never send this msg
@@ -178,7 +193,6 @@ class TestHyundaiSafety(HyundaiButtonBase, common.PandaCarSafetyTest, common.Dri
self.safety.set_current_safety_param_sp(has_lda_button)
self.safety.set_safety_hooks(default_safety_mode, default_safety_param)
self._mads_states_cleanup()
self.safety.set_mads_params(enable_mads, False, False)
self.assertEqual(enable_mads, self.safety.get_enable_mads())
@@ -188,7 +202,6 @@ class TestHyundaiSafety(HyundaiButtonBase, common.PandaCarSafetyTest, common.Dri
self._rx(self._speed_msg(0))
self.assertEqual(enable_mads and has_lda_button_param, self.safety.get_controls_allowed_lat())
finally:
self._mads_states_cleanup()
self.safety.set_current_safety_param_sp(default_safety_param_sp)
@@ -465,5 +478,90 @@ class TestHyundaiLongitudinalESCCSafety(HyundaiLongitudinalBase, TestHyundaiSafe
pass
@parameterized_class(LDA_BUTTON)
class TestHyundaiNonSCCSafety(TestHyundaiSafety):
@classmethod
def setUpClass(cls):
if cls.__name__ == "TestHyundaiNonSCCSafety":
cls.safety = None
raise unittest.SkipTest
def setUp(self):
self.packer = CANPackerPanda("hyundai_kia_generic")
self.safety = libsafety_py.libsafety
self.safety.set_current_safety_param_sp(HyundaiSafetyFlagsSP.NON_SCC | self.SAFETY_PARAM_SP)
self.safety.set_safety_hooks(CarParams.SafetyModel.hyundai, 0)
self.safety.init_tests()
def _pcm_status_msg(self, enable):
values = {"CRUISE_LAMP_S": enable, "AliveCounter": self.cnt_gas % 4}
self.__class__.cnt_gas += 1
return self.packer.make_can_msg_panda("EMS16", 0, values, fix_checksum=checksum)
def _acc_state_msg(self, enable):
values = {"CRUISE_LAMP_M": enable, "AliveCounter": self.cnt_gas % 4}
self.__class__.cnt_gas += 1
return self.packer.make_can_msg_panda("EMS16", 0, values, fix_checksum=checksum)
def _user_gas_msg(self, gas: float, controls_allowed: bool = True):
values = {"CF_Ems_AclAct": gas, "CRUISE_LAMP_M": 1, "CRUISE_LAMP_S": controls_allowed, "AliveCounter": self.cnt_gas % 4}
self.__class__.cnt_gas += 1
return self.packer.make_can_msg_panda("EMS16", 0, values, fix_checksum=checksum)
def test_allow_engage_with_gas_pressed(self):
self._rx(self._user_gas_msg(1, self.safety.get_controls_allowed()))
self.safety.set_controls_allowed(True)
self._rx(self._user_gas_msg(1, self.safety.get_controls_allowed()))
self.assertTrue(self.safety.get_controls_allowed())
self._rx(self._user_gas_msg(1, self.safety.get_controls_allowed()))
self.assertTrue(self.safety.get_controls_allowed())
def test_no_disengage_on_gas(self):
self._rx(self._user_gas_msg(0, self.safety.get_controls_allowed()))
self.safety.set_controls_allowed(True)
self._rx(self._user_gas_msg(self.GAS_PRESSED_THRESHOLD + 1, self.safety.get_controls_allowed()))
# Test we allow lateral, but not longitudinal
self.assertTrue(self.safety.get_controls_allowed())
self.assertFalse(self.safety.get_longitudinal_allowed())
# Make sure we can re-gain longitudinal actuation
self._rx(self._user_gas_msg(0, self.safety.get_controls_allowed()))
self.assertTrue(self.safety.get_longitudinal_allowed())
@parameterized_class(ALL_NON_SCC_HEV_EV_COMBOS)
class TestHyundaiNonSCCSafety_HEV_EV(TestHyundaiSafety):
PCM_STATUS_MSG = ("", "")
ACC_STATE_MSG = ("", "")
GAS_MSG = ("", "")
SAFETY_PARAM = 0
@classmethod
def setUpClass(cls):
if cls.__name__ == "TestHyundaiNonSCCSafety_HEV_EV":
cls.safety = None
raise unittest.SkipTest
def setUp(self):
self.packer = CANPackerPanda("hyundai_kia_generic")
self.safety = libsafety_py.libsafety
self.safety.set_current_safety_param_sp(HyundaiSafetyFlagsSP.NON_SCC | self.SAFETY_PARAM_SP)
self.safety.set_safety_hooks(CarParams.SafetyModel.hyundai, self.SAFETY_PARAM)
self.safety.init_tests()
def _pcm_status_msg(self, enable):
values = {self.PCM_STATUS_MSG[1]: enable}
return self.packer.make_can_msg_panda(self.PCM_STATUS_MSG[0], 0, values)
def _acc_state_msg(self, enable):
values = {self.ACC_STATE_MSG[1]: enable}
return self.packer.make_can_msg_panda(self.ACC_STATE_MSG[0], 0, values)
def _user_gas_msg(self, gas):
values = {self.GAS_MSG[1]: gas}
return self.packer.make_can_msg_panda(self.GAS_MSG[0], 0, values, fix_checksum=checksum)
if __name__ == "__main__":
unittest.main()
@@ -0,0 +1,90 @@
#!/usr/bin/env python3
import unittest
from opendbc.car.structs import CarParams
from opendbc.safety.tests.libsafety import libsafety_py
import opendbc.safety.tests.common as common
from opendbc.safety.tests.common import CANPackerPanda
LANE_KEEP_ASSIST = 0x3F2
class TestPsaSafetyBase(common.PandaCarSafetyTest, common.AngleSteeringSafetyTest):
RELAY_MALFUNCTION_ADDRS = {0: (LANE_KEEP_ASSIST,)}
FWD_BLACKLISTED_ADDRS = {2: [LANE_KEEP_ASSIST]}
TX_MSGS = [[1010, 0]]
MAIN_BUS = 0
ADAS_BUS = 1
CAM_BUS = 2
STEER_ANGLE_MAX = 390
DEG_TO_CAN = 10
ANGLE_RATE_BP = [0., 5., 25.]
ANGLE_RATE_UP = [2.5, 1.5, .2]
ANGLE_RATE_DOWN = [5., 2., .3]
def setUp(self):
self.packer = CANPackerPanda("psa_aee2010_r3")
self.safety = libsafety_py.libsafety
self.safety.set_safety_hooks(CarParams.SafetyModel.psa, 0)
self.safety.init_tests()
def _angle_cmd_msg(self, angle: float, enabled: bool):
values = {"SET_ANGLE": angle, "TORQUE_FACTOR": 100 if enabled else 0}
return self.packer.make_can_msg_panda("LANE_KEEP_ASSIST", self.MAIN_BUS, values)
def _angle_meas_msg(self, angle: float):
values = {"ANGLE": angle}
return self.packer.make_can_msg_panda("STEERING_ALT", self.MAIN_BUS, values)
def _pcm_status_msg(self, enable):
values = {"RVV_ACC_ACTIVATION_REQ": enable}
return self.packer.make_can_msg_panda("HS2_DAT_MDD_CMD_452", self.ADAS_BUS, values)
def _speed_msg(self, speed):
values = {"VITESSE_VEHICULE_ROUES": speed * 3.6}
return self.packer.make_can_msg_panda("HS2_DYN_ABR_38D", self.MAIN_BUS, values)
def _user_brake_msg(self, brake):
values = {"P013_MainBrake": brake}
return self.packer.make_can_msg_panda("Dat_BSI", self.CAM_BUS, values)
def _user_gas_msg(self, gas):
values = {"P002_Com_rAPP": int(gas * 100)}
return self.packer.make_can_msg_panda("Dyn_CMM", self.MAIN_BUS, values)
def test_rx_hook(self):
# speed
for _ in range(10):
self.assertTrue(self._rx(self._speed_msg(0)))
msg = self._speed_msg(0)
# invalidate checksum
msg[0].data[5] = 0x00
self.assertFalse(self._rx(msg))
# cruise
for _ in range(10):
self.assertTrue(self._rx(self._pcm_status_msg(0)))
msg = self._pcm_status_msg(0)
# invalidate checksum
msg[0].data[5] = 0x00
self.assertFalse(self._rx(msg))
msg = self._pcm_status_msg(0)
# write to unused payload byte
msg[0].data[6] = 0xAB
self.assertTrue(self._rx(msg))
class TestPsaStockSafety(TestPsaSafetyBase):
def setUp(self):
self.packer = CANPackerPanda("psa_aee2010_r3")
self.safety = libsafety_py.libsafety
self.safety.set_safety_hooks(CarParams.SafetyModel.psa, 0)
self.safety.init_tests()
if __name__ == "__main__":
unittest.main()
@@ -120,13 +120,11 @@ class TestSubaruSafetyBase(common.PandaCarSafetyTest):
with self.subTest("enable_mads", mads_enabled=enable_mads):
for mads_button_press in range(4):
with self.subTest("mads_button_press", button_state=mads_button_press):
self._mads_states_cleanup()
self.safety.set_mads_params(enable_mads, False, False)
self._rx(self._lkas_button_msg(False, mads_button_press))
self.assertEqual(enable_mads and mads_button_press in range(1, 4),
self.safety.get_controls_allowed_lat())
self._mads_states_cleanup()
class TestSubaruStockLongitudinalSafetyBase(TestSubaruSafetyBase):
+10 -31
View File
@@ -1,6 +1,5 @@
#!/usr/bin/env python3
import random
from parameterized import parameterized_class
import unittest
import numpy as np
@@ -13,19 +12,12 @@ from opendbc.can import CANDefine
from opendbc.safety.tests.libsafety import libsafety_py
import opendbc.safety.tests.common as common
from opendbc.safety.tests.common import CANPackerPanda, MAX_SPEED_DELTA, MAX_WRONG_COUNTERS, away_round, round_speed
from opendbc.sunnypilot.car.tesla.values import TeslaSafetyFlagsSP
MSG_DAS_steeringControl = 0x488
MSG_APS_eacMonitor = 0x27d
MSG_DAS_Control = 0x2b9
VIRTUAL_TORQUE_BLENDING_SAFETY_PARAM_SP = [
{"SAFETY_PARAM_SP": TeslaSafetyFlagsSP.DEFAULT},
{"SAFETY_PARAM_SP": TeslaSafetyFlagsSP.VIRTUAL_TORQUE_BLENDING},
]
def round_angle(apply_angle, can_offset=0):
apply_angle_can = (apply_angle + 1638.35) / 0.1 + can_offset
# 0.49999_ == 0.5
@@ -64,8 +56,6 @@ class TestTeslaSafetyBase(common.PandaCarSafetyTest, common.AngleSteeringSafetyT
packer: CANPackerPanda
SAFETY_PARAM_SP: int = 0
def _get_steer_cmd_angle_max(self, speed):
return get_max_angle_vm(max(speed, 1), self.VM, CarControllerParams)
@@ -215,24 +205,18 @@ class TestTeslaSafetyBase(common.PandaCarSafetyTest, common.AngleSteeringSafetyT
for hands_on_level in range(4):
for eac_status in range(8):
for eac_error_code in range(16):
for virtual_torque_blending_enabled in (True, False):
self.safety.set_controls_allowed(True)
self.safety.set_controls_allowed(True)
virtual_torque_blending = TeslaSafetyFlagsSP.VIRTUAL_TORQUE_BLENDING if virtual_torque_blending_enabled else 0
hands_on_level_check = False if virtual_torque_blending_enabled else (hands_on_level >= 3)
hands_on_level = 0 if virtual_torque_blending_enabled else hands_on_level
self.safety.set_current_safety_param_sp(virtual_torque_blending)
should_disengage = hands_on_level >= 3 or (eac_status == 0 and eac_error_code == 9)
self.assertTrue(self._rx(self._angle_meas_msg(0, hands_on_level=hands_on_level, eac_status=eac_status,
eac_error_code=eac_error_code)))
self.assertNotEqual(should_disengage, self.safety.get_controls_allowed())
self.assertEqual(should_disengage, self.safety.get_steering_disengage_prev())
should_disengage = hands_on_level_check or (eac_status == 0 and eac_error_code == 9)
self.assertTrue(self._rx(self._angle_meas_msg(0, hands_on_level=hands_on_level, eac_status=eac_status,
eac_error_code=eac_error_code)))
self.assertNotEqual(should_disengage, self.safety.get_controls_allowed())
self.assertEqual(should_disengage, self.safety.get_steering_disengage_prev())
# Should not recover
self.assertTrue(self._rx(self._angle_meas_msg(0, hands_on_level=0, eac_status=1, eac_error_code=0)))
self.assertNotEqual(should_disengage, self.safety.get_controls_allowed())
self.assertFalse(self.safety.get_steering_disengage_prev())
# Should not recover
self.assertTrue(self._rx(self._angle_meas_msg(0, hands_on_level=0, eac_status=1, eac_error_code=0)))
self.assertNotEqual(should_disengage, self.safety.get_controls_allowed())
self.assertFalse(self.safety.get_steering_disengage_prev())
def test_autopark_summon_while_enabled(self):
# We should not respect Autopark that activates while controls are allowed
@@ -289,7 +273,6 @@ class TestTeslaSafetyBase(common.PandaCarSafetyTest, common.AngleSteeringSafetyT
lkas_msg_cam = self._angle_cmd_msg(0, state=self.steer_control_types['LANE_KEEP_ASSIST'], bus=2)
for enable_mads in (True, False):
self._mads_states_cleanup()
self.safety.set_mads_params(enable_mads, True, False)
# stock system sends no LKAS -> no forwarding, and OP is allowed to TX
self.assertEqual(1, self._rx(no_lkas_msg_cam))
@@ -373,7 +356,6 @@ class TestTeslaSafetyBase(common.PandaCarSafetyTest, common.AngleSteeringSafetyT
self.assertTrue(self._tx(self._angle_cmd_msg(0, True)))
@parameterized_class(VIRTUAL_TORQUE_BLENDING_SAFETY_PARAM_SP)
class TestTeslaStockSafety(TestTeslaSafetyBase):
LONGITUDINAL = False
@@ -381,7 +363,6 @@ class TestTeslaStockSafety(TestTeslaSafetyBase):
def setUp(self):
super().setUp()
self.safety = libsafety_py.libsafety
self.safety.set_current_safety_param_sp(self.SAFETY_PARAM_SP)
self.safety.set_safety_hooks(CarParams.SafetyModel.tesla, 0)
self.safety.init_tests()
@@ -416,7 +397,6 @@ class TestTeslaStockSafety(TestTeslaSafetyBase):
self.assertFalse(self._tx(no_aeb_msg))
@parameterized_class(VIRTUAL_TORQUE_BLENDING_SAFETY_PARAM_SP)
class TestTeslaLongitudinalSafety(TestTeslaSafetyBase):
RELAY_MALFUNCTION_ADDRS = {0: (MSG_DAS_steeringControl, MSG_APS_eacMonitor, MSG_DAS_Control)}
FWD_BLACKLISTED_ADDRS = {2: [MSG_DAS_steeringControl, MSG_APS_eacMonitor, MSG_DAS_Control]}
@@ -424,7 +404,6 @@ class TestTeslaLongitudinalSafety(TestTeslaSafetyBase):
def setUp(self):
super().setUp()
self.safety = libsafety_py.libsafety
self.safety.set_current_safety_param_sp(self.SAFETY_PARAM_SP)
self.safety.set_safety_hooks(CarParams.SafetyModel.tesla, TeslaSafetyFlags.LONG_CONTROL)
self.safety.init_tests()
@@ -112,7 +112,6 @@ class TestToyotaSafetyBase(common.PandaCarSafetyTest, common.LongitudinalAccelSa
[0, 1], [0, 1],
[0, 50, 100],
np.linspace(-20, 20, 5)):
self._mads_states_cleanup()
self.safety.set_controls_allowed(engaged)
should_tx = not req and not req2 and angle == 0 and torque_wind_down == 0
@@ -211,7 +210,6 @@ class TestToyotaSafetyAngle(TestToyotaSafetyBase, common.AngleSteeringSafetyTest
"""
for controls_allowed in (True, False):
for angle in np.arange(-90, 90, 1):
self._mads_states_cleanup()
self.safety.set_controls_allowed(controls_allowed)
self._reset_angle_measurement(angle)
self._set_prev_desired_angle(angle)

Some files were not shown because too many files have changed in this diff Show More