dragonpilot beta3

date: 2023-12-23T21:19:29
commit: 38612b14f1a8aa49d1c6ef61bd67f5a095abb3f9
This commit is contained in:
dragonpilot
2023-12-23 21:18:48 -07:00
parent dd4c663a58
commit 7ee7cb59b3
389 changed files with 36391 additions and 48841 deletions
-1
View File
@@ -46,7 +46,6 @@ selfdrive/boardd/boardd
selfdrive/logcatd/logcatd
selfdrive/mapd/default_speeds_by_region.json
system/proclogd/proclogd
selfdrive/ui/_ui
selfdrive/ui/translations/alerts_generated.h
selfdrive/ui/translations/tmp
selfdrive/test/longitudinal_maneuvers/out
+22 -1
View File
@@ -1,4 +1,25 @@
dragonpilot beta3 2023.11.20
dragonpilot beta3 2023.12.23
=======================
* Comma 0.9.6 release
* New driving model (Blue Diamond).
* Vision model trained on more data
* Improved driving performance
* AGNOS 9
* comma body streaming and controls over WebRTC
* Hyundai Staria 2023 support thanks to sunnyhaibin!
* Kia Niro Plug-in Hybrid 2022 support thanks to sunnyhaibin!
* Toyota RAV4 2023 support
* Toyota RAV4 Hybrid 2023 support
* DP HIGHLIGHT:
* Flight Panel (compass, height, pitch).
* Model Confidence indicator (in the max speed box).
* New version of dynamic e2e controller with better detection logic.
* Adjustable lane change speed (default 20mph, OFF = no control during lane change)
* TSS2 long, Dynamic Follow and Accel profile tune has been updated.
* Re-added: Full Screen Nav, Lane Priority Mode and Vision Turn Controller.
* Remove Frogai Agressive take off and re-add improved krkeegen sng boot.
dragonpilot beta3 [2023.11.20]
=======================
* Comma 0.9.5 release
* New driving model (Farm Ville)
+27 -87
View File
@@ -1,18 +1,4 @@
![openpilot on the comma 3X](https://github.com/commaai/openpilot/assets/4038174/f1081737-8718-4241-a22a-3ceba526361a)
Table of Contents
=======================
* [What is openpilot?](#what-is-openpilot)
* [Running in a car](#running-on-a-dedicated-device-in-a-car)
* [Running on PC](#running-on-pc)
* [Community and Contributing](#community-and-contributing)
* [User Data and comma Account](#user-data-and-comma-account)
* [Safety and Testing](#safety-and-testing)
* [Directory Structure](#directory-structure)
* [Licensing](#licensing)
---
[![openpilot on the comma 3X](https://github.com/commaai/openpilot/assets/8762862/f09e6d29-db2d-4179-80c2-51e8d92bdb5c)](https://comma.ai/shop/comma-3x)
What is openpilot?
------
@@ -21,35 +7,22 @@ What is openpilot?
<table>
<tr>
<td><a href="https://youtu.be/NmBfgOanCyk" title="Video By Greer Viau"><img src="https://i.imgur.com/1w8c6d2.jpg"></a></td>
<td><a href="https://youtu.be/VHKyqZ7t8Gw" title="Video By Logan LeGrand"><img src="https://i.imgur.com/LnBucik.jpg"></a></td>
<td><a href="https://youtu.be/VxiR4iyBruo" title="Video By Charlie Kim"><img src="https://i.imgur.com/4Qoy48c.jpg"></a></td>
<td><a href="https://youtu.be/-IkImTe1NYE" title="Video By Aragon"><img src="https://i.imgur.com/04VNzPf.jpg"></a></td>
</tr>
<tr>
<td><a href="https://youtu.be/iIUICQkdwFQ" title="Video By Logan LeGrand"><img src="https://i.imgur.com/b1LHQTy.jpg"></a></td>
<td><a href="https://youtu.be/XOsa0FsVIsg" title="Video By PinoyDrives"><img src="https://i.imgur.com/6FG0Bd8.jpg"></a></td>
<td><a href="https://youtu.be/bCwcJ98R_Xw" title="Video By JS"><img src="https://i.imgur.com/zO18CbW.jpg"></a></td>
<td><a href="https://youtu.be/BQ0tF3MTyyc" title="Video By Tsai-Fi"><img src="https://i.imgur.com/eZzelq3.jpg"></a></td>
<td><a href="https://youtu.be/NmBfgOanCyk" title="Video By Greer Viau"><img src="https://github.com/commaai/openpilot/assets/8762862/2f7112ae-f748-4f39-b617-fabd689c3772"></a></td>
<td><a href="https://youtu.be/VHKyqZ7t8Gw" title="Video By Logan LeGrand"><img src="https://github.com/commaai/openpilot/assets/8762862/92351544-2833-40d7-9e0b-7ef7ae37ec4c"></a></td>
<td><a href="https://youtu.be/SUIZYzxtMQs" title="A drive to Taco Bell"><img src="https://github.com/commaai/openpilot/assets/8762862/05ceefc5-2628-439c-a9b2-89ce77dc6f63"></a></td>
</tr>
</table>
Running on a dedicated device in a car
------
To use openpilot in a car, you need four things
1. **Supported Device:** A comma 3/3X. You can purchase these devices from (https://comma.ai/shop/comma-3x)
2. **Software:** The setup procedure for the comma 3/3X allows users to enter a URL for custom software.
To install the release version of openpilot, use the URL `openpilot.comma.ai`.
To install openpilot master (for more advanced users), use the URL `installer.comma.ai/commaai/master`. You can replace "commaai" with another GitHub username to install a fork.
3. **Supported Car:** Ensure that you have one of [the 250+ supported cars](docs/CARS.md). openpilot supports a wide range of car makes including Honda, Toyota, Hyundai, Nissan, Kia, Chrysler, Lexus, Acura, Audi, VW, Ford, and many more.
If your car is not officially listed as supported but has adaptive cruise control and lane-keeping assist, it's likely capable of running openpilot.
To use openpilot in a car, you need four things:
1. **Supported Device:** a comma 3/3X, available at [comma.ai/shop](https://comma.ai/shop/comma-3x).
2. **Software:** The setup procedure for the comma 3/3X allows users to enter a URL for custom software. Use the URL `openpilot.comma.ai` to install the release version.
3. **Supported Car:** Ensure that you have one of [the 250+ supported cars](docs/CARS.md).
4. **Car Harness:** You will also need a [car harness](https://comma.ai/shop/car-harness) to connect your comma 3/3X to your car.
We have detailed instructions for [how to install the harness and device in a car](https://comma.ai/setup).
We have detailed instructions for [how to install the harness and device in a car](https://comma.ai/setup).
Running on PC
------
@@ -58,22 +31,32 @@ All openpilot services can run as usual on a PC without requiring special hardwa
With openpilot's tools, you can plot logs, replay drives, and watch the full-res camera streams. See [the tools README](tools/README.md) for more information.
You can also run openpilot in simulation [with the CARLA simulator](tools/sim/README.md). This allows openpilot to drive around a virtual car on your Ubuntu machine. The whole setup should only take a few minutes but does require a decent GPU.
You can also run openpilot in simulation [with the MetaDrive simulator](tools/sim/README.md). This allows openpilot to drive around a virtual car on your Ubuntu machine.
A PC running openpilot can also control your vehicle if it is connected to a [webcam](https://github.com/commaai/openpilot/tree/master/tools/webcam), a [black panda](https://comma.ai/shop/products/panda), and a [harness](https://comma.ai/shop/products/car-harness).
Community and Contributing
------
openpilot is developed by [comma](https://comma.ai/) and by users like you. We welcome both pull requests and issues on [GitHub](http://github.com/commaai/openpilot). Bug fixes and new car ports are encouraged. Check out [the contributing docs](docs/CONTRIBUTING.md).
openpilot is developed by [comma](https://comma.ai/) and by users like you. We welcome both pull requests and issues on [GitHub](http://github.com/commaai/openpilot).
Documentation related to openpilot development can be found on [docs.comma.ai](https://docs.comma.ai). Information about running openpilot (e.g. FAQ, fingerprinting, troubleshooting, custom forks, community hardware) should go on the [wiki](https://github.com/commaai/openpilot/wiki).
* Join the [community Discord](https://discord.comma.ai)
* Check out [the contributing docs](docs/CONTRIBUTING.md)
* Code documentation lives at https://docs.comma.ai
* Information about running openpilot lives on the [community wiki](https://github.com/commaai/openpilot/wiki)
You can add support for your car by following guides we have written for [Brand](https://blog.comma.ai/how-to-write-a-car-port-for-openpilot/) and [Model](https://blog.comma.ai/openpilot-port-guide-for-toyota-models/) ports. Generally, a car with adaptive cruise control and lane keep assist is a good candidate. [Join our Discord](https://discord.comma.ai) to discuss car ports: most car makes have a dedicated channel.
Want to get paid to work on openpilot? [comma is hiring](https://comma.ai/jobs#open-positions) and offers lots of [bounties](docs/BOUNTIES.md).
Want to get paid to work on openpilot? [comma is hiring](https://comma.ai/jobs#open-positions).
Safety and Testing
----
And [follow us on Twitter](https://twitter.com/comma_ai).
* openpilot observes [ISO26262](https://en.wikipedia.org/wiki/ISO_26262) guidelines, see [SAFETY.md](docs/SAFETY.md) for more details.
* openpilot has software-in-the-loop [tests](.github/workflows/selfdrive_tests.yaml) that run on every commit.
* The code enforcing the safety model lives in panda and is written in C, see [code rigor](https://github.com/commaai/panda#code-rigor) for more details.
* panda has software-in-the-loop [safety tests](https://github.com/commaai/panda/tree/master/tests/safety).
* Internally, we have a hardware-in-the-loop Jenkins test suite that builds and unit tests the various processes.
* panda has additional hardware-in-the-loop [tests](https://github.com/commaai/panda/blob/master/Jenkinsfile).
* We run the latest openpilot in a testing closet containing 10 comma devices continuously replaying routes.
User Data and comma Account
------
@@ -87,49 +70,6 @@ The driver-facing camera is only logged if you explicitly opt-in in settings. Th
By using openpilot, you agree to [our Privacy Policy](https://comma.ai/privacy). You understand that use of this software or its related services will generate certain types of user data, which may be logged and stored at the sole discretion of comma. By accepting this agreement, you grant an irrevocable, perpetual, worldwide right to comma for the use of this data.
Safety and Testing
----
* openpilot observes ISO26262 guidelines, see [SAFETY.md](docs/SAFETY.md) for more details.
* openpilot has software-in-the-loop [tests](.github/workflows/selfdrive_tests.yaml) that run on every commit.
* The code enforcing the safety model lives in panda and is written in C, see [code rigor](https://github.com/commaai/panda#code-rigor) for more details.
* panda has software-in-the-loop [safety tests](https://github.com/commaai/panda/tree/master/tests/safety).
* Internally, we have a hardware-in-the-loop Jenkins test suite that builds and unit tests the various processes.
* panda has additional hardware-in-the-loop [tests](https://github.com/commaai/panda/blob/master/Jenkinsfile).
* We run the latest openpilot in a testing closet containing 10 comma devices continuously replaying routes.
Directory Structure
------
.
├── cereal # The messaging spec and libs used for all logs
├── common # Library like functionality we've developed here
├── docs # Documentation
├── opendbc # Files showing how to interpret data from cars
├── panda # Code used to communicate on CAN
├── third_party # External libraries
└── system # Generic services
├── camerad # Driver to capture images from the camera sensors
├── hardware # Hardware abstraction classes
├── logcatd # systemd journal as a service
├── loggerd # Logger and uploader of car data
├── proclogd # Logs information from /proc
├── sensord # IMU interface code
└── ubloxd # u-blox GNSS module interface code
└── selfdrive # Code needed to drive the car
├── assets # Fonts, images, and sounds for UI
├── athena # Allows communication with the app
├── boardd # Daemon to talk to the board
├── car # Car specific code to read states and control actuators
├── controls # Planning and controls
├── debug # Tools to help you debug and do car ports
├── locationd # Precise localization and vehicle parameter estimation
├── manager # Daemon that starts/stops all other daemons as needed
├── modeld # Driving and monitoring model runners
├── monitoring # Daemon to determine driver attention
├── navd # Turn-by-turn navigation
├── test # Unit tests, system tests, and a car simulator
└── ui # The UI
Licensing
------
@@ -145,5 +85,5 @@ NO WARRANTY EXPRESSED OR IMPLIED.**
<img src="https://d1qb2nb5cznatu.cloudfront.net/startups/i/1061157-bc7e9bf3b246ece7322e6ffe653f6af8-medium_jpg.jpg?buster=1458363130" width="75"></img> <img src="https://cdn-images-1.medium.com/max/1600/1*C87EjxGeMPrkTuVRVWVg4w.png" width="225"></img>
[![openpilot tests](https://github.com/commaai/openpilot/workflows/openpilot%20tests/badge.svg?event=push)](https://github.com/commaai/openpilot/actions)
![openpilot tests](https://github.com/commaai/openpilot/actions/workflows/selfdrive_tests.yaml/badge.svg)
[![codecov](https://codecov.io/gh/commaai/openpilot/branch/master/graph/badge.svg)](https://codecov.io/gh/commaai/openpilot)
+16 -3
View File
@@ -1,4 +1,16 @@
Version 0.9.5 (2023-XX-XX)
Version 0.9.6 (20XX-XX-XX)
========================
* New driving model
* Vision model trained on more data
* Improved driving performance
* AGNOS 9
* comma body streaming and controls over WebRTC
* Hyundai Staria 2023 support thanks to sunnyhaibin!
* Kia Niro Plug-in Hybrid 2022 support thanks to sunnyhaibin!
* Toyota RAV4 2023 support
* Toyota RAV4 Hybrid 2023 support
Version 0.9.5 (2023-11-17)
========================
* New driving model
* Improved navigate on openpilot performance using navigation instructions as an additional model input
@@ -8,11 +20,12 @@ Version 0.9.5 (2023-XX-XX)
* Hyundai Azera 2022 support thanks to sunnyhaibin!
* Hyundai Azera Hybrid 2020 support thanks to chanhojung and haram-KONA!
* Hyundai Custin 2023 support thanks to sunnyhaibin and Saber422!
* Hyundai Ioniq 6 2023 support thanks to sunnyhaibin, alamo3, and sshane!
* Hyundai Ioniq 6 2023 support thanks to sunnyhaibin and alamo3!
* Hyundai Kona Electric 2023 (Korean version) support thanks to sunnyhaibin and haram-KONA!
* Kia K8 Hybrid (with HDA II) 2023 support thanks to sunnyhaibin!
* Kia Sorento Hybrid 2023 support thanks to sunnyhaibin!
* Kia Optima Hybrid 2019 support
* Kia Sorento Hybrid 2023 support thanks to sunnyhaibin!
* Lexus GS F 2016 support thanks to snyperifle!
* Lexus IS 2023 support thanks to L3R5!
Version 0.9.4 (2023-07-27)
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1 -1
View File
@@ -1 +1 @@
const uint8_t gitversion[8] = "bcce255c";
const uint8_t gitversion[8] = "4ba36d72";
+1
View File
@@ -484,6 +484,7 @@ struct CarParams {
openpilotLongitudinalControl @37 :Bool; # is openpilot doing the longitudinal control?
carVin @38 :Text; # VIN number queried during fingerprinting
dashcamOnly @41: Bool;
passive @73: Bool; # is openpilot in control?
transmissionType @43 :TransmissionType;
carFw @44 :List(CarFw);
+5 -27
View File
@@ -32,24 +32,11 @@ struct LiveMapData @0x81c2f05a394cf4af {
}
struct LongitudinalPlanExt @0xaedffd8f31e7b55d {
visionTurnControllerState @0 :VisionTurnControllerState;
visionTurnSpeed @1 :Float32;
speedLimitControlState @2 :SpeedLimitControlState;
speedLimit @3 :Float32;
speedLimitOffset @4 :Float32;
distToSpeedLimit @5 :Float32;
isMapSpeedLimit @6 :Bool;
speedLimitPercOffset @7 :Bool;
speedLimitValueOffset @8 :Float32;
distToTurn @9 :Float32;
turnSpeed @10 :Float32;
turnSpeedControlState @11 :SpeedLimitControlState;
turnSign @12 :Int16;
dpE2EIsBlended @13 :Bool;
longitudinalPlanExtSource @14 :LongitudinalPlanExtSource;
de2eIsEnabled @15 :Bool;
dpE2EIsBlended @0 :Bool;
de2eIsEnabled @1 :Bool;
visionTurnControllerState @2 :VisionTurnControllerState;
visionTurnSpeed @3 :Float32;
longitudinalPlanExtSource @4 :LongitudinalPlanExtSource;
enum LongitudinalPlanExtSource {
cruise @0;
@@ -58,15 +45,6 @@ struct LongitudinalPlanExt @0xaedffd8f31e7b55d {
lead2 @3;
e2e @4;
turn @5;
limit @6;
turnlimit @7;
}
enum SpeedLimitControlState {
inactive @0; # No speed limit set or not enabled by parameter.
tempInactive @1; # User wants to ignore speed limit until it changes.
adapting @2; # Reducing speed to match new speed limit.
active @3; # Cruising at speed limit.
}
enum VisionTurnControllerState {
+330 -315
View File
@@ -3502,7 +3502,7 @@ const ::capnp::_::RawSchema s_f5a5e26c954e339e = {
};
#endif // !CAPNP_LITE
CAPNP_DEFINE_ENUM(AudibleAlert_f5a5e26c954e339e, f5a5e26c954e339e);
static const ::capnp::_::AlignedData<1269> b_8c69372490aaa9da = {
static const ::capnp::_::AlignedData<1284> b_8c69372490aaa9da = {
{ 0, 0, 0, 0, 5, 0, 6, 0,
218, 169, 170, 144, 36, 55, 105, 140,
10, 0, 0, 0, 1, 0, 17, 0,
@@ -3512,7 +3512,7 @@ static const ::capnp::_::AlignedData<1269> b_8c69372490aaa9da = {
21, 0, 0, 0, 162, 0, 0, 0,
29, 0, 0, 0, 231, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
17, 1, 0, 0, 87, 15, 0, 0,
17, 1, 0, 0, 143, 15, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
99, 97, 114, 46, 99, 97, 112, 110,
@@ -3581,497 +3581,504 @@ static const ::capnp::_::AlignedData<1269> b_8c69372490aaa9da = {
101, 0, 0, 0, 0, 0, 0, 0,
78, 101, 116, 119, 111, 114, 107, 76,
111, 99, 97, 116, 105, 111, 110, 0,
24, 1, 0, 0, 3, 0, 4, 0,
28, 1, 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,
153, 7, 0, 0, 66, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
148, 7, 0, 0, 3, 0, 1, 0,
160, 7, 0, 0, 2, 0, 1, 0,
1, 0, 0, 0, 1, 0, 0, 0,
0, 0, 1, 0, 1, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
157, 7, 0, 0, 122, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
156, 7, 0, 0, 3, 0, 1, 0,
168, 7, 0, 0, 2, 0, 1, 0,
4, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1, 0, 2, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
165, 7, 0, 0, 170, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
168, 7, 0, 0, 3, 0, 1, 0,
180, 7, 0, 0, 2, 0, 1, 0,
5, 0, 0, 0, 1, 0, 0, 0,
0, 0, 1, 0, 3, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
177, 7, 0, 0, 82, 0, 0, 0,
181, 7, 0, 0, 66, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
176, 7, 0, 0, 3, 0, 1, 0,
188, 7, 0, 0, 2, 0, 1, 0,
51, 0, 0, 0, 2, 0, 0, 0,
0, 0, 1, 0, 4, 0, 0, 0,
1, 0, 0, 0, 1, 0, 0, 0,
0, 0, 1, 0, 1, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
185, 7, 0, 0, 186, 0, 0, 0,
185, 7, 0, 0, 122, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
188, 7, 0, 0, 3, 0, 1, 0,
200, 7, 0, 0, 2, 0, 1, 0,
6, 0, 0, 0, 3, 0, 0, 0,
0, 0, 1, 0, 5, 0, 0, 0,
184, 7, 0, 0, 3, 0, 1, 0,
196, 7, 0, 0, 2, 0, 1, 0,
4, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1, 0, 2, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
197, 7, 0, 0, 82, 0, 0, 0,
193, 7, 0, 0, 170, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
196, 7, 0, 0, 3, 0, 1, 0,
208, 7, 0, 0, 2, 0, 1, 0,
52, 0, 0, 0, 4, 0, 0, 0,
0, 0, 1, 0, 6, 0, 0, 0,
5, 0, 0, 0, 1, 0, 0, 0,
0, 0, 1, 0, 3, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
205, 7, 0, 0, 170, 0, 0, 0,
205, 7, 0, 0, 82, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
208, 7, 0, 0, 3, 0, 1, 0,
220, 7, 0, 0, 2, 0, 1, 0,
10, 0, 0, 0, 1, 0, 0, 0,
0, 0, 1, 0, 7, 0, 0, 0,
204, 7, 0, 0, 3, 0, 1, 0,
216, 7, 0, 0, 2, 0, 1, 0,
52, 0, 0, 0, 2, 0, 0, 0,
0, 0, 1, 0, 4, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
217, 7, 0, 0, 122, 0, 0, 0,
213, 7, 0, 0, 186, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
216, 7, 0, 0, 3, 0, 1, 0,
228, 7, 0, 0, 2, 0, 1, 0,
11, 0, 0, 0, 2, 0, 0, 0,
0, 0, 1, 0, 8, 0, 0, 0,
6, 0, 0, 0, 3, 0, 0, 0,
0, 0, 1, 0, 5, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
225, 7, 0, 0, 114, 0, 0, 0,
225, 7, 0, 0, 82, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
224, 7, 0, 0, 3, 0, 1, 0,
236, 7, 0, 0, 2, 0, 1, 0,
57, 0, 0, 0, 1, 0, 0, 0,
0, 0, 1, 0, 9, 0, 0, 0,
53, 0, 0, 0, 4, 0, 0, 0,
0, 0, 1, 0, 6, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
233, 7, 0, 0, 178, 0, 0, 0,
233, 7, 0, 0, 170, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
236, 7, 0, 0, 3, 0, 1, 0,
248, 7, 0, 0, 2, 0, 1, 0,
56, 0, 0, 0, 6, 0, 0, 0,
10, 0, 0, 0, 1, 0, 0, 0,
0, 0, 1, 0, 7, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
245, 7, 0, 0, 122, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
244, 7, 0, 0, 3, 0, 1, 0,
0, 8, 0, 0, 2, 0, 1, 0,
11, 0, 0, 0, 2, 0, 0, 0,
0, 0, 1, 0, 8, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
253, 7, 0, 0, 114, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
252, 7, 0, 0, 3, 0, 1, 0,
8, 8, 0, 0, 2, 0, 1, 0,
58, 0, 0, 0, 1, 0, 0, 0,
0, 0, 1, 0, 9, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
5, 8, 0, 0, 178, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
8, 8, 0, 0, 3, 0, 1, 0,
20, 8, 0, 0, 2, 0, 1, 0,
57, 0, 0, 0, 6, 0, 0, 0,
0, 0, 1, 0, 10, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
245, 7, 0, 0, 178, 0, 0, 0,
17, 8, 0, 0, 178, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
248, 7, 0, 0, 3, 0, 1, 0,
4, 8, 0, 0, 2, 0, 1, 0,
62, 0, 0, 0, 2, 0, 0, 0,
20, 8, 0, 0, 3, 0, 1, 0,
32, 8, 0, 0, 2, 0, 1, 0,
63, 0, 0, 0, 2, 0, 0, 0,
0, 0, 1, 0, 11, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 8, 0, 0, 170, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
4, 8, 0, 0, 3, 0, 1, 0,
32, 8, 0, 0, 2, 0, 1, 0,
63, 0, 0, 0, 3, 0, 0, 0,
0, 0, 1, 0, 12, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
29, 8, 0, 0, 162, 0, 0, 0,
29, 8, 0, 0, 170, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
32, 8, 0, 0, 3, 0, 1, 0,
60, 8, 0, 0, 2, 0, 1, 0,
64, 0, 0, 0, 4, 0, 0, 0,
0, 0, 1, 0, 13, 0, 0, 0,
64, 0, 0, 0, 3, 0, 0, 0,
0, 0, 1, 0, 12, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
57, 8, 0, 0, 154, 0, 0, 0,
57, 8, 0, 0, 162, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
60, 8, 0, 0, 3, 0, 1, 0,
88, 8, 0, 0, 2, 0, 1, 0,
65, 0, 0, 0, 5, 0, 0, 0,
0, 0, 1, 0, 14, 0, 0, 0,
65, 0, 0, 0, 4, 0, 0, 0,
0, 0, 1, 0, 13, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
85, 8, 0, 0, 146, 0, 0, 0,
85, 8, 0, 0, 154, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
88, 8, 0, 0, 3, 0, 1, 0,
116, 8, 0, 0, 2, 0, 1, 0,
66, 0, 0, 0, 6, 0, 0, 0,
0, 0, 1, 0, 15, 0, 0, 0,
66, 0, 0, 0, 5, 0, 0, 0,
0, 0, 1, 0, 14, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
113, 8, 0, 0, 170, 0, 0, 0,
113, 8, 0, 0, 146, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
116, 8, 0, 0, 3, 0, 1, 0,
144, 8, 0, 0, 2, 0, 1, 0,
67, 0, 0, 0, 7, 0, 0, 0,
0, 0, 1, 0, 16, 0, 0, 0,
67, 0, 0, 0, 6, 0, 0, 0,
0, 0, 1, 0, 15, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
141, 8, 0, 0, 162, 0, 0, 0,
141, 8, 0, 0, 170, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
144, 8, 0, 0, 3, 0, 1, 0,
172, 8, 0, 0, 2, 0, 1, 0,
68, 0, 0, 0, 7, 0, 0, 0,
0, 0, 1, 0, 16, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
169, 8, 0, 0, 162, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
172, 8, 0, 0, 3, 0, 1, 0,
200, 8, 0, 0, 2, 0, 1, 0,
16, 0, 0, 0, 4, 0, 0, 0,
0, 0, 1, 0, 17, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
169, 8, 0, 0, 42, 0, 0, 0,
197, 8, 0, 0, 42, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
164, 8, 0, 0, 3, 0, 1, 0,
176, 8, 0, 0, 2, 0, 1, 0,
192, 8, 0, 0, 3, 0, 1, 0,
204, 8, 0, 0, 2, 0, 1, 0,
17, 0, 0, 0, 5, 0, 0, 0,
0, 0, 1, 0, 18, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
173, 8, 0, 0, 82, 0, 0, 0,
201, 8, 0, 0, 82, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
172, 8, 0, 0, 3, 0, 1, 0,
184, 8, 0, 0, 2, 0, 1, 0,
200, 8, 0, 0, 3, 0, 1, 0,
212, 8, 0, 0, 2, 0, 1, 0,
18, 0, 0, 0, 6, 0, 0, 0,
0, 0, 1, 0, 19, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
181, 8, 0, 0, 114, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
180, 8, 0, 0, 3, 0, 1, 0,
192, 8, 0, 0, 2, 0, 1, 0,
19, 0, 0, 0, 7, 0, 0, 0,
0, 0, 1, 0, 20, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
189, 8, 0, 0, 90, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
188, 8, 0, 0, 3, 0, 1, 0,
200, 8, 0, 0, 2, 0, 1, 0,
20, 0, 0, 0, 8, 0, 0, 0,
0, 0, 1, 0, 21, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
197, 8, 0, 0, 122, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
196, 8, 0, 0, 3, 0, 1, 0,
208, 8, 0, 0, 2, 0, 1, 0,
21, 0, 0, 0, 9, 0, 0, 0,
0, 0, 1, 0, 22, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
205, 8, 0, 0, 146, 0, 0, 0,
209, 8, 0, 0, 114, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
208, 8, 0, 0, 3, 0, 1, 0,
220, 8, 0, 0, 2, 0, 1, 0,
19, 0, 0, 0, 7, 0, 0, 0,
0, 0, 1, 0, 20, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
217, 8, 0, 0, 90, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
216, 8, 0, 0, 3, 0, 1, 0,
228, 8, 0, 0, 2, 0, 1, 0,
20, 0, 0, 0, 8, 0, 0, 0,
0, 0, 1, 0, 21, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
225, 8, 0, 0, 122, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
224, 8, 0, 0, 3, 0, 1, 0,
236, 8, 0, 0, 2, 0, 1, 0,
21, 0, 0, 0, 9, 0, 0, 0,
0, 0, 1, 0, 22, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
233, 8, 0, 0, 146, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
236, 8, 0, 0, 3, 0, 1, 0,
248, 8, 0, 0, 2, 0, 1, 0,
23, 0, 0, 0, 10, 0, 0, 0,
0, 0, 1, 0, 23, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
217, 8, 0, 0, 154, 0, 0, 0,
245, 8, 0, 0, 154, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
220, 8, 0, 0, 3, 0, 1, 0,
232, 8, 0, 0, 2, 0, 1, 0,
248, 8, 0, 0, 3, 0, 1, 0,
4, 9, 0, 0, 2, 0, 1, 0,
24, 0, 0, 0, 11, 0, 0, 0,
0, 0, 1, 0, 24, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
229, 8, 0, 0, 146, 0, 0, 0,
1, 9, 0, 0, 146, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
232, 8, 0, 0, 3, 0, 1, 0,
244, 8, 0, 0, 2, 0, 1, 0,
4, 9, 0, 0, 3, 0, 1, 0,
16, 9, 0, 0, 2, 0, 1, 0,
25, 0, 0, 0, 8, 0, 0, 0,
0, 0, 1, 0, 25, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
241, 8, 0, 0, 154, 0, 0, 0,
13, 9, 0, 0, 154, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
244, 8, 0, 0, 3, 0, 1, 0,
0, 9, 0, 0, 2, 0, 1, 0,
16, 9, 0, 0, 3, 0, 1, 0,
28, 9, 0, 0, 2, 0, 1, 0,
27, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
104, 149, 51, 53, 10, 88, 252, 147,
253, 8, 0, 0, 114, 0, 0, 0,
25, 9, 0, 0, 114, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
28, 0, 0, 0, 5, 0, 0, 0,
0, 0, 1, 0, 28, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
233, 8, 0, 0, 130, 0, 0, 0,
5, 9, 0, 0, 130, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
232, 8, 0, 0, 3, 0, 1, 0,
244, 8, 0, 0, 2, 0, 1, 0,
4, 9, 0, 0, 3, 0, 1, 0,
16, 9, 0, 0, 2, 0, 1, 0,
30, 0, 0, 0, 12, 0, 0, 0,
0, 0, 1, 0, 29, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
241, 8, 0, 0, 106, 0, 0, 0,
13, 9, 0, 0, 106, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
240, 8, 0, 0, 3, 0, 1, 0,
252, 8, 0, 0, 2, 0, 1, 0,
68, 0, 0, 0, 6, 0, 0, 0,
12, 9, 0, 0, 3, 0, 1, 0,
24, 9, 0, 0, 2, 0, 1, 0,
69, 0, 0, 0, 6, 0, 0, 0,
0, 0, 1, 0, 30, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
249, 8, 0, 0, 234, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 9, 0, 0, 3, 0, 1, 0,
12, 9, 0, 0, 2, 0, 1, 0,
32, 0, 0, 0, 7, 0, 0, 0,
0, 0, 1, 0, 31, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
9, 9, 0, 0, 130, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
8, 9, 0, 0, 3, 0, 1, 0,
20, 9, 0, 0, 2, 0, 1, 0,
37, 0, 0, 0, 13, 0, 0, 0,
0, 0, 1, 0, 32, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
17, 9, 0, 0, 90, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
16, 9, 0, 0, 3, 0, 1, 0,
28, 9, 0, 0, 2, 0, 1, 0,
53, 0, 0, 0, 14, 0, 0, 0,
0, 0, 1, 0, 33, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
25, 9, 0, 0, 194, 0, 0, 0,
21, 9, 0, 0, 234, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
28, 9, 0, 0, 3, 0, 1, 0,
40, 9, 0, 0, 2, 0, 1, 0,
32, 0, 0, 0, 7, 0, 0, 0,
0, 0, 1, 0, 31, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
37, 9, 0, 0, 130, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
36, 9, 0, 0, 3, 0, 1, 0,
48, 9, 0, 0, 2, 0, 1, 0,
37, 0, 0, 0, 13, 0, 0, 0,
0, 0, 1, 0, 32, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
45, 9, 0, 0, 90, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
44, 9, 0, 0, 3, 0, 1, 0,
56, 9, 0, 0, 2, 0, 1, 0,
54, 0, 0, 0, 14, 0, 0, 0,
0, 0, 1, 0, 33, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
53, 9, 0, 0, 194, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
56, 9, 0, 0, 3, 0, 1, 0,
68, 9, 0, 0, 2, 0, 1, 0,
33, 0, 0, 0, 30, 0, 0, 0,
0, 0, 1, 0, 34, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
37, 9, 0, 0, 138, 0, 0, 0,
65, 9, 0, 0, 138, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
40, 9, 0, 0, 3, 0, 1, 0,
52, 9, 0, 0, 2, 0, 1, 0,
68, 9, 0, 0, 3, 0, 1, 0,
80, 9, 0, 0, 2, 0, 1, 0,
34, 0, 0, 0, 8, 0, 0, 0,
0, 0, 1, 0, 35, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
49, 9, 0, 0, 138, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
52, 9, 0, 0, 3, 0, 1, 0,
64, 9, 0, 0, 2, 0, 1, 0,
39, 0, 0, 0, 16, 0, 0, 0,
0, 0, 1, 0, 36, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
61, 9, 0, 0, 154, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
64, 9, 0, 0, 3, 0, 1, 0,
76, 9, 0, 0, 2, 0, 1, 0,
42, 0, 0, 0, 9, 0, 0, 0,
0, 0, 1, 0, 37, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
73, 9, 0, 0, 234, 0, 0, 0,
77, 9, 0, 0, 138, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
80, 9, 0, 0, 3, 0, 1, 0,
92, 9, 0, 0, 2, 0, 1, 0,
39, 0, 0, 0, 16, 0, 0, 0,
0, 0, 1, 0, 36, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
89, 9, 0, 0, 154, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
92, 9, 0, 0, 3, 0, 1, 0,
104, 9, 0, 0, 2, 0, 1, 0,
42, 0, 0, 0, 9, 0, 0, 0,
0, 0, 1, 0, 37, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
101, 9, 0, 0, 234, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
108, 9, 0, 0, 3, 0, 1, 0,
120, 9, 0, 0, 2, 0, 1, 0,
43, 0, 0, 0, 10, 0, 0, 0,
0, 0, 1, 0, 38, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
89, 9, 0, 0, 58, 0, 0, 0,
117, 9, 0, 0, 58, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
84, 9, 0, 0, 3, 0, 1, 0,
96, 9, 0, 0, 2, 0, 1, 0,
54, 0, 0, 0, 10, 0, 0, 0,
112, 9, 0, 0, 3, 0, 1, 0,
124, 9, 0, 0, 2, 0, 1, 0,
55, 0, 0, 0, 10, 0, 0, 0,
0, 0, 1, 0, 39, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
93, 9, 0, 0, 186, 0, 0, 0,
121, 9, 0, 0, 186, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
96, 9, 0, 0, 3, 0, 1, 0,
108, 9, 0, 0, 2, 0, 1, 0,
124, 9, 0, 0, 3, 0, 1, 0,
136, 9, 0, 0, 2, 0, 1, 0,
44, 0, 0, 0, 11, 0, 0, 0,
0, 0, 1, 0, 41, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
105, 9, 0, 0, 98, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
104, 9, 0, 0, 3, 0, 1, 0,
116, 9, 0, 0, 2, 0, 1, 0,
58, 0, 0, 0, 31, 0, 0, 0,
0, 0, 1, 0, 42, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
113, 9, 0, 0, 234, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
120, 9, 0, 0, 3, 0, 1, 0,
132, 9, 0, 0, 2, 0, 1, 0,
45, 0, 0, 0, 34, 0, 0, 0,
0, 0, 1, 0, 43, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
129, 9, 0, 0, 138, 0, 0, 0,
133, 9, 0, 0, 98, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
132, 9, 0, 0, 3, 0, 1, 0,
144, 9, 0, 0, 2, 0, 1, 0,
46, 0, 0, 0, 11, 0, 0, 0,
0, 0, 1, 0, 44, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
141, 9, 0, 0, 50, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
136, 9, 0, 0, 3, 0, 1, 0,
164, 9, 0, 0, 2, 0, 1, 0,
47, 0, 0, 0, 18, 0, 0, 0,
0, 0, 1, 0, 45, 0, 0, 0,
59, 0, 0, 0, 31, 0, 0, 0,
0, 0, 1, 0, 42, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
161, 9, 0, 0, 114, 0, 0, 0,
141, 9, 0, 0, 234, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
148, 9, 0, 0, 3, 0, 1, 0,
160, 9, 0, 0, 2, 0, 1, 0,
46, 0, 0, 0, 34, 0, 0, 0,
0, 0, 1, 0, 43, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
157, 9, 0, 0, 138, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
160, 9, 0, 0, 3, 0, 1, 0,
172, 9, 0, 0, 2, 0, 1, 0,
60, 0, 0, 0, 12, 0, 0, 0,
47, 0, 0, 0, 11, 0, 0, 0,
0, 0, 1, 0, 44, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
169, 9, 0, 0, 50, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
164, 9, 0, 0, 3, 0, 1, 0,
192, 9, 0, 0, 2, 0, 1, 0,
48, 0, 0, 0, 18, 0, 0, 0,
0, 0, 1, 0, 45, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
189, 9, 0, 0, 114, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
188, 9, 0, 0, 3, 0, 1, 0,
200, 9, 0, 0, 2, 0, 1, 0,
61, 0, 0, 0, 12, 0, 0, 0,
0, 0, 1, 0, 46, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
169, 9, 0, 0, 218, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
176, 9, 0, 0, 3, 0, 1, 0,
188, 9, 0, 0, 2, 0, 1, 0,
29, 0, 0, 0, 19, 0, 0, 0,
0, 0, 1, 0, 47, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
185, 9, 0, 0, 130, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
184, 9, 0, 0, 3, 0, 1, 0,
196, 9, 0, 0, 2, 0, 1, 0,
26, 0, 0, 0, 12, 0, 0, 0,
0, 0, 1, 0, 48, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
193, 9, 0, 0, 114, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
192, 9, 0, 0, 3, 0, 1, 0,
204, 9, 0, 0, 2, 0, 1, 0,
48, 0, 0, 0, 35, 0, 0, 0,
0, 0, 1, 0, 49, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
201, 9, 0, 0, 146, 0, 0, 0,
197, 9, 0, 0, 218, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
204, 9, 0, 0, 3, 0, 1, 0,
216, 9, 0, 0, 2, 0, 1, 0,
49, 0, 0, 0, 40, 0, 0, 0,
0, 0, 1, 0, 50, 0, 0, 0,
29, 0, 0, 0, 19, 0, 0, 0,
0, 0, 1, 0, 47, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
213, 9, 0, 0, 130, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
212, 9, 0, 0, 3, 0, 1, 0,
224, 9, 0, 0, 2, 0, 1, 0,
59, 0, 0, 0, 21, 0, 0, 0,
26, 0, 0, 0, 12, 0, 0, 0,
0, 0, 1, 0, 48, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
221, 9, 0, 0, 114, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
220, 9, 0, 0, 3, 0, 1, 0,
232, 9, 0, 0, 2, 0, 1, 0,
49, 0, 0, 0, 35, 0, 0, 0,
0, 0, 1, 0, 49, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
229, 9, 0, 0, 146, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
232, 9, 0, 0, 3, 0, 1, 0,
244, 9, 0, 0, 2, 0, 1, 0,
50, 0, 0, 0, 40, 0, 0, 0,
0, 0, 1, 0, 50, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
241, 9, 0, 0, 130, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
240, 9, 0, 0, 3, 0, 1, 0,
252, 9, 0, 0, 2, 0, 1, 0,
60, 0, 0, 0, 21, 0, 0, 0,
0, 0, 1, 0, 51, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
221, 9, 0, 0, 178, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
224, 9, 0, 0, 3, 0, 1, 0,
236, 9, 0, 0, 2, 0, 1, 0,
36, 0, 0, 0, 22, 0, 0, 0,
0, 0, 1, 0, 52, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
233, 9, 0, 0, 146, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
236, 9, 0, 0, 3, 0, 1, 0,
248, 9, 0, 0, 2, 0, 1, 0,
61, 0, 0, 0, 23, 0, 0, 0,
0, 0, 1, 0, 53, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
245, 9, 0, 0, 226, 0, 0, 0,
249, 9, 0, 0, 178, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
252, 9, 0, 0, 3, 0, 1, 0,
8, 10, 0, 0, 2, 0, 1, 0,
69, 0, 0, 0, 24, 0, 0, 0,
0, 0, 1, 0, 54, 0, 0, 0,
36, 0, 0, 0, 22, 0, 0, 0,
0, 0, 1, 0, 52, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
5, 10, 0, 0, 242, 0, 0, 0,
5, 10, 0, 0, 146, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
12, 10, 0, 0, 3, 0, 1, 0,
24, 10, 0, 0, 2, 0, 1, 0,
2, 0, 0, 0, 13, 0, 0, 0,
0, 0, 1, 0, 55, 0, 0, 0,
8, 10, 0, 0, 3, 0, 1, 0,
20, 10, 0, 0, 2, 0, 1, 0,
62, 0, 0, 0, 23, 0, 0, 0,
0, 0, 1, 0, 53, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
21, 10, 0, 0, 138, 0, 0, 0,
17, 10, 0, 0, 226, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
24, 10, 0, 0, 3, 0, 1, 0,
36, 10, 0, 0, 2, 0, 1, 0,
70, 0, 0, 0, 24, 0, 0, 0,
0, 0, 1, 0, 54, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
33, 10, 0, 0, 242, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
40, 10, 0, 0, 3, 0, 1, 0,
52, 10, 0, 0, 2, 0, 1, 0,
2, 0, 0, 0, 13, 0, 0, 0,
0, 0, 1, 0, 55, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
49, 10, 0, 0, 138, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
52, 10, 0, 0, 3, 0, 1, 0,
64, 10, 0, 0, 2, 0, 1, 0,
7, 0, 0, 0, 14, 0, 0, 0,
0, 0, 1, 0, 56, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
33, 10, 0, 0, 82, 0, 0, 0,
61, 10, 0, 0, 82, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
32, 10, 0, 0, 3, 0, 1, 0,
44, 10, 0, 0, 2, 0, 1, 0,
55, 0, 0, 0, 15, 0, 0, 0,
60, 10, 0, 0, 3, 0, 1, 0,
72, 10, 0, 0, 2, 0, 1, 0,
56, 0, 0, 0, 15, 0, 0, 0,
0, 0, 1, 0, 57, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
41, 10, 0, 0, 202, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
48, 10, 0, 0, 3, 0, 1, 0,
60, 10, 0, 0, 2, 0, 1, 0,
41, 0, 0, 0, 25, 0, 0, 0,
0, 0, 1, 0, 58, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
57, 10, 0, 0, 34, 1, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
68, 10, 0, 0, 3, 0, 1, 0,
80, 10, 0, 0, 2, 0, 1, 0,
31, 0, 0, 0, 26, 0, 0, 0,
0, 0, 1, 0, 59, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
77, 10, 0, 0, 106, 0, 0, 0,
69, 10, 0, 0, 202, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
76, 10, 0, 0, 3, 0, 1, 0,
88, 10, 0, 0, 2, 0, 1, 0,
35, 0, 0, 0, 27, 0, 0, 0,
0, 0, 1, 0, 60, 0, 0, 0,
41, 0, 0, 0, 25, 0, 0, 0,
0, 0, 1, 0, 58, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
85, 10, 0, 0, 82, 0, 0, 0,
85, 10, 0, 0, 34, 1, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
84, 10, 0, 0, 3, 0, 1, 0,
96, 10, 0, 0, 2, 0, 1, 0,
40, 0, 0, 0, 28, 0, 0, 0,
0, 0, 1, 0, 61, 0, 0, 0,
96, 10, 0, 0, 3, 0, 1, 0,
108, 10, 0, 0, 2, 0, 1, 0,
31, 0, 0, 0, 26, 0, 0, 0,
0, 0, 1, 0, 59, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
93, 10, 0, 0, 34, 1, 0, 0,
105, 10, 0, 0, 106, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
104, 10, 0, 0, 3, 0, 1, 0,
116, 10, 0, 0, 2, 0, 1, 0,
35, 0, 0, 0, 27, 0, 0, 0,
0, 0, 1, 0, 60, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
113, 10, 0, 0, 82, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
112, 10, 0, 0, 3, 0, 1, 0,
124, 10, 0, 0, 2, 0, 1, 0,
40, 0, 0, 0, 28, 0, 0, 0,
0, 0, 1, 0, 61, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
121, 10, 0, 0, 34, 1, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
132, 10, 0, 0, 3, 0, 1, 0,
144, 10, 0, 0, 2, 0, 1, 0,
12, 0, 0, 0, 13, 0, 0, 0,
0, 0, 1, 0, 62, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
113, 10, 0, 0, 114, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
112, 10, 0, 0, 3, 0, 1, 0,
140, 10, 0, 0, 2, 0, 1, 0,
50, 0, 0, 0, 29, 0, 0, 0,
0, 0, 1, 0, 63, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
137, 10, 0, 0, 138, 0, 0, 0,
141, 10, 0, 0, 114, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
140, 10, 0, 0, 3, 0, 1, 0,
152, 10, 0, 0, 2, 0, 1, 0,
8, 0, 0, 0, 30, 0, 0, 0,
0, 0, 1, 0, 64, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
149, 10, 0, 0, 50, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
144, 10, 0, 0, 3, 0, 1, 0,
156, 10, 0, 0, 2, 0, 1, 0,
13, 0, 0, 0, 41, 0, 0, 0,
0, 0, 1, 0, 65, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
153, 10, 0, 0, 178, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
156, 10, 0, 0, 3, 0, 1, 0,
168, 10, 0, 0, 2, 0, 1, 0,
3, 0, 0, 0, 224, 3, 0, 0,
0, 0, 1, 0, 66, 0, 0, 0,
51, 0, 0, 0, 29, 0, 0, 0,
0, 0, 1, 0, 63, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
165, 10, 0, 0, 58, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
160, 10, 0, 0, 3, 0, 1, 0,
172, 10, 0, 0, 2, 0, 1, 0,
14, 0, 0, 0, 32, 0, 0, 0,
0, 0, 1, 0, 68, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
169, 10, 0, 0, 130, 0, 0, 0,
165, 10, 0, 0, 138, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
168, 10, 0, 0, 3, 0, 1, 0,
180, 10, 0, 0, 2, 0, 1, 0,
15, 0, 0, 0, 225, 3, 0, 0,
0, 0, 1, 0, 69, 0, 0, 0,
8, 0, 0, 0, 30, 0, 0, 0,
0, 0, 1, 0, 64, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
177, 10, 0, 0, 114, 0, 0, 0,
177, 10, 0, 0, 50, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
176, 10, 0, 0, 3, 0, 1, 0,
188, 10, 0, 0, 2, 0, 1, 0,
38, 0, 0, 0, 226, 3, 0, 0,
0, 0, 1, 0, 70, 0, 0, 0,
172, 10, 0, 0, 3, 0, 1, 0,
184, 10, 0, 0, 2, 0, 1, 0,
13, 0, 0, 0, 41, 0, 0, 0,
0, 0, 1, 0, 65, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
185, 10, 0, 0, 114, 0, 0, 0,
181, 10, 0, 0, 178, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
184, 10, 0, 0, 3, 0, 1, 0,
196, 10, 0, 0, 2, 0, 1, 0,
9, 0, 0, 0, 227, 3, 0, 0,
0, 0, 1, 0, 71, 0, 0, 0,
3, 0, 0, 0, 224, 3, 0, 0,
0, 0, 1, 0, 66, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
193, 10, 0, 0, 18, 1, 0, 0,
193, 10, 0, 0, 58, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
188, 10, 0, 0, 3, 0, 1, 0,
200, 10, 0, 0, 2, 0, 1, 0,
14, 0, 0, 0, 32, 0, 0, 0,
0, 0, 1, 0, 68, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
197, 10, 0, 0, 130, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
196, 10, 0, 0, 3, 0, 1, 0,
208, 10, 0, 0, 2, 0, 1, 0,
15, 0, 0, 0, 225, 3, 0, 0,
0, 0, 1, 0, 69, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
205, 10, 0, 0, 114, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
204, 10, 0, 0, 3, 0, 1, 0,
216, 10, 0, 0, 2, 0, 1, 0,
38, 0, 0, 0, 226, 3, 0, 0,
0, 0, 1, 0, 70, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
213, 10, 0, 0, 114, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
212, 10, 0, 0, 3, 0, 1, 0,
224, 10, 0, 0, 2, 0, 1, 0,
9, 0, 0, 0, 227, 3, 0, 0,
0, 0, 1, 0, 71, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
221, 10, 0, 0, 18, 1, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
232, 10, 0, 0, 3, 0, 1, 0,
244, 10, 0, 0, 2, 0, 1, 0,
22, 0, 0, 0, 33, 0, 0, 0,
0, 0, 1, 0, 72, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
213, 10, 0, 0, 162, 0, 0, 0,
241, 10, 0, 0, 162, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
216, 10, 0, 0, 3, 0, 1, 0,
228, 10, 0, 0, 2, 0, 1, 0,
244, 10, 0, 0, 3, 0, 1, 0,
0, 11, 0, 0, 2, 0, 1, 0,
45, 0, 0, 0, 228, 3, 0, 0,
0, 0, 1, 0, 73, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
253, 10, 0, 0, 66, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
248, 10, 0, 0, 3, 0, 1, 0,
4, 11, 0, 0, 2, 0, 1, 0,
99, 97, 114, 78, 97, 109, 101, 0,
12, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
@@ -4770,6 +4777,14 @@ static const ::capnp::_::AlignedData<1269> b_8c69372490aaa9da = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
10, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
112, 97, 115, 115, 105, 118, 101, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, }
};
@@ -4787,11 +4802,11 @@ static const ::capnp::_::RawSchema* const d_8c69372490aaa9da[] = {
&s_e836349c6056b0c9,
&s_ff99e3682a833c51,
};
static const uint16_t m_8c69372490aaa9da[] = {63, 66, 15, 16, 1, 42, 0, 37, 19, 44, 39, 29, 6, 54, 4, 5, 2, 68, 47, 62, 53, 13, 14, 55, 38, 46, 26, 59, 56, 25, 17, 65, 52, 7, 49, 8, 48, 64, 36, 3, 43, 34, 22, 60, 9, 40, 10, 31, 51, 67, 35, 33, 27, 45, 11, 12, 32, 20, 21, 58, 30, 50, 69, 23, 24, 41, 57, 28, 61, 18};
static const uint16_t i_8c69372490aaa9da[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 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, 67, 68, 69};
static const uint16_t m_8c69372490aaa9da[] = {63, 66, 15, 16, 1, 42, 0, 37, 19, 44, 39, 29, 6, 54, 4, 5, 2, 68, 47, 62, 53, 13, 14, 55, 38, 46, 26, 59, 56, 25, 17, 65, 52, 7, 49, 8, 48, 64, 36, 70, 3, 43, 34, 22, 60, 9, 40, 10, 31, 51, 67, 35, 33, 27, 45, 11, 12, 32, 20, 21, 58, 30, 50, 69, 23, 24, 41, 57, 28, 61, 18};
static const uint16_t i_8c69372490aaa9da[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 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, 67, 68, 69, 70};
const ::capnp::_::RawSchema s_8c69372490aaa9da = {
0x8c69372490aaa9da, b_8c69372490aaa9da.words, 1269, d_8c69372490aaa9da, m_8c69372490aaa9da,
10, 70, i_8c69372490aaa9da, nullptr, nullptr, { &s_8c69372490aaa9da, nullptr, nullptr, 0, 0, nullptr }
0x8c69372490aaa9da, b_8c69372490aaa9da.words, 1284, d_8c69372490aaa9da, m_8c69372490aaa9da,
10, 71, i_8c69372490aaa9da, nullptr, nullptr, { &s_8c69372490aaa9da, nullptr, nullptr, 0, 0, nullptr }
};
#endif // !CAPNP_LITE
static const ::capnp::_::AlignedData<85> b_e836349c6056b0c9 = {
+19
View File
@@ -2345,6 +2345,8 @@ public:
inline float getTireStiffnessFactor() const;
inline bool getPassive() const;
private:
::capnp::_::StructReader _reader;
template <typename, ::capnp::Kind>
@@ -2641,6 +2643,9 @@ public:
inline float getTireStiffnessFactor();
inline void setTireStiffnessFactor(float value);
inline bool getPassive();
inline void setPassive(bool value);
private:
::capnp::_::StructBuilder _builder;
template <typename, ::capnp::Kind>
@@ -7159,6 +7164,20 @@ inline void CarParams::Builder::setTireStiffnessFactor(float value) {
::capnp::bounded<33>() * ::capnp::ELEMENTS, value);
}
inline bool CarParams::Reader::getPassive() const {
return _reader.getDataField<bool>(
::capnp::bounded<996>() * ::capnp::ELEMENTS);
}
inline bool CarParams::Builder::getPassive() {
return _builder.getDataField<bool>(
::capnp::bounded<996>() * ::capnp::ELEMENTS);
}
inline void CarParams::Builder::setPassive(bool value) {
_builder.setDataField<bool>(
::capnp::bounded<996>() * ::capnp::ELEMENTS, value);
}
inline ::cereal::CarParams::SafetyModel CarParams::SafetyConfig::Reader::getSafetyModel() const {
return _reader.getDataField< ::cereal::CarParams::SafetyModel>(
::capnp::bounded<0>() * ::capnp::ELEMENTS);
+52 -300
View File
@@ -382,17 +382,17 @@ const ::capnp::_::RawSchema s_81c2f05a394cf4af = {
0, 20, i_81c2f05a394cf4af, nullptr, nullptr, { &s_81c2f05a394cf4af, nullptr, nullptr, 0, 0, nullptr }
};
#endif // !CAPNP_LITE
static const ::capnp::_::AlignedData<302> b_aedffd8f31e7b55d = {
static const ::capnp::_::AlignedData<115> b_aedffd8f31e7b55d = {
{ 0, 0, 0, 0, 5, 0, 6, 0,
93, 181, 231, 49, 143, 253, 223, 174,
13, 0, 0, 0, 1, 0, 5, 0,
13, 0, 0, 0, 1, 0, 2, 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, 10, 1, 0, 0,
37, 0, 0, 0, 55, 0, 0, 0,
37, 0, 0, 0, 39, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
101, 0, 0, 0, 135, 3, 0, 0,
81, 0, 0, 0, 31, 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,
@@ -400,137 +400,73 @@ static const ::capnp::_::AlignedData<302> b_aedffd8f31e7b55d = {
103, 105, 116, 117, 100, 105, 110, 97,
108, 80, 108, 97, 110, 69, 120, 116,
0, 0, 0, 0, 0, 0, 0, 0,
12, 0, 0, 0, 1, 0, 1, 0,
8, 0, 0, 0, 1, 0, 1, 0,
206, 31, 115, 238, 186, 117, 42, 180,
17, 0, 0, 0, 210, 0, 0, 0,
2, 8, 153, 155, 54, 132, 119, 158,
25, 0, 0, 0, 186, 0, 0, 0,
9, 0, 0, 0, 210, 0, 0, 0,
218, 174, 84, 82, 132, 78, 18, 209,
29, 0, 0, 0, 210, 0, 0, 0,
17, 0, 0, 0, 210, 0, 0, 0,
76, 111, 110, 103, 105, 116, 117, 100,
105, 110, 97, 108, 80, 108, 97, 110,
69, 120, 116, 83, 111, 117, 114, 99,
101, 0, 0, 0, 0, 0, 0, 0,
83, 112, 101, 101, 100, 76, 105, 109,
105, 116, 67, 111, 110, 116, 114, 111,
108, 83, 116, 97, 116, 101, 0, 0,
86, 105, 115, 105, 111, 110, 84, 117,
114, 110, 67, 111, 110, 116, 114, 111,
108, 108, 101, 114, 83, 116, 97, 116,
101, 0, 0, 0, 0, 0, 0, 0,
64, 0, 0, 0, 3, 0, 4, 0,
20, 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,
177, 1, 0, 0, 210, 0, 0, 0,
125, 0, 0, 0, 122, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
184, 1, 0, 0, 3, 0, 1, 0,
196, 1, 0, 0, 2, 0, 1, 0,
124, 0, 0, 0, 3, 0, 1, 0,
136, 0, 0, 0, 2, 0, 1, 0,
1, 0, 0, 0, 1, 0, 0, 0,
0, 0, 1, 0, 1, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
193, 1, 0, 0, 130, 0, 0, 0,
133, 0, 0, 0, 114, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
192, 1, 0, 0, 3, 0, 1, 0,
204, 1, 0, 0, 2, 0, 1, 0,
132, 0, 0, 0, 3, 0, 1, 0,
144, 0, 0, 0, 2, 0, 1, 0,
2, 0, 0, 0, 1, 0, 0, 0,
0, 0, 1, 0, 2, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
201, 1, 0, 0, 186, 0, 0, 0,
141, 0, 0, 0, 210, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
204, 1, 0, 0, 3, 0, 1, 0,
216, 1, 0, 0, 2, 0, 1, 0,
3, 0, 0, 0, 2, 0, 0, 0,
148, 0, 0, 0, 3, 0, 1, 0,
160, 0, 0, 0, 2, 0, 1, 0,
3, 0, 0, 0, 1, 0, 0, 0,
0, 0, 1, 0, 3, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
213, 1, 0, 0, 90, 0, 0, 0,
157, 0, 0, 0, 130, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
212, 1, 0, 0, 3, 0, 1, 0,
224, 1, 0, 0, 2, 0, 1, 0,
4, 0, 0, 0, 3, 0, 0, 0,
156, 0, 0, 0, 3, 0, 1, 0,
168, 0, 0, 0, 2, 0, 1, 0,
4, 0, 0, 0, 4, 0, 0, 0,
0, 0, 1, 0, 4, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
221, 1, 0, 0, 138, 0, 0, 0,
165, 0, 0, 0, 210, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
224, 1, 0, 0, 3, 0, 1, 0,
236, 1, 0, 0, 2, 0, 1, 0,
5, 0, 0, 0, 4, 0, 0, 0,
0, 0, 1, 0, 5, 0, 0, 0,
172, 0, 0, 0, 3, 0, 1, 0,
184, 0, 0, 0, 2, 0, 1, 0,
100, 112, 69, 50, 69, 73, 115, 66,
108, 101, 110, 100, 101, 100, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
233, 1, 0, 0, 138, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
236, 1, 0, 0, 3, 0, 1, 0,
248, 1, 0, 0, 2, 0, 1, 0,
6, 0, 0, 0, 160, 0, 0, 0,
0, 0, 1, 0, 6, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
245, 1, 0, 0, 130, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
244, 1, 0, 0, 3, 0, 1, 0,
0, 2, 0, 0, 2, 0, 1, 0,
7, 0, 0, 0, 161, 0, 0, 0,
0, 0, 1, 0, 7, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
253, 1, 0, 0, 170, 0, 0, 0,
100, 101, 50, 101, 73, 115, 69, 110,
97, 98, 108, 101, 100, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 2, 0, 0, 3, 0, 1, 0,
12, 2, 0, 0, 2, 0, 1, 0,
8, 0, 0, 0, 6, 0, 0, 0,
0, 0, 1, 0, 8, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
9, 2, 0, 0, 178, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
12, 2, 0, 0, 3, 0, 1, 0,
24, 2, 0, 0, 2, 0, 1, 0,
9, 0, 0, 0, 7, 0, 0, 0,
0, 0, 1, 0, 9, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
21, 2, 0, 0, 90, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
20, 2, 0, 0, 3, 0, 1, 0,
32, 2, 0, 0, 2, 0, 1, 0,
10, 0, 0, 0, 8, 0, 0, 0,
0, 0, 1, 0, 10, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
29, 2, 0, 0, 82, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
28, 2, 0, 0, 3, 0, 1, 0,
40, 2, 0, 0, 2, 0, 1, 0,
11, 0, 0, 0, 11, 0, 0, 0,
0, 0, 1, 0, 11, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
37, 2, 0, 0, 178, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
40, 2, 0, 0, 3, 0, 1, 0,
52, 2, 0, 0, 2, 0, 1, 0,
12, 0, 0, 0, 18, 0, 0, 0,
0, 0, 1, 0, 12, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
49, 2, 0, 0, 74, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
48, 2, 0, 0, 3, 0, 1, 0,
60, 2, 0, 0, 2, 0, 1, 0,
13, 0, 0, 0, 162, 0, 0, 0,
0, 0, 1, 0, 13, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
57, 2, 0, 0, 122, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
56, 2, 0, 0, 3, 0, 1, 0,
68, 2, 0, 0, 2, 0, 1, 0,
14, 0, 0, 0, 19, 0, 0, 0,
0, 0, 1, 0, 14, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
65, 2, 0, 0, 210, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
72, 2, 0, 0, 3, 0, 1, 0,
84, 2, 0, 0, 2, 0, 1, 0,
15, 0, 0, 0, 163, 0, 0, 0,
0, 0, 1, 0, 15, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
81, 2, 0, 0, 114, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
80, 2, 0, 0, 3, 0, 1, 0,
92, 2, 0, 0, 2, 0, 1, 0,
118, 105, 115, 105, 111, 110, 84, 117,
114, 110, 67, 111, 110, 116, 114, 111,
108, 108, 101, 114, 83, 116, 97, 116,
@@ -551,120 +487,6 @@ static const ::capnp::_::AlignedData<302> b_aedffd8f31e7b55d = {
10, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
115, 112, 101, 101, 100, 76, 105, 109,
105, 116, 67, 111, 110, 116, 114, 111,
108, 83, 116, 97, 116, 101, 0, 0,
15, 0, 0, 0, 0, 0, 0, 0,
2, 8, 153, 155, 54, 132, 119, 158,
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,
115, 112, 101, 101, 100, 76, 105, 109,
105, 116, 0, 0, 0, 0, 0, 0,
10, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
10, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
115, 112, 101, 101, 100, 76, 105, 109,
105, 116, 79, 102, 102, 115, 101, 116,
0, 0, 0, 0, 0, 0, 0, 0,
10, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
10, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
100, 105, 115, 116, 84, 111, 83, 112,
101, 101, 100, 76, 105, 109, 105, 116,
0, 0, 0, 0, 0, 0, 0, 0,
10, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
10, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
105, 115, 77, 97, 112, 83, 112, 101,
101, 100, 76, 105, 109, 105, 116, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
115, 112, 101, 101, 100, 76, 105, 109,
105, 116, 80, 101, 114, 99, 79, 102,
102, 115, 101, 116, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
115, 112, 101, 101, 100, 76, 105, 109,
105, 116, 86, 97, 108, 117, 101, 79,
102, 102, 115, 101, 116, 0, 0, 0,
10, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
10, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
100, 105, 115, 116, 84, 111, 84, 117,
114, 110, 0, 0, 0, 0, 0, 0,
10, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
10, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
116, 117, 114, 110, 83, 112, 101, 101,
100, 0, 0, 0, 0, 0, 0, 0,
10, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
10, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
116, 117, 114, 110, 83, 112, 101, 101,
100, 67, 111, 110, 116, 114, 111, 108,
83, 116, 97, 116, 101, 0, 0, 0,
15, 0, 0, 0, 0, 0, 0, 0,
2, 8, 153, 155, 54, 132, 119, 158,
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,
116, 117, 114, 110, 83, 105, 103, 110,
0, 0, 0, 0, 0, 0, 0, 0,
3, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
3, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
100, 112, 69, 50, 69, 73, 115, 66,
108, 101, 110, 100, 101, 100, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
108, 111, 110, 103, 105, 116, 117, 100,
105, 110, 97, 108, 80, 108, 97, 110,
69, 120, 116, 83, 111, 117, 114, 99,
@@ -674,33 +496,23 @@ static const ::capnp::_::AlignedData<302> b_aedffd8f31e7b55d = {
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,
100, 101, 50, 101, 73, 115, 69, 110,
97, 98, 108, 101, 100, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, }
};
::capnp::word const* const bp_aedffd8f31e7b55d = b_aedffd8f31e7b55d.words;
#if !CAPNP_LITE
static const ::capnp::_::RawSchema* const d_aedffd8f31e7b55d[] = {
&s_9e7784369b990802,
&s_b42a75baee731fce,
&s_d1124e845254aeda,
};
static const uint16_t m_aedffd8f31e7b55d[] = {15, 5, 9, 13, 6, 14, 3, 2, 4, 7, 8, 12, 10, 11, 0, 1};
static const uint16_t i_aedffd8f31e7b55d[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
static const uint16_t m_aedffd8f31e7b55d[] = {1, 0, 4, 2, 3};
static const uint16_t i_aedffd8f31e7b55d[] = {0, 1, 2, 3, 4};
const ::capnp::_::RawSchema s_aedffd8f31e7b55d = {
0xaedffd8f31e7b55d, b_aedffd8f31e7b55d.words, 302, d_aedffd8f31e7b55d, m_aedffd8f31e7b55d,
3, 16, i_aedffd8f31e7b55d, nullptr, nullptr, { &s_aedffd8f31e7b55d, nullptr, nullptr, 0, 0, nullptr }
0xaedffd8f31e7b55d, b_aedffd8f31e7b55d.words, 115, d_aedffd8f31e7b55d, m_aedffd8f31e7b55d,
2, 5, i_aedffd8f31e7b55d, nullptr, nullptr, { &s_aedffd8f31e7b55d, nullptr, nullptr, 0, 0, nullptr }
};
#endif // !CAPNP_LITE
static const ::capnp::_::AlignedData<55> b_b42a75baee731fce = {
static const ::capnp::_::AlignedData<46> b_b42a75baee731fce = {
{ 0, 0, 0, 0, 5, 0, 6, 0,
206, 31, 115, 238, 186, 117, 42, 180,
33, 0, 0, 0, 2, 0, 0, 0,
@@ -710,7 +522,7 @@ static const ::capnp::_::AlignedData<55> b_b42a75baee731fce = {
21, 0, 0, 0, 218, 1, 0, 0,
49, 0, 0, 0, 7, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
45, 0, 0, 0, 199, 0, 0, 0,
45, 0, 0, 0, 151, 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,
@@ -722,101 +534,41 @@ static const ::capnp::_::AlignedData<55> b_b42a75baee731fce = {
110, 69, 120, 116, 83, 111, 117, 114,
99, 101, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 1, 0, 1, 0,
32, 0, 0, 0, 1, 0, 2, 0,
24, 0, 0, 0, 1, 0, 2, 0,
0, 0, 0, 0, 0, 0, 0, 0,
89, 0, 0, 0, 58, 0, 0, 0,
65, 0, 0, 0, 58, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
81, 0, 0, 0, 50, 0, 0, 0,
57, 0, 0, 0, 50, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
2, 0, 0, 0, 0, 0, 0, 0,
73, 0, 0, 0, 50, 0, 0, 0,
49, 0, 0, 0, 50, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
3, 0, 0, 0, 0, 0, 0, 0,
65, 0, 0, 0, 50, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
4, 0, 0, 0, 0, 0, 0, 0,
57, 0, 0, 0, 34, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
5, 0, 0, 0, 0, 0, 0, 0,
49, 0, 0, 0, 42, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
6, 0, 0, 0, 0, 0, 0, 0,
41, 0, 0, 0, 50, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
7, 0, 0, 0, 0, 0, 0, 0,
33, 0, 0, 0, 82, 0, 0, 0,
4, 0, 0, 0, 0, 0, 0, 0,
33, 0, 0, 0, 34, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
5, 0, 0, 0, 0, 0, 0, 0,
25, 0, 0, 0, 42, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
99, 114, 117, 105, 115, 101, 0, 0,
108, 101, 97, 100, 48, 0, 0, 0,
108, 101, 97, 100, 49, 0, 0, 0,
108, 101, 97, 100, 50, 0, 0, 0,
101, 50, 101, 0, 0, 0, 0, 0,
116, 117, 114, 110, 0, 0, 0, 0,
108, 105, 109, 105, 116, 0, 0, 0,
116, 117, 114, 110, 108, 105, 109, 105,
116, 0, 0, 0, 0, 0, 0, 0, }
116, 117, 114, 110, 0, 0, 0, 0, }
};
::capnp::word const* const bp_b42a75baee731fce = b_b42a75baee731fce.words;
#if !CAPNP_LITE
static const uint16_t m_b42a75baee731fce[] = {0, 4, 1, 2, 3, 6, 5, 7};
static const uint16_t m_b42a75baee731fce[] = {0, 4, 1, 2, 3, 5};
const ::capnp::_::RawSchema s_b42a75baee731fce = {
0xb42a75baee731fce, b_b42a75baee731fce.words, 55, nullptr, m_b42a75baee731fce,
0, 8, nullptr, nullptr, nullptr, { &s_b42a75baee731fce, nullptr, nullptr, 0, 0, nullptr }
0xb42a75baee731fce, b_b42a75baee731fce.words, 46, nullptr, m_b42a75baee731fce,
0, 6, nullptr, nullptr, nullptr, { &s_b42a75baee731fce, nullptr, nullptr, 0, 0, nullptr }
};
#endif // !CAPNP_LITE
CAPNP_DEFINE_ENUM(LongitudinalPlanExtSource_b42a75baee731fce, b42a75baee731fce);
static const ::capnp::_::AlignedData<40> b_9e7784369b990802 = {
{ 0, 0, 0, 0, 5, 0, 6, 0,
2, 8, 153, 155, 54, 132, 119, 158,
33, 0, 0, 0, 2, 0, 0, 0,
93, 181, 231, 49, 143, 253, 223, 174,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
21, 0, 0, 0, 194, 1, 0, 0,
45, 0, 0, 0, 7, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
41, 0, 0, 0, 103, 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, 76, 111, 110,
103, 105, 116, 117, 100, 105, 110, 97,
108, 80, 108, 97, 110, 69, 120, 116,
46, 83, 112, 101, 101, 100, 76, 105,
109, 105, 116, 67, 111, 110, 116, 114,
111, 108, 83, 116, 97, 116, 101, 0,
0, 0, 0, 0, 1, 0, 1, 0,
16, 0, 0, 0, 1, 0, 2, 0,
0, 0, 0, 0, 0, 0, 0, 0,
41, 0, 0, 0, 74, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
37, 0, 0, 0, 106, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
2, 0, 0, 0, 0, 0, 0, 0,
33, 0, 0, 0, 74, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
3, 0, 0, 0, 0, 0, 0, 0,
29, 0, 0, 0, 58, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
105, 110, 97, 99, 116, 105, 118, 101,
0, 0, 0, 0, 0, 0, 0, 0,
116, 101, 109, 112, 73, 110, 97, 99,
116, 105, 118, 101, 0, 0, 0, 0,
97, 100, 97, 112, 116, 105, 110, 103,
0, 0, 0, 0, 0, 0, 0, 0,
97, 99, 116, 105, 118, 101, 0, 0, }
};
::capnp::word const* const bp_9e7784369b990802 = b_9e7784369b990802.words;
#if !CAPNP_LITE
static const uint16_t m_9e7784369b990802[] = {3, 2, 0, 1};
const ::capnp::_::RawSchema s_9e7784369b990802 = {
0x9e7784369b990802, b_9e7784369b990802.words, 40, nullptr, m_9e7784369b990802,
0, 4, nullptr, nullptr, nullptr, { &s_9e7784369b990802, nullptr, nullptr, 0, 0, nullptr }
};
#endif // !CAPNP_LITE
CAPNP_DEFINE_ENUM(SpeedLimitControlState_9e7784369b990802, 9e7784369b990802);
static const ::capnp::_::AlignedData<40> b_d1124e845254aeda = {
{ 0, 0, 0, 0, 5, 0, 6, 0,
218, 174, 84, 82, 132, 78, 18, 209,
+45 -266
View File
@@ -24,18 +24,8 @@ enum class LongitudinalPlanExtSource_b42a75baee731fce: uint16_t {
LEAD2,
E2E,
TURN,
LIMIT,
TURNLIMIT,
};
CAPNP_DECLARE_ENUM(LongitudinalPlanExtSource, b42a75baee731fce);
CAPNP_DECLARE_SCHEMA(9e7784369b990802);
enum class SpeedLimitControlState_9e7784369b990802: uint16_t {
INACTIVE,
TEMP_INACTIVE,
ADAPTING,
ACTIVE,
};
CAPNP_DECLARE_ENUM(SpeedLimitControlState, 9e7784369b990802);
CAPNP_DECLARE_SCHEMA(d1124e845254aeda);
enum class VisionTurnControllerState_d1124e845254aeda: uint16_t {
DISABLED,
@@ -81,13 +71,11 @@ struct LongitudinalPlanExt {
class Pipeline;
typedef ::capnp::schemas::LongitudinalPlanExtSource_b42a75baee731fce LongitudinalPlanExtSource;
typedef ::capnp::schemas::SpeedLimitControlState_9e7784369b990802 SpeedLimitControlState;
typedef ::capnp::schemas::VisionTurnControllerState_d1124e845254aeda VisionTurnControllerState;
struct _capnpPrivate {
CAPNP_DECLARE_STRUCT_HEADER(aedffd8f31e7b55d, 5, 0)
CAPNP_DECLARE_STRUCT_HEADER(aedffd8f31e7b55d, 2, 0)
#if !CAPNP_LITE
static constexpr ::capnp::_::RawBrandedSchema const* brand() { return &schema->defaultBrand; }
#endif // !CAPNP_LITE
@@ -427,38 +415,16 @@ public:
}
#endif // !CAPNP_LITE
inline bool getDpE2EIsBlended() const;
inline bool getDe2eIsEnabled() const;
inline ::cereal::LongitudinalPlanExt::VisionTurnControllerState getVisionTurnControllerState() const;
inline float getVisionTurnSpeed() const;
inline ::cereal::LongitudinalPlanExt::SpeedLimitControlState getSpeedLimitControlState() const;
inline float getSpeedLimit() const;
inline float getSpeedLimitOffset() const;
inline float getDistToSpeedLimit() const;
inline bool getIsMapSpeedLimit() const;
inline bool getSpeedLimitPercOffset() const;
inline float getSpeedLimitValueOffset() const;
inline float getDistToTurn() const;
inline float getTurnSpeed() const;
inline ::cereal::LongitudinalPlanExt::SpeedLimitControlState getTurnSpeedControlState() const;
inline ::int16_t getTurnSign() const;
inline bool getDpE2EIsBlended() const;
inline ::cereal::LongitudinalPlanExt::LongitudinalPlanExtSource getLongitudinalPlanExtSource() const;
inline bool getDe2eIsEnabled() const;
private:
::capnp::_::StructReader _reader;
template <typename, ::capnp::Kind>
@@ -487,54 +453,21 @@ public:
inline ::kj::StringTree toString() const { return asReader().toString(); }
#endif // !CAPNP_LITE
inline bool getDpE2EIsBlended();
inline void setDpE2EIsBlended(bool value);
inline bool getDe2eIsEnabled();
inline void setDe2eIsEnabled(bool value);
inline ::cereal::LongitudinalPlanExt::VisionTurnControllerState getVisionTurnControllerState();
inline void setVisionTurnControllerState( ::cereal::LongitudinalPlanExt::VisionTurnControllerState value);
inline float getVisionTurnSpeed();
inline void setVisionTurnSpeed(float value);
inline ::cereal::LongitudinalPlanExt::SpeedLimitControlState getSpeedLimitControlState();
inline void setSpeedLimitControlState( ::cereal::LongitudinalPlanExt::SpeedLimitControlState value);
inline float getSpeedLimit();
inline void setSpeedLimit(float value);
inline float getSpeedLimitOffset();
inline void setSpeedLimitOffset(float value);
inline float getDistToSpeedLimit();
inline void setDistToSpeedLimit(float value);
inline bool getIsMapSpeedLimit();
inline void setIsMapSpeedLimit(bool value);
inline bool getSpeedLimitPercOffset();
inline void setSpeedLimitPercOffset(bool value);
inline float getSpeedLimitValueOffset();
inline void setSpeedLimitValueOffset(float value);
inline float getDistToTurn();
inline void setDistToTurn(float value);
inline float getTurnSpeed();
inline void setTurnSpeed(float value);
inline ::cereal::LongitudinalPlanExt::SpeedLimitControlState getTurnSpeedControlState();
inline void setTurnSpeedControlState( ::cereal::LongitudinalPlanExt::SpeedLimitControlState value);
inline ::int16_t getTurnSign();
inline void setTurnSign( ::int16_t value);
inline bool getDpE2EIsBlended();
inline void setDpE2EIsBlended(bool value);
inline ::cereal::LongitudinalPlanExt::LongitudinalPlanExtSource getLongitudinalPlanExtSource();
inline void setLongitudinalPlanExtSource( ::cereal::LongitudinalPlanExt::LongitudinalPlanExtSource value);
inline bool getDe2eIsEnabled();
inline void setDe2eIsEnabled(bool value);
private:
::capnp::_::StructBuilder _builder;
template <typename, ::capnp::Kind>
@@ -1535,18 +1468,46 @@ inline void LiveMapData::Builder::setLastGpsBearingAccuracyDeg(float value) {
::capnp::bounded<15>() * ::capnp::ELEMENTS, value);
}
inline bool LongitudinalPlanExt::Reader::getDpE2EIsBlended() const {
return _reader.getDataField<bool>(
::capnp::bounded<0>() * ::capnp::ELEMENTS);
}
inline bool LongitudinalPlanExt::Builder::getDpE2EIsBlended() {
return _builder.getDataField<bool>(
::capnp::bounded<0>() * ::capnp::ELEMENTS);
}
inline void LongitudinalPlanExt::Builder::setDpE2EIsBlended(bool value) {
_builder.setDataField<bool>(
::capnp::bounded<0>() * ::capnp::ELEMENTS, value);
}
inline bool LongitudinalPlanExt::Reader::getDe2eIsEnabled() const {
return _reader.getDataField<bool>(
::capnp::bounded<1>() * ::capnp::ELEMENTS);
}
inline bool LongitudinalPlanExt::Builder::getDe2eIsEnabled() {
return _builder.getDataField<bool>(
::capnp::bounded<1>() * ::capnp::ELEMENTS);
}
inline void LongitudinalPlanExt::Builder::setDe2eIsEnabled(bool value) {
_builder.setDataField<bool>(
::capnp::bounded<1>() * ::capnp::ELEMENTS, value);
}
inline ::cereal::LongitudinalPlanExt::VisionTurnControllerState LongitudinalPlanExt::Reader::getVisionTurnControllerState() const {
return _reader.getDataField< ::cereal::LongitudinalPlanExt::VisionTurnControllerState>(
::capnp::bounded<0>() * ::capnp::ELEMENTS);
::capnp::bounded<1>() * ::capnp::ELEMENTS);
}
inline ::cereal::LongitudinalPlanExt::VisionTurnControllerState LongitudinalPlanExt::Builder::getVisionTurnControllerState() {
return _builder.getDataField< ::cereal::LongitudinalPlanExt::VisionTurnControllerState>(
::capnp::bounded<0>() * ::capnp::ELEMENTS);
::capnp::bounded<1>() * ::capnp::ELEMENTS);
}
inline void LongitudinalPlanExt::Builder::setVisionTurnControllerState( ::cereal::LongitudinalPlanExt::VisionTurnControllerState value) {
_builder.setDataField< ::cereal::LongitudinalPlanExt::VisionTurnControllerState>(
::capnp::bounded<0>() * ::capnp::ELEMENTS, value);
::capnp::bounded<1>() * ::capnp::ELEMENTS, value);
}
inline float LongitudinalPlanExt::Reader::getVisionTurnSpeed() const {
@@ -1563,200 +1524,18 @@ inline void LongitudinalPlanExt::Builder::setVisionTurnSpeed(float value) {
::capnp::bounded<1>() * ::capnp::ELEMENTS, value);
}
inline ::cereal::LongitudinalPlanExt::SpeedLimitControlState LongitudinalPlanExt::Reader::getSpeedLimitControlState() const {
return _reader.getDataField< ::cereal::LongitudinalPlanExt::SpeedLimitControlState>(
::capnp::bounded<1>() * ::capnp::ELEMENTS);
}
inline ::cereal::LongitudinalPlanExt::SpeedLimitControlState LongitudinalPlanExt::Builder::getSpeedLimitControlState() {
return _builder.getDataField< ::cereal::LongitudinalPlanExt::SpeedLimitControlState>(
::capnp::bounded<1>() * ::capnp::ELEMENTS);
}
inline void LongitudinalPlanExt::Builder::setSpeedLimitControlState( ::cereal::LongitudinalPlanExt::SpeedLimitControlState value) {
_builder.setDataField< ::cereal::LongitudinalPlanExt::SpeedLimitControlState>(
::capnp::bounded<1>() * ::capnp::ELEMENTS, value);
}
inline float LongitudinalPlanExt::Reader::getSpeedLimit() const {
return _reader.getDataField<float>(
::capnp::bounded<2>() * ::capnp::ELEMENTS);
}
inline float LongitudinalPlanExt::Builder::getSpeedLimit() {
return _builder.getDataField<float>(
::capnp::bounded<2>() * ::capnp::ELEMENTS);
}
inline void LongitudinalPlanExt::Builder::setSpeedLimit(float value) {
_builder.setDataField<float>(
::capnp::bounded<2>() * ::capnp::ELEMENTS, value);
}
inline float LongitudinalPlanExt::Reader::getSpeedLimitOffset() const {
return _reader.getDataField<float>(
::capnp::bounded<3>() * ::capnp::ELEMENTS);
}
inline float LongitudinalPlanExt::Builder::getSpeedLimitOffset() {
return _builder.getDataField<float>(
::capnp::bounded<3>() * ::capnp::ELEMENTS);
}
inline void LongitudinalPlanExt::Builder::setSpeedLimitOffset(float value) {
_builder.setDataField<float>(
::capnp::bounded<3>() * ::capnp::ELEMENTS, value);
}
inline float LongitudinalPlanExt::Reader::getDistToSpeedLimit() const {
return _reader.getDataField<float>(
::capnp::bounded<4>() * ::capnp::ELEMENTS);
}
inline float LongitudinalPlanExt::Builder::getDistToSpeedLimit() {
return _builder.getDataField<float>(
::capnp::bounded<4>() * ::capnp::ELEMENTS);
}
inline void LongitudinalPlanExt::Builder::setDistToSpeedLimit(float value) {
_builder.setDataField<float>(
::capnp::bounded<4>() * ::capnp::ELEMENTS, value);
}
inline bool LongitudinalPlanExt::Reader::getIsMapSpeedLimit() const {
return _reader.getDataField<bool>(
::capnp::bounded<160>() * ::capnp::ELEMENTS);
}
inline bool LongitudinalPlanExt::Builder::getIsMapSpeedLimit() {
return _builder.getDataField<bool>(
::capnp::bounded<160>() * ::capnp::ELEMENTS);
}
inline void LongitudinalPlanExt::Builder::setIsMapSpeedLimit(bool value) {
_builder.setDataField<bool>(
::capnp::bounded<160>() * ::capnp::ELEMENTS, value);
}
inline bool LongitudinalPlanExt::Reader::getSpeedLimitPercOffset() const {
return _reader.getDataField<bool>(
::capnp::bounded<161>() * ::capnp::ELEMENTS);
}
inline bool LongitudinalPlanExt::Builder::getSpeedLimitPercOffset() {
return _builder.getDataField<bool>(
::capnp::bounded<161>() * ::capnp::ELEMENTS);
}
inline void LongitudinalPlanExt::Builder::setSpeedLimitPercOffset(bool value) {
_builder.setDataField<bool>(
::capnp::bounded<161>() * ::capnp::ELEMENTS, value);
}
inline float LongitudinalPlanExt::Reader::getSpeedLimitValueOffset() const {
return _reader.getDataField<float>(
::capnp::bounded<6>() * ::capnp::ELEMENTS);
}
inline float LongitudinalPlanExt::Builder::getSpeedLimitValueOffset() {
return _builder.getDataField<float>(
::capnp::bounded<6>() * ::capnp::ELEMENTS);
}
inline void LongitudinalPlanExt::Builder::setSpeedLimitValueOffset(float value) {
_builder.setDataField<float>(
::capnp::bounded<6>() * ::capnp::ELEMENTS, value);
}
inline float LongitudinalPlanExt::Reader::getDistToTurn() const {
return _reader.getDataField<float>(
::capnp::bounded<7>() * ::capnp::ELEMENTS);
}
inline float LongitudinalPlanExt::Builder::getDistToTurn() {
return _builder.getDataField<float>(
::capnp::bounded<7>() * ::capnp::ELEMENTS);
}
inline void LongitudinalPlanExt::Builder::setDistToTurn(float value) {
_builder.setDataField<float>(
::capnp::bounded<7>() * ::capnp::ELEMENTS, value);
}
inline float LongitudinalPlanExt::Reader::getTurnSpeed() const {
return _reader.getDataField<float>(
::capnp::bounded<8>() * ::capnp::ELEMENTS);
}
inline float LongitudinalPlanExt::Builder::getTurnSpeed() {
return _builder.getDataField<float>(
::capnp::bounded<8>() * ::capnp::ELEMENTS);
}
inline void LongitudinalPlanExt::Builder::setTurnSpeed(float value) {
_builder.setDataField<float>(
::capnp::bounded<8>() * ::capnp::ELEMENTS, value);
}
inline ::cereal::LongitudinalPlanExt::SpeedLimitControlState LongitudinalPlanExt::Reader::getTurnSpeedControlState() const {
return _reader.getDataField< ::cereal::LongitudinalPlanExt::SpeedLimitControlState>(
::capnp::bounded<11>() * ::capnp::ELEMENTS);
}
inline ::cereal::LongitudinalPlanExt::SpeedLimitControlState LongitudinalPlanExt::Builder::getTurnSpeedControlState() {
return _builder.getDataField< ::cereal::LongitudinalPlanExt::SpeedLimitControlState>(
::capnp::bounded<11>() * ::capnp::ELEMENTS);
}
inline void LongitudinalPlanExt::Builder::setTurnSpeedControlState( ::cereal::LongitudinalPlanExt::SpeedLimitControlState value) {
_builder.setDataField< ::cereal::LongitudinalPlanExt::SpeedLimitControlState>(
::capnp::bounded<11>() * ::capnp::ELEMENTS, value);
}
inline ::int16_t LongitudinalPlanExt::Reader::getTurnSign() const {
return _reader.getDataField< ::int16_t>(
::capnp::bounded<18>() * ::capnp::ELEMENTS);
}
inline ::int16_t LongitudinalPlanExt::Builder::getTurnSign() {
return _builder.getDataField< ::int16_t>(
::capnp::bounded<18>() * ::capnp::ELEMENTS);
}
inline void LongitudinalPlanExt::Builder::setTurnSign( ::int16_t value) {
_builder.setDataField< ::int16_t>(
::capnp::bounded<18>() * ::capnp::ELEMENTS, value);
}
inline bool LongitudinalPlanExt::Reader::getDpE2EIsBlended() const {
return _reader.getDataField<bool>(
::capnp::bounded<162>() * ::capnp::ELEMENTS);
}
inline bool LongitudinalPlanExt::Builder::getDpE2EIsBlended() {
return _builder.getDataField<bool>(
::capnp::bounded<162>() * ::capnp::ELEMENTS);
}
inline void LongitudinalPlanExt::Builder::setDpE2EIsBlended(bool value) {
_builder.setDataField<bool>(
::capnp::bounded<162>() * ::capnp::ELEMENTS, value);
}
inline ::cereal::LongitudinalPlanExt::LongitudinalPlanExtSource LongitudinalPlanExt::Reader::getLongitudinalPlanExtSource() const {
return _reader.getDataField< ::cereal::LongitudinalPlanExt::LongitudinalPlanExtSource>(
::capnp::bounded<19>() * ::capnp::ELEMENTS);
::capnp::bounded<4>() * ::capnp::ELEMENTS);
}
inline ::cereal::LongitudinalPlanExt::LongitudinalPlanExtSource LongitudinalPlanExt::Builder::getLongitudinalPlanExtSource() {
return _builder.getDataField< ::cereal::LongitudinalPlanExt::LongitudinalPlanExtSource>(
::capnp::bounded<19>() * ::capnp::ELEMENTS);
::capnp::bounded<4>() * ::capnp::ELEMENTS);
}
inline void LongitudinalPlanExt::Builder::setLongitudinalPlanExtSource( ::cereal::LongitudinalPlanExt::LongitudinalPlanExtSource value) {
_builder.setDataField< ::cereal::LongitudinalPlanExt::LongitudinalPlanExtSource>(
::capnp::bounded<19>() * ::capnp::ELEMENTS, value);
}
inline bool LongitudinalPlanExt::Reader::getDe2eIsEnabled() const {
return _reader.getDataField<bool>(
::capnp::bounded<163>() * ::capnp::ELEMENTS);
}
inline bool LongitudinalPlanExt::Builder::getDe2eIsEnabled() {
return _builder.getDataField<bool>(
::capnp::bounded<163>() * ::capnp::ELEMENTS);
}
inline void LongitudinalPlanExt::Builder::setDe2eIsEnabled(bool value) {
_builder.setDataField<bool>(
::capnp::bounded<163>() * ::capnp::ELEMENTS, value);
::capnp::bounded<4>() * ::capnp::ELEMENTS, value);
}
inline bool LateralPlanExt::Reader::hasDPathWLinesX() const {
+146 -140
View File
@@ -2202,7 +2202,7 @@ const ::capnp::_::RawSchema s_ddb169f01e102879 = {
};
#endif // !CAPNP_LITE
CAPNP_DEFINE_ENUM(FrameType_ddb169f01e102879, ddb169f01e102879);
static const ::capnp::_::AlignedData<30> b_d810b1e7705dd69c = {
static const ::capnp::_::AlignedData<34> b_d810b1e7705dd69c = {
{ 0, 0, 0, 0, 5, 0, 6, 0,
156, 214, 93, 112, 231, 177, 16, 216,
20, 0, 0, 0, 2, 0, 0, 0,
@@ -2212,7 +2212,7 @@ static const ::capnp::_::AlignedData<30> b_d810b1e7705dd69c = {
21, 0, 0, 0, 2, 1, 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,
29, 0, 0, 0, 103, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
108, 111, 103, 46, 99, 97, 112, 110,
@@ -2220,26 +2220,30 @@ static const ::capnp::_::AlignedData<30> b_d810b1e7705dd69c = {
97, 116, 97, 46, 73, 109, 97, 103,
101, 83, 101, 110, 115, 111, 114, 0,
0, 0, 0, 0, 1, 0, 1, 0,
12, 0, 0, 0, 1, 0, 2, 0,
16, 0, 0, 0, 1, 0, 2, 0,
0, 0, 0, 0, 0, 0, 0, 0,
29, 0, 0, 0, 66, 0, 0, 0,
41, 0, 0, 0, 66, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
21, 0, 0, 0, 58, 0, 0, 0,
33, 0, 0, 0, 58, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
2, 0, 0, 0, 0, 0, 0, 0,
13, 0, 0, 0, 66, 0, 0, 0,
25, 0, 0, 0, 66, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
3, 0, 0, 0, 0, 0, 0, 0,
17, 0, 0, 0, 66, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
117, 110, 107, 110, 111, 119, 110, 0,
97, 114, 48, 50, 51, 49, 0, 0,
111, 120, 48, 51, 99, 49, 48, 0, }
111, 120, 48, 51, 99, 49, 48, 0,
111, 115, 48, 52, 99, 49, 48, 0, }
};
::capnp::word const* const bp_d810b1e7705dd69c = b_d810b1e7705dd69c.words;
#if !CAPNP_LITE
static const uint16_t m_d810b1e7705dd69c[] = {1, 2, 0};
static const uint16_t m_d810b1e7705dd69c[] = {1, 3, 2, 0};
const ::capnp::_::RawSchema s_d810b1e7705dd69c = {
0xd810b1e7705dd69c, b_d810b1e7705dd69c.words, 30, nullptr, m_d810b1e7705dd69c,
0, 3, nullptr, nullptr, nullptr, { &s_d810b1e7705dd69c, nullptr, nullptr, 0, 0, nullptr }
0xd810b1e7705dd69c, b_d810b1e7705dd69c.words, 34, nullptr, m_d810b1e7705dd69c,
0, 4, nullptr, nullptr, nullptr, { &s_d810b1e7705dd69c, nullptr, nullptr, 0, 0, nullptr }
};
#endif // !CAPNP_LITE
CAPNP_DEFINE_ENUM(ImageSensor_d810b1e7705dd69c, d810b1e7705dd69c);
@@ -4618,7 +4622,7 @@ const ::capnp::_::RawSchema s_b98c64ea27898ea0 = {
0, 2, i_b98c64ea27898ea0, nullptr, nullptr, { &s_b98c64ea27898ea0, nullptr, nullptr, 0, 0, nullptr }
};
#endif // !CAPNP_LITE
static const ::capnp::_::AlignedData<643> b_a7649e2575e4591e = {
static const ::capnp::_::AlignedData<645> b_a7649e2575e4591e = {
{ 0, 0, 0, 0, 5, 0, 6, 0,
30, 89, 228, 117, 37, 158, 100, 167,
10, 0, 0, 0, 1, 0, 9, 0,
@@ -4656,14 +4660,14 @@ static const ::capnp::_::AlignedData<643> b_a7649e2575e4591e = {
80, 97, 110, 100, 97, 67, 97, 110,
83, 116, 97, 116, 101, 0, 0, 0,
148, 0, 0, 0, 3, 0, 4, 0,
29, 0, 0, 0, 0, 0, 0, 0,
28, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
253, 3, 0, 0, 66, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
248, 3, 0, 0, 3, 0, 1, 0,
4, 4, 0, 0, 2, 0, 1, 0,
30, 0, 0, 0, 1, 0, 0, 0,
29, 0, 0, 0, 1, 0, 0, 0,
0, 0, 1, 0, 1, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 4, 0, 0, 66, 0, 0, 0,
@@ -4677,244 +4681,244 @@ static const ::capnp::_::AlignedData<643> b_a7649e2575e4591e = {
0, 0, 0, 0, 0, 0, 0, 0,
4, 4, 0, 0, 3, 0, 1, 0,
16, 4, 0, 0, 2, 0, 1, 0,
22, 0, 0, 0, 65, 0, 0, 0,
21, 0, 0, 0, 65, 0, 0, 0,
0, 0, 1, 0, 3, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
13, 4, 0, 0, 130, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
12, 4, 0, 0, 3, 0, 1, 0,
24, 4, 0, 0, 2, 0, 1, 0,
1, 0, 0, 0, 66, 0, 0, 0,
30, 0, 0, 0, 66, 0, 0, 0,
0, 0, 1, 0, 4, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
21, 4, 0, 0, 186, 0, 0, 0,
21, 4, 0, 0, 10, 1, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
24, 4, 0, 0, 3, 0, 1, 0,
36, 4, 0, 0, 2, 0, 1, 0,
32, 4, 0, 0, 3, 0, 1, 0,
44, 4, 0, 0, 2, 0, 1, 0,
31, 0, 0, 0, 67, 0, 0, 0,
0, 0, 1, 0, 5, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
33, 4, 0, 0, 2, 1, 0, 0,
41, 4, 0, 0, 2, 1, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
40, 4, 0, 0, 3, 0, 1, 0,
52, 4, 0, 0, 2, 0, 1, 0,
48, 4, 0, 0, 3, 0, 1, 0,
60, 4, 0, 0, 2, 0, 1, 0,
32, 0, 0, 0, 68, 0, 0, 0,
0, 0, 1, 0, 6, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
49, 4, 0, 0, 138, 0, 0, 0,
57, 4, 0, 0, 138, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
52, 4, 0, 0, 3, 0, 1, 0,
64, 4, 0, 0, 2, 0, 1, 0,
2, 0, 0, 0, 3, 0, 0, 0,
60, 4, 0, 0, 3, 0, 1, 0,
72, 4, 0, 0, 2, 0, 1, 0,
1, 0, 0, 0, 3, 0, 0, 0,
0, 0, 1, 0, 7, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
61, 4, 0, 0, 138, 0, 0, 0,
69, 4, 0, 0, 138, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
64, 4, 0, 0, 3, 0, 1, 0,
76, 4, 0, 0, 2, 0, 1, 0,
3, 0, 0, 0, 4, 0, 0, 0,
72, 4, 0, 0, 3, 0, 1, 0,
84, 4, 0, 0, 2, 0, 1, 0,
2, 0, 0, 0, 4, 0, 0, 0,
0, 0, 1, 0, 8, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
73, 4, 0, 0, 138, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
76, 4, 0, 0, 3, 0, 1, 0,
88, 4, 0, 0, 2, 0, 1, 0,
4, 0, 0, 0, 5, 0, 0, 0,
0, 0, 1, 0, 9, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
85, 4, 0, 0, 114, 0, 0, 0,
81, 4, 0, 0, 138, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
84, 4, 0, 0, 3, 0, 1, 0,
96, 4, 0, 0, 2, 0, 1, 0,
5, 0, 0, 0, 5, 0, 0, 0,
0, 0, 1, 0, 10, 0, 0, 0,
3, 0, 0, 0, 5, 0, 0, 0,
0, 0, 1, 0, 9, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
93, 4, 0, 0, 82, 0, 0, 0,
93, 4, 0, 0, 114, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
92, 4, 0, 0, 3, 0, 1, 0,
104, 4, 0, 0, 2, 0, 1, 0,
4, 0, 0, 0, 5, 0, 0, 0,
0, 0, 1, 0, 10, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
101, 4, 0, 0, 82, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
100, 4, 0, 0, 3, 0, 1, 0,
112, 4, 0, 0, 2, 0, 1, 0,
33, 0, 0, 0, 12, 0, 0, 0,
0, 0, 1, 0, 11, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
101, 4, 0, 0, 178, 0, 0, 0,
109, 4, 0, 0, 178, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
104, 4, 0, 0, 3, 0, 1, 0,
116, 4, 0, 0, 2, 0, 1, 0,
112, 4, 0, 0, 3, 0, 1, 0,
124, 4, 0, 0, 2, 0, 1, 0,
34, 0, 0, 0, 13, 0, 0, 0,
0, 0, 1, 0, 12, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
113, 4, 0, 0, 186, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
116, 4, 0, 0, 3, 0, 1, 0,
128, 4, 0, 0, 2, 0, 1, 0,
6, 0, 0, 0, 69, 0, 0, 0,
0, 0, 1, 0, 13, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
125, 4, 0, 0, 98, 0, 0, 0,
121, 4, 0, 0, 186, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
124, 4, 0, 0, 3, 0, 1, 0,
136, 4, 0, 0, 2, 0, 1, 0,
25, 0, 0, 0, 14, 0, 0, 0,
0, 0, 1, 0, 14, 0, 0, 0,
5, 0, 0, 0, 69, 0, 0, 0,
0, 0, 1, 0, 13, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
133, 4, 0, 0, 98, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
132, 4, 0, 0, 3, 0, 1, 0,
144, 4, 0, 0, 2, 0, 1, 0,
7, 0, 0, 0, 15, 0, 0, 0,
0, 0, 1, 0, 15, 0, 0, 0,
24, 0, 0, 0, 14, 0, 0, 0,
0, 0, 1, 0, 14, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
141, 4, 0, 0, 98, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
140, 4, 0, 0, 3, 0, 1, 0,
152, 4, 0, 0, 2, 0, 1, 0,
8, 0, 0, 0, 70, 0, 0, 0,
6, 0, 0, 0, 15, 0, 0, 0,
0, 0, 1, 0, 15, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
149, 4, 0, 0, 98, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
148, 4, 0, 0, 3, 0, 1, 0,
160, 4, 0, 0, 2, 0, 1, 0,
7, 0, 0, 0, 70, 0, 0, 0,
0, 0, 1, 0, 16, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
149, 4, 0, 0, 138, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
152, 4, 0, 0, 3, 0, 1, 0,
164, 4, 0, 0, 2, 0, 1, 0,
9, 0, 0, 0, 8, 0, 0, 0,
0, 0, 1, 0, 17, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
161, 4, 0, 0, 58, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
156, 4, 0, 0, 3, 0, 1, 0,
168, 4, 0, 0, 2, 0, 1, 0,
10, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1, 0, 18, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
165, 4, 0, 0, 58, 0, 0, 0,
157, 4, 0, 0, 138, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
160, 4, 0, 0, 3, 0, 1, 0,
188, 4, 0, 0, 2, 0, 1, 0,
23, 0, 0, 0, 9, 0, 0, 0,
172, 4, 0, 0, 2, 0, 1, 0,
8, 0, 0, 0, 8, 0, 0, 0,
0, 0, 1, 0, 17, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
169, 4, 0, 0, 58, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
164, 4, 0, 0, 3, 0, 1, 0,
176, 4, 0, 0, 2, 0, 1, 0,
9, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1, 0, 18, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
173, 4, 0, 0, 58, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
168, 4, 0, 0, 3, 0, 1, 0,
196, 4, 0, 0, 2, 0, 1, 0,
22, 0, 0, 0, 9, 0, 0, 0,
0, 0, 1, 0, 19, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
185, 4, 0, 0, 130, 0, 0, 0,
193, 4, 0, 0, 130, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
184, 4, 0, 0, 3, 0, 1, 0,
196, 4, 0, 0, 2, 0, 1, 0,
192, 4, 0, 0, 3, 0, 1, 0,
204, 4, 0, 0, 2, 0, 1, 0,
35, 0, 0, 0, 20, 0, 0, 0,
0, 0, 1, 0, 20, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
193, 4, 0, 0, 178, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
196, 4, 0, 0, 3, 0, 1, 0,
208, 4, 0, 0, 2, 0, 1, 0,
16, 0, 0, 0, 21, 0, 0, 0,
0, 0, 1, 0, 21, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
205, 4, 0, 0, 114, 0, 0, 0,
201, 4, 0, 0, 178, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
204, 4, 0, 0, 3, 0, 1, 0,
216, 4, 0, 0, 2, 0, 1, 0,
11, 0, 0, 0, 71, 0, 0, 0,
0, 0, 1, 0, 22, 0, 0, 0,
15, 0, 0, 0, 21, 0, 0, 0,
0, 0, 1, 0, 21, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
213, 4, 0, 0, 114, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
212, 4, 0, 0, 3, 0, 1, 0,
224, 4, 0, 0, 2, 0, 1, 0,
27, 0, 0, 0, 22, 0, 0, 0,
10, 0, 0, 0, 71, 0, 0, 0,
0, 0, 1, 0, 22, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
221, 4, 0, 0, 114, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
220, 4, 0, 0, 3, 0, 1, 0,
232, 4, 0, 0, 2, 0, 1, 0,
26, 0, 0, 0, 22, 0, 0, 0,
0, 0, 1, 0, 23, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
221, 4, 0, 0, 178, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
224, 4, 0, 0, 3, 0, 1, 0,
236, 4, 0, 0, 2, 0, 1, 0,
24, 0, 0, 0, 12, 0, 0, 0,
0, 0, 1, 0, 24, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
233, 4, 0, 0, 130, 0, 0, 0,
229, 4, 0, 0, 178, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
232, 4, 0, 0, 3, 0, 1, 0,
244, 4, 0, 0, 2, 0, 1, 0,
12, 0, 0, 0, 13, 0, 0, 0,
0, 0, 1, 0, 25, 0, 0, 0,
23, 0, 0, 0, 12, 0, 0, 0,
0, 0, 1, 0, 24, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
241, 4, 0, 0, 114, 0, 0, 0,
241, 4, 0, 0, 130, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
240, 4, 0, 0, 3, 0, 1, 0,
252, 4, 0, 0, 2, 0, 1, 0,
11, 0, 0, 0, 13, 0, 0, 0,
0, 0, 1, 0, 25, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
249, 4, 0, 0, 114, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
248, 4, 0, 0, 3, 0, 1, 0,
4, 5, 0, 0, 2, 0, 1, 0,
36, 0, 0, 0, 14, 0, 0, 0,
0, 0, 1, 0, 26, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
249, 4, 0, 0, 186, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
252, 4, 0, 0, 3, 0, 1, 0,
8, 5, 0, 0, 2, 0, 1, 0,
26, 0, 0, 0, 23, 0, 0, 0,
0, 0, 1, 0, 27, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
5, 5, 0, 0, 98, 0, 0, 0,
1, 5, 0, 0, 186, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
4, 5, 0, 0, 3, 0, 1, 0,
16, 5, 0, 0, 2, 0, 1, 0,
13, 0, 0, 0, 9, 0, 0, 0,
0, 0, 1, 0, 28, 0, 0, 0,
25, 0, 0, 0, 23, 0, 0, 0,
0, 0, 1, 0, 27, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
13, 5, 0, 0, 74, 0, 0, 0,
13, 5, 0, 0, 98, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
12, 5, 0, 0, 3, 0, 1, 0,
24, 5, 0, 0, 2, 0, 1, 0,
19, 0, 0, 0, 1, 0, 0, 0,
0, 0, 1, 0, 29, 0, 0, 0,
12, 0, 0, 0, 9, 0, 0, 0,
0, 0, 1, 0, 28, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
21, 5, 0, 0, 82, 0, 0, 0,
21, 5, 0, 0, 74, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
20, 5, 0, 0, 3, 0, 1, 0,
32, 5, 0, 0, 2, 0, 1, 0,
20, 0, 0, 0, 2, 0, 0, 0,
0, 0, 1, 0, 30, 0, 0, 0,
18, 0, 0, 0, 1, 0, 0, 0,
0, 0, 1, 0, 29, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
29, 5, 0, 0, 82, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
28, 5, 0, 0, 3, 0, 1, 0,
40, 5, 0, 0, 2, 0, 1, 0,
21, 0, 0, 0, 3, 0, 0, 0,
0, 0, 1, 0, 31, 0, 0, 0,
19, 0, 0, 0, 2, 0, 0, 0,
0, 0, 1, 0, 30, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
37, 5, 0, 0, 82, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
36, 5, 0, 0, 3, 0, 1, 0,
48, 5, 0, 0, 2, 0, 1, 0,
28, 0, 0, 0, 224, 1, 0, 0,
20, 0, 0, 0, 3, 0, 0, 0,
0, 0, 1, 0, 31, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
45, 5, 0, 0, 82, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
44, 5, 0, 0, 3, 0, 1, 0,
56, 5, 0, 0, 2, 0, 1, 0,
27, 0, 0, 0, 224, 1, 0, 0,
0, 0, 1, 0, 32, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
45, 5, 0, 0, 178, 0, 0, 0,
53, 5, 0, 0, 178, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
48, 5, 0, 0, 3, 0, 1, 0,
60, 5, 0, 0, 2, 0, 1, 0,
15, 0, 0, 0, 31, 0, 0, 0,
56, 5, 0, 0, 3, 0, 1, 0,
68, 5, 0, 0, 2, 0, 1, 0,
14, 0, 0, 0, 31, 0, 0, 0,
0, 0, 1, 0, 33, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
57, 5, 0, 0, 178, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
60, 5, 0, 0, 3, 0, 1, 0,
72, 5, 0, 0, 2, 0, 1, 0,
14, 0, 0, 0, 61, 0, 0, 0,
0, 0, 1, 0, 34, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
69, 5, 0, 0, 114, 0, 0, 0,
65, 5, 0, 0, 178, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
68, 5, 0, 0, 3, 0, 1, 0,
80, 5, 0, 0, 2, 0, 1, 0,
17, 0, 0, 0, 16, 0, 0, 0,
0, 0, 1, 0, 35, 0, 0, 0,
13, 0, 0, 0, 61, 0, 0, 0,
0, 0, 1, 0, 34, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
77, 5, 0, 0, 98, 0, 0, 0,
77, 5, 0, 0, 114, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
76, 5, 0, 0, 3, 0, 1, 0,
88, 5, 0, 0, 2, 0, 1, 0,
18, 0, 0, 0, 17, 0, 0, 0,
0, 0, 1, 0, 36, 0, 0, 0,
16, 0, 0, 0, 16, 0, 0, 0,
0, 0, 1, 0, 35, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
85, 5, 0, 0, 98, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
84, 5, 0, 0, 3, 0, 1, 0,
96, 5, 0, 0, 2, 0, 1, 0,
17, 0, 0, 0, 17, 0, 0, 0,
0, 0, 1, 0, 36, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
93, 5, 0, 0, 98, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
92, 5, 0, 0, 3, 0, 1, 0,
104, 5, 0, 0, 2, 0, 1, 0,
118, 111, 108, 116, 97, 103, 101, 0,
8, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
@@ -4951,7 +4955,9 @@ static const ::capnp::_::AlignedData<643> b_a7649e2575e4591e = {
0, 0, 0, 0, 0, 0, 0, 0,
103, 97, 115, 73, 110, 116, 101, 114,
99, 101, 112, 116, 111, 114, 68, 101,
116, 101, 99, 116, 101, 100, 0, 0,
116, 101, 99, 116, 101, 100, 68, 69,
80, 82, 69, 67, 65, 84, 69, 68,
0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
@@ -5277,7 +5283,7 @@ static const ::capnp::_::RawSchema* const d_a7649e2575e4591e[] = {
static const uint16_t m_a7649e2575e4591e[] = {23, 29, 30, 31, 3, 1, 28, 11, 34, 15, 18, 4, 9, 21, 6, 22, 13, 2, 25, 10, 16, 7, 14, 27, 26, 20, 32, 19, 24, 35, 36, 33, 5, 8, 17, 12, 0};
static const uint16_t i_a7649e2575e4591e[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36};
const ::capnp::_::RawSchema s_a7649e2575e4591e = {
0xa7649e2575e4591e, b_a7649e2575e4591e.words, 643, d_a7649e2575e4591e, m_a7649e2575e4591e,
0xa7649e2575e4591e, b_a7649e2575e4591e.words, 645, d_a7649e2575e4591e, m_a7649e2575e4591e,
7, 37, i_a7649e2575e4591e, nullptr, nullptr, { &s_a7649e2575e4591e, nullptr, nullptr, 0, 0, nullptr }
};
#endif // !CAPNP_LITE
@@ -27600,7 +27606,7 @@ static const ::capnp::_::AlignedData<2162> b_d314cfd957229c11 = {
37, 0, 189, 255, 0, 0, 0, 0,
0, 0, 1, 0, 68, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
61, 17, 0, 0, 82, 0, 0, 0,
61, 17, 0, 0, 106, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
60, 17, 0, 0, 3, 0, 1, 0,
88, 17, 0, 0, 2, 0, 1, 0,
@@ -28704,8 +28710,8 @@ static const ::capnp::_::AlignedData<2162> b_d314cfd957229c11 = {
1, 0, 1, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
99, 97, 114, 69, 118, 101, 110, 116,
115, 0, 0, 0, 0, 0, 0, 0,
111, 110, 114, 111, 97, 100, 69, 118,
101, 110, 116, 115, 0, 0, 0, 0,
14, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
@@ -29358,7 +29364,7 @@ static const ::capnp::_::RawSchema* const d_d314cfd957229c11[] = {
&s_fe346a9de48d9b50,
&s_fe35ad896ffaeacf,
};
static const uint16_t m_d314cfd957229c11[] = {98, 101, 30, 20, 55, 42, 60, 63, 5, 23, 68, 69, 22, 28, 35, 7, 110, 111, 112, 113, 114, 115, 116, 124, 125, 126, 6, 70, 87, 76, 71, 59, 92, 85, 26, 10, 91, 21, 48, 3, 41, 40, 99, 100, 1, 65, 64, 109, 32, 96, 19, 8, 46, 25, 72, 51, 44, 37, 107, 62, 36, 61, 94, 16, 14, 122, 119, 120, 117, 121, 118, 49, 18, 0, 24, 108, 95, 78, 105, 103, 9, 75, 82, 104, 83, 38, 84, 27, 54, 58, 56, 47, 53, 45, 12, 81, 80, 33, 89, 90, 31, 13, 2, 86, 15, 17, 4, 11, 73, 97, 123, 52, 66, 43, 34, 39, 102, 57, 50, 106, 79, 93, 67, 74, 88, 77, 29};
static const uint16_t m_d314cfd957229c11[] = {98, 101, 30, 20, 55, 42, 60, 63, 5, 23, 69, 22, 28, 35, 7, 110, 111, 112, 113, 114, 115, 116, 124, 125, 126, 6, 70, 87, 76, 71, 59, 92, 85, 26, 10, 91, 21, 48, 3, 41, 40, 99, 100, 1, 65, 64, 109, 32, 96, 19, 8, 46, 25, 72, 51, 44, 37, 107, 62, 36, 61, 94, 16, 14, 122, 119, 120, 117, 121, 118, 49, 18, 0, 24, 108, 95, 78, 105, 103, 9, 75, 82, 104, 83, 38, 84, 27, 68, 54, 58, 56, 47, 53, 45, 12, 81, 80, 33, 89, 90, 31, 13, 2, 86, 15, 17, 4, 11, 73, 97, 123, 52, 66, 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, 0, 67};
const ::capnp::_::RawSchema s_d314cfd957229c11 = {
0xd314cfd957229c11, b_d314cfd957229c11.words, 2162, d_d314cfd957229c11, m_d314cfd957229c11,
+38 -37
View File
@@ -58,6 +58,7 @@ enum class ImageSensor_d810b1e7705dd69c: uint16_t {
UNKNOWN,
AR0231,
OX03C10,
OS04C10,
};
CAPNP_DECLARE_ENUM(ImageSensor, d810b1e7705dd69c);
CAPNP_DECLARE_SCHEMA(bcc3efbac41d2048);
@@ -2402,7 +2403,7 @@ struct Event {
LATERAL_PLAN,
KALMAN_ODOMETRY_D_E_P_R_E_C_A_T_E_D,
THUMBNAIL,
CAR_EVENTS,
ONROAD_EVENTS,
CAR_PARAMS,
DRIVER_CAMERA_STATE,
DRIVER_MONITORING_STATE,
@@ -5443,7 +5444,7 @@ public:
inline bool getControlsAllowed() const;
inline bool getGasInterceptorDetected() const;
inline bool getGasInterceptorDetectedDEPRECATED() const;
inline bool getStartedSignalDetectedDEPRECATED() const;
@@ -5553,8 +5554,8 @@ public:
inline bool getControlsAllowed();
inline void setControlsAllowed(bool value);
inline bool getGasInterceptorDetected();
inline void setGasInterceptorDetected(bool value);
inline bool getGasInterceptorDetectedDEPRECATED();
inline void setGasInterceptorDetectedDEPRECATED(bool value);
inline bool getStartedSignalDetectedDEPRECATED();
inline void setStartedSignalDetectedDEPRECATED(bool value);
@@ -18844,9 +18845,9 @@ public:
inline bool getValid() const;
inline bool isCarEvents() const;
inline bool hasCarEvents() const;
inline ::capnp::List< ::cereal::CarEvent, ::capnp::Kind::STRUCT>::Reader getCarEvents() const;
inline bool isOnroadEvents() const;
inline bool hasOnroadEvents() const;
inline ::capnp::List< ::cereal::CarEvent, ::capnp::Kind::STRUCT>::Reader getOnroadEvents() const;
inline bool isCarParams() const;
inline bool hasCarParams() const;
@@ -19643,13 +19644,13 @@ public:
inline bool getValid();
inline void setValid(bool value);
inline bool isCarEvents();
inline bool hasCarEvents();
inline ::capnp::List< ::cereal::CarEvent, ::capnp::Kind::STRUCT>::Builder getCarEvents();
inline void setCarEvents( ::capnp::List< ::cereal::CarEvent, ::capnp::Kind::STRUCT>::Reader value);
inline ::capnp::List< ::cereal::CarEvent, ::capnp::Kind::STRUCT>::Builder initCarEvents(unsigned int size);
inline void adoptCarEvents(::capnp::Orphan< ::capnp::List< ::cereal::CarEvent, ::capnp::Kind::STRUCT>>&& value);
inline ::capnp::Orphan< ::capnp::List< ::cereal::CarEvent, ::capnp::Kind::STRUCT>> disownCarEvents();
inline bool isOnroadEvents();
inline bool hasOnroadEvents();
inline ::capnp::List< ::cereal::CarEvent, ::capnp::Kind::STRUCT>::Builder getOnroadEvents();
inline void setOnroadEvents( ::capnp::List< ::cereal::CarEvent, ::capnp::Kind::STRUCT>::Reader value);
inline ::capnp::List< ::cereal::CarEvent, ::capnp::Kind::STRUCT>::Builder initOnroadEvents(unsigned int size);
inline void adoptOnroadEvents(::capnp::Orphan< ::capnp::List< ::cereal::CarEvent, ::capnp::Kind::STRUCT>>&& value);
inline ::capnp::Orphan< ::capnp::List< ::cereal::CarEvent, ::capnp::Kind::STRUCT>> disownOnroadEvents();
inline bool isCarParams();
inline bool hasCarParams();
@@ -25183,16 +25184,16 @@ inline void PandaState::Builder::setControlsAllowed(bool value) {
::capnp::bounded<65>() * ::capnp::ELEMENTS, value);
}
inline bool PandaState::Reader::getGasInterceptorDetected() const {
inline bool PandaState::Reader::getGasInterceptorDetectedDEPRECATED() const {
return _reader.getDataField<bool>(
::capnp::bounded<66>() * ::capnp::ELEMENTS);
}
inline bool PandaState::Builder::getGasInterceptorDetected() {
inline bool PandaState::Builder::getGasInterceptorDetectedDEPRECATED() {
return _builder.getDataField<bool>(
::capnp::bounded<66>() * ::capnp::ELEMENTS);
}
inline void PandaState::Builder::setGasInterceptorDetected(bool value) {
inline void PandaState::Builder::setGasInterceptorDetectedDEPRECATED(bool value) {
_builder.setDataField<bool>(
::capnp::bounded<66>() * ::capnp::ELEMENTS, value);
}
@@ -49623,55 +49624,55 @@ inline void Event::Builder::setValid(bool value) {
::capnp::bounded<80>() * ::capnp::ELEMENTS, value, true);
}
inline bool Event::Reader::isCarEvents() const {
return which() == Event::CAR_EVENTS;
inline bool Event::Reader::isOnroadEvents() const {
return which() == Event::ONROAD_EVENTS;
}
inline bool Event::Builder::isCarEvents() {
return which() == Event::CAR_EVENTS;
inline bool Event::Builder::isOnroadEvents() {
return which() == Event::ONROAD_EVENTS;
}
inline bool Event::Reader::hasCarEvents() const {
if (which() != Event::CAR_EVENTS) return false;
inline bool Event::Reader::hasOnroadEvents() const {
if (which() != Event::ONROAD_EVENTS) return false;
return !_reader.getPointerField(
::capnp::bounded<0>() * ::capnp::POINTERS).isNull();
}
inline bool Event::Builder::hasCarEvents() {
if (which() != Event::CAR_EVENTS) return false;
inline bool Event::Builder::hasOnroadEvents() {
if (which() != Event::ONROAD_EVENTS) return false;
return !_builder.getPointerField(
::capnp::bounded<0>() * ::capnp::POINTERS).isNull();
}
inline ::capnp::List< ::cereal::CarEvent, ::capnp::Kind::STRUCT>::Reader Event::Reader::getCarEvents() const {
KJ_IREQUIRE((which() == Event::CAR_EVENTS),
inline ::capnp::List< ::cereal::CarEvent, ::capnp::Kind::STRUCT>::Reader Event::Reader::getOnroadEvents() const {
KJ_IREQUIRE((which() == Event::ONROAD_EVENTS),
"Must check which() before get()ing a union member.");
return ::capnp::_::PointerHelpers< ::capnp::List< ::cereal::CarEvent, ::capnp::Kind::STRUCT>>::get(_reader.getPointerField(
::capnp::bounded<0>() * ::capnp::POINTERS));
}
inline ::capnp::List< ::cereal::CarEvent, ::capnp::Kind::STRUCT>::Builder Event::Builder::getCarEvents() {
KJ_IREQUIRE((which() == Event::CAR_EVENTS),
inline ::capnp::List< ::cereal::CarEvent, ::capnp::Kind::STRUCT>::Builder Event::Builder::getOnroadEvents() {
KJ_IREQUIRE((which() == Event::ONROAD_EVENTS),
"Must check which() before get()ing a union member.");
return ::capnp::_::PointerHelpers< ::capnp::List< ::cereal::CarEvent, ::capnp::Kind::STRUCT>>::get(_builder.getPointerField(
::capnp::bounded<0>() * ::capnp::POINTERS));
}
inline void Event::Builder::setCarEvents( ::capnp::List< ::cereal::CarEvent, ::capnp::Kind::STRUCT>::Reader value) {
inline void Event::Builder::setOnroadEvents( ::capnp::List< ::cereal::CarEvent, ::capnp::Kind::STRUCT>::Reader value) {
_builder.setDataField<Event::Which>(
::capnp::bounded<4>() * ::capnp::ELEMENTS, Event::CAR_EVENTS);
::capnp::bounded<4>() * ::capnp::ELEMENTS, Event::ONROAD_EVENTS);
::capnp::_::PointerHelpers< ::capnp::List< ::cereal::CarEvent, ::capnp::Kind::STRUCT>>::set(_builder.getPointerField(
::capnp::bounded<0>() * ::capnp::POINTERS), value);
}
inline ::capnp::List< ::cereal::CarEvent, ::capnp::Kind::STRUCT>::Builder Event::Builder::initCarEvents(unsigned int size) {
inline ::capnp::List< ::cereal::CarEvent, ::capnp::Kind::STRUCT>::Builder Event::Builder::initOnroadEvents(unsigned int size) {
_builder.setDataField<Event::Which>(
::capnp::bounded<4>() * ::capnp::ELEMENTS, Event::CAR_EVENTS);
::capnp::bounded<4>() * ::capnp::ELEMENTS, Event::ONROAD_EVENTS);
return ::capnp::_::PointerHelpers< ::capnp::List< ::cereal::CarEvent, ::capnp::Kind::STRUCT>>::init(_builder.getPointerField(
::capnp::bounded<0>() * ::capnp::POINTERS), size);
}
inline void Event::Builder::adoptCarEvents(
inline void Event::Builder::adoptOnroadEvents(
::capnp::Orphan< ::capnp::List< ::cereal::CarEvent, ::capnp::Kind::STRUCT>>&& value) {
_builder.setDataField<Event::Which>(
::capnp::bounded<4>() * ::capnp::ELEMENTS, Event::CAR_EVENTS);
::capnp::bounded<4>() * ::capnp::ELEMENTS, Event::ONROAD_EVENTS);
::capnp::_::PointerHelpers< ::capnp::List< ::cereal::CarEvent, ::capnp::Kind::STRUCT>>::adopt(_builder.getPointerField(
::capnp::bounded<0>() * ::capnp::POINTERS), kj::mv(value));
}
inline ::capnp::Orphan< ::capnp::List< ::cereal::CarEvent, ::capnp::Kind::STRUCT>> Event::Builder::disownCarEvents() {
KJ_IREQUIRE((which() == Event::CAR_EVENTS),
inline ::capnp::Orphan< ::capnp::List< ::cereal::CarEvent, ::capnp::Kind::STRUCT>> Event::Builder::disownOnroadEvents() {
KJ_IREQUIRE((which() == Event::ONROAD_EVENTS),
"Must check which() before get()ing a union member.");
return ::capnp::_::PointerHelpers< ::capnp::List< ::cereal::CarEvent, ::capnp::Kind::STRUCT>>::disown(_builder.getPointerField(
::capnp::bounded<0>() * ::capnp::POINTERS));
Binary file not shown.
+3 -2
View File
@@ -166,6 +166,7 @@ struct FrameData {
unknown @0;
ar0231 @1;
ox03c10 @2;
os04c10 @3;
}
frameLengthDEPRECATED @3 :Int32;
@@ -408,7 +409,6 @@ struct DeviceState @0xa4d8b5af2aa492eb {
struct PandaState @0xa7649e2575e4591e {
ignitionLine @2 :Bool;
gasInterceptorDetected @4 :Bool;
rxBufferOverflow @7 :UInt32;
txBufferOverflow @8 :UInt32;
gmlanSendErrs @9 :UInt32;
@@ -541,6 +541,7 @@ struct PandaState @0xa7649e2575e4591e {
}
}
gasInterceptorDetectedDEPRECATED @4 :Bool;
startedSignalDetectedDEPRECATED @5 :Bool;
hasGpsDEPRECATED @6 :Bool;
fanSpeedRpmDEPRECATED @11 :UInt16;
@@ -2226,7 +2227,7 @@ struct Event {
liveTorqueParameters @94 :LiveTorqueParametersData;
cameraOdometry @63 :CameraOdometry;
thumbnail @66: Thumbnail;
carEvents @68: List(Car.CarEvent);
onroadEvents @68: List(Car.CarEvent);
carParams @69: Car.CarParams;
driverMonitoringState @71: DriverMonitoringState;
liveLocationKalman @72 :LiveLocationKalman;
+13 -8
View File
@@ -41,10 +41,13 @@ def log_from_bytes(dat: bytes) -> capnp.lib.capnp._DynamicStructReader:
return msg
def new_message(service: Optional[str] = None, size: Optional[int] = None) -> capnp.lib.capnp._DynamicStructBuilder:
dat = log.Event.new_message()
dat.logMonoTime = int(time.monotonic() * 1e9)
dat.valid = True
def new_message(service: Optional[str], size: Optional[int] = None, **kwargs) -> capnp.lib.capnp._DynamicStructBuilder:
args = {
'valid': False,
'logMonoTime': int(time.monotonic() * 1e9),
**kwargs
}
dat = log.Event.new_message(**args)
if service is not None:
if size is None:
dat.init(service)
@@ -154,7 +157,7 @@ def recv_one_retry(sock: SubSocket) -> capnp.lib.capnp._DynamicStructReader:
class SubMaster:
def __init__(self, services: List[str], poll: Optional[List[str]] = None,
ignore_alive: Optional[List[str]] = None, ignore_avg_freq: Optional[List[str]] = None,
addr: str = "127.0.0.1"):
ignore_valid: Optional[List[str]] = None, addr: str = "127.0.0.1"):
self.frame = -1
self.updated = {s: False for s in services}
self.rcv_time = {s: 0. for s in services}
@@ -174,6 +177,7 @@ class SubMaster:
self.ignore_average_freq = [] if ignore_avg_freq is None else ignore_avg_freq
self.ignore_alive = [] if ignore_alive is None else ignore_alive
self.ignore_valid = [] if ignore_valid is None else ignore_valid
self.simulation = bool(int(os.getenv("SIMULATION", "0")))
for s in services:
@@ -187,9 +191,10 @@ class SubMaster:
except capnp.lib.capnp.KjException: # pylint: disable=c-extension-no-member
data = new_message(s, 0) # lists
self.data[s] = getattr(data, s)
self.data[s] = getattr(data.as_reader(), s)
self.logMonoTime[s] = 0
self.valid[s] = data.valid
# TODO: this should default to False
self.valid[s] = True
def __getitem__(self, s: str) -> capnp.lib.capnp._DynamicStructReader:
return self.data[s]
@@ -266,7 +271,7 @@ class SubMaster:
def all_valid(self, service_list=None) -> bool:
if service_list is None: # check all
service_list = self.valid.keys()
return all(self.valid[s] for s in service_list)
return all(self.valid[s] for s in service_list if s not in self.ignore_valid)
def all_checks(self, service_list=None) -> bool:
if service_list is None: # check all
Binary file not shown.
File diff suppressed because it is too large Load Diff
Binary file not shown.
+1 -1
View File
@@ -44,7 +44,7 @@ static std::map<std::string, service> services = {
{ "cameraOdometry", {"cameraOdometry", 8038, true, 20, 5}},
{ "lateralPlan", {"lateralPlan", 8039, true, 20, 5}},
{ "thumbnail", {"thumbnail", 8040, true, 0, 1}},
{ "carEvents", {"carEvents", 8041, true, 1, 1}},
{ "onroadEvents", {"onroadEvents", 8041, true, 1, 1}},
{ "carParams", {"carParams", 8042, true, 0, 1}},
{ "roadCameraState", {"roadCameraState", 8043, true, 20, 20}},
{ "driverCameraState", {"driverCameraState", 8044, true, 20, 20}},
+1 -1
View File
@@ -60,7 +60,7 @@ services: dict[str, tuple] = {
"cameraOdometry": (True, 20., 5),
"lateralPlan": (True, 20., 5),
"thumbnail": (True, 0.2, 1),
"carEvents": (True, 1., 1),
"onroadEvents": (True, 1., 1),
"carParams": (True, 0.02, 1),
"roadCameraState": (True, 20., 20),
"driverCameraState": (True, 20., 20),
File diff suppressed because it is too large Load Diff
Binary file not shown.
+2 -2
View File
@@ -2,7 +2,7 @@ import jwt
import os
import requests
from datetime import datetime, timedelta
from openpilot.common.basedir import PERSIST
from openpilot.system.hardware.hw import Paths
from openpilot.system.version import get_version
API_HOST = os.getenv('API_HOST', 'https://api.commadotai.com')
@@ -10,7 +10,7 @@ API_HOST = os.getenv('API_HOST', 'https://api.commadotai.com')
class Api():
def __init__(self, dongle_id):
self.dongle_id = dongle_id
with open(PERSIST+'/comma/id_rsa') as f:
with open(Paths.persist_root()+'/comma/id_rsa') as f:
self.private_key = f.read()
def get(self, *args, **kwargs):
-7
View File
@@ -1,11 +1,4 @@
import os
from pathlib import Path
from openpilot.system.hardware import PC
BASEDIR = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), "../"))
if PC:
PERSIST = os.path.join(str(Path.home()), ".comma", "persist")
else:
PERSIST = "/persist"
-10
View File
@@ -4,16 +4,6 @@ import tempfile
from atomicwrites import AtomicWriter
def mkdirs_exists_ok(path):
if path.startswith(('http://', 'https://')):
raise ValueError('URL path')
try:
os.makedirs(path)
except OSError:
if not os.path.isdir(path):
raise
def rm_not_exists_ok(path):
try:
os.remove(path)
+1 -1
View File
@@ -9,4 +9,4 @@ def get_kalman_gain(dt, A, C, Q, R, iterations=100):
S = C.dot(P).dot(C.T) + R
K = P.dot(C.T).dot(np.linalg.inv(S))
P = (np.eye(len(P)) - K.dot(C)).dot(P)
return K
return K
File diff suppressed because it is too large Load Diff
Binary file not shown.
+12
View File
@@ -0,0 +1,12 @@
class lazy_property():
"""Defines a property whose value will be computed only once and as needed.
This can only be used on instance methods.
"""
def __init__(self, func):
self._func = func
def __get__(self, obj_self, cls):
value = self._func(obj_self)
setattr(obj_self, self._func.__name__, value)
return value
-38
View File
@@ -1,38 +0,0 @@
#pragma once
#include <array>
#include "common/mat.h"
#include "system/hardware/hw.h"
const int TRAJECTORY_SIZE = 33;
const int LAT_MPC_N = 16;
const int LON_MPC_N = 32;
const float MIN_DRAW_DISTANCE = 10.0;
const float MAX_DRAW_DISTANCE = 100.0;
const float RYG_GREEN = 0.01165;
const float RYG_YELLOW = 0.06157;
template <typename T, size_t size>
constexpr std::array<T, size> build_idxs(float max_val) {
std::array<T, size> result{};
for (int i = 0; i < size; ++i) {
result[i] = max_val * ((i / (double)(size - 1)) * (i / (double)(size - 1)));
}
return result;
}
constexpr auto T_IDXS = build_idxs<double, TRAJECTORY_SIZE>(10.0);
constexpr auto T_IDXS_FLOAT = build_idxs<float, TRAJECTORY_SIZE>(10.0);
constexpr auto X_IDXS = build_idxs<double, TRAJECTORY_SIZE>(192.0);
constexpr auto X_IDXS_FLOAT = build_idxs<float, TRAJECTORY_SIZE>(192.0);
const mat3 FCAM_INTRINSIC_MATRIX = (mat3){{2648.0, 0.0, 1928.0 / 2,
0.0, 2648.0, 1208.0 / 2,
0.0, 0.0, 1.0}};
// tici ecam focal probably wrong? magnification is not consistent across frame
// Need to retrain model before this can be changed
const mat3 ECAM_INTRINSIC_MATRIX = (mat3){{567.0, 0.0, 1928.0 / 2,
0.0, 567.0, 1208.0 / 2,
0.0, 0.0, 1.0}};
+22
View File
@@ -0,0 +1,22 @@
import numpy as np
def deep_interp_np(x, xp, fp, axis=None):
if axis is not None:
fp = fp.swapaxes(0,axis)
x = np.atleast_1d(x)
xp = np.array(xp)
if len(xp) < 2:
return np.repeat(fp, len(x), axis=0)
if min(np.diff(xp)) < 0:
raise RuntimeError('Bad x array for interpolation')
j = np.searchsorted(xp, x) - 1
j = np.clip(j, 0, len(xp)-2)
d = np.divide(x - xp[j], xp[j + 1] - xp[j], out=np.ones_like(x, dtype=np.float64), where=xp[j + 1] - xp[j] != 0)
vals_interp = (fp[j].T*(1 - d)).T + (fp[j + 1].T*d).T
if axis is not None:
vals_interp = vals_interp.swapaxes(0,axis)
if len(vals_interp) == 1:
return vals_interp[0]
else:
return vals_interp
+19 -2
View File
@@ -1,21 +1,28 @@
#pragma once
#include <future>
#include <map>
#include <string>
#include <tuple>
#include <utility>
#include <vector>
#include "common/queue.h"
enum ParamKeyType {
PERSISTENT = 0x02,
CLEAR_ON_MANAGER_START = 0x04,
CLEAR_ON_ONROAD_TRANSITION = 0x08,
CLEAR_ON_OFFROAD_TRANSITION = 0x10,
DONT_LOG = 0x20,
DEVELOPMENT_ONLY = 0x40,
ALL = 0xFFFFFFFF
};
class Params {
public:
explicit Params(const std::string &path = {});
~Params();
// Not copyable.
Params(const Params&) = delete;
Params& operator=(const Params&) = delete;
@@ -24,7 +31,7 @@ public:
bool checkKey(const std::string &key);
ParamKeyType getKeyType(const std::string &key);
inline std::string getParamPath(const std::string &key = {}) {
return params_path + prefix + (key.empty() ? "" : "/" + key);
return params_path + params_prefix + (key.empty() ? "" : "/" + key);
}
// Delete a value
@@ -46,8 +53,18 @@ public:
inline int putBool(const std::string &key, bool val) {
return put(key.c_str(), val ? "1" : "0", 1);
}
void putNonBlocking(const std::string &key, const std::string &val);
inline void putBoolNonBlocking(const std::string &key, bool val) {
putNonBlocking(key, val ? "1" : "0");
}
private:
void asyncWriteThread();
std::string params_path;
std::string prefix;
std::string params_prefix;
// for nonblocking write
std::future<void> future;
SafeQueue<std::pair<std::string, std::string>> queue;
};
+1 -4
View File
@@ -1,10 +1,7 @@
from openpilot.common.params_pyx import Params, ParamKeyType, UnknownKeyName, put_nonblocking, \
put_bool_nonblocking
from openpilot.common.params_pyx import Params, ParamKeyType, UnknownKeyName
assert Params
assert ParamKeyType
assert UnknownKeyName
assert put_nonblocking
assert put_bool_nonblocking
if __name__ == "__main__":
import sys
+4111 -3518
View File
File diff suppressed because it is too large Load Diff
+15 -8
View File
@@ -3,7 +3,6 @@
from libcpp cimport bool
from libcpp.string cimport string
from libcpp.vector cimport vector
import threading
cdef extern from "common/params.h":
cpdef enum ParamKeyType:
@@ -11,6 +10,7 @@ cdef extern from "common/params.h":
CLEAR_ON_MANAGER_START
CLEAR_ON_ONROAD_TRANSITION
CLEAR_ON_OFFROAD_TRANSITION
DEVELOPMENT_ONLY
ALL
cdef cppclass c_Params "Params":
@@ -19,6 +19,8 @@ cdef extern from "common/params.h":
bool getBool(string, bool) nogil
int remove(string) nogil
int put(string, string) nogil
void putNonBlocking(string, string) nogil
void putBoolNonBlocking(string, bool) nogil
int putBool(string, bool) nogil
bool checkKey(string) nogil
string getParamPath(string) nogil
@@ -79,7 +81,7 @@ cdef class Params:
"""
Warning: This function blocks until the param is written to disk!
In very rare cases this can take over a second, and your code will hang.
Use the put_nonblocking helper function in time sensitive code, but
Use the put_nonblocking, put_bool_nonblocking in time sensitive code, but
in general try to avoid writing params as much as possible.
"""
cdef string k = self.check_key(key)
@@ -92,6 +94,17 @@ cdef class Params:
with nogil:
self.p.putBool(k, val)
def put_nonblocking(self, key, dat):
cdef string k = self.check_key(key)
cdef string dat_bytes = ensure_bytes(dat)
with nogil:
self.p.putNonBlocking(k, dat_bytes)
def put_bool_nonblocking(self, key, bool val):
cdef string k = self.check_key(key)
with nogil:
self.p.putBoolNonBlocking(k, val)
def remove(self, key):
cdef string k = self.check_key(key)
with nogil:
@@ -103,9 +116,3 @@ cdef class Params:
def all_keys(self):
return self.p.allKeys()
def put_nonblocking(key, val, d=""):
threading.Thread(target=lambda: Params(d).put(key, val)).start()
def put_bool_nonblocking(key, bool val, d=""):
threading.Thread(target=lambda: Params(d).put_bool(key, val)).start()
Binary file not shown.
+46
View File
@@ -0,0 +1,46 @@
import os
import shutil
import uuid
from typing import Optional
from openpilot.common.params import Params
from openpilot.system.hardware.hw import Paths
class OpenpilotPrefix:
def __init__(self, prefix: Optional[str] = None, clean_dirs_on_exit: bool = True):
self.prefix = prefix if prefix else str(uuid.uuid4().hex[0:15])
self.msgq_path = os.path.join('/dev/shm', self.prefix)
self.clean_dirs_on_exit = clean_dirs_on_exit
def __enter__(self):
self.original_prefix = os.environ.get('OPENPILOT_PREFIX', None)
os.environ['OPENPILOT_PREFIX'] = self.prefix
try:
os.mkdir(self.msgq_path)
except FileExistsError:
pass
os.makedirs(Paths.log_root(), exist_ok=True)
return self
def __exit__(self, exc_type, exc_obj, exc_tb):
if self.clean_dirs_on_exit:
self.clean_dirs()
try:
del os.environ['OPENPILOT_PREFIX']
if self.original_prefix is not None:
os.environ['OPENPILOT_PREFIX'] = self.original_prefix
except KeyError:
pass
return False
def clean_dirs(self):
symlink_path = Params().get_param_path()
if os.path.exists(symlink_path):
shutil.rmtree(os.path.realpath(symlink_path), ignore_errors=True)
os.remove(symlink_path)
shutil.rmtree(self.msgq_path, ignore_errors=True)
shutil.rmtree(Paths.log_root(), ignore_errors=True)
shutil.rmtree(Paths.download_cache_root(), ignore_errors=True)
shutil.rmtree(Paths.comma_home(), ignore_errors=True)
+30
View File
@@ -0,0 +1,30 @@
import time
import functools
from openpilot.common.swaglog import cloudlog
def retry(attempts=3, delay=1.0, ignore_failure=False):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
for _ in range(attempts):
try:
return func(*args, **kwargs)
except Exception:
cloudlog.exception(f"{func.__name__} failed, trying again")
time.sleep(delay)
if ignore_failure:
cloudlog.error(f"{func.__name__} failed after retry")
else:
raise Exception(f"{func.__name__} failed after retry")
return wrapper
return decorator
if __name__ == "__main__":
@retry(attempts=10)
def abc():
raise ValueError("abc failed :(")
abc()
+1 -1
View File
@@ -3,4 +3,4 @@ import datetime
MIN_DATE = datetime.datetime(year=2023, month=6, day=1)
def system_time_valid():
return datetime.datetime.now() > MIN_DATE
return datetime.datetime.now() > MIN_DATE
File diff suppressed because it is too large Load Diff
Binary file not shown.
+1 -1
View File
@@ -1 +1 @@
#define COMMA_VERSION "2023.11.20"
#define COMMA_VERSION "2023.12.23"
+61
View File
@@ -0,0 +1,61 @@
import sys
import pygame
import cv2
class Window:
def __init__(self, w, h, caption="window", double=False, halve=False):
self.w = w
self.h = h
pygame.display.init()
pygame.display.set_caption(caption)
self.double = double
self.halve = halve
if self.double:
self.rw, self.rh = w*2, h*2
elif self.halve:
self.rw, self.rh = w//2, h//2
else:
self.rw, self.rh = w, h
self.screen = pygame.display.set_mode((self.rw, self.rh))
pygame.display.flip()
# hack for xmonad, it shrinks the window by 6 pixels after the display.flip
if self.screen.get_width() != self.rw:
self.screen = pygame.display.set_mode((self.rw+(self.rw-self.screen.get_width()), self.rh+(self.rh-self.screen.get_height())))
pygame.display.flip()
def draw(self, out):
pygame.event.pump()
if self.double:
out2 = cv2.resize(out, (self.w*2, self.h*2))
pygame.surfarray.blit_array(self.screen, out2.swapaxes(0, 1))
elif self.halve:
out2 = cv2.resize(out, (self.w//2, self.h//2))
pygame.surfarray.blit_array(self.screen, out2.swapaxes(0, 1))
else:
pygame.surfarray.blit_array(self.screen, out.swapaxes(0, 1))
pygame.display.flip()
def getkey(self):
while 1:
event = pygame.event.wait()
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
return event.key
def getclick(self):
for event in pygame.event.get():
if event.type == pygame.MOUSEBUTTONDOWN:
mx, my = pygame.mouse.get_pos()
return mx, my
if __name__ == "__main__":
import numpy as np
win = Window(200, 200, double=True)
img: np.ndarray = np.zeros((200, 200, 3), np.uint8)
while 1:
print("draw")
img += 1
win.draw(img)
+87 -80
View File
@@ -4,19 +4,19 @@
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.
# 267 Supported Cars
# 273 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|
|---|---|---|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
|Acura|ILX 2016-19|AcuraWatch Plus|openpilot|25 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 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Acura&model=ILX 2016-19">Buy Here</a></sub></details>||
|Acura|RDX 2016-18|AcuraWatch Plus|openpilot|25 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 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Acura&model=RDX 2016-18">Buy Here</a></sub></details>||
|Acura|RDX 2019-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 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Acura&model=RDX 2019-22">Buy Here</a></sub></details>||
|Audi|A3 2014-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Audi&model=A3 2014-19">Buy Here</a></sub></details>||
|Audi|A3 Sportback e-tron 2017-18|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Audi&model=A3 Sportback e-tron 2017-18">Buy Here</a></sub></details>||
|Audi|Q2 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Audi&model=Q2 2018">Buy Here</a></sub></details>||
|Audi|Q3 2019-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Audi&model=Q3 2019-23">Buy Here</a></sub></details>||
|Audi|RS3 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Audi&model=RS3 2018">Buy Here</a></sub></details>||
|Audi|S3 2015-17|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Audi&model=S3 2015-17">Buy Here</a></sub></details>||
|Audi|A3 2014-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Audi&model=A3 2014-19">Buy Here</a></sub></details>||
|Audi|A3 Sportback e-tron 2017-18|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Audi&model=A3 Sportback e-tron 2017-18">Buy Here</a></sub></details>||
|Audi|Q2 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Audi&model=Q2 2018">Buy Here</a></sub></details>||
|Audi|Q3 2019-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Audi&model=Q3 2019-23">Buy Here</a></sub></details>||
|Audi|RS3 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Audi&model=RS3 2018">Buy Here</a></sub></details>||
|Audi|S3 2015-17|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Audi&model=S3 2015-17">Buy Here</a></sub></details>||
|Buick|LaCrosse 2017-19[<sup>4</sup>](#footnotes)|Driver Confidence Package 2|openpilot|18 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-II connector<br>- 1 comma 3X<br>- 2 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Buick&model=LaCrosse 2017-19">Buy Here</a></sub></details>||
|Cadillac|Escalade 2017[<sup>4</sup>](#footnotes)|Driver Assist Package|openpilot|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-II connector<br>- 1 comma 3X<br>- 2 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Cadillac&model=Escalade 2017">Buy Here</a></sub></details>||
|Cadillac|Escalade ESV 2016[<sup>4</sup>](#footnotes)|Adaptive Cruise Control (ACC) & LKAS|openpilot|0 mph|7 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 OBD-II connector<br>- 1 comma 3X<br>- 2 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Cadillac&model=Escalade ESV 2016">Buy Here</a></sub></details>||
@@ -34,7 +34,7 @@ A supported vehicle is one that just works when you install a comma device. All
|comma|body|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|None||
|Ford|Bronco Sport 2021-22|Co-Pilot360 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 Ford Q3 connector<br>- 1 RJ45 cable (7 ft)<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Ford&model=Bronco Sport 2021-22">Buy Here</a></sub></details>||
|Ford|Escape 2020-22|Co-Pilot360 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 Ford Q3 connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Ford&model=Escape 2020-22">Buy Here</a></sub></details>||
|Ford|Explorer 2020-22|Co-Pilot360 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 Ford Q3 connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Ford&model=Explorer 2020-22">Buy Here</a></sub></details>||
|Ford|Explorer 2020-23|Co-Pilot360 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 Ford Q3 connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Ford&model=Explorer 2020-23">Buy Here</a></sub></details>||
|Ford|Focus 2018[<sup>3</sup>](#footnotes)|Adaptive Cruise Control with Lane Centering|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 Ford Q3 connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Ford&model=Focus 2018">Buy Here</a></sub></details>||
|Ford|Kuga 2020-22|Adaptive Cruise Control with Lane Centering|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 Ford Q3 connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Ford&model=Kuga 2020-22">Buy Here</a></sub></details>||
|Ford|Maverick 2022|LARIAT Luxury|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 Ford Q3 connector<br>- 1 RJ45 cable (7 ft)<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 comma power v2<br>- 1 harness box<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Ford&model=Maverick 2022">Buy Here</a></sub></details>||
@@ -73,6 +73,7 @@ A supported vehicle is one that just works when you install a comma device. All
|Honda|Pilot 2016-22|Honda Sensing|openpilot|25 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 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Honda&model=Pilot 2016-22">Buy Here</a></sub></details>||
|Honda|Ridgeline 2017-23|Honda Sensing|openpilot|25 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 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Honda&model=Ridgeline 2017-23">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 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Hyundai&model=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 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Hyundai&model=Azera Hybrid 2019">Buy Here</a></sub></details>||
|Hyundai|Azera Hybrid 2020|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 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Hyundai&model=Azera Hybrid 2020">Buy Here</a></sub></details>||
|Hyundai|Custin 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 Hyundai K connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Hyundai&model=Custin 2023">Buy Here</a></sub></details>||
|Hyundai|Elantra 2017-18|Smart Cruise Control (SCC)|Stock|19 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai B connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Hyundai&model=Elantra 2017-18">Buy Here</a></sub></details>||
@@ -96,25 +97,26 @@ A supported vehicle is one that just works when you install a comma device. All
|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 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Hyundai&model=Kona Electric 2018-21">Buy Here</a></sub></details>||
|Hyundai|Kona Electric 2022-23|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 O connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Hyundai&model=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 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Hyundai&model=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 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 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Hyundai&model=Kona Hybrid 2020">Buy Here</a></sub></details>|<a href="https://youtu.be/0dwpAHiZgFo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|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 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Hyundai&model=Kona Hybrid 2020">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 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Hyundai&model=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-23[<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 N connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Hyundai&model=Santa Cruz 2022-23">Buy Here</a></sub></details>||
|Hyundai|Santa Fe 2019-20|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 D connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Hyundai&model=Santa Fe 2019-20">Buy Here</a></sub></details>||
|Hyundai|Santa Cruz 2022-23[<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 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Hyundai&model=Santa Cruz 2022-23">Buy Here</a></sub></details>||
|Hyundai|Santa Fe 2019-20|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 D connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Hyundai&model=Santa Fe 2019-20">Buy Here</a></sub></details>|<a href="https://youtu.be/bjDR0YjM__s" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Hyundai|Santa Fe 2021-23|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 L connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Hyundai&model=Santa Fe 2021-23">Buy Here</a></sub></details>|<a href="https://youtu.be/VnHzSTygTS4" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Hyundai|Santa Fe Hybrid 2022-23|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 L connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Hyundai&model=Santa Fe Hybrid 2022-23">Buy Here</a></sub></details>||
|Hyundai|Santa Fe Plug-in Hybrid 2022-23|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 L connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Hyundai&model=Santa Fe Plug-in Hybrid 2022-23">Buy Here</a></sub></details>||
|Hyundai|Sonata 2018-19|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 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Hyundai&model=Sonata 2018-19">Buy Here</a></sub></details>||
|Hyundai|Sonata 2020-23|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 A connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Hyundai&model=Sonata 2020-23">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=ix63r9kE3Fw" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Hyundai|Sonata Hybrid 2020-23|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 A connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Hyundai&model=Sonata Hybrid 2020-23">Buy Here</a></sub></details>||
|Hyundai|Staria 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 K connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Hyundai&model=Staria 2023">Buy Here</a></sub></details>||
|Hyundai|Tucson 2021|Smart Cruise Control (SCC)|openpilot available[<sup>1</sup>](#footnotes)|19 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 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Hyundai&model=Tucson 2021">Buy Here</a></sub></details>||
|Hyundai|Tucson 2022[<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 N connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Hyundai&model=Tucson 2022">Buy Here</a></sub></details>||
|Hyundai|Tucson 2023[<sup>6</sup>](#footnotes)|All|Stock|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 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Hyundai&model=Tucson 2023">Buy Here</a></sub></details>||
|Hyundai|Tucson 2022[<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 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Hyundai&model=Tucson 2022">Buy Here</a></sub></details>||
|Hyundai|Tucson 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 N connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Hyundai&model=Tucson 2023">Buy Here</a></sub></details>||
|Hyundai|Tucson Diesel 2019|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 L connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Hyundai&model=Tucson Diesel 2019">Buy Here</a></sub></details>||
|Hyundai|Tucson Hybrid 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 N connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Hyundai&model=Tucson Hybrid 2022-24">Buy Here</a></sub></details>||
|Hyundai|Veloster 2019-20|Smart Cruise Control (SCC)|Stock|5 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 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Hyundai&model=Veloster 2019-20">Buy Here</a></sub></details>||
|Jeep|Grand Cherokee 2016-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Jeep&model=Grand Cherokee 2016-18">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=eLR9o2JkuRk" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Jeep|Grand Cherokee 2019-21|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 FCA connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Jeep&model=Grand Cherokee 2019-21">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=jBe4lWnRSu4" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Kia|Carnival 2023-24[<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 A connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Kia&model=Carnival 2023-24">Buy Here</a></sub></details>||
|Kia|Carnival 2022-24[<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 A connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Kia&model=Carnival 2022-24">Buy Here</a></sub></details>||
|Kia|Carnival (China 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 K connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Kia&model=Carnival (China only) 2023">Buy Here</a></sub></details>||
|Kia|Ceed 2019|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 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Kia&model=Ceed 2019">Buy Here</a></sub></details>||
|Kia|EV6 (Southeast Asia only) 2022-23[<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 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Kia&model=EV6 (Southeast Asia only) 2022-23">Buy Here</a></sub></details>||
@@ -134,6 +136,7 @@ A supported vehicle is one that just works when you install a comma device. All
|Kia|Niro Hybrid 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 A connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Kia&model=Niro Hybrid 2023">Buy Here</a></sub></details>||
|Kia|Niro Plug-in Hybrid 2018-19|All|Stock|10 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 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Kia&model=Niro Plug-in Hybrid 2018-19">Buy Here</a></sub></details>||
|Kia|Niro Plug-in Hybrid 2020|All|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai D connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Kia&model=Niro Plug-in Hybrid 2020">Buy Here</a></sub></details>||
|Kia|Niro Plug-in 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 Hyundai F connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Kia&model=Niro Plug-in Hybrid 2022">Buy Here</a></sub></details>||
|Kia|Optima 2017|Advanced Smart Cruise Control|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Hyundai B connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Kia&model=Optima 2017">Buy Here</a></sub></details>||
|Kia|Optima 2019-20|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 G connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Kia&model=Optima 2019-20">Buy Here</a></sub></details>||
|Kia|Optima Hybrid 2019|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 H connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Kia&model=Optima Hybrid 2019">Buy Here</a></sub></details>||
@@ -143,16 +146,17 @@ A supported vehicle is one that just works when you install a comma device. All
|Kia|Sorento 2021-23[<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 K connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Kia&model=Sorento 2021-23">Buy Here</a></sub></details>||
|Kia|Sorento Hybrid 2021-23[<sup>6</sup>](#footnotes)|All|Stock|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 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Kia&model=Sorento Hybrid 2021-23">Buy Here</a></sub></details>||
|Kia|Sorento Plug-in Hybrid 2022-23[<sup>6</sup>](#footnotes)|All|Stock|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 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Kia&model=Sorento Plug-in Hybrid 2022-23">Buy Here</a></sub></details>||
|Kia|Sportage 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 N connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Kia&model=Sportage 2023">Buy Here</a></sub></details>||
|Kia|Sportage 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 N connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Kia&model=Sportage 2023">Buy Here</a></sub></details>||
|Kia|Sportage Hybrid 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 N connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Kia&model=Sportage Hybrid 2023">Buy Here</a></sub></details>||
|Kia|Stinger 2018-20|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 C connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Kia&model=Stinger 2018-20">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=MJ94qoofYw0" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Kia|Stinger 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 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Kia&model=Stinger 2022">Buy Here</a></sub></details>||
|Kia|Stinger 2022-23|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 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Kia&model=Stinger 2022-23">Buy Here</a></sub></details>||
|Kia|Telluride 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 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Kia&model=Telluride 2020-22">Buy Here</a></sub></details>||
|Lexus|CT Hybrid 2017-18|Lexus Safety System+|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Lexus&model=CT Hybrid 2017-18">Buy Here</a></sub></details>||
|Lexus|ES 2017-18|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 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Lexus&model=ES 2017-18">Buy Here</a></sub></details>||
|Lexus|ES 2019-24|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Lexus&model=ES 2019-24">Buy Here</a></sub></details>||
|Lexus|ES Hybrid 2017-18|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Lexus&model=ES Hybrid 2017-18">Buy Here</a></sub></details>||
|Lexus|ES Hybrid 2019-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Lexus&model=ES Hybrid 2019-23">Buy Here</a></sub></details>|<a href="https://youtu.be/BZ29osRVJeg?t=12" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Lexus|GS F 2016|All|Stock|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Lexus&model=GS F 2016">Buy Here</a></sub></details>||
|Lexus|IS 2017-19|All|Stock|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Lexus&model=IS 2017-19">Buy Here</a></sub></details>||
|Lexus|IS 2022-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Lexus&model=IS 2022-23">Buy Here</a></sub></details>||
|Lexus|NX 2018-19|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Lexus&model=NX 2018-19">Buy Here</a></sub></details>||
@@ -168,8 +172,8 @@ A supported vehicle is one that just works when you install a comma device. All
|Lexus|RX Hybrid 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Lexus&model=RX Hybrid 2020-22">Buy Here</a></sub></details>||
|Lexus|UX Hybrid 2019-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Lexus&model=UX Hybrid 2019-23">Buy Here</a></sub></details>||
|Lincoln|Aviator 2020-21|Co-Pilot360 Plus|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 Ford Q3 connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Lincoln&model=Aviator 2020-21">Buy Here</a></sub></details>||
|MAN|eTGE 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=MAN&model=eTGE 2020-23">Buy Here</a></sub></details>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|MAN|TGE 2017-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=MAN&model=TGE 2017-23">Buy Here</a></sub></details>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|MAN|eTGE 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=MAN&model=eTGE 2020-23">Buy Here</a></sub></details>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|MAN|TGE 2017-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=MAN&model=TGE 2017-23">Buy Here</a></sub></details>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Mazda|CX-5 2022-24|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Mazda connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Mazda&model=CX-5 2022-24">Buy Here</a></sub></details>||
|Mazda|CX-9 2021-23|All|Stock|0 mph|28 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 Mazda connector<br>- 1 RJ45 cable (7 ft)<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Mazda&model=CX-9 2021-23">Buy Here</a></sub></details>|<a href="https://youtu.be/dA3duO4a0O4" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Nissan|Altima 2019-20|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Nissan B connector<br>- 1 RJ45 cable (7 ft)<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Nissan&model=Altima 2019-20">Buy Here</a></sub></details>||
@@ -177,26 +181,26 @@ A supported vehicle is one that just works when you install a comma device. All
|Nissan|Rogue 2018-20|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Nissan A connector<br>- 1 RJ45 cable (7 ft)<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Nissan&model=Rogue 2018-20">Buy Here</a></sub></details>||
|Nissan|X-Trail 2017|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 Nissan A connector<br>- 1 RJ45 cable (7 ft)<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Nissan&model=X-Trail 2017">Buy Here</a></sub></details>||
|Ram|1500 2019-23|Adaptive Cruise Control (ACC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Ram connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Ram&model=1500 2019-23">Buy Here</a></sub></details>||
|SEAT|Ateca 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=SEAT&model=Ateca 2018">Buy Here</a></sub></details>||
|SEAT|Leon 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=SEAT&model=Leon 2014-20">Buy Here</a></sub></details>||
|Subaru|Ascent 2019-21|All[<sup>7</sup>](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Subaru A connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Subaru&model=Ascent 2019-21">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>||
|Subaru|Crosstrek 2018-19|EyeSight Driver Assistance[<sup>7</sup>](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Subaru A connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Subaru&model=Crosstrek 2018-19">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>|<a href="https://youtu.be/Agww7oE1k-s?t=26" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Subaru|Crosstrek 2020-23|EyeSight Driver Assistance[<sup>7</sup>](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Subaru A connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Subaru&model=Crosstrek 2020-23">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>||
|Subaru|Forester 2019-21|All[<sup>7</sup>](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Subaru A connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Subaru&model=Forester 2019-21">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>||
|Subaru|Impreza 2017-19|EyeSight Driver Assistance[<sup>7</sup>](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Subaru A connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Subaru&model=Impreza 2017-19">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>||
|Subaru|Impreza 2020-22|EyeSight Driver Assistance[<sup>7</sup>](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Subaru A connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Subaru&model=Impreza 2020-22">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>||
|SEAT|Ateca 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=SEAT&model=Ateca 2018">Buy Here</a></sub></details>||
|SEAT|Leon 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=SEAT&model=Leon 2014-20">Buy Here</a></sub></details>||
|Subaru|Ascent 2019-21|All[<sup>7</sup>](#footnotes)|openpilot available[<sup>1,8</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Subaru A connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Subaru&model=Ascent 2019-21">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>||
|Subaru|Crosstrek 2018-19|EyeSight Driver Assistance[<sup>7</sup>](#footnotes)|openpilot available[<sup>1,8</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Subaru A connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Subaru&model=Crosstrek 2018-19">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>|<a href="https://youtu.be/Agww7oE1k-s?t=26" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Subaru|Crosstrek 2020-23|EyeSight Driver Assistance[<sup>7</sup>](#footnotes)|openpilot available[<sup>1,8</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Subaru A connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Subaru&model=Crosstrek 2020-23">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>||
|Subaru|Forester 2019-21|All[<sup>7</sup>](#footnotes)|openpilot available[<sup>1,8</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Subaru A connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Subaru&model=Forester 2019-21">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>||
|Subaru|Impreza 2017-19|EyeSight Driver Assistance[<sup>7</sup>](#footnotes)|openpilot available[<sup>1,8</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Subaru A connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Subaru&model=Impreza 2017-19">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>||
|Subaru|Impreza 2020-22|EyeSight Driver Assistance[<sup>7</sup>](#footnotes)|openpilot available[<sup>1,8</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Subaru A connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Subaru&model=Impreza 2020-22">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>||
|Subaru|Legacy 2020-22|All[<sup>7</sup>](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Subaru B connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Subaru&model=Legacy 2020-22">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>||
|Subaru|Outback 2020-22|All[<sup>7</sup>](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Subaru B connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Subaru&model=Outback 2020-22">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>||
|Subaru|XV 2018-19|EyeSight Driver Assistance[<sup>7</sup>](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Subaru A connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Subaru&model=XV 2018-19">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>|<a href="https://youtu.be/Agww7oE1k-s?t=26" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Subaru|XV 2020-21|EyeSight Driver Assistance[<sup>7</sup>](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Subaru A connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Subaru&model=XV 2020-21">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>||
|Škoda|Fabia 2022-23[<sup>11</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Škoda&model=Fabia 2022-23">Buy Here</a></sub></details>[<sup>13</sup>](#footnotes)||
|Škoda|Kamiq 2021[<sup>9,11</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Škoda&model=Kamiq 2021">Buy Here</a></sub></details>[<sup>13</sup>](#footnotes)||
|Škoda|Karoq 2019-23[<sup>11</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Škoda&model=Karoq 2019-23">Buy Here</a></sub></details>||
|Škoda|Kodiaq 2017-23[<sup>11</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Škoda&model=Kodiaq 2017-23">Buy Here</a></sub></details>||
|Škoda|Octavia 2015-19[<sup>11</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Škoda&model=Octavia 2015-19">Buy Here</a></sub></details>||
|Škoda|Octavia RS 2016[<sup>11</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Škoda&model=Octavia RS 2016">Buy Here</a></sub></details>||
|Škoda|Scala 2020-23[<sup>11</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Škoda&model=Scala 2020-23">Buy Here</a></sub></details>[<sup>13</sup>](#footnotes)||
|Škoda|Superb 2015-22[<sup>11</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Škoda&model=Superb 2015-22">Buy Here</a></sub></details>||
|Subaru|XV 2018-19|EyeSight Driver Assistance[<sup>7</sup>](#footnotes)|openpilot available[<sup>1,8</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Subaru A connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Subaru&model=XV 2018-19">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>|<a href="https://youtu.be/Agww7oE1k-s?t=26" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Subaru|XV 2020-21|EyeSight Driver Assistance[<sup>7</sup>](#footnotes)|openpilot available[<sup>1,8</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Subaru A connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Subaru&model=XV 2020-21">Buy Here</a></sub></details><details><summary>Tools</summary><sub>- 1 Pry Tool<br>- 1 Socket Wrench 8mm or 5/16" (deep)</sub></details>||
|Škoda|Fabia 2022-23[<sup>12</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Škoda&model=Fabia 2022-23">Buy Here</a></sub></details>[<sup>14</sup>](#footnotes)||
|Škoda|Kamiq 2021-23[<sup>10,12</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Škoda&model=Kamiq 2021-23">Buy Here</a></sub></details>[<sup>14</sup>](#footnotes)||
|Škoda|Karoq 2019-23[<sup>12</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Škoda&model=Karoq 2019-23">Buy Here</a></sub></details>||
|Škoda|Kodiaq 2017-23[<sup>12</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Škoda&model=Kodiaq 2017-23">Buy Here</a></sub></details>||
|Škoda|Octavia 2015-19[<sup>12</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Škoda&model=Octavia 2015-19">Buy Here</a></sub></details>||
|Škoda|Octavia RS 2016[<sup>12</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Škoda&model=Octavia RS 2016">Buy Here</a></sub></details>||
|Škoda|Scala 2020-23[<sup>12</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Škoda&model=Scala 2020-23">Buy Here</a></sub></details>[<sup>14</sup>](#footnotes)||
|Škoda|Superb 2015-22[<sup>12</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Škoda&model=Superb 2015-22">Buy Here</a></sub></details>||
|Toyota|Alphard 2019-20|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Toyota&model=Alphard 2019-20">Buy Here</a></sub></details>||
|Toyota|Alphard Hybrid 2021|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Toyota&model=Alphard Hybrid 2021">Buy Here</a></sub></details>||
|Toyota|Avalon 2016|Toyota Safety Sense P|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 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Toyota&model=Avalon 2016">Buy Here</a></sub></details>||
@@ -209,8 +213,8 @@ A supported vehicle is one that just works when you install a comma device. All
|Toyota|C-HR 2021|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Toyota&model=C-HR 2021">Buy Here</a></sub></details>||
|Toyota|C-HR Hybrid 2017-20|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Toyota&model=C-HR Hybrid 2017-20">Buy Here</a></sub></details>||
|Toyota|C-HR Hybrid 2021-22|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Toyota&model=C-HR Hybrid 2021-22">Buy Here</a></sub></details>||
|Toyota|Camry 2018-20|All|Stock|0 mph[<sup>8</sup>](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Toyota&model=Camry 2018-20">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=fkcjviZY9CM" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Toyota|Camry 2021-23|All|openpilot|0 mph[<sup>8</sup>](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Toyota&model=Camry 2021-23">Buy Here</a></sub></details>||
|Toyota|Camry 2018-20|All|Stock|0 mph[<sup>9</sup>](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Toyota&model=Camry 2018-20">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=fkcjviZY9CM" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Toyota|Camry 2021-24|All|openpilot|0 mph[<sup>9</sup>](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Toyota&model=Camry 2021-24">Buy Here</a></sub></details>||
|Toyota|Camry Hybrid 2018-20|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Toyota&model=Camry Hybrid 2018-20">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=Q2DYY0AWKgk" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Toyota|Camry Hybrid 2021-24|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Toyota&model=Camry Hybrid 2021-24">Buy Here</a></sub></details>||
|Toyota|Corolla 2017-19|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 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Toyota&model=Corolla 2017-19">Buy Here</a></sub></details>||
@@ -235,46 +239,48 @@ A supported vehicle is one that just works when you install a comma device. All
|Toyota|RAV4 2017-18|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 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Toyota&model=RAV4 2017-18">Buy Here</a></sub></details>||
|Toyota|RAV4 2019-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Toyota&model=RAV4 2019-21">Buy Here</a></sub></details>|<a href="https://www.youtube.com/watch?v=wJxjDd42gGA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Toyota|RAV4 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Toyota&model=RAV4 2022">Buy Here</a></sub></details>||
|Toyota|RAV4 2023|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Toyota&model=RAV4 2023">Buy Here</a></sub></details>||
|Toyota|RAV4 Hybrid 2016|Toyota Safety Sense P|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Toyota&model=RAV4 Hybrid 2016">Buy Here</a></sub></details>|<a href="https://youtu.be/LhT5VzJVfNI?t=26" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Toyota|RAV4 Hybrid 2017-18|All|openpilot available[<sup>2</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Toyota&model=RAV4 Hybrid 2017-18">Buy Here</a></sub></details>|<a href="https://youtu.be/LhT5VzJVfNI?t=26" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Toyota|RAV4 Hybrid 2019-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Toyota&model=RAV4 Hybrid 2019-21">Buy Here</a></sub></details>||
|Toyota|RAV4 Hybrid 2022|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Toyota&model=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|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Toyota&model=RAV4 Hybrid 2023">Buy Here</a></sub></details>||
|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-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 RJ45 cable (7 ft)<br>- 1 Toyota A connector<br>- 1 comma 3X<br>- 1 comma power v2<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.html?make=Toyota&model=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>|
|Volkswagen|Arteon 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=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,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=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,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=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>|
|Volkswagen|Atlas 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Atlas 2018-23">Buy Here</a></sub></details>||
|Volkswagen|Atlas Cross Sport 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Atlas Cross Sport 2021-22">Buy Here</a></sub></details>||
|Volkswagen|California 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=California 2021-23">Buy Here</a></sub></details>||
|Volkswagen|Caravelle 2020|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Caravelle 2020">Buy Here</a></sub></details>||
|Volkswagen|CC 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=CC 2018-22">Buy Here</a></sub></details>|<a href="https://youtu.be/FAomFKPFlDA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Volkswagen|Crafter 2017-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Crafter 2017-23">Buy Here</a></sub></details>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Volkswagen|e-Crafter 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=e-Crafter 2018-23">Buy Here</a></sub></details>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Volkswagen|e-Golf 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=e-Golf 2014-20">Buy Here</a></sub></details>||
|Volkswagen|Golf 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Golf 2015-20">Buy Here</a></sub></details>||
|Volkswagen|Golf Alltrack 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Golf Alltrack 2015-19">Buy Here</a></sub></details>||
|Volkswagen|Golf GTD 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Golf GTD 2015-20">Buy Here</a></sub></details>||
|Volkswagen|Golf GTE 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Golf GTE 2015-20">Buy Here</a></sub></details>||
|Volkswagen|Golf GTI 2015-21|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Golf GTI 2015-21">Buy Here</a></sub></details>||
|Volkswagen|Golf R 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Golf R 2015-19">Buy Here</a></sub></details>||
|Volkswagen|Golf SportsVan 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Golf SportsVan 2015-20">Buy Here</a></sub></details>||
|Volkswagen|Grand California 2019-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Grand California 2019-23">Buy Here</a></sub></details>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Volkswagen|Jetta 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Jetta 2018-22">Buy Here</a></sub></details>||
|Volkswagen|Jetta GLI 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Jetta GLI 2021-22">Buy Here</a></sub></details>||
|Volkswagen|Passat 2015-22[<sup>10</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Passat 2015-22">Buy Here</a></sub></details>||
|Volkswagen|Passat Alltrack 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Passat Alltrack 2015-22">Buy Here</a></sub></details>||
|Volkswagen|Passat GTE 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Passat GTE 2015-22">Buy Here</a></sub></details>||
|Volkswagen|Polo 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Polo 2018-23">Buy Here</a></sub></details>[<sup>13</sup>](#footnotes)||
|Volkswagen|Polo GTI 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Polo GTI 2018-23">Buy Here</a></sub></details>[<sup>13</sup>](#footnotes)||
|Volkswagen|T-Cross 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=T-Cross 2021">Buy Here</a></sub></details>[<sup>13</sup>](#footnotes)||
|Volkswagen|T-Roc 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=T-Roc 2021">Buy Here</a></sub></details>[<sup>13</sup>](#footnotes)||
|Volkswagen|Taos 2022-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Taos 2022-23">Buy Here</a></sub></details>||
|Volkswagen|Teramont 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Teramont 2018-22">Buy Here</a></sub></details>||
|Volkswagen|Teramont Cross Sport 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Teramont Cross Sport 2021-22">Buy Here</a></sub></details>||
|Volkswagen|Teramont X 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Teramont X 2021-22">Buy Here</a></sub></details>||
|Volkswagen|Tiguan 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Tiguan 2018-23">Buy Here</a></sub></details>||
|Volkswagen|Tiguan eHybrid 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Tiguan eHybrid 2021-23">Buy Here</a></sub></details>||
|Volkswagen|Touran 2016-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,12</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Touran 2016-23">Buy Here</a></sub></details>||
|Volkswagen|Arteon 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=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,13</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=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,13</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=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>|
|Volkswagen|Atlas 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Atlas 2018-23">Buy Here</a></sub></details>||
|Volkswagen|Atlas Cross Sport 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Atlas Cross Sport 2020-22">Buy Here</a></sub></details>||
|Volkswagen|California 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=California 2021-23">Buy Here</a></sub></details>||
|Volkswagen|Caravelle 2020|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Caravelle 2020">Buy Here</a></sub></details>||
|Volkswagen|CC 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=CC 2018-22">Buy Here</a></sub></details>|<a href="https://youtu.be/FAomFKPFlDA" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Volkswagen|Crafter 2017-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Crafter 2017-23">Buy Here</a></sub></details>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Volkswagen|e-Crafter 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=e-Crafter 2018-23">Buy Here</a></sub></details>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Volkswagen|e-Golf 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=e-Golf 2014-20">Buy Here</a></sub></details>||
|Volkswagen|Golf 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Golf 2015-20">Buy Here</a></sub></details>||
|Volkswagen|Golf Alltrack 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Golf Alltrack 2015-19">Buy Here</a></sub></details>||
|Volkswagen|Golf GTD 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Golf GTD 2015-20">Buy Here</a></sub></details>||
|Volkswagen|Golf GTE 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Golf GTE 2015-20">Buy Here</a></sub></details>||
|Volkswagen|Golf GTI 2015-21|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Golf GTI 2015-21">Buy Here</a></sub></details>||
|Volkswagen|Golf R 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Golf R 2015-19">Buy Here</a></sub></details>||
|Volkswagen|Golf SportsVan 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Golf SportsVan 2015-20">Buy Here</a></sub></details>||
|Volkswagen|Grand California 2019-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 angled mount (8 degrees)<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Grand California 2019-23">Buy Here</a></sub></details>|<a href="https://youtu.be/4100gLeabmo" target="_blank"><img height="18px" src="assets/icon-youtube.svg"></img></a>|
|Volkswagen|Jetta 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Jetta 2018-22">Buy Here</a></sub></details>||
|Volkswagen|Jetta GLI 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Jetta GLI 2021-22">Buy Here</a></sub></details>||
|Volkswagen|Passat 2015-22[<sup>11</sup>](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Passat 2015-22">Buy Here</a></sub></details>||
|Volkswagen|Passat Alltrack 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Passat Alltrack 2015-22">Buy Here</a></sub></details>||
|Volkswagen|Passat GTE 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Passat GTE 2015-22">Buy Here</a></sub></details>||
|Volkswagen|Polo 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Polo 2018-23">Buy Here</a></sub></details>[<sup>14</sup>](#footnotes)||
|Volkswagen|Polo GTI 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Polo GTI 2018-23">Buy Here</a></sub></details>[<sup>14</sup>](#footnotes)||
|Volkswagen|T-Cross 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=T-Cross 2021">Buy Here</a></sub></details>[<sup>14</sup>](#footnotes)||
|Volkswagen|T-Roc 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=T-Roc 2018-22">Buy Here</a></sub></details>[<sup>14</sup>](#footnotes)||
|Volkswagen|Taos 2022-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Taos 2022-23">Buy Here</a></sub></details>||
|Volkswagen|Teramont 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Teramont 2018-22">Buy Here</a></sub></details>||
|Volkswagen|Teramont Cross Sport 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Teramont Cross Sport 2021-22">Buy Here</a></sub></details>||
|Volkswagen|Teramont X 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Teramont X 2021-22">Buy Here</a></sub></details>||
|Volkswagen|Tiguan 2018-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Tiguan 2018-24">Buy Here</a></sub></details>||
|Volkswagen|Tiguan eHybrid 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Tiguan eHybrid 2021-23">Buy Here</a></sub></details>||
|Volkswagen|Touran 2016-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[<sup>1,13</sup>](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|<details><summary>Parts</summary><sub>- 1 J533 connector<br>- 1 USB-C coupler<br>- 1 comma 3X<br>- 1 harness box<br>- 1 long OBD-C cable<br>- 1 mount<br>- 1 right angle OBD-C cable (1.5 ft)<br><a href="https://comma.ai/shop/comma-3x.html?make=Volkswagen&model=Touran 2016-23">Buy Here</a></sub></details>||
### Footnotes
<sup>1</sup>openpilot Longitudinal Control (Alpha) is available behind a toggle; the toggle is only available in non-release branches such as `devel` or `master-ci`. <br />
@@ -284,12 +290,13 @@ A supported vehicle is one that just works when you install a comma device. All
<sup>5</sup>2019 Honda Civic 1.6L Diesel Sedan does not have ALC below 12mph. <br />
<sup>6</sup>Requires a <a href="https://comma.ai/shop/can-fd-panda-kit" target="_blank">CAN FD panda kit</a> if not using comma 3X for this <a href="https://en.wikipedia.org/wiki/CAN_FD" target="_blank">CAN FD car</a>. <br />
<sup>7</sup>In the non-US market, openpilot requires the car to come equipped with EyeSight with Lane Keep Assistance. <br />
<sup>8</sup>openpilot operates above 28mph for Camry 4CYL L, 4CYL LE and 4CYL SE which don't have Full-Speed Range Dynamic Radar Cruise Control. <br />
<sup>9</sup>Not including the China market Kamiq, which is based on the (currently) unsupported PQ34 platform. <br />
<sup>10</sup>Refers only to the MQB-based European B8 Passat, not the NMS Passat in the USA/China/Mideast markets. <br />
<sup>11</sup>Some Škoda vehicles are equipped with heated windshields, which are known to block GPS signal needed for some comma 3X functionality. <br />
<sup>12</sup>Only available for vehicles using a gateway (J533) harness. At this time, vehicles using a camera harness are limited to using stock ACC. <br />
<sup>13</sup>Model-years 2022 and beyond may have a combined CAN gateway and BCM, which is supported by openpilot in software, but doesn't yet have a harness available from the comma store. <br />
<sup>8</sup>Enabling longitudinal control (alpha) will disable all EyeSight functionality, including AEB, LDW, and RAB. <br />
<sup>9</sup>openpilot operates above 28mph for Camry 4CYL L, 4CYL LE and 4CYL SE which don't have Full-Speed Range Dynamic Radar Cruise Control. <br />
<sup>10</sup>Not including the China market Kamiq, which is based on the (currently) unsupported PQ34 platform. <br />
<sup>11</sup>Refers only to the MQB-based European B8 Passat, not the NMS Passat in the USA/China/Mideast markets. <br />
<sup>12</sup>Some Škoda vehicles are equipped with heated windshields, which are known to block GPS signal needed for some comma 3X functionality. <br />
<sup>13</sup>Only available for vehicles using a gateway (J533) harness. At this time, vehicles using a camera harness are limited to using stock ACC. <br />
<sup>14</sup>Model-years 2022 and beyond may have a combined CAN gateway and BCM, which is supported by openpilot in software, but doesn't yet have a harness available from the comma store. <br />
## Community Maintained Cars
Although they're not upstream, the community has openpilot running on other makes and models. See the 'Community Supported Models' section of each make [on our wiki](https://wiki.comma.ai/).
@@ -318,7 +325,7 @@ If your car has the following packages or features, then it's a good candidate f
### FlexRay
All the cars that openpilot supports use a [CAN bus](https://en.wikipedia.org/wiki/CAN_bus) for communication between all the car's computers, however a CAN bus isn't the only way that the cars in your computer can communicate. Most, if not all, vehicles from the following manufacturers use [FlexRay](https://en.wikipedia.org/wiki/FlexRay) instead of a CAN bus: **BMW, Mercedes, Audi, Land Rover, and some Volvo**. These cars may one day be supported, but we have no immediate plans to support FlexRay.
All the cars that openpilot supports use a [CAN bus](https://en.wikipedia.org/wiki/CAN_bus) for communication between all the car's computers, however a CAN bus isn't the only way that the computers in your car can communicate. Most, if not all, vehicles from the following manufacturers use [FlexRay](https://en.wikipedia.org/wiki/FlexRay) instead of a CAN bus: **BMW, Mercedes, Audi, Land Rover, and some Volvo**. These cars may one day be supported, but we have no immediate plans to support FlexRay.
### Toyota Security
+43 -26
View File
@@ -1,26 +1,50 @@
# How to contribute
Our software is open source so you can solve your own problems without needing help from others. And if you solve a problem and are so kind, you can upstream it for the rest of the world to use. Check out our [post about externalization](https://blog.comma.ai/a-2020-theme-externalization/).
Most open source development activity is coordinated through our [GitHub Discussions](https://github.com/commaai/openpilot/discussions) and [Discord](https://discord.comma.ai). A lot of documentation is available at https://docs.comma.ai and on our [blog](https://blog.comma.ai/).
Our software is open source so you can solve your own problems without needing help from others. And if you solve a problem and are so kind, you can upstream it for the rest of the world to use. Check out our [post about externalization](https://blog.comma.ai/a-2020-theme-externalization/). Development activity is coordinated through our GitHub Issues, [GitHub Discussions](https://github.com/commaai/openpilot/discussions), and [Discord](https://discord.comma.ai).
### Getting Started
* Setup your [development environment](../tools/)
* Join our [Discord](https://discord.comma.ai)
* Make sure you have a [GitHub account](https://github.com/signup/free)
* Fork [our repositories](https://github.com/commaai) on GitHub
* Setup your [development environment](../tools/)
* Read about the [development workflow](WORKFLOW.md)
* Join our [Discord](https://discord.comma.ai)
* Docs are at https://docs.comma.ai and https://blog.comma.ai
## What contributions are we looking for?
**openpilot's priorities are [safety](SAFETY.md), stability, quality, and features, in that order.** openpilot is part of comma's mission to *solve self-driving cars while delivering shippable intermediaries*, and **all** developoment is towards that goal.
### What gets merged?
The probability of a pull request being merged is a function of its value to the project and the effort it will take us to get it merged.
If a PR offers *some* value but will take lots of time to get merged, it will be closed.
Simple, well-tested bug fixes are the easiest to merge, and new features are the hardest to get merged.
All of these are examples of good PRs:
* typo fix: https://github.com/commaai/openpilot/pull/30678
* removing unused code: https://github.com/commaai/openpilot/pull/30573
* simple car model port: https://github.com/commaai/openpilot/pull/30245
* car brand port: https://github.com/commaai/openpilot/pull/23331
### What doesn't get merged?
* **arbitrary style changes**: code is art, and it's up to the author to make it beautiful
* **500+ line PRs**: clean it up, break it up into smaller PRs, or both
* **PRs without a clear goal**: every PR must have a singular and clear goal
* **UI design changes**: we do not have a good review process for this yet
* **New features**: We believe openpilot is mostly feature-complete, and the rest is a matter of refinement and fixing bugs. As a result of this, most feature PRs will be immediately closed, however the beauty of open source is that forks can and do offer features that upstream openpilot doesn't.
### First contribution
Try out some of these first pull requests ideas to dive into the codebase:
* Increase our [mypy](http://mypy-lang.org/) coverage
* Write some documentation
* Tackle an open [good first issue](https://github.com/commaai/openpilot/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22)
Check out any [good first issue](https://github.com/commaai/openpilot/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) to get started.
### What do I need to contribute?
A lot of openpilot work requires only a PC, and some requires a comma device.
Most car-related contributions require access to that car, plus a comma device installed in the car.
## Pull Requests
Pull requests should be against the master branch. Welcomed contributions include bug reports, car ports, and any [open issue](https://github.com/commaai/openpilot/issues). If you're unsure about a contribution, feel free to open a discussion, issue, or draft PR to discuss the problem you're trying to solve.
Pull requests should be against the master branch. If you're unsure about a contribution, feel free to open a discussion, issue, or draft PR to discuss the problem you're trying to solve.
A good pull request has all of the following:
* a clearly stated purpose
@@ -31,18 +55,11 @@ A good pull request has all of the following:
* if you've improved your car's tuning, post before and after plots
* passes the CI tests
### Car Ports
## Contributing without Code
We've released a [Model Port guide](https://blog.comma.ai/openpilot-port-guide-for-toyota-models/) for porting to Toyota/Lexus models.
If you port openpilot to a substantially new car brand, see this more generic [Brand Port guide](https://blog.comma.ai/how-to-write-a-car-port-for-openpilot/).
## Testing
### Automated Testing
All PRs and commits are automatically checked by GitHub Actions. Check out `.github/workflows/` for what GitHub Actions runs. Any new tests should be added to GitHub Actions.
### Code Style and Linting
Code is automatically checked for style by GitHub Actions as part of the automated tests. You can also run these tests yourself by running `pre-commit run --all`.
* Report bugs in GitHub issues.
* Report driving issues in the `#driving-feedback` Discord channel.
* Consider opting into driver camera uploads to improve the driver monitoring model.
* Connect your device to Wi-Fi regularly, so that we can pull data for training better driving models.
* Run the `nightly` branch and report issues. This branch is like `master` but it's built just like a release.
* Annotate images in the [comma10k dateset](https://github.com/commaai/comma10k).
-9
View File
@@ -1,9 +0,0 @@
import logging
import os
from .astro_dog import AstroDog
assert AstroDog is not None
# setup logging
LOGLEVEL = os.environ.get('LOGLEVEL', 'INFO').upper()
logging.basicConfig(level=LOGLEVEL, format='%(message)s')
-396
View File
@@ -1,396 +0,0 @@
from collections import defaultdict
from concurrent.futures import ThreadPoolExecutor
from typing import DefaultDict, Dict, Iterable, List, Optional, Union
from .constants import SECS_IN_DAY, SECS_IN_HR
from .helpers import ConstellationId, get_constellation, get_closest, get_el_az, TimeRangeHolder
from .ephemeris import Ephemeris, EphemerisType, GLONASSEphemeris, GPSEphemeris, PolyEphemeris, parse_sp3_orbits, parse_rinex_nav_msg_gps, \
parse_rinex_nav_msg_glonass
from .downloader import download_orbits_gps, download_orbits_russia_src, download_nav, download_ionex, download_dcb, download_prediction_orbits_russia_src
from .downloader import download_cors_station
from .trop import saast
from .iono import IonexMap, parse_ionex, get_slant_delay
from .dcb import DCB, parse_dcbs
from .gps_time import GPSTime
from .dgps import get_closest_station_names, parse_dgps
from . import constants
MAX_DGPS_DISTANCE = 100_000 # in meters, because we're not barbarians
class AstroDog:
'''
auto_update: flag indicating whether laika should fetch files from web automatically
cache_dir: directory where data files are downloaded to and cached
dgps: flag indicating whether laika should use dgps (CORS)
data to calculate pseudorange corrections
valid_const: list of constellation identifiers laika will try process
valid_ephem_types: set of ephemeris types that are allowed to use and download.
Default is set to use all orbit ephemeris types
clear_old_ephemeris: flag indicating if ephemeris for an individual satellite should be overwritten when new ephemeris is added.
'''
def __init__(self, auto_update=True,
cache_dir='/tmp/gnss/',
dgps=False,
valid_const=(ConstellationId.GPS, ConstellationId.GLONASS),
valid_ephem_types=EphemerisType.all_orbits(),
clear_old_ephemeris=False):
for const in valid_const:
if not isinstance(const, ConstellationId):
raise TypeError(f"valid_const must be a list of ConstellationId, got {const}")
self.auto_update = auto_update
self.cache_dir = cache_dir
self.clear_old_ephemeris = clear_old_ephemeris
self.dgps = dgps
if not isinstance(valid_ephem_types, Iterable):
valid_ephem_types = [valid_ephem_types]
self.pull_orbit = len(set(EphemerisType.all_orbits()) & set(valid_ephem_types)) > 0
self.pull_nav = EphemerisType.NAV in valid_ephem_types
self.use_qcom_poly = EphemerisType.QCOM_POLY in valid_ephem_types
self.valid_const = valid_const
self.valid_ephem_types = valid_ephem_types
self.orbit_fetched_times = TimeRangeHolder()
self.navs_fetched_times = TimeRangeHolder()
self.dcbs_fetched_times = TimeRangeHolder()
self.dgps_delays = []
self.ionex_maps: List[IonexMap] = []
self.orbits: DefaultDict[str, List[PolyEphemeris]] = defaultdict(list)
self.qcom_polys: DefaultDict[str, List[PolyEphemeris]] = defaultdict(list)
self.navs: DefaultDict[str, List[Union[GPSEphemeris, GLONASSEphemeris]]] = defaultdict(list)
self.dcbs: DefaultDict[str, List[DCB]] = defaultdict(list)
self.cached_ionex: Optional[IonexMap] = None
self.cached_dgps = None
self.cached_orbit: DefaultDict[str, Optional[PolyEphemeris]] = defaultdict(lambda: None)
self.cached_qcom_polys: DefaultDict[str, Optional[PolyEphemeris]] = defaultdict(lambda: None)
self.cached_nav: DefaultDict[str, Union[GPSEphemeris, GLONASSEphemeris, None]] = defaultdict(lambda: None)
self.cached_dcb: DefaultDict[str, Optional[DCB]] = defaultdict(lambda: None)
def get_ionex(self, time) -> Optional[IonexMap]:
ionex: Optional[IonexMap] = self._get_latest_valid_data(self.ionex_maps, self.cached_ionex, self.get_ionex_data, time)
if ionex is None:
if self.auto_update:
raise RuntimeError("Pulled ionex, but still can't get valid for time " + str(time))
else:
self.cached_ionex = ionex
return ionex
def get_nav(self, prn, time):
skip_download = time in self.navs_fetched_times
nav = self._get_latest_valid_data(self.navs[prn], self.cached_nav[prn], self.get_nav_data, time, skip_download)
if nav is not None:
self.cached_nav[prn] = nav
return nav
@staticmethod
def _select_valid_temporal_items(item_dict, time, cache):
'''Returns only valid temporal item for specific time from currently fetched
data.'''
result = {}
for prn, temporal_objects in item_dict.items():
cached = cache[prn]
if cached is not None and cached.valid(time):
obj = cached
else:
obj = get_closest(time, temporal_objects)
if obj is None or not obj.valid(time):
continue
cache[prn] = obj
result[prn] = obj
return result
def get_all_ephem_prns(self):
return set(self.orbits.keys()).union(set(self.navs.keys())).union(set(self.qcom_polys.keys()))
def get_navs(self, time):
if time not in self.navs_fetched_times:
self.get_nav_data(time)
return AstroDog._select_valid_temporal_items(self.navs, time, self.cached_nav)
def get_orbit(self, prn: str, time: GPSTime):
skip_download = time in self.orbit_fetched_times
orbit = self._get_latest_valid_data(self.orbits[prn], self.cached_orbit[prn], self.get_orbit_data, time, skip_download)
if orbit is not None:
self.cached_orbit[prn] = orbit
return orbit
def get_qcom_poly(self, prn: str, time: GPSTime):
poly = self._get_latest_valid_data(self.qcom_polys[prn], self.cached_qcom_polys[prn], None, time, True)
if poly is not None:
self.cached_qcom_polys[prn] = poly
return poly
def get_orbits(self, time):
if time not in self.orbit_fetched_times:
self.get_orbit_data(time)
return AstroDog._select_valid_temporal_items(self.orbits, time, self.cached_orbit)
def get_dcb(self, prn, time):
skip_download = time in self.dcbs_fetched_times
dcb = self._get_latest_valid_data(self.dcbs[prn], self.cached_dcb[prn], self.get_dcb_data, time, skip_download)
if dcb is not None:
self.cached_dcb[prn] = dcb
return dcb
def get_dgps_corrections(self, time, recv_pos):
latest_data = self._get_latest_valid_data(self.dgps_delays, self.cached_dgps, self.get_dgps_data, time, recv_pos=recv_pos)
if latest_data is None:
if self.auto_update:
raise RuntimeError("Pulled dgps, but still can't get valid for time " + str(time))
else:
self.cached_dgps = latest_data
return latest_data
def add_qcom_polys(self, new_ephems: Dict[str, List[Ephemeris]]):
self._add_ephems(new_ephems, self.qcom_polys)
def add_orbits(self, new_ephems: Dict[str, List[Ephemeris]]):
self._add_ephems(new_ephems, self.orbits)
def add_navs(self, new_ephems: Dict[str, List[Ephemeris]]):
self._add_ephems(new_ephems, self.navs)
def _add_ephems(self, new_ephems: Dict[str, List[Ephemeris]], ephems_dict):
for k, v in new_ephems.items():
if len(v) > 0:
if self.clear_old_ephemeris:
ephems_dict[k] = v
else:
ephems_dict[k].extend(v)
def add_ephem_fetched_time(self, ephems, fetched_times):
min_epochs = []
max_epochs = []
for v in ephems.values():
if len(v) > 0:
min_ephem, max_ephem = self.get_epoch_range(v)
min_epochs.append(min_ephem)
max_epochs.append(max_ephem)
if len(min_epochs) > 0:
min_epoch = min(min_epochs)
max_epoch = max(max_epochs)
fetched_times.add(min_epoch, max_epoch)
def get_nav_data(self, time):
def download_and_parse(constellation, parse_rinex_nav_func):
file_path = download_nav(time, cache_dir=self.cache_dir, constellation=constellation)
return parse_rinex_nav_func(file_path) if file_path else {}
fetched_ephems = {}
if ConstellationId.GPS in self.valid_const:
fetched_ephems = download_and_parse(ConstellationId.GPS, parse_rinex_nav_msg_gps)
if ConstellationId.GLONASS in self.valid_const:
for k, v in download_and_parse(ConstellationId.GLONASS, parse_rinex_nav_msg_glonass).items():
fetched_ephems.setdefault(k, []).extend(v)
self.add_navs(fetched_ephems)
if sum([len(v) for v in fetched_ephems.values()]) == 0:
begin_day = GPSTime(time.week, SECS_IN_DAY * (time.tow // SECS_IN_DAY))
end_day = GPSTime(time.week, SECS_IN_DAY * (1 + (time.tow // SECS_IN_DAY)))
self.navs_fetched_times.add(begin_day, end_day)
def download_parse_orbit(self, gps_time: GPSTime, skip_before_epoch=None) -> Dict[str, List[PolyEphemeris]]:
# Download multiple days to be able to polyfit at the start-end of the day
time_steps = [gps_time - SECS_IN_DAY, gps_time, gps_time + SECS_IN_DAY]
with ThreadPoolExecutor() as executor:
futures_other = [executor.submit(download_orbits_russia_src, t, self.cache_dir, self.valid_ephem_types) for t in time_steps]
futures_gps = None
if ConstellationId.GPS in self.valid_const:
futures_gps = [executor.submit(download_orbits_gps, t, self.cache_dir, self.valid_ephem_types) for t in time_steps]
ephems_other = parse_sp3_orbits([f.result() for f in futures_other if f.result()], self.valid_const, skip_before_epoch)
ephems_us = parse_sp3_orbits([f.result() for f in futures_gps if f.result()], self.valid_const, skip_before_epoch) if futures_gps else {}
return {k: ephems_other.get(k, []) + ephems_us.get(k, []) for k in set(list(ephems_other.keys()) + list(ephems_us.keys()))}
def download_parse_prediction_orbit(self, gps_time: GPSTime):
assert EphemerisType.ULTRA_RAPID_ORBIT in self.valid_ephem_types
skip_until_epoch = gps_time - 2 * SECS_IN_HR
result = download_prediction_orbits_russia_src(gps_time, self.cache_dir)
if result is not None:
result = [result]
elif ConstellationId.GPS in self.valid_const:
# Slower fallback. Russia src prediction orbits are published from 2022
result = [download_orbits_gps(t, self.cache_dir, self.valid_ephem_types) for t in [gps_time - SECS_IN_DAY, gps_time]]
if result is None:
return {}
return parse_sp3_orbits(result, self.valid_const, skip_until_epoch=skip_until_epoch)
def get_orbit_data(self, time: GPSTime, only_predictions=False):
if only_predictions:
ephems_sp3 = self.download_parse_prediction_orbit(time)
else:
ephems_sp3 = self.download_parse_orbit(time)
if sum([len(v) for v in ephems_sp3.values()]) < 5:
raise RuntimeError(f'No orbit data found. For Time {time.as_datetime()} constellations {self.valid_const} valid ephem types {self.valid_ephem_types}')
self.add_ephem_fetched_time(ephems_sp3, self.orbit_fetched_times)
self.add_orbits(ephems_sp3)
def get_dcb_data(self, time):
file_path_dcb = download_dcb(time, cache_dir=self.cache_dir)
dcbs = parse_dcbs(file_path_dcb, self.valid_const)
for dcb in dcbs:
self.dcbs[dcb.prn].append(dcb)
if len(dcbs) != 0:
min_epoch, max_epoch = self.get_epoch_range(dcbs)
self.dcbs_fetched_times.add(min_epoch, max_epoch)
def get_epoch_range(self, new_ephems):
min_ephem = min(new_ephems, key=lambda e: e.epoch)
max_ephem = max(new_ephems, key=lambda e: e.epoch)
min_epoch = min_ephem.epoch - min_ephem.max_time_diff
max_epoch = max_ephem.epoch + max_ephem.max_time_diff
return min_epoch, max_epoch
def get_ionex_data(self, time):
file_path_ionex = download_ionex(time, cache_dir=self.cache_dir)
ionex_maps = parse_ionex(file_path_ionex)
for im in ionex_maps:
self.ionex_maps.append(im)
def get_dgps_data(self, time, recv_pos):
station_names = get_closest_station_names(recv_pos, k=8, max_distance=MAX_DGPS_DISTANCE, cache_dir=self.cache_dir)
for station_name in station_names:
file_path_station = download_cors_station(time, station_name, cache_dir=self.cache_dir)
if file_path_station:
dgps = parse_dgps(station_name, file_path_station,
self, max_distance=MAX_DGPS_DISTANCE,
required_constellations=self.valid_const)
if dgps is not None:
self.dgps_delays.append(dgps)
break
def get_tgd_from_nav(self, prn, time):
if get_constellation(prn) not in self.valid_const:
return None
eph = self.get_nav(prn, time)
if eph:
return eph.get_tgd()
return None
def get_eph(self, prn, time):
if get_constellation(prn) not in self.valid_const:
return None
eph = None
if self.pull_orbit:
eph = self.get_orbit(prn, time)
if not eph and self.pull_nav:
eph = self.get_nav(prn, time)
if not eph and self.use_qcom_poly:
eph = self.get_qcom_poly(prn, time)
return eph
def get_sat_info(self, prn, time):
eph = self.get_eph(prn, time)
if eph:
return eph.get_sat_info(time)
return None
def get_all_sat_info(self, time):
ephs = {}
if self.pull_orbit:
ephs = self.get_orbits(time)
if len(ephs) == 0 and self.pull_nav:
ephs = self.get_navs(time)
return {prn: eph.get_sat_info(time) for prn, eph in ephs.items()}
def get_glonass_channel(self, prn, time):
nav = self.get_nav(prn, time)
if nav:
return nav.channel
return None
def get_frequency(self, prn, time, signal='C1C'):
if get_constellation(prn) == ConstellationId.GPS:
switch = {'1': constants.GPS_L1,
'2': constants.GPS_L2,
'5': constants.GPS_L5,
'6': constants.GALILEO_E6,
'7': constants.GALILEO_E5B,
'8': constants.GALILEO_E5AB}
freq = switch.get(signal[1])
if freq:
return freq
raise NotImplementedError("Dont know this GPS frequency: ", signal, prn)
elif get_constellation(prn) == ConstellationId.GLONASS:
n = self.get_glonass_channel(prn, time)
if n is None:
return None
switch = {'1': constants.GLONASS_L1 + n * constants.GLONASS_L1_DELTA,
'2': constants.GLONASS_L2 + n * constants.GLONASS_L2_DELTA,
'5': constants.GLONASS_L5 + n * constants.GLONASS_L5_DELTA,
'6': constants.GALILEO_E6,
'7': constants.GALILEO_E5B,
'8': constants.GALILEO_E5AB}
freq = switch.get(signal[1])
if freq:
return freq
raise NotImplementedError("Dont know this GLONASS frequency: ", signal, prn)
def get_delay(self, prn, time, rcv_pos, no_dgps=False, signal='C1C', freq=None):
sat_info = self.get_sat_info(prn, time)
if sat_info is None:
return None
sat_pos = sat_info[0]
el, az = get_el_az(rcv_pos, sat_pos)
if el < 0.2:
return None
if self.dgps and not no_dgps:
return self._get_delay_dgps(prn, rcv_pos, time)
ionex = self.get_ionex(time)
if not freq and ionex is not None:
freq = self.get_frequency(prn, time, signal)
dcb = self.get_dcb(prn, time)
# When using internet we expect all data or return None
if self.auto_update and (ionex is None or dcb is None or freq is None):
return None
if ionex is not None:
iono_delay = ionex.get_delay(rcv_pos, az, el, sat_pos, time, freq)
else:
# 5m vertical delay is a good default
iono_delay = get_slant_delay(rcv_pos, az, el, sat_pos, time, freq, vertical_delay=5.0)
trop_delay = saast(rcv_pos, el)
code_bias = dcb.get_delay(signal) if dcb is not None else 0.
return iono_delay + trop_delay + code_bias
def _get_delay_dgps(self, prn, rcv_pos, time):
dgps_corrections = self.get_dgps_corrections(time, rcv_pos)
if dgps_corrections is None:
return None
return dgps_corrections.get_delay(prn, time)
def _get_latest_valid_data(self, data, latest_data, download_data_func, time, skip_download=False, recv_pos=None):
def is_valid(latest_data):
if recv_pos is None:
return latest_data is not None and latest_data.valid(time)
else:
return latest_data is not None and latest_data.valid(time, recv_pos)
if is_valid(latest_data):
return latest_data
latest_data = get_closest(time, data, recv_pos=recv_pos)
if is_valid(latest_data):
return latest_data
if skip_download or not self.auto_update:
return None
if recv_pos is not None:
download_data_func(time, recv_pos)
else:
download_data_func(time)
latest_data = get_closest(time, data, recv_pos=recv_pos)
if is_valid(latest_data):
return latest_data
return None
-34
View File
@@ -1,34 +0,0 @@
# These are all from IS-GPS-200G unless otherwise noted
SPEED_OF_LIGHT = 2.99792458e8 # m/s
# Physical parameters of the Earth
EARTH_GM = 3.986005e14 # m^3/s^2 (gravitational constant * mass of earth)
EARTH_RADIUS = 6.3781e6 # m
EARTH_ROTATION_RATE = 7.2921151467e-005 # rad/s (WGS84 earth rotation rate)
# GPS system parameters:
GPS_L1 = l1 = 1.57542e9 # Hz
GPS_L2 = l2 = 1.22760e9 # Hz
GPS_L5 = l5 = 1.17645e9 # Hz Also E5
#GLONASS system parameters
#TODO this is old convention
GLONASS_L1 = 1.602e9
GLONASS_L1_DELTA = 0.5625e6
GLONASS_L2 = 1.246e9
GLONASS_L2_DELTA = 0.4375e6
GLONASS_L5 = 1.201e9
GLONASS_L5_DELTA = 0.4375e6
#Galileo system parameters: # Has additional frequencies on E6
#Source RINEX 2.11 document
GALILEO_E5B = 1.207140e9 # Hz
GALILEO_E5AB = 1.191795e9 # Hz
GALILEO_E6 = 1.27875e9 # Hz
SECS_IN_MIN = 60
SECS_IN_HR = 60*SECS_IN_MIN
SECS_IN_DAY = 24*SECS_IN_HR
SECS_IN_WEEK = 7*SECS_IN_DAY
SECS_IN_YEAR = 365*SECS_IN_DAY
-84
View File
@@ -1,84 +0,0 @@
from datetime import datetime
from .constants import SECS_IN_HR, SECS_IN_WEEK, \
SPEED_OF_LIGHT, GPS_L1, GPS_L2
from .gps_time import GPSTime
from .helpers import get_constellation
import warnings
class DCB:
def __init__(self, prn, data):
self.max_time_diff = 2*SECS_IN_WEEK
self.prn = prn
self.epoch = data['epoch']
self.healthy = True
if 'C1W_C2W' in data:
self.C1W_C2W = data['C1W_C2W']
elif 'C1P_C2P' in data:
self.C1W_C2W = data['C1P_C2P']
else:
self.healthy = False
if 'C1C_C1W' in data:
self.C1C_C1W = data['C1C_C1W']
elif 'C1C_C1P' in data:
self.C1C_C1W = data['C1C_C1P']
else:
self.healthy = False
def valid(self, time):
return abs(time - self.epoch) <= self.max_time_diff and self.healthy
def get_delay(self, signal):
if signal == 'C1C':
return (- SPEED_OF_LIGHT*1e-9*self.C1W_C2W*GPS_L2**2/(GPS_L1**2 - GPS_L2**2)
+ SPEED_OF_LIGHT*1e-9*self.C1C_C1W)
if signal == 'C2P':
return (- SPEED_OF_LIGHT*1e-9*self.C1W_C2W*GPS_L1**2/(GPS_L1**2 - GPS_L2**2))
if signal == 'C1P':
return (SPEED_OF_LIGHT*1e-9*self.C1C_C1W)
## Todo: update dcb database and get delay to include additional signals
if signal == 'C2C':
warnings.warn("Differential code bias not implemented for signal C2C", UserWarning)
return 0
if signal == 'C5C':
warnings.warn("Differential code bias not implemented for signal C5C", UserWarning)
return 0
if signal == 'C6C':
warnings.warn("Differential code bias not implemented for signal C6C", UserWarning)
return 0
if signal == 'C7C':
warnings.warn("Differential code bias not implemented for signal C7C", UserWarning)
return 0
if signal == 'C8C':
warnings.warn("Differential code bias not implemented for signal C8C", UserWarning)
return 0
def parse_dcbs(file_name, SUPPORTED_CONSTELLATIONS):
with open(file_name, 'r+') as DCB_file:
contents = DCB_file.readlines()
data_started = False
dcbs_dict = {}
for line in contents:
if not data_started:
if line[1:4] == 'DSB':
data_started = True
else:
continue
line_components = line.split()
if len(line_components[2]) < 3:
break
prn = line_components[2]
if get_constellation(prn) not in SUPPORTED_CONSTELLATIONS:
continue
dcb_type = line_components[3] + '_' + line_components[4]
epoch = GPSTime.from_datetime(datetime.strptime(line_components[5], '%Y:%j:%f')) + 12*SECS_IN_HR
if prn not in dcbs_dict:
dcbs_dict[prn] = {}
dcbs_dict[prn][dcb_type] = float(line_components[8])
dcbs_dict[prn]['epoch'] = epoch
dcbs = []
for prn in dcbs_dict:
dcbs.append(DCB(prn, dcbs_dict[prn]))
return dcbs
-161
View File
@@ -1,161 +0,0 @@
import os
import numpy as np
from datetime import datetime
from .gps_time import GPSTime
from .constants import SECS_IN_YEAR
from . import raw_gnss as raw
from . import opt
from .rinex_file import RINEXFile
from .downloader import download_cors_coords
from .helpers import get_constellation, ConstellationId
def mean_filter(delay):
d2 = delay.copy()
max_step = 10
for i in range(max_step, len(delay) - max_step):
finite_idxs = np.where(np.isfinite(delay[i - max_step:i + max_step]))
if max_step in finite_idxs[0]:
step = min([max_step, finite_idxs[0][-1] - max_step, max_step - finite_idxs[0][0]])
d2[i] = np.nanmean(delay[i - step:i + step + 1])
return d2
def download_and_parse_station_postions(cors_station_positions_path, cache_dir):
if not os.path.isfile(cors_station_positions_path):
cors_stations = {}
coord_file_paths = download_cors_coords(cache_dir=cache_dir)
for coord_file_path in coord_file_paths:
try:
station_id = coord_file_path.split('/')[-1][:4]
with open(coord_file_path, 'r+') as coord_file:
contents = coord_file.readlines()
phase_center = False
for line_number in range(len(contents)):
if 'L1 Phase Center' in contents[line_number]:
phase_center = True
if not phase_center and 'ITRF2014 POSITION' in contents[line_number]:
velocity = [float(contents[line_number+8].split()[3]),
float(contents[line_number+9].split()[3]),
float(contents[line_number+10].split()[3])]
if phase_center and 'ITRF2014 POSITION' in contents[line_number]:
epoch = GPSTime.from_datetime(datetime(2005,1,1))
position = [float(contents[line_number+2].split()[3]),
float(contents[line_number+3].split()[3]),
float(contents[line_number+4].split()[3])]
cors_stations[station_id] = [epoch, position, velocity]
break
except ValueError:
pass
cors_station_positions_file = open(cors_station_positions_path, 'wb')
np.save(cors_station_positions_file, cors_stations)
cors_station_positions_file.close()
def get_closest_station_names(pos, k=5, max_distance=100000, cache_dir='/tmp/gnss/'):
from scipy.spatial import cKDTree
cors_station_positions_dict = load_cors_station_positions(cache_dir)
station_ids = list(cors_station_positions_dict.keys())
station_positions = []
for station_id in station_ids:
station_positions.append(cors_station_positions_dict[station_id][1])
tree = cKDTree(station_positions)
distances, idxs = tree.query(pos, k=k, distance_upper_bound=max_distance)
return np.array(station_ids)[idxs]
def load_cors_station_positions(cache_dir):
cors_station_positions_path = cache_dir + 'cors_coord/cors_station_positions'
download_and_parse_station_postions(cors_station_positions_path, cache_dir)
with open(cors_station_positions_path, 'rb') as f:
return np.load(f, allow_pickle=True).item() # pylint: disable=unexpected-keyword-arg
def get_station_position(station_id, cache_dir='/tmp/gnss/', time=GPSTime.from_datetime(datetime.utcnow())):
cors_station_positions_dict = load_cors_station_positions(cache_dir)
epoch, pos, vel = cors_station_positions_dict[station_id]
return ((time - epoch)/SECS_IN_YEAR)*np.array(vel) + np.array(pos)
def parse_dgps(station_id, station_obs_file_path, dog, max_distance=100000, required_constellations=[ConstellationId.GPS]):
station_pos = get_station_position(station_id, cache_dir=dog.cache_dir)
obsdata = RINEXFile(station_obs_file_path)
measurements = raw.read_rinex_obs(obsdata)
# if not all constellations in first 100 epochs bail
detected_constellations = set()
for m in sum(measurements[:100],[]):
detected_constellations.add(get_constellation(m.prn))
for constellation in required_constellations:
if constellation not in detected_constellations:
return None
proc_measurements = []
for measurement in measurements:
proc_measurements.append(raw.process_measurements(measurement, dog=dog))
# sample at 30s
if len(proc_measurements) > 2880:
proc_measurements = proc_measurements[::int(len(proc_measurements)/2880)]
if len(proc_measurements) != 2880:
return None
station_delays = {}
n = len(proc_measurements)
for signal in ['C1C', 'C2P']:
times = []
station_delays[signal] = {}
for i, proc_measurement in enumerate(proc_measurements):
times.append(proc_measurement[0].recv_time)
Fx_pos = opt.pr_residual(proc_measurement, signal=signal)
residual, _ = Fx_pos(list(station_pos) + [0,0])
residual = -np.array(residual)
for j, m in enumerate(proc_measurement):
prn = m.prn
if prn not in station_delays[signal]:
station_delays[signal][prn] = np.nan*np.ones(n)
station_delays[signal][prn][i] = residual[j]
assert len(times) == n
# TODO crude way to get dgps station's clock errors,
# could this be biased? Only use GPS for convenience.
model_delays = {}
for prn in station_delays['C1C']:
if get_constellation(prn) == ConstellationId.GPS:
model_delays[prn] = np.nan*np.zeros(n)
for i in range(n):
model_delays[prn][i] = dog.get_delay(prn, times[i], station_pos, no_dgps=True)
station_clock_errs = np.zeros(n)
for i in range(n):
station_clock_errs[i] = np.nanmean([(station_delays['C1C'][prn][i] - model_delays[prn][i]) for prn in model_delays])
# remove clock errors and smooth out signal
for prn in station_delays['C1C']:
station_delays['C1C'][prn] = mean_filter(station_delays['C1C'][prn] - station_clock_errs)
for prn in station_delays['C2P']:
station_delays['C2P'][prn] = station_delays['C2P'][prn] - station_clock_errs
return DGPSDelay(station_id, station_pos, station_delays,
times, max_distance)
class DGPSDelay:
def __init__(self, station_id, station_pos,
station_delays, station_delays_t, max_distance):
self.id = station_id
self.pos = station_pos
self.delays = station_delays
self.delays_t = station_delays_t
self.max_distance = max_distance
def get_delay(self, prn, time, signal='C1C'):
time_index = int((time - self.delays_t[0])/30)
assert abs(self.delays_t[time_index] - time) < 30
if prn in self.delays[signal] and np.isfinite(self.delays[signal][prn][time_index]):
return self.delays[signal][prn][time_index]
return None
def valid(self, time, recv_pos):
return (np.linalg.norm(recv_pos - self.pos) <= self.max_distance and
time - self.delays_t[0] > -30 and
self.delays_t[-1] - time > -30)
-473
View File
@@ -1,473 +0,0 @@
import certifi
import ftplib
import hatanaka
import os
import pycurl
import re
import time
import socket
import logging
from datetime import datetime, timedelta
from urllib.parse import urlparse
from io import BytesIO
from ftplib import FTP_TLS, FTP
from atomicwrites import atomic_write
from laika.ephemeris import EphemerisType
from .constants import SECS_IN_HR, SECS_IN_DAY, SECS_IN_WEEK
from .gps_time import GPSTime, tow_to_datetime
from .helpers import ConstellationId
dir_path = os.path.dirname(os.path.realpath(__file__))
class DownloadFailed(Exception):
pass
def retryable(f):
"""
Decorator to allow us to pass multiple URLs from which to download.
Automatically retry the request with the next URL on failure
"""
def wrapped(url_bases, *args, **kwargs):
if isinstance(url_bases, str):
# only one url passed, don't do the retry thing
return f(url_bases, *args, **kwargs)
# not a string, must be a list of url_bases
for url_base in url_bases:
try:
return f(url_base, *args, **kwargs)
except DownloadFailed as e:
logging.warning(e)
# none of them succeeded
raise DownloadFailed("Multiple URL failures attempting to pull file(s)")
return wrapped
def ftp_connect(url):
parsed = urlparse(url)
assert parsed.scheme == 'ftp'
try:
domain = parsed.netloc
ftp = ftplib.FTP(domain, timeout=10)
ftp.login()
except (OSError, ftplib.error_perm):
raise DownloadFailed("Could not connect/auth to: " + domain)
try:
ftp.cwd(parsed.path)
except ftplib.error_perm:
raise DownloadFailed("Permission failure with folder: " + url)
return ftp
@retryable
def list_dir(url):
parsed = urlparse(url)
if parsed.scheme == 'ftp':
try:
ftp = ftp_connect(url)
return ftp.nlst()
except ftplib.error_perm:
raise DownloadFailed("Permission failure listing folder: " + url)
else:
# just connect and do simple url parsing
listing = https_download_file(url)
urls = re.findall(b"<a href=\"([^\"]+)\">", listing)
# decode the urls to normal strings. If they are complicated paths, ignore them
return [name.decode("latin1") for name in urls if name and b"/" not in name[1:]]
def ftp_download_files(url_base, folder_path, cacheDir, filenames):
"""
Like download file, but more of them. Keeps a persistent FTP connection open
to be more efficient.
"""
folder_path_abs = os.path.join(cacheDir, folder_path)
ftp = ftp_connect(url_base + folder_path)
filepaths = []
for filename in filenames:
# os.path.join will be dumb if filename has a leading /
# if there is a / in the filename, then it's using a different folder
filename = filename.lstrip("/")
if "/" in filename:
continue
filepath = os.path.join(folder_path_abs, filename)
logging.debug("pulling from", url_base, "to", filepath)
if not os.path.isfile(filepath):
os.makedirs(folder_path_abs, exist_ok=True)
try:
ftp.retrbinary('RETR ' + filename, open(filepath, 'wb').write)
except (ftplib.error_perm):
raise DownloadFailed("Could not download file from: " + url_base + folder_path + filename)
except (socket.timeout):
raise DownloadFailed("Read timed out from: " + url_base + folder_path + filename)
filepaths.append(filepath)
else:
filepaths.append(filepath)
return filepaths
def http_download_files(url_base, folder_path, cacheDir, filenames):
"""
Similar to ftp_download_files, attempt to download multiple files faster than
just downloading them one-by-one.
Returns a list of filepaths instead of the raw data
"""
folder_path_abs = os.path.join(cacheDir, folder_path)
def write_function(disk_path, handle):
def do_write(data):
open(disk_path, "wb").write(data)
return do_write
fetcher = pycurl.CurlMulti()
fetcher.setopt(pycurl.M_PIPELINING, 3)
fetcher.setopt(pycurl.M_MAX_HOST_CONNECTIONS, 64)
fetcher.setopt(pycurl.M_MAX_TOTAL_CONNECTIONS, 64)
filepaths = []
for filename in filenames:
# os.path.join will be dumb if filename has a leading /
# if there is a / in the filename, then it's using a different folder
filename = filename.lstrip("/")
if "/" in filename:
continue
filepath = os.path.join(folder_path_abs, filename)
if not os.path.isfile(filepath):
logging.debug("pulling from", url_base, "to", filepath)
os.makedirs(folder_path_abs, exist_ok=True)
url_path = url_base + folder_path + filename
handle = pycurl.Curl()
handle.setopt(pycurl.URL, url_path)
handle.setopt(pycurl.CONNECTTIMEOUT, 10)
handle.setopt(pycurl.WRITEFUNCTION, write_function(filepath, handle))
fetcher.add_handle(handle)
filepaths.append(filepath)
requests_processing = len(filepaths)
timeout = 10.0 # after 10 seconds of nothing happening, restart
deadline = time.time() + timeout
while requests_processing and time.time() < deadline:
while True:
ret, cur_requests_processing = fetcher.perform()
if ret != pycurl.E_CALL_MULTI_PERFORM:
_, success, failed = fetcher.info_read()
break
if requests_processing > cur_requests_processing:
deadline = time.time() + timeout
requests_processing = cur_requests_processing
if fetcher.select(1) < 0:
continue
# if there are downloads left to be done, repeat, and don't overwrite
_, requests_processing = fetcher.perform()
if requests_processing > 0:
logging.warning("some requests stalled, retrying them")
return http_download_files(url_base, folder_path, cacheDir, filenames)
return filepaths
def https_download_file(url):
crl = pycurl.Curl()
crl.setopt(crl.CAINFO, certifi.where())
crl.setopt(crl.URL, url)
crl.setopt(crl.FOLLOWLOCATION, True)
crl.setopt(crl.SSL_CIPHER_LIST, 'DEFAULT@SECLEVEL=1')
crl.setopt(crl.COOKIEJAR, '/tmp/cddis_cookies')
crl.setopt(pycurl.CONNECTTIMEOUT, 10)
buf = BytesIO()
crl.setopt(crl.WRITEDATA, buf)
crl.perform()
response = crl.getinfo(pycurl.RESPONSE_CODE)
crl.close()
if response != 200:
raise DownloadFailed('HTTPS error ' + str(response))
return buf.getvalue()
def ftp_download_file(url):
parsed = urlparse(url)
is_sftp = parsed.scheme == "sftp"
try:
buf = BytesIO()
with FTP_TLS(parsed.hostname) if is_sftp else FTP(parsed.hostname) as ftp:
ftp.login(user='anonymous')
if is_sftp:
ftp.prot_p()
ftp.retrbinary('RETR ' + parsed.path, buf.write)
return buf.getvalue()
except ftplib.all_errors as e:
raise DownloadFailed(e)
@retryable
def download_files(url_base, folder_path, cacheDir, filenames):
parsed = urlparse(url_base)
if parsed.scheme == 'ftp':
return ftp_download_files(url_base, folder_path, cacheDir, filenames)
else:
return http_download_files(url_base, folder_path, cacheDir, filenames)
@retryable
def download_file(url_base, folder_path, filename_zipped):
url = url_base + folder_path + filename_zipped
logging.debug('Downloading ' + url)
if url.startswith('https://'):
return https_download_file(url)
elif url.startswith(('ftp://', 'sftp://')):
return ftp_download_file(url)
raise NotImplementedError('Did not find supported url scheme')
def download_and_cache_file_return_first_success(url_bases, folder_and_file_names, cache_dir, compression='', overwrite=False, raise_error=False):
last_error = None
for folder_path, filename in folder_and_file_names:
try:
file = download_and_cache_file(url_bases, folder_path, cache_dir, filename, compression, overwrite)
return file
except DownloadFailed as e:
last_error = e
if last_error and raise_error:
raise last_error
def download_and_cache_file(url_base, folder_path: str, cache_dir: str, filename: str, compression='', overwrite=False):
filename_zipped = filename + compression
folder_path_abs = os.path.join(cache_dir, folder_path)
filepath = str(hatanaka.get_decompressed_path(os.path.join(folder_path_abs, filename)))
filepath_attempt = filepath + '.attempt_time'
if os.path.exists(filepath_attempt):
with open(filepath_attempt, 'r') as rf:
last_attempt_time = float(rf.read())
if time.time() - last_attempt_time < SECS_IN_HR:
raise DownloadFailed(f"Too soon to try downloading {folder_path + filename_zipped} from {url_base} again since last attempt")
if not os.path.isfile(filepath) or overwrite:
try:
data_zipped = download_file(url_base, folder_path, filename_zipped)
except (DownloadFailed, pycurl.error, socket.timeout):
unix_time = time.time()
os.makedirs(folder_path_abs, exist_ok=True)
with atomic_write(filepath_attempt, mode='w', overwrite=True) as wf:
wf.write(str(unix_time))
raise DownloadFailed(f"Could not download {folder_path + filename_zipped} from {url_base} ")
os.makedirs(folder_path_abs, exist_ok=True)
ephem_bytes = hatanaka.decompress(data_zipped)
try:
with atomic_write(filepath, mode='wb', overwrite=overwrite) as f:
f.write(ephem_bytes)
except FileExistsError:
# Only happens when same file is downloaded in parallel by another process.
pass
return filepath
# Currently, only GPS and Glonass are supported for daily and hourly data.
CONSTELLATION_NASA_CHAR = {ConstellationId.GPS: 'n', ConstellationId.GLONASS: 'g'}
def download_nav(time: GPSTime, cache_dir, constellation: ConstellationId):
t = time.as_datetime()
try:
if constellation not in CONSTELLATION_NASA_CHAR:
return None
c = CONSTELLATION_NASA_CHAR[constellation]
if GPSTime.from_datetime(datetime.utcnow()) - time > SECS_IN_DAY:
url_bases = (
'https://github.com/commaai/gnss-data/raw/master/gnss/data/daily/',
'sftp://gdc.cddis.eosdis.nasa.gov/gnss/data/daily/',
)
filename = t.strftime(f"brdc%j0.%y{c}")
folder_path = t.strftime(f'%Y/%j/%y{c}/')
compression = '.gz' if folder_path >= '2020/335/' else '.Z'
return download_and_cache_file(url_bases, folder_path, cache_dir+'daily_nav/', filename, compression)
else:
url_bases = (
'https://github.com/commaai/gnss-data-hourly/raw/master/',
'sftp://gdc.cddis.eosdis.nasa.gov/gnss/data/hourly/',
)
times = [t, (t - timedelta(hours=1))]
folder_and_filenames = [(t.strftime('%Y/%j/'), t.strftime(f"hour%j0.%y{c}")) for t in times]
compression = '.gz' if folder_and_filenames[0][0] >= '2020/336/' else '.Z'
# always overwrite as this file is appended
return download_and_cache_file_return_first_success(url_bases,
folder_and_filenames, cache_dir+'hourly_nav/', compression, overwrite=True)
except DownloadFailed:
pass
def download_orbits_gps_cod0(time, cache_dir, ephem_types):
url_bases = (
'https://github.com/commaai/gnss-data/raw/master/gnss/products/',
'sftp://gdc.cddis.eosdis.nasa.gov/gnss/products/',
)
if EphemerisType.ULTRA_RAPID_ORBIT not in ephem_types:
# TODO: raise error here
return None
tm = tow_to_datetime(time.tow, time.week).timetuple()
doy = str(tm.tm_yday).zfill(3)
filename = f"COD0OPSULT_{tm.tm_year}{doy}0000_02D_05M_ORB.SP3"
# TODO: add hour management
folder_path = "%i/" % time.week
folder_file_names = [(folder_path, filename)]
return download_and_cache_file_return_first_success(url_bases, folder_file_names, cache_dir+'cddis_products/', compression='.gz')
def download_orbits_gps(time, cache_dir, ephem_types):
url_bases = (
'https://github.com/commaai/gnss-data/raw/master/gnss/products/',
'sftp://gdc.cddis.eosdis.nasa.gov/gnss/products/',
'ftp://igs.ign.fr/pub/igs/products/',
)
folder_path = "%i/" % time.week
filenames = []
time_str = "%i%i" % (time.week, time.day)
# Download filenames in order of quality. Final -> Rapid -> Ultra-Rapid(newest first)
if EphemerisType.FINAL_ORBIT in ephem_types and GPSTime.from_datetime(datetime.utcnow()) - time > 3 * SECS_IN_WEEK:
filenames.append(f"igs{time_str}.sp3")
if EphemerisType.RAPID_ORBIT in ephem_types:
filenames.append(f"igr{time_str}.sp3")
if EphemerisType.ULTRA_RAPID_ORBIT in ephem_types:
filenames.extend([f"igu{time_str}_18.sp3",
f"igu{time_str}_12.sp3",
f"igu{time_str}_06.sp3",
f"igu{time_str}_00.sp3"])
folder_file_names = [(folder_path, filename) for filename in filenames]
ret = download_and_cache_file_return_first_success(url_bases, folder_file_names, cache_dir+'cddis_products/', compression='.Z')
if ret is not None:
return ret
# fallback to COD0 Ultra Rapid Orbits
return download_orbits_gps_cod0(time, cache_dir, ephem_types)
def download_prediction_orbits_russia_src(gps_time, cache_dir):
# Download single file that contains Ultra_Rapid predictions for GPS, GLONASS and other constellations
t = gps_time.as_datetime()
# Files exist starting at 29-01-2022
if t < datetime(2022, 1, 29):
return None
url_bases = 'https://github.com/commaai/gnss-data-alt/raw/master/MCC/PRODUCTS/'
folder_path = t.strftime('%y%j/ultra/')
file_prefix = "Stark_1D_" + t.strftime('%y%m%d')
# Predictions are 24H so previous day can also be used.
prev_day = (t - timedelta(days=1))
file_prefix_prev = "Stark_1D_" + prev_day.strftime('%y%m%d')
folder_path_prev = prev_day.strftime('%y%j/ultra/')
current_day = GPSTime.from_datetime(datetime(t.year, t.month, t.day))
# Ultra-Orbit is published in gnss-data-alt every 10th minute past the 5,11,17,23 hour.
# Predictions published are delayed by around 10 hours.
# Download latest file that includes gps_time with 20 minutes margin.:
if gps_time > current_day + 23.5 * SECS_IN_HR:
prev_day, current_day = [], [6, 12]
elif gps_time > current_day + 17.5 * SECS_IN_HR:
prev_day, current_day = [], [0, 6]
elif gps_time > current_day + 11.5 * SECS_IN_HR:
prev_day, current_day = [18], [0]
elif gps_time > current_day + 5.5 * SECS_IN_HR:
prev_day, current_day = [12, 18], []
else:
prev_day, current_day = [6, 12], []
# Example: Stark_1D_22060100.sp3
folder_and_file_names = [(folder_path, file_prefix + f"{h:02}.sp3") for h in reversed(current_day)] + \
[(folder_path_prev, file_prefix_prev + f"{h:02}.sp3") for h in reversed(prev_day)]
return download_and_cache_file_return_first_success(url_bases, folder_and_file_names, cache_dir+'russian_products/', raise_error=True)
def download_orbits_russia_src(time, cache_dir, ephem_types):
# Orbits from russian source. Contains GPS, GLONASS, GALILEO, BEIDOU
url_bases = (
'https://github.com/commaai/gnss-data-alt/raw/master/MCC/PRODUCTS/',
'ftp://ftp.glonass-iac.ru/MCC/PRODUCTS/',
)
t = time.as_datetime()
folder_paths = []
current_gps_time = GPSTime.from_datetime(datetime.utcnow())
filename = "Sta%i%i.sp3" % (time.week, time.day)
if EphemerisType.FINAL_ORBIT in ephem_types and current_gps_time - time > 2 * SECS_IN_WEEK:
folder_paths.append(t.strftime('%y%j/final/'))
if EphemerisType.RAPID_ORBIT in ephem_types:
folder_paths.append(t.strftime('%y%j/rapid/'))
if EphemerisType.ULTRA_RAPID_ORBIT in ephem_types:
folder_paths.append(t.strftime('%y%j/ultra/'))
folder_file_names = [(folder_path, filename) for folder_path in folder_paths]
return download_and_cache_file_return_first_success(url_bases, folder_file_names, cache_dir+'russian_products/')
def download_ionex(time, cache_dir):
t = time.as_datetime()
url_bases = (
'https://github.com/commaai/gnss-data/raw/master/gnss/products/ionex/',
'sftp://gdc.cddis.eosdis.nasa.gov/gnss/products/ionex/',
'ftp://igs.ensg.ign.fr/pub/igs/products/ionosphere/',
'ftp://gssc.esa.int/gnss/products/ionex/',
)
folder_path = t.strftime('%Y/%j/')
filenames = [t.strftime("codg%j0.%yi"), t.strftime("c1pg%j0.%yi"), t.strftime("c2pg%j0.%yi")]
folder_file_names = [(folder_path, f) for f in filenames]
return download_and_cache_file_return_first_success(url_bases, folder_file_names, cache_dir+'ionex/', compression='.Z', raise_error=True)
def download_dcb(time, cache_dir):
filenames = []
folder_paths = []
url_bases = (
'https://github.com/commaai/gnss-data/raw/master/gnss/products/bias/',
'sftp://gdc.cddis.eosdis.nasa.gov/gnss/products/bias/',
'ftp://igs.ign.fr/pub/igs/products/mgex/dcb/',
)
# seem to be a lot of data missing, so try many days
for time_step in [time - i * SECS_IN_DAY for i in range(14)]:
t = time_step.as_datetime()
folder_paths.append(t.strftime('%Y/'))
filenames.append(t.strftime("CAS0MGXRAP_%Y%j0000_01D_01D_DCB.BSX"))
return download_and_cache_file_return_first_success(url_bases, list(zip(folder_paths, filenames)), cache_dir+'dcb/', compression='.gz', raise_error=True)
def download_cors_coords(cache_dir):
cache_subdir = cache_dir + 'cors_coord/'
url_bases = (
'https://geodesy.noaa.gov/corsdata/coord/coord_14/',
'https://alt.ngs.noaa.gov/corsdata/coord/coord_14/',
)
file_names = list_dir(url_bases)
file_names = [file_name for file_name in file_names if file_name.endswith('coord.txt')]
filepaths = download_files(url_bases, '', cache_subdir, file_names)
return filepaths
def download_cors_station(time, station_name, cache_dir):
t = time.as_datetime()
folder_path = t.strftime('%Y/%j/') + station_name + '/'
filename = station_name + t.strftime("%j0.%yd")
url_bases = (
'https://geodesy.noaa.gov/corsdata/rinex/',
'https://alt.ngs.noaa.gov/corsdata/rinex/',
)
try:
filepath = download_and_cache_file(url_bases, folder_path, cache_dir+'cors_obs/', filename, compression='.gz')
return filepath
except DownloadFailed:
logging.warning("File not downloaded, check availability on server.")
return None
-106
View File
@@ -1,106 +0,0 @@
@0xb3ca6d2462778bb1;
struct Ephemeris {
# This is according to the rinex (2?) format
svId @0 :UInt16;
year @1 :UInt16;
month @2 :UInt16;
day @3 :UInt16;
hour @4 :UInt16;
minute @5 :UInt16;
second @6 :Float32;
af0 @7 :Float64;
af1 @8 :Float64;
af2 @9 :Float64;
iode @10 :Float64;
crs @11 :Float64;
deltaN @12 :Float64;
m0 @13 :Float64;
cuc @14 :Float64;
ecc @15 :Float64;
cus @16 :Float64;
a @17 :Float64; # note that this is not the root!!
toe @18 :Float64;
cic @19 :Float64;
omega0 @20 :Float64;
cis @21 :Float64;
i0 @22 :Float64;
crc @23 :Float64;
omega @24 :Float64;
omegaDot @25 :Float64;
iDot @26 :Float64;
codesL2 @27 :Float64;
gpsWeekDEPRECATED @28 :Float64;
l2 @29 :Float64;
svAcc @30 :Float64;
svHealth @31 :Float64;
tgd @32 :Float64;
iodc @33 :Float64;
transmissionTime @34 :Float64;
fitInterval @35 :Float64;
toc @36 :Float64;
ionoCoeffsValid @37 :Bool;
ionoAlpha @38 :List(Float64);
ionoBeta @39 :List(Float64);
towCount @40 :UInt32;
toeWeek @41 :UInt16;
tocWeek @42 :UInt16;
}
struct GlonassEphemeris {
svId @0 :UInt16;
year @1 :UInt16;
dayInYear @2 :UInt16;
hour @3 :UInt16;
minute @4 :UInt16;
second @5 :Float32;
x @6 :Float64;
xVel @7 :Float64;
xAccel @8 :Float64;
y @9 :Float64;
yVel @10 :Float64;
yAccel @11 :Float64;
z @12 :Float64;
zVel @13 :Float64;
zAccel @14 :Float64;
svType @15 :UInt8;
svURA @16 :Float32;
age @17 :UInt8;
svHealth @18 :UInt8;
tkDEPRECATED @19 :UInt16;
tb @20 :UInt16;
tauN @21 :Float64;
deltaTauN @22 :Float64;
gammaN @23 :Float64;
p1 @24 :UInt8;
p2 @25 :UInt8;
p3 @26 :UInt8;
p4 @27 :UInt8;
freqNumDEPRECATED @28 :UInt32;
n4 @29 :UInt8;
nt @30 :UInt16;
freqNum @31 :Int16;
tkSeconds @32 :UInt32;
}
struct EphemerisCache {
gpsEphemerides @0 :List(Ephemeris);
glonassEphemerides @1 :List(GlonassEphemeris);
}
-498
View File
@@ -1,498 +0,0 @@
import warnings
from abc import ABC, abstractmethod
from collections import defaultdict
from enum import IntEnum
from typing import Dict, List, Optional
import numpy as np
import numpy.polynomial.polynomial as poly
from datetime import datetime
from math import sin, cos, sqrt, fabs, atan2
from .gps_time import GPSTime, utc_to_gpst
from .constants import SPEED_OF_LIGHT, SECS_IN_MIN, SECS_IN_HR, SECS_IN_DAY, \
EARTH_ROTATION_RATE, EARTH_GM
from .helpers import get_constellation, get_prn_from_nmea_id
import capnp
import os
capnp.remove_import_hook()
capnp_path = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), "ephemeris.capnp"))
ephemeris_structs = capnp.load(capnp_path)
def read4(f, rinex_ver):
line = f.readline()[:-1]
if rinex_ver == 2:
line = ' ' + line # Shift 1 char to the right
line = line.replace('D', 'E') # Handle bizarro float format
return float(line[4:23]), float(line[23:42]), float(line[42:61]), float(line[61:80])
class EphemerisType(IntEnum):
# Matches the enum in log.capnp
NAV = 0
FINAL_ORBIT = 1
RAPID_ORBIT = 2
ULTRA_RAPID_ORBIT = 3
QCOM_POLY = 4
@staticmethod
def all_orbits():
return EphemerisType.FINAL_ORBIT, EphemerisType.RAPID_ORBIT, EphemerisType.ULTRA_RAPID_ORBIT
@classmethod
def from_file_name(cls, file_name: str):
if "/final" in file_name or "/igs" in file_name:
return EphemerisType.FINAL_ORBIT
if "/rapid" in file_name or "/igr" in file_name:
return EphemerisType.RAPID_ORBIT
if "/ultra" in file_name or "/igu" in file_name or "COD0OPSULT" in file_name:
return EphemerisType.ULTRA_RAPID_ORBIT
raise RuntimeError(f"Ephemeris type not found in filename: {file_name}")
class Ephemeris(ABC):
def __init__(self, prn: str, epoch: GPSTime, eph_type: EphemerisType, healthy: bool, max_time_diff: float,
file_epoch: Optional[GPSTime] = None, file_name=None):
self.prn = prn
self.epoch = epoch
self.eph_type = eph_type
self.healthy = healthy
self.max_time_diff = max_time_diff
self.file_epoch = file_epoch
self.file_name = file_name
self.file_source = '' if file_name is None else file_name.split('/')[-1][:3] # File source for the ephemeris (e.g. igu, igr, Sta)
def valid(self, time):
return abs(time - self.epoch) <= self.max_time_diff
def __repr__(self):
time = self.epoch.as_datetime().strftime('%Y-%m-%dT%H:%M:%S.%f')
return f"<{self.__class__.__name__} from {self.prn} at {time}>"
def get_sat_info(self, time: GPSTime):
"""
Returns: (pos, vel, clock_err, clock_rate_err, ephemeris)
"""
if not self.healthy:
return None
return list(self._get_sat_info(time)) + [self]
@abstractmethod
def _get_sat_info(self, time):
pass
class GLONASSEphemeris(Ephemeris):
def __init__(self, data, file_name=None):
self.epoch = GPSTime.from_glonass(data.n4, data.nt, data.tb*15*SECS_IN_MIN)
super().__init__('R%02i' % data.svId, self.epoch, EphemerisType.NAV, data.svHealth==0, max_time_diff=25*SECS_IN_MIN, file_name=file_name)
self.data = data
self.epoch = GPSTime.from_glonass(data.n4, data.nt, data.tb*15 * SECS_IN_MIN)
self.channel = data.freqNum
def _get_sat_info(self, time: GPSTime):
# see the russian doc for this:
# http://gauss.gge.unb.ca/GLONASS.ICD.pdf
eph = self.data
tdiff = time - self.epoch
# Clock correction (except for general relativity which is applied later)
clock_err = -eph.tauN + tdiff * eph.gammaN
clock_rate_err = eph.gammaN
def glonass_diff_eq(state, acc):
J2 = 1.0826257e-3
mu = 3.9860044e14
omega = 7.292115e-5
ae = 6378136.0
r = np.sqrt(state[0]**2 + state[1]**2 + state[2]**2)
ders = np.zeros(6)
if r**2 < 0:
return ders
a = 1.5 * J2 * mu * (ae**2)/ (r**5)
b = 5 * (state[2]**2) / (r**2)
c = -mu/(r**3) - a*(1-b)
ders[0:3] = state[3:6]
ders[3] = (c + omega**2)*state[0] + 2*omega*state[4] + acc[0]
ders[4] = (c + omega**2)*state[1] - 2*omega*state[3] + acc[1]
ders[5] = (c - 2*a)*state[2] + acc[2]
return ders
init_state = np.empty(6)
init_state[0] = eph.x
init_state[1] = eph.y
init_state[2] = eph.z
init_state[3] = eph.xVel
init_state[4] = eph.yVel
init_state[5] = eph.zVel
init_state = 1000*init_state
acc = 1000*np.array([eph.xAccel, eph.yAccel, eph.zAccel])
state = init_state
tstep = 90
if tdiff < 0:
tt = -tstep
elif tdiff > 0:
tt = tstep
while abs(tdiff) > 1e-9:
if abs(tdiff) < tstep:
tt = tdiff
k1 = glonass_diff_eq(state, acc)
k2 = glonass_diff_eq(state + k1*tt/2, -acc)
k3 = glonass_diff_eq(state + k2*tt/2, -acc)
k4 = glonass_diff_eq(state + k3*tt, -acc)
state += (k1 + 2*k2 + 2*k3 + k4)*tt/6.0
tdiff -= tt
pos = state[0:3]
vel = state[3:6]
return pos, vel, clock_err, clock_rate_err
class PolyEphemeris(Ephemeris):
def __init__(self, prn: str, data, epoch: GPSTime, ephem_type: EphemerisType,
file_epoch: Optional[GPSTime] = None, file_name: Optional[str] = None, healthy=True, tgd=0,
max_time_diff: int=SECS_IN_HR):
super().__init__(prn, epoch, ephem_type, healthy, max_time_diff=max_time_diff, file_epoch=file_epoch, file_name=file_name)
self.data = data
self.tgd = tgd
def _get_sat_info(self, time: GPSTime):
dt = time - self.data['t0']
deg = self.data['deg']
deg_t = self.data['deg_t']
indices = np.arange(deg+1)[:,np.newaxis]
sat_pos = np.sum((dt**indices)*self.data['xyz'], axis=0)
indices = indices[1:]
sat_vel = np.sum(indices*(dt**(indices-1)*self.data['xyz'][1:]), axis=0)
time_err = sum((dt**p)*self.data['clock'][deg_t-p] for p in range(deg_t+1))
time_err_rate = sum(p*(dt**(p-1))*self.data['clock'][deg_t-p] for p in range(1,deg_t+1))
time_err_with_rel = time_err - 2*np.inner(sat_pos, sat_vel)/SPEED_OF_LIGHT**2
return sat_pos, sat_vel, time_err_with_rel, time_err_rate
class GPSEphemeris(Ephemeris):
def __init__(self, data, file_name=None):
self.toe = GPSTime(data.toeWeek, data.toe)
self.toc = GPSTime(data.tocWeek, data.toc)
self.epoch = self.toc
super().__init__('G%02i' % data.svId, self.epoch, EphemerisType.NAV, data.svHealth==0, max_time_diff=2*SECS_IN_HR, file_name=file_name)
self.max_time_diff_tgd = SECS_IN_DAY
self.data = data
self.sqrta = np.sqrt(data.a)
def get_tgd(self):
return self.datatgd
def _get_sat_info(self, time: GPSTime):
eph = self.data
tdiff = time - self.toc # Time of clock
clock_err = eph.af0 + tdiff * (eph.af1 + tdiff * eph.af2)
clock_rate_err = eph.af1 + 2 * tdiff * eph.af2\
# Orbit propagation
tdiff = time - self.toe # Time of ephemeris (might be different from time of clock)
# Calculate position per IS-GPS-200D p 97 Table 20-IV
a = self.sqrta * self.sqrta # [m] Semi-major axis
ma_dot = sqrt(EARTH_GM / (a * a * a)) + eph.deltaN # [rad/sec] Corrected mean motion
ma = eph.m0 + ma_dot * tdiff # [rad] Corrected mean anomaly
# Iteratively solve for the Eccentric Anomaly (from Keith Alter and David Johnston)
ea = ma # Starting value for E
ea_old = 2222
while fabs(ea - ea_old) > 1.0E-14:
ea_old = ea
tempd1 = 1.0 - eph.ecc * cos(ea_old)
ea = ea + (ma - ea_old + eph.ecc * sin(ea_old)) / tempd1
ea_dot = ma_dot / tempd1
# Relativistic correction term
einstein = -4.442807633E-10 * eph.ecc * self.sqrta * sin(ea)
# Begin calc for True Anomaly and Argument of Latitude
tempd2 = sqrt(1.0 - eph.ecc * eph.ecc)
# [rad] Argument of Latitude = True Anomaly + Argument of Perigee
al = atan2(tempd2 * sin(ea), cos(ea) - eph.ecc) + eph.omega
al_dot = tempd2 * ea_dot / tempd1
# Calculate corrected argument of latitude based on position
cal = al + eph.cus * sin(2.0 * al) + eph.cuc * cos(2.0 * al)
cal_dot = al_dot * (1.0 + 2.0 * (eph.cus * cos(2.0 * al) -
eph.cuc * sin(2.0 * al)))
# Calculate corrected radius based on argument of latitude
r = a * tempd1 + eph.crc * cos(2.0 * al) + eph.crs * sin(2.0 * al)
r_dot = (a * eph.ecc * sin(ea) * ea_dot +
2.0 * al_dot * (eph.crs * cos(2.0 * al) -
eph.crc * sin(2.0 * al)))
# Calculate inclination based on argument of latitude
inc = (eph.i0 + eph.iDot * tdiff +
eph.cic * cos(2.0 * al) +
eph.cis * sin(2.0 * al))
inc_dot = (eph.iDot +
2.0 * al_dot * (eph.cis * cos(2.0 * al) -
eph.cic * sin(2.0 * al)))
# Calculate position and velocity in orbital plane
x = r * cos(cal)
y = r * sin(cal)
x_dot = r_dot * cos(cal) - y * cal_dot
y_dot = r_dot * sin(cal) + x * cal_dot
# Corrected longitude of ascending node
om_dot = eph.omegaDot - EARTH_ROTATION_RATE
om = eph.omega0 + tdiff * om_dot - EARTH_ROTATION_RATE * self.toe.tow
# Compute the satellite's position in Earth-Centered Earth-Fixed coordinates
pos = np.empty(3)
pos[0] = x * cos(om) - y * cos(inc) * sin(om)
pos[1] = x * sin(om) + y * cos(inc) * cos(om)
pos[2] = y * sin(inc)
tempd3 = y_dot * cos(inc) - y * sin(inc) * inc_dot
# Compute the satellite's velocity in Earth-Centered Earth-Fixed coordinates
vel = np.empty(3)
vel[0] = -om_dot * pos[1] + x_dot * cos(om) - tempd3 * sin(om)
vel[1] = om_dot * pos[0] + x_dot * sin(om) + tempd3 * cos(om)
vel[2] = y * cos(inc) * inc_dot + y_dot * sin(inc)
clock_err += einstein
return pos, vel, clock_err, clock_rate_err
def parse_sp3_orbits(file_names, supported_constellations, skip_until_epoch: Optional[GPSTime] = None) -> Dict[str, List[PolyEphemeris]]:
if skip_until_epoch is None:
skip_until_epoch = GPSTime(0, 0)
data: Dict[str, List] = {}
for file_name in file_names:
if file_name is None:
continue
with open(file_name) as f:
ephem_type = EphemerisType.from_file_name(file_name)
file_epoch = None
while True:
line = f.readline()[:-1]
if not line:
break
# epoch header
if line[0:2] == '* ':
year = int(line[3:7])
month = int(line[8:10])
day = int(line[11:13])
hour = int(line[14:16])
minute = int(line[17:19])
second = int(float(line[20:31]))
epoch = GPSTime.from_datetime(datetime(year, month, day, hour, minute, second))
if file_epoch is None:
file_epoch = epoch
# pos line
elif line[0] == 'P':
# Skipping data can reduce the time significantly when parsing the ephemeris
if epoch < skip_until_epoch:
continue
prn = line[1:4].replace(' ', '0')
# In old SP3 files vehicle ID doesn't contain constellation
# identifier. We assume that constellation is GPS when missing.
if prn[0] == '0':
prn = 'G' + prn[1:]
if get_constellation(prn) not in supported_constellations:
continue
if prn not in data:
data[prn] = []
#TODO this is a crappy way to deal with overlapping ultra rapid
if len(data[prn]) < 1 or epoch - data[prn][-1][1] > 0:
parsed = [(ephem_type, file_epoch, file_name),
epoch,
1e3 * float(line[4:18]),
1e3 * float(line[18:32]),
1e3 * float(line[32:46]),
1e-6 * float(line[46:60])]
if (np.array(parsed[2:]) != 0).all():
data[prn].append(parsed)
ephems = {}
for prn in data:
ephems[prn] = read_prn_data(data, prn)
return ephems
def read_prn_data(data, prn, deg=16, deg_t=1):
np_data_prn = np.array(data[prn], dtype=object)
# Currently, don't even bother with satellites that have unhealthy times
if len(np_data_prn) == 0 or (np_data_prn[:, 5] > .99).any():
return []
ephems = []
for i in range(len(np_data_prn) - deg):
epoch_index = i + deg // 2
epoch = np_data_prn[epoch_index][1]
measurements = np_data_prn[i:i + deg + 1, 1:5]
times = (measurements[:, 0] - epoch).astype(float)
if not (np.diff(times) != 900).any() and not (np.diff(times) != 300).any():
continue
poly_data = {}
poly_data['t0'] = epoch
with warnings.catch_warnings():
warnings.simplefilter("ignore") # Ignores: UserWarning: The value of the smallest subnormal for <class 'numpy.float64'> type is zero.
poly_data['xyz'] = poly.polyfit(times, measurements[:, 1:].astype(float), deg)
poly_data['clock'] = [(np_data_prn[epoch_index + 1][5] - np_data_prn[epoch_index - 1][5]) / 1800, np_data_prn[epoch_index][5]]
poly_data['deg'] = deg
poly_data['deg_t'] = deg_t
# It can happen that a mix of orbit ephemeris types are used in the polyfit.
ephem_type, file_epoch, file_name = np_data_prn[epoch_index][0]
ephems.append(PolyEphemeris(prn, poly_data, epoch, ephem_type, file_epoch, file_name, healthy=True))
return ephems
def parse_rinex_nav_msg_gps(file_name):
ephems = defaultdict(list)
got_header = False
rinex_ver = None
#ion_alpha = None
#ion_beta = None
f = open(file_name)
while True:
line = f.readline()[:-1]
if not line:
break
if not got_header:
if rinex_ver is None:
if line[60:80] != "RINEX VERSION / TYPE":
raise RuntimeError("Doesn't appear to be a RINEX file")
rinex_ver = int(float(line[0:9]))
if line[20] != "N":
raise RuntimeError("Doesn't appear to be a Navigation Message file")
#if line[60:69] == "ION ALPHA":
# line = line.replace('D', 'E') # Handle bizarro float format
# ion_alpha= [float(line[3:14]), float(line[15:26]), float(line[27:38]), float(line[39:50])]
#if line[60:68] == "ION BETA":
# line = line.replace('D', 'E') # Handle bizarro float format
# ion_beta= [float(line[3:14]), float(line[15:26]), float(line[27:38]), float(line[39:50])]
if line[60:73] == "END OF HEADER":
#ion = ion_alpha + ion_beta
got_header = True
continue
if rinex_ver == 3:
if line[0] != 'G':
continue
if rinex_ver == 3:
sv_id = int(line[1:3])
epoch = GPSTime.from_datetime(datetime.strptime(line[4:23], "%y %m %d %H %M %S"))
elif rinex_ver == 2:
sv_id = int(line[0:2])
# 2000 year is in RINEX file as 0, but Python requires two digit year: 00
epoch_str = line[3:20]
if epoch_str[0] == ' ':
epoch_str = '0' + epoch_str[1:]
epoch = GPSTime.from_datetime(datetime.strptime(epoch_str, "%y %m %d %H %M %S"))
line = ' ' + line # Shift 1 char to the right
line = line.replace('D', 'E') # Handle bizarro float format
e = {'svId': sv_id}
# TODO are TOC and TOE the same?
e['toc'] = epoch.tow
e['tocWeek'] = epoch.week
e['af0'] = float(line[23:42])
e['af1'] = float(line[42:61])
e['af2'] = float(line[61:80])
e['iode'], e['crs'], e['deltaN'], e['m0'] = read4(f, rinex_ver)
e['cuc'], e['ecc'], e['cus'], sqrta = read4(f, rinex_ver)
e['a'] = sqrta ** 2
e['toe'], e['cic'], e['omega0'], e['cis'] = read4(f, rinex_ver)
e['i0'], e['crc'], e['omega'], e['omegaDot'] = read4(f, rinex_ver)
e['iDot'], e['codesL2'], e['toeWeek'], l2_pflag = read4(f, rinex_ver)
e['svAcc'], e['svHealth'], e['tgd'], e['iodc'] = read4(f, rinex_ver)
f.readline() # Discard last row
data_struct = ephemeris_structs.Ephemeris.new_message(**e)
ephem = GPSEphemeris(data_struct, file_name=file_name)
ephems[ephem.prn].append(ephem)
f.close()
return ephems
def parse_rinex_nav_msg_glonass(file_name):
ephems = defaultdict(list)
f = open(file_name)
got_header = False
rinex_ver = None
while True:
line = f.readline()[:-1]
if not line:
break
if not got_header:
if rinex_ver is None:
if line[60:80] != "RINEX VERSION / TYPE":
raise RuntimeError("Doesn't appear to be a RINEX file")
rinex_ver = int(float(line[0:9]))
if line[20] != "G":
raise RuntimeError("Doesn't appear to be a Navigation Message file")
if line[60:73] == "END OF HEADER":
got_header = True
continue
if rinex_ver == 3:
sv_id = int(line[1:3])
epoch = utc_to_gpst(GPSTime.from_datetime(datetime.strptime(line[4:23], "%y %m %d %H %M %S")))
elif rinex_ver == 2:
sv_id = int(line[0:2])
epoch = utc_to_gpst(GPSTime.from_datetime(datetime.strptime(line[3:20], "%y %m %d %H %M %S")))
line = ' ' + line # Shift 1 char to the right
line = line.replace('D', 'E') # Handle bizarro float format
e = {'svId': sv_id}
e['n4'], e['nt'], toe_seconds = epoch.as_glonass()
tb = toe_seconds / (15 * SECS_IN_MIN)
e['tb'] = tb
e['tauN'] = -float(line[23:42])
e['gammaN'] = float(line[42:61])
e['tkSeconds'] = float(line[61:80])
e['x'], e['xVel'], e['xAccel'], e['svHealth'] = read4(f, rinex_ver)
e['y'], e['yVel'], e['yAccel'], e['freqNum'] = read4(f, rinex_ver)
e['z'], e['zVel'], e['zAccel'], e['age'] = read4(f, rinex_ver)
# TODO unclear why glonass sometimes has nav messages 3s after correct one
if abs(tb - int(tb)) > 1e-3:
continue
data_struct = ephemeris_structs.GlonassEphemeris.new_message(**e)
ephem = GLONASSEphemeris(data_struct, file_name=file_name)
ephems[ephem.prn].append(ephem)
f.close()
return ephems
def parse_qcom_ephem(qcom_poly):
svId = qcom_poly.svId
prn = get_prn_from_nmea_id(svId)
epoch = GPSTime(qcom_poly.gpsWeek, qcom_poly.gpsTow)
data = qcom_poly
poly_data = {}
poly_data['t0'] = epoch
poly_data['xyz'] = np.array([
[data.xyz0[0], data.xyzN[0], data.xyzN[1], data.xyzN[2]],
[data.xyz0[1], data.xyzN[3], data.xyzN[4], data.xyzN[5]],
[data.xyz0[2], data.xyzN[6], data.xyzN[7], data.xyzN[8]] ]).T
poly_data['clock'] = [1e-3*data.other[3], 1e-3*data.other[2], 1e-3*data.other[1], 1e-3*data.other[0]]
poly_data['deg'] = 3
poly_data['deg_t'] = 3
return PolyEphemeris(prn, poly_data, epoch, ephem_type=EphemerisType.QCOM_POLY, max_time_diff=300, file_name='qcom')
-203
View File
@@ -1,203 +0,0 @@
import datetime
def datetime_to_tow(t):
"""
Convert a Python datetime object to GPS Week and Time Of Week.
Does *not* convert from UTC to GPST.
Fractional seconds are supported.
Parameters
----------
t : datetime
A time to be converted, on the GPST timescale.
mod1024 : bool, optional
If True (default), the week number will be output in 10-bit form.
Returns
-------
week, tow : tuple (int, float)
The GPS week number and time-of-week.
"""
# DateTime to GPS week and TOW
wk_ref = datetime.datetime(2014, 2, 16, 0, 0, 0, 0, None)
refwk = 1780
wk = (t - wk_ref).days // 7 + refwk
tow = ((t - wk_ref) - datetime.timedelta((wk - refwk) * 7.0)).total_seconds()
return wk, tow
def tow_to_datetime(tow, week):
"""
Convert a GPS Week and Time Of Week to Python datetime object.
Does *not* convert from GPST to UTC.
Fractional seconds are supported.
Parameters
----------
tow : time of week in seconds
weeks : gps week
Returns
-------
t : datetime
Python datetime
"""
# GPS week and TOW to DateTime
t = datetime.datetime(1980, 1, 6, 0, 0, 0, 0, None)
t += datetime.timedelta(seconds=tow)
t += datetime.timedelta(weeks=week)
return t
def get_leap_seconds(time):
# TODO use library for this
if time <= GPSTime.from_datetime(datetime.datetime(2006, 1, 1)):
raise ValueError("Don't know how many leap seconds to use before 2006")
elif time <= GPSTime.from_datetime(datetime.datetime(2009, 1, 1)):
return 14
elif time <= GPSTime.from_datetime(datetime.datetime(2012, 7, 1)):
return 15
elif time <= GPSTime.from_datetime(datetime.datetime(2015, 7, 1)):
return 16
elif time <= GPSTime.from_datetime(datetime.datetime(2017, 1, 1)):
return 17
else:
return 18
def gpst_to_utc(t_gpst):
t_utc = t_gpst - get_leap_seconds(t_gpst)
if utc_to_gpst(t_utc) - t_gpst != 0:
return t_utc + 1
else:
return t_utc
def utc_to_gpst(t_utc):
t_gpst = t_utc + get_leap_seconds(t_utc)
return t_gpst
class GPSTime:
"""
GPS time class to add and subtract [week, tow]
"""
def __init__(self, week, tow):
self.week = week
self.tow = tow
self.seconds_in_week = 604800
@classmethod
def from_datetime(cls, datetime):
week, tow = datetime_to_tow(datetime)
return cls(week, tow)
@classmethod
def from_glonass(cls, cycle, days, tow):
# https://en.wikipedia.org/wiki/GLONASS
# Day number (1 to 1461) within a four-year interval
# starting on 1 January of the last leap year
t = datetime.datetime(1992, 1, 1, 0, 0, 0, 0, None)
t += datetime.timedelta(days=cycle*(365*4+1)+(days-1))
# according to Moscow decree time.
t -= datetime.timedelta(hours=3)
t += datetime.timedelta(seconds=tow)
ret = cls.from_datetime(t)
return utc_to_gpst(ret)
@classmethod
def from_meas(cls, meas):
return cls(meas[1], meas[2])
def __sub__(self, other):
if isinstance(other, type(self)):
return (self.week - other.week)*self.seconds_in_week + self.tow - other.tow
elif isinstance(other, float) or isinstance(other, int):
new_week = self.week
new_tow = self.tow - other
while new_tow < 0:
new_tow += self.seconds_in_week
new_week -= 1
return GPSTime(new_week, new_tow)
raise NotImplementedError(f"subtracting {other} from {self}")
def __add__(self, other):
if isinstance(other, float) or isinstance(other, int):
new_week = self.week
new_tow = self.tow + other
while new_tow >= self.seconds_in_week:
new_tow -= self.seconds_in_week
new_week += 1
return GPSTime(new_week, new_tow)
raise NotImplementedError(f"adding {other} from {self}")
def __lt__(self, other):
return self - other < 0
def __gt__(self, other):
return self - other > 0
def __le__(self, other):
return self - other <= 0
def __ge__(self, other):
return self - other >= 0
def __eq__(self, other):
return self - other == 0
def as_datetime(self):
return tow_to_datetime(self.tow, self.week)
def as_glonass(self):
time_utc = gpst_to_utc(self)
datetime_utc = time_utc.as_datetime()
datetime_glonass = datetime_utc + datetime.timedelta(hours=3)
year = datetime_glonass.year
cycle = (year - 1992) // 4
days = (datetime_glonass - datetime.datetime(1992 + cycle*4, 1, 1)).days + 1
tod = (datetime_glonass - datetime_glonass.replace(hour=0, minute=0, second=0, microsecond=0)).total_seconds()
return cycle, days, tod
def as_unix_timestamp(self):
return (gpst_to_utc(self).as_datetime() - datetime.datetime(1970, 1, 1)).total_seconds()
@property
def day(self):
return int(self.tow/(24*3600))
def __repr__(self):
return f"GPSTime(week={self.week}, tow={self.tow})"
class TimeSyncer:
"""
Converts logmonotime to gps_time and vice versa
"""
def __init__(self, mono_time, gps_time):
self.ref_mono_time = mono_time
self.ref_gps_time = gps_time
@classmethod
def from_datetime(cls, datetime):
week, tow = datetime_to_tow(datetime)
return cls(week, tow)
@classmethod
def from_logs(cls, raw_qcom_measurement_report, clocks):
#TODO
#return cls(week, mono_time, gps_time)
return None
def mono2gps(self, mono_time):
return self.ref_gps_time + mono_time - self.ref_mono_time
def gps2mono(self, gps_time):
return gps_time - self.ref_gps_time + self.ref_mono_time
def __str__(self):
return f"Reference mono time: {self.ref_mono_time} \n Reference gps time: {self.ref_gps_time}"
-221
View File
@@ -1,221 +0,0 @@
from enum import IntEnum
from typing import Dict
import numpy as np
from .lib.coordinates import LocalCoord
class ConstellationId(IntEnum):
# Int values match Ublox gnssid version 8
GPS = 0
SBAS = 1
GALILEO = 2
BEIDOU = 3
IMES = 4
QZNSS = 5
GLONASS = 6
# Not supported by Ublox:
IRNSS = 7
def to_rinex_char(self) -> str:
# returns single character id
return RINEX_CONSTELLATION_TO_ID[self]
@classmethod
def from_rinex_char(cls, c: str):
if c in RINEX_ID_TO_CONSTELLATION:
return RINEX_ID_TO_CONSTELLATION[c]
else:
raise ValueError("Unknown rinex constellation id: ", c)
@classmethod
def from_qcom_source(cls, report_source: int):
if report_source == 0:
return ConstellationId.GPS
if report_source == 1:
return ConstellationId.GLONASS
if report_source == 2:
return ConstellationId.BEIDOU
if report_source == 6:
return ConstellationId.SBAS
raise NotImplementedError('Only GPS (0), GLONASS (1), BEIDOU (2) and SBAS (6) are supported from qcom, not:', {report_source})
# From https://gpsd.gitlab.io/gpsd/NMEA.html#_satellite_ids
# NmeaId is the unique 3 digits id for every satellite globally. (Example: 001, 201)
# SvId is the 2 digits satellite id that is unique within a constellation. (Get the unique satellite with the constellation id. Examples: G01, R01)
CONSTELLATION_TO_NMEA_RANGES = {
# NmeaId ranges for each constellation with its svId offset.
# constellation: [(start, end, svIdOffset)]
# svId = nmeaId + offset
ConstellationId.GPS: [(1, 32, 0)], # svId [1,32]
ConstellationId.SBAS: [(33, 64, -32), (120, 158, -87)], # svId [1,71]
ConstellationId.GLONASS: [(65, 96, -64)], # svId [1,31]
ConstellationId.IMES: [(173, 182, -172)], # svId [1,9]
ConstellationId.QZNSS: [(193, 200, -192)], # svId [1,28] # todo should be QZSS
ConstellationId.BEIDOU: [(201, 235, -200), (401, 437, -365)], # svId 1-72
ConstellationId.GALILEO: [(301, 336, -300)] # svId 1-36
}
#
# # Source: RINEX 3.04
RINEX_CONSTELLATION_TO_ID: Dict[ConstellationId, str] = {
ConstellationId.GPS: 'G',
ConstellationId.GLONASS: 'R',
ConstellationId.SBAS: 'S',
ConstellationId.GALILEO: 'E',
ConstellationId.BEIDOU: 'C',
ConstellationId.QZNSS: 'J',
ConstellationId.IRNSS: 'I'
}
# Make above dictionary bidirectional map:
# Now you can ask for constellation using:
# >>> RINEX_CONSTELLATION_IDENTIFIERS['R']
# "GLONASS"
RINEX_ID_TO_CONSTELLATION: Dict[str, ConstellationId] = {con_id: con for con, con_id in RINEX_CONSTELLATION_TO_ID.items()}
def get_el_az(pos, sat_pos):
converter = LocalCoord.from_ecef(pos)
sat_ned = converter.ecef2ned(sat_pos)
sat_range = np.linalg.norm(sat_ned)
el = np.arcsin(-sat_ned[2] / sat_range) # pylint: disable=unsubscriptable-object
az = np.arctan2(sat_ned[1], sat_ned[0]) # pylint: disable=unsubscriptable-object
return el, az
def get_closest(time, candidates, recv_pos=None):
if recv_pos is None:
# Takes a list of object that have an epoch(GPSTime) value
# and return the one that is closest the given time (GPSTime)
return min(candidates, key=lambda candidate: abs(time - candidate.epoch), default=None)
return min(
(candidate for candidate in candidates if candidate.valid(time, recv_pos)),
key=lambda candidate: np.linalg.norm(recv_pos - candidate.pos),
default=None,
)
def get_constellation(prn: str):
identifier = prn[0]
return ConstellationId.from_rinex_char(identifier)
def get_sv_id(prn: str):
return int(prn[1:])
def get_constellation_and_sv_id(nmea_id):
for c, ranges in CONSTELLATION_TO_NMEA_RANGES.items():
for (start, end, sv_id_offset) in ranges:
if start <= nmea_id <= end:
sv_id = nmea_id + sv_id_offset
return c, sv_id
raise ValueError(f"constellation not found for nmeaid {nmea_id}")
def get_prn_from_nmea_id(nmea_id: int):
c_id, sv_id = get_constellation_and_sv_id(nmea_id)
return "%s%02d" % (c_id.to_rinex_char(), sv_id)
def get_nmea_id_from_prn(prn: str):
constellation = get_constellation(prn)
sv_id = int(prn[1:]) # satellite id
return get_nmea_id_from_constellation_and_svid(constellation, sv_id)
def get_nmea_id_from_constellation_and_svid(constellation: ConstellationId, sv_id: int):
ranges = CONSTELLATION_TO_NMEA_RANGES[constellation]
for (start, end, sv_id_offset) in ranges:
new_nmea_id = sv_id - sv_id_offset
if start <= new_nmea_id <= end:
return new_nmea_id
raise ValueError(f"NMEA ID not found for constellation {constellation.name} with satellite id {sv_id}")
def rinex3_obs_from_rinex2_obs(observable):
if observable == 'P2':
return 'C2P'
if len(observable) == 2:
return observable + 'C'
raise NotImplementedError("Don't know this: " + observable)
class TimeRangeHolder:
'''Class to support test if date is in any of the multiple, sparse ranges'''
def __init__(self):
# Sorted list
self._ranges = []
def _previous_and_contains_index(self, time):
prev = None
current = None
for idx, (start, end) in enumerate(self._ranges):
# Time may be in next range
if time > end:
continue
# Time isn't in any next range
if time < start:
prev = idx - 1
current = None
# Time is in current range
else:
prev = idx - 1
current = idx
break
# Break in last loop
if prev is None:
prev = len(self._ranges) - 1
return prev, current
def add(self, start_time, end_time):
prev_start, current_start = self._previous_and_contains_index(start_time)
_, current_end = self._previous_and_contains_index(end_time)
# Merge ranges
if current_start is not None and current_end is not None:
# If ranges are different then merge
if current_start != current_end:
new_start, _ = self._ranges[current_start]
_, new_end = self._ranges[current_end]
new_range = (new_start, new_end)
# Required reversed order to correct remove
del self._ranges[current_end]
del self._ranges[current_start]
self._ranges.insert(current_start, new_range)
# Extend range - left
elif current_start is not None:
new_start, _ = self._ranges[current_start]
new_range = (new_start, end_time)
del self._ranges[current_start]
self._ranges.insert(current_start, new_range)
# Extend range - right
elif current_end is not None:
_, new_end = self._ranges[current_end]
new_range = (start_time, new_end)
del self._ranges[current_end]
self._ranges.insert(prev_start + 1, new_range)
# Create new range
else:
new_range = (start_time, end_time)
self._ranges.insert(prev_start + 1, new_range)
def __contains__(self, time):
for start, end in self._ranges:
# Time may be in next range
if time > end:
continue
# Time isn't in any next range
if time < start:
return False
# Time is in current range
return True
return False
-256
View File
@@ -1,256 +0,0 @@
import datetime as dt
import numpy as np
import re
from math import cos, sin, pi, floor
from .constants import SECS_IN_MIN, SECS_IN_HR, EARTH_RADIUS
from .lib.coordinates import LocalCoord
from .gps_time import GPSTime
# Altitude of Ionospheric-pierce-point
IPP_ALT = 6821000
def get_alpha_beta(rcv_pos, el):
geocentric_alt = np.linalg.norm(rcv_pos)
alpha = np.pi/2 + el
arcsin_arg = geocentric_alt*np.sin(alpha)/IPP_ALT
beta = np.arcsin(np.clip(arcsin_arg, -1, 1))
return alpha, beta
def get_slant_delay(rcv_pos, az, el, sat_pos, time, freq, vertical_delay):
alpha, beta = get_alpha_beta(rcv_pos, el)
slant_delay = vertical_delay * ((1 - ((EARTH_RADIUS * np.sin(beta)) /
(EARTH_RADIUS + 3.5e5))**2)**(-0.5))
return slant_delay
def closest_in_list(lst, val, num=2):
"""
Returns two (`num` in general) closest values of `val` in list `lst`
"""
idxs = sorted(lst, key=lambda x: abs(x - val))[:num]
return sorted(list(lst).index(x) for x in idxs)
def get_header_line(headr, proprty):
"""
:param headr: the header of the RINEX-file
:param proprty: string-like property to search for (e.g. 'delta-utc')
:return: the string of the ``headr`` containing ``property``
"""
pattern = re.compile(proprty, re.IGNORECASE)
for d in headr:
if pattern.search(d):
return d
def get_header_body(file_path):
"""
Opens `file_path`, reads file and returns header and body
separated with "END OF HEADER"
:param file_path: path to RINEX-like file
:return: header, body (arrays of lines)
"""
with open(file_path) as fd:
data = fd.readlines()
for j, d in enumerate(data):
if "END OF HEADER" in d:
header_end = j
break
return data[:header_end], data[header_end + 1:]
def get_int_from_header(hdr, seq):
"""
Returns the first int from the line that contains `seq` of lines `hdr`.
In fact, _header_ here may not be header of RINEX/IONEX, just some set of lines.
"""
return int(get_header_line(hdr, seq).split()[0])
def compute_grid_lats_lons(data):
grid = np.array([], dtype='uint16')
lats = np.array([])
for j, line in enumerate(data[1:]):
if "LAT" in line:
lat, lon1, lon2, dlon, h = (float(line[x:x + 6]) for x in range(2, 32, 6))
lats = np.append(lats, lat)
row_length = (lon2 - lon1) / dlon + 1 # total number of values of longitudes
next_lines_with_numbers = int(np.ceil(row_length / 16))
elems_in_row = [
min(16, int(row_length - i * 16)) for i in range(next_lines_with_numbers)
]
row = np.array([], dtype='int16')
for i, elem in enumerate(elems_in_row):
row = np.append(
row,
np.array(
[int(data[j + 2 + i][5 * x:5 * x + 5]) for x in range(elem)],
dtype='int16',
),
)
if len(grid) > 0:
grid = np.vstack((grid, row))
else:
grid = np.append(grid, row)
lons = np.linspace(lon1, lon2, int(row_length))
return (grid, lats, lons)
class IonexMap:
def __init__(self, exp, data1, data2):
self.exp = exp
self.t1 = GPSTime.from_datetime(dt.datetime(*[int(d) for d in data1[0].split()[:6]]))
self.t2 = GPSTime.from_datetime(dt.datetime(*[int(d) for d in data2[0].split()[:6]]))
assert self.t2 - self.t1 == SECS_IN_HR
assert len(data1) == len(data2)
self.max_time_diff = SECS_IN_MIN*30
self.epoch = self.t1 + self.max_time_diff
self.grid_TEC1, self.lats, self.lons = compute_grid_lats_lons(data1)
self.grid_TEC2, self.lats, self.lons = compute_grid_lats_lons(data2)
def valid(self, time):
return abs(time - self.epoch) <= self.max_time_diff
@staticmethod
def find_nearest(lst, val):
return (np.abs(lst - val)).argmin()
def get_TEC(self, pos, time):
"""
Returns TEC in a position `pos` of ionosphere
:param pos: (lat, lon) [deg, deg]
:return:
"""
if pos[0] in self.lats and pos[1] in self.lons:
lat = self.find_nearest(self.lats, pos[0])
lon = self.find_nearest(self.lons, pos[1])
E = self.grid_TEC1[lat][lon] + self.grid_TEC2[lat][lon]
return E
lat_idxs = closest_in_list(self.lats, pos[0])
lon_idxs = closest_in_list(self.lons, pos[1])
lat0, lat1 = self.lats[lat_idxs[0]], self.lats[lat_idxs[1]]
lon0, lon1 = self.lons[lon_idxs[0]], self.lons[lon_idxs[1]]
dlat = lat1 - lat0
dlon = lon1 - lon0
p = float(pos[0] - lat0) / dlat
q = float(pos[1] - lon0) / dlon
(E00, E10), (E01, E11) = self.grid_TEC1[lat_idxs[0]:lat_idxs[1] + 1, lon_idxs[0]:lon_idxs[1] + 1]
TEC_1 = ((1 - p) * (1 - q) * E00 + p * (1 - q) * E01 + (1 - p) * q * E10 + p * q * E11)
(E00, E10), (E01, E11) = self.grid_TEC2[lat_idxs[0]:lat_idxs[1] + 1, lon_idxs[0]:lon_idxs[1] + 1]
TEC_2 = ((1 - p) * (1 - q) * E00 + p * (1 - q) * E01 + (1 - p) * q * E10 + p * q * E11)
return (1 - (time - self.t1)/SECS_IN_HR)*TEC_1 + ((time - self.t1)/SECS_IN_HR)*TEC_2
def get_delay(self, rcv_pos, az, el, sat_pos, time, freq):
# To get a delay from a TEC map, we need to calculate
# the ionospheric pierce point, geometry described here
# https://en.wikipedia.org/wiki/Ionospheric_pierce_point
alpha, beta = get_alpha_beta(rcv_pos, el)
conv = LocalCoord.from_ecef(rcv_pos)
gamma = np.pi - alpha - beta
geocentric_alt = np.linalg.norm(rcv_pos)
ipp_dist = geocentric_alt*np.sin(gamma)/np.sin(beta)
ipp_ned = conv.ecef2ned(sat_pos)*(ipp_dist)/np.linalg.norm(sat_pos)
ipp_geo = conv.ned2geodetic(ipp_ned)
factor = 40.30E16 / (freq**2) * 10**(self.exp)
vertical_delay = self.get_TEC(ipp_geo, time) * factor
slant_delay = get_slant_delay(rcv_pos, az, el, sat_pos, time, freq, vertical_delay)
return slant_delay
@staticmethod
def round_to_grid(number, base):
return int(base * round(float(number) / base))
def parse_ionex(ionex_file):
"""
:param ionex_file: path to the IONEX file
:return: TEC interpolation function `f( (lat,lon), datetime )`
"""
header, body = get_header_body(ionex_file)
exponent = get_int_from_header(header, "EXPONENT")
maps_count = get_int_from_header(header, "MAPS IN FILE")
# =============
# Separate maps
# =============
map_start_idx = []
map_end_idx = []
for j, line in enumerate(body):
if "START OF TEC MAP" in line:
map_start_idx += [j]
elif "END OF TEC MAP" in line:
map_end_idx += [j]
if maps_count != len(map_start_idx):
raise LookupError("Parsing error: the number of maps in the header " +
"is not equal to the number of maps in the body.")
if len(map_start_idx) != len(map_end_idx):
raise IndexError("Starts end ends numbers are not equal.")
map_dates = []
for i in range(maps_count):
date_components = body[map_start_idx[i] + 1].split()[:6]
map_dates.append(dt.datetime(*[int(d) for d in date_components]))
maps = []
iono_map = iono_map_prev = None
for m in range(maps_count):
iono_map_prev = iono_map
iono_map = body[map_start_idx[m] + 1:map_end_idx[m]]
if iono_map and iono_map_prev:
maps += [IonexMap(exponent, iono_map_prev, iono_map)]
return maps
def klobuchar(pos, az, el, time, iono_coeffs):
"""
Details are taken from [5]: IS-GPS-200H, Fig. 20-4
Note: result is referred to the GPS L₁ frequency;
if the user is operating on the GPS L₂ frequency, the correction term must
be multiplied by γ = f₂²/f₁¹ = 0.6071850227694382
:param pos: [lat, lon, alt] in radians and meters
"""
tow = time.tow
if pos[2] < -1E3 or el < 0:
return 0.0
if len(iono_coeffs) < 8:
return None
# earth centered angle (semi-circle)
psi = 0.0137 / (el / pi + 0.11) - 0.022
# subionospheric latitude/longitude (semi-circle)
phi = pos[0] / pi + psi * cos(az)
if phi > 0.416:
phi = 0.416
elif phi < -0.416:
phi = -0.416
lam = pos[1] / pi + psi * sin(az) / cos(phi * pi)
# geomagnetic latitude (semi-circle) */
phi += 0.064 * cos((lam - 1.617) * pi)
# local time (s)
tt = 43200.0 * lam + tow
tt -= floor(tt / 86400.0) * 86400.0 # 0<=tt<86400
# slant factor
f = 1.0 + 16.0 * pow(0.53 - el / pi, 3.0)
# ionospheric delay
amp = iono_coeffs[0] + phi * (iono_coeffs[1] + phi *
(iono_coeffs[2] + phi * iono_coeffs[3]))
per = iono_coeffs[4] + phi * (iono_coeffs[5] + phi *
(iono_coeffs[6] + phi * iono_coeffs[7]))
if amp < 0.0:
amp = 0.
if per < 72000.0:
per = 72000.0
x = 2.0 * pi * (tt - 50400.0) / per
mul = 5E-9
if abs(x) < 1.57:
mul = (5E-9 + amp * (1.0 + x * x * (-0.5 + x * x / 24.0)))
return 2.99792458E8 * f * mul
-106
View File
@@ -1,106 +0,0 @@
import numpy as np
"""
Coordinate transformation module. All methods accept arrays as input
with each row as a position.
"""
a = 6378137
b = 6356752.3142
esq = 6.69437999014 * 0.001
e1sq = 6.73949674228 * 0.001
def geodetic2ecef(geodetic, radians=False):
geodetic = np.array(geodetic)
input_shape = geodetic.shape
geodetic = np.atleast_2d(geodetic)
ratio = 1.0 if radians else (np.pi / 180.0)
lat = ratio*geodetic[:,0]
lon = ratio*geodetic[:,1]
alt = geodetic[:,2]
xi = np.sqrt(1 - esq * np.sin(lat)**2)
x = (a / xi + alt) * np.cos(lat) * np.cos(lon)
y = (a / xi + alt) * np.cos(lat) * np.sin(lon)
z = (a / xi * (1 - esq) + alt) * np.sin(lat)
ecef = np.array([x, y, z]).T
return ecef.reshape(input_shape)
def ecef2geodetic(ecef, radians=False):
"""
Convert ECEF coordinates to geodetic using ferrari's method
"""
# Save shape and export column
ecef = np.atleast_1d(ecef)
input_shape = ecef.shape
ecef = np.atleast_2d(ecef)
x, y, z = ecef[:, 0], ecef[:, 1], ecef[:, 2]
ratio = 1.0 if radians else (180.0 / np.pi)
# Conver from ECEF to geodetic using Ferrari's methods
# https://en.wikipedia.org/wiki/Geographic_coordinate_conversion#Ferrari.27s_solution
r = np.sqrt(x * x + y * y)
Esq = a * a - b * b
F = 54 * b * b * z * z
G = r * r + (1 - esq) * z * z - esq * Esq
C = (esq * esq * F * r * r) / (pow(G, 3))
S = np.cbrt(1 + C + np.sqrt(C * C + 2 * C))
P = F / (3 * pow((S + 1 / S + 1), 2) * G * G)
Q = np.sqrt(1 + 2 * esq * esq * P)
r_0 = -(P * esq * r) / (1 + Q) + np.sqrt(0.5 * a * a*(1 + 1.0 / Q) -
P * (1 - esq) * z * z / (Q * (1 + Q)) - 0.5 * P * r * r)
U = np.sqrt(pow((r - esq * r_0), 2) + z * z)
V = np.sqrt(pow((r - esq * r_0), 2) + (1 - esq) * z * z)
Z_0 = b * b * z / (a * V)
h = U * (1 - b * b / (a * V))
lat = ratio*np.arctan((z + e1sq * Z_0) / r)
lon = ratio*np.arctan2(y, x)
# stack the new columns and return to the original shape
geodetic = np.column_stack((lat, lon, h))
return geodetic.reshape(input_shape)
class LocalCoord:
"""
Allows conversions to local frames. In this case NED.
That is: North East Down from the start position in
meters.
"""
def __init__(self, init_geodetic, init_ecef):
self.init_ecef = init_ecef
lat, lon, _ = (np.pi/180)*np.array(init_geodetic)
self.ned2ecef_matrix = np.array([[-np.sin(lat)*np.cos(lon), -np.sin(lon), -np.cos(lat)*np.cos(lon)],
[-np.sin(lat)*np.sin(lon), np.cos(lon), -np.cos(lat)*np.sin(lon)],
[np.cos(lat), 0, -np.sin(lat)]])
self.ecef2ned_matrix = self.ned2ecef_matrix.T
@classmethod
def from_geodetic(cls, init_geodetic):
init_ecef = geodetic2ecef(init_geodetic)
return LocalCoord(init_geodetic, init_ecef)
@classmethod
def from_ecef(cls, init_ecef):
init_geodetic = ecef2geodetic(init_ecef)
return LocalCoord(init_geodetic, init_ecef)
def ecef2ned(self, ecef):
ecef = np.array(ecef)
return np.dot(self.ecef2ned_matrix, (ecef - self.init_ecef).T).T
def ned2ecef(self, ned):
ned = np.array(ned)
# Transpose so that init_ecef will broadcast correctly for 1d or 2d ned.
return (np.dot(self.ned2ecef_matrix, ned.T).T + self.init_ecef)
def geodetic2ned(self, geodetic):
ecef = geodetic2ecef(geodetic)
return self.ecef2ned(ecef)
def ned2geodetic(self, ned):
ecef = self.ned2ecef(ned)
return ecef2geodetic(ecef)
-291
View File
@@ -1,291 +0,0 @@
import numpy as np
from numpy import dot, inner, array, linalg
from .coordinates import LocalCoord
'''
Vectorized functions that transform between
rotation matrices, euler angles and quaternions.
All support lists, array or array of arrays as inputs.
Supports both x2y and y_from_x format (y_from_x preferred!).
'''
def euler2quat(eulers):
eulers = array(eulers)
if len(eulers.shape) > 1:
output_shape = (-1,4)
else:
output_shape = (4,)
eulers = np.atleast_2d(eulers)
gamma, theta, psi = eulers[:,0], eulers[:,1], eulers[:,2]
cos_half_gamma = np.cos(gamma / 2)
cos_half_theta = np.cos(theta / 2)
cos_half_psi = np.cos(psi / 2)
sin_half_gamma = np.sin(gamma / 2)
sin_half_theta = np.sin(theta / 2)
sin_half_psi = np.sin(psi / 2)
q0 = cos_half_gamma * cos_half_theta * cos_half_psi + sin_half_gamma * sin_half_theta * sin_half_psi
q1 = sin_half_gamma * cos_half_theta * cos_half_psi - cos_half_gamma * sin_half_theta * sin_half_psi
q2 = cos_half_gamma * sin_half_theta * cos_half_psi + sin_half_gamma * cos_half_theta * sin_half_psi
q3 = cos_half_gamma * cos_half_theta * sin_half_psi - sin_half_gamma * sin_half_theta * cos_half_psi
quats = array([q0, q1, q2, q3]).T
for i in range(len(quats)):
if quats[i,0] < 0:
quats[i] = -quats[i]
return quats.reshape(output_shape)
def quat2euler(quats):
quats = array(quats)
if len(quats.shape) > 1:
output_shape = (-1,3)
else:
output_shape = (3,)
quats = np.atleast_2d(quats)
q0, q1, q2, q3 = quats[:,0], quats[:,1], quats[:,2], quats[:,3]
gamma = np.arctan2(2 * (q0 * q1 + q2 * q3), 1 - 2 * (q1**2 + q2**2))
theta = np.arcsin(2 * (q0 * q2 - q3 * q1))
psi = np.arctan2(2 * (q0 * q3 + q1 * q2), 1 - 2 * (q2**2 + q3**2))
eulers = array([gamma, theta, psi]).T
return eulers.reshape(output_shape)
def quat2rot(quats):
quats = array(quats)
input_shape = quats.shape
quats = np.atleast_2d(quats)
Rs = np.zeros((quats.shape[0], 3, 3))
q0 = quats[:, 0]
q1 = quats[:, 1]
q2 = quats[:, 2]
q3 = quats[:, 3]
Rs[:, 0, 0] = q0 * q0 + q1 * q1 - q2 * q2 - q3 * q3
Rs[:, 0, 1] = 2 * (q1 * q2 - q0 * q3)
Rs[:, 0, 2] = 2 * (q0 * q2 + q1 * q3)
Rs[:, 1, 0] = 2 * (q1 * q2 + q0 * q3)
Rs[:, 1, 1] = q0 * q0 - q1 * q1 + q2 * q2 - q3 * q3
Rs[:, 1, 2] = 2 * (q2 * q3 - q0 * q1)
Rs[:, 2, 0] = 2 * (q1 * q3 - q0 * q2)
Rs[:, 2, 1] = 2 * (q0 * q1 + q2 * q3)
Rs[:, 2, 2] = q0 * q0 - q1 * q1 - q2 * q2 + q3 * q3
if len(input_shape) < 2:
return Rs[0]
return Rs
def rot2quat(rots):
input_shape = rots.shape
if len(input_shape) < 3:
rots = array([rots])
K3 = np.empty((len(rots), 4, 4))
K3[:, 0, 0] = (rots[:, 0, 0] - rots[:, 1, 1] - rots[:, 2, 2]) / 3.0
K3[:, 0, 1] = (rots[:, 1, 0] + rots[:, 0, 1]) / 3.0
K3[:, 0, 2] = (rots[:, 2, 0] + rots[:, 0, 2]) / 3.0
K3[:, 0, 3] = (rots[:, 1, 2] - rots[:, 2, 1]) / 3.0
K3[:, 1, 0] = K3[:, 0, 1]
K3[:, 1, 1] = (rots[:, 1, 1] - rots[:, 0, 0] - rots[:, 2, 2]) / 3.0
K3[:, 1, 2] = (rots[:, 2, 1] + rots[:, 1, 2]) / 3.0
K3[:, 1, 3] = (rots[:, 2, 0] - rots[:, 0, 2]) / 3.0
K3[:, 2, 0] = K3[:, 0, 2]
K3[:, 2, 1] = K3[:, 1, 2]
K3[:, 2, 2] = (rots[:, 2, 2] - rots[:, 0, 0] - rots[:, 1, 1]) / 3.0
K3[:, 2, 3] = (rots[:, 0, 1] - rots[:, 1, 0]) / 3.0
K3[:, 3, 0] = K3[:, 0, 3]
K3[:, 3, 1] = K3[:, 1, 3]
K3[:, 3, 2] = K3[:, 2, 3]
K3[:, 3, 3] = (rots[:, 0, 0] + rots[:, 1, 1] + rots[:, 2, 2]) / 3.0
q = np.empty((len(rots), 4))
for i in range(len(rots)):
_, eigvecs = linalg.eigh(K3[i].T)
eigvecs = eigvecs[:,3:]
q[i, 0] = eigvecs[-1]
q[i, 1:] = -eigvecs[:-1].flatten()
if q[i, 0] < 0:
q[i] = -q[i]
if len(input_shape) < 3:
return q[0]
return q
def euler2rot(eulers):
return rotations_from_quats(euler2quat(eulers))
def rot2euler(rots):
return quat2euler(quats_from_rotations(rots))
quats_from_rotations = rot2quat
quat_from_rot = rot2quat
rotations_from_quats = quat2rot
rot_from_quat= quat2rot
rot_from_quat= quat2rot
euler_from_rot = rot2euler
euler_from_quat = quat2euler
rot_from_euler = euler2rot
quat_from_euler = euler2quat
'''
Random helpers below
'''
def quat_product(q, r):
t = np.zeros(4)
t[0] = r[0] * q[0] - r[1] * q[1] - r[2] * q[2] - r[3] * q[3]
t[1] = r[0] * q[1] + r[1] * q[0] - r[2] * q[3] + r[3] * q[2]
t[2] = r[0] * q[2] + r[1] * q[3] + r[2] * q[0] - r[3] * q[1]
t[3] = r[0] * q[3] - r[1] * q[2] + r[2] * q[1] + r[3] * q[0]
return t
def rot_matrix(roll, pitch, yaw):
cr, sr = np.cos(roll), np.sin(roll)
cp, sp = np.cos(pitch), np.sin(pitch)
cy, sy = np.cos(yaw), np.sin(yaw)
rr = array([[1,0,0],[0, cr,-sr],[0, sr, cr]])
rp = array([[cp,0,sp],[0, 1,0],[-sp, 0, cp]])
ry = array([[cy,-sy,0],[sy, cy,0],[0, 0, 1]])
return ry.dot(rp.dot(rr))
def rot(axis, angle):
# Rotates around an arbitrary axis
ret_1 = (1 - np.cos(angle)) * array([[axis[0]**2, axis[0] * axis[1], axis[0] * axis[2]], [
axis[1] * axis[0], axis[1]**2, axis[1] * axis[2]
], [axis[2] * axis[0], axis[2] * axis[1], axis[2]**2]])
ret_2 = np.cos(angle) * np.eye(3)
ret_3 = np.sin(angle) * array([[0, -axis[2], axis[1]], [axis[2], 0, -axis[0]],
[-axis[1], axis[0], 0]])
return ret_1 + ret_2 + ret_3
def ecef_euler_from_ned(ned_ecef_init, ned_pose):
'''
Got it from here:
Using Rotations to Build Aerospace Coordinate Systems
-Don Koks
'''
converter = LocalCoord.from_ecef(ned_ecef_init)
x0 = converter.ned2ecef([1, 0, 0]) - converter.ned2ecef([0, 0, 0])
y0 = converter.ned2ecef([0, 1, 0]) - converter.ned2ecef([0, 0, 0])
z0 = converter.ned2ecef([0, 0, 1]) - converter.ned2ecef([0, 0, 0])
x1 = rot(z0, ned_pose[2]).dot(x0)
y1 = rot(z0, ned_pose[2]).dot(y0)
z1 = rot(z0, ned_pose[2]).dot(z0)
x2 = rot(y1, ned_pose[1]).dot(x1)
y2 = rot(y1, ned_pose[1]).dot(y1)
z2 = rot(y1, ned_pose[1]).dot(z1)
x3 = rot(x2, ned_pose[0]).dot(x2)
y3 = rot(x2, ned_pose[0]).dot(y2)
#z3 = rot(x2, ned_pose[0]).dot(z2)
x0 = array([1, 0, 0])
y0 = array([0, 1, 0])
z0 = array([0, 0, 1])
psi = np.arctan2(inner(x3, y0), inner(x3, x0))
theta = np.arctan2(-inner(x3, z0), np.sqrt(inner(x3, x0)**2 + inner(x3, y0)**2))
y2 = rot(z0, psi).dot(y0)
z2 = rot(y2, theta).dot(z0)
phi = np.arctan2(inner(y3, z2), inner(y3, y2))
ret = array([phi, theta, psi])
return ret
def ned_euler_from_ecef(ned_ecef_init, ecef_poses):
'''
Got the math from here:
Using Rotations to Build Aerospace Coordinate Systems
-Don Koks
Also accepts array of ecef_poses and array of ned_ecef_inits.
Where each row is a pose and an ecef_init.
'''
ned_ecef_init = array(ned_ecef_init)
ecef_poses = array(ecef_poses)
output_shape = ecef_poses.shape
ned_ecef_init = np.atleast_2d(ned_ecef_init)
if ned_ecef_init.shape[0] == 1:
ned_ecef_init = np.tile(ned_ecef_init[0], (output_shape[0], 1))
ecef_poses = np.atleast_2d(ecef_poses)
ned_poses = np.zeros(ecef_poses.shape)
for i, ecef_pose in enumerate(ecef_poses):
converter = LocalCoord.from_ecef(ned_ecef_init[i])
x0 = array([1, 0, 0])
y0 = array([0, 1, 0])
z0 = array([0, 0, 1])
x1 = rot(z0, ecef_pose[2]).dot(x0)
y1 = rot(z0, ecef_pose[2]).dot(y0)
z1 = rot(z0, ecef_pose[2]).dot(z0)
x2 = rot(y1, ecef_pose[1]).dot(x1)
y2 = rot(y1, ecef_pose[1]).dot(y1)
z2 = rot(y1, ecef_pose[1]).dot(z1)
x3 = rot(x2, ecef_pose[0]).dot(x2)
y3 = rot(x2, ecef_pose[0]).dot(y2)
#z3 = rot(x2, ecef_pose[0]).dot(z2)
x0 = converter.ned2ecef([1, 0, 0]) - converter.ned2ecef([0, 0, 0])
y0 = converter.ned2ecef([0, 1, 0]) - converter.ned2ecef([0, 0, 0])
z0 = converter.ned2ecef([0, 0, 1]) - converter.ned2ecef([0, 0, 0])
psi = np.arctan2(inner(x3, y0), inner(x3, x0))
theta = np.arctan2(-inner(x3, z0), np.sqrt(inner(x3, x0)**2 + inner(x3, y0)**2))
y2 = rot(z0, psi).dot(y0)
z2 = rot(y2, theta).dot(z0)
phi = np.arctan2(inner(y3, z2), inner(y3, y2))
ned_poses[i] = array([phi, theta, psi])
return ned_poses.reshape(output_shape)
def ecef2car(car_ecef, psi, theta, points_ecef, ned_converter):
"""
TODO: add roll rotation
Converts an array of points in ecef coordinates into
x-forward, y-left, z-up coordinates
Parameters
----------
psi: yaw, radian
theta: pitch, radian
Returns
-------
[x, y, z] coordinates in car frame
"""
# input is an array of points in ecef cocrdinates
# output is an array of points in car's coordinate (x-front, y-left, z-up)
# convert points to NED
points_ned = []
for p in points_ecef:
points_ned.append(ned_converter.ecef2ned_matrix.dot(array(p) - car_ecef))
points_ned = np.vstack(points_ned).T
# n, e, d -> x, y, z
# Calculate relative positions and rotate wrt to heading and pitch of car
invert_R = array([[1., 0., 0.], [0., -1., 0.], [0., 0., -1.]])
c, s = np.cos(psi), np.sin(psi)
yaw_R = array([[c, s, 0.], [-s, c, 0.], [0., 0., 1.]])
c, s = np.cos(theta), np.sin(theta)
pitch_R = array([[c, 0., -s], [0., 1., 0.], [s, 0., c]])
return dot(pitch_R, dot(yaw_R, dot(invert_R, points_ned)))
-192
View File
@@ -1,192 +0,0 @@
import sympy
import numpy as np
from typing import List
from .constants import EARTH_ROTATION_RATE, SPEED_OF_LIGHT
from .helpers import ConstellationId
from .raw_gnss import GNSSMeasurement
def gauss_newton(fun, b, M, xtol=1e-8, max_n=25):
W = np.linalg.inv(M)
for _ in range(max_n):
# Compute function and jacobian on current estimate
r, J = fun(b)
# Update estimate, WLS https://en.wikipedia.org/wiki/Weighted_least_squares
delta = np.linalg.pinv(J.T.dot(W).dot(J)).dot(J.T).dot(W) @ r
b -= delta
# Check step size for stopping condition
if np.linalg.norm(delta) < xtol:
break
r, J = fun(b)
Mb = np.linalg.pinv(J.T.dot(W).dot(J))
x_std = np.sqrt(np.diagonal(Mb))
return b, r, x_std
def calc_pos_fix(measurements, posfix_functions=None, x0=None, signal='C1C', min_measurements=5):
'''
Calculates gps fix using gauss newton method
To solve the problem a minimal of 4 measurements are required.
If Glonass is included 5 are required to solve for the additional free variable.
returns:
0 -> list with positions
1 -> pseudorange errs
'''
if x0 is None:
x0 = [0, 0, 0, 0, 0]
if len(measurements) < min_measurements:
return [],[],[]
Fx_pos = pr_residual(measurements, posfix_functions, signal=signal, no_nans=True)
meas_cov = np.diag([meas.observables_std[signal]**2 for meas in measurements])
x, residual, x_std = gauss_newton(Fx_pos, x0, meas_cov)
return x.tolist(), residual.tolist(), x_std
def calc_vel_fix(measurements, est_pos, velfix_function=None, v0=None, signal='D1C', min_measurements=5):
'''
Calculates gps velocity fix using gauss newton method
returns:
0 -> list with velocities
1 -> pseudorange_rate errs
'''
if v0 is None:
v0 = [0, 0, 0, 0]
if len(measurements) < min_measurements:
return [], [], []
Fx_vel = prr_residual(measurements, est_pos, velfix_function, signal=signal, no_nans=True)
meas_cov = np.diag([meas.observables_std[signal]**2 for meas in measurements])
v, residual, x_std = gauss_newton(Fx_vel, v0, meas_cov)
return v.tolist(), residual.tolist(), x_std
def get_posfix_sympy_fun(constellation):
# Unknowns
x, y, z = sympy.Symbol('x'), sympy.Symbol('y'), sympy.Symbol('z')
bc = sympy.Symbol('bc')
bg = sympy.Symbol('bg')
zero_theta = sympy.Symbol('zero_theta')
var = [x, y, z, bc, bg]
# Knowns
pr = sympy.Symbol('pr')
sat_x, sat_y, sat_z = sympy.Symbol('sat_x'), sympy.Symbol('sat_y'), sympy.Symbol('sat_z')
theta = (EARTH_ROTATION_RATE * (pr - bc) / SPEED_OF_LIGHT)*zero_theta
val = sympy.sqrt(
(sat_x * sympy.cos(theta) + sat_y * sympy.sin(theta) - x) ** 2 +
(sat_y * sympy.cos(theta) - sat_x * sympy.sin(theta) - y) ** 2 +
(sat_z - z) ** 2
)
if constellation == ConstellationId.GLONASS:
res = val - (pr - bc - bg)
elif constellation == ConstellationId.GPS:
res = val - (pr - bc)
else:
raise NotImplementedError(f"Constellation {constellation} not supported")
res = [res] + [sympy.diff(res, v) for v in var]
return sympy.lambdify([x, y, z, bc, bg, pr, zero_theta, sat_x, sat_y, sat_z], res, modules=["numpy"])
def get_velfix_sympy_func():
# implementing this without sympy.Matrix gives a 2x speedup at generation
# knowns, receiver position, satellite position, satellite velocity
ep_x, ep_y, ep_z = sympy.Symbol('ep_x'), sympy.Symbol('ep_y'), sympy.Symbol('ep_z')
est_pos = np.array([ep_x, ep_y, ep_z])
sp_x, sp_y, sp_z = sympy.Symbol('sp_x'), sympy.Symbol('sp_y'), sympy.Symbol('sp_z')
sat_pos = np.array([sp_x, sp_y, sp_z])
sv_x, sv_y, sv_z = sympy.Symbol('sv_x'), sympy.Symbol('sv_y'), sympy.Symbol('sv_z')
sat_vel = np.array([sv_x, sv_y, sv_z])
observables = sympy.Symbol('observables')
# unknown, receiver velocity
v_x, v_y, v_z = sympy.Symbol('v_x'), sympy.Symbol('v_y'), sympy.Symbol('v_z')
vel = np.array([v_x, v_y, v_z])
vel_o = sympy.Symbol('vel_o')
loss = sat_pos - est_pos
loss /= sympy.sqrt(loss.dot(loss))
res = loss.dot(sat_vel - vel) - (observables - vel_o)
res = [res] + [sympy.diff(res, v) for v in [v_x, v_y, v_z, vel_o]]
return sympy.lambdify([
ep_x, ep_y, ep_z, sp_x, sp_y, sp_z,
sv_x, sv_y, sv_z, observables,
v_x, v_y, v_z, vel_o
],
res, modules=["numpy"])
def pr_residual(measurements: List[GNSSMeasurement], posfix_functions=None, signal='C1C', no_nans=False):
if posfix_functions is None:
posfix_functions = {constellation: get_posfix_sympy_fun(constellation) for constellation in (ConstellationId.GPS, ConstellationId.GLONASS)}
def Fx_pos(inp):
vals, gradients = [], []
for meas in measurements:
if signal in meas.observables_final and np.isfinite(meas.observables_final[signal]):
pr = meas.observables_final[signal]
sat_pos = meas.sat_pos_final
zero_theta = 0
elif signal in meas.observables and np.isfinite(meas.observables[signal]) and meas.processed:
pr = meas.observables[signal]
pr += meas.sat_clock_err * SPEED_OF_LIGHT
sat_pos = meas.sat_pos
zero_theta = 1
else:
if not no_nans:
vals.append(np.nan)
gradients.append(np.nan)
continue
val, *gradient = posfix_functions[meas.constellation_id](*inp, pr, zero_theta, *sat_pos)
vals.append(val)
gradients.append(gradient)
return np.asarray(vals), np.asarray(gradients)
return Fx_pos
def prr_residual(measurements: List[GNSSMeasurement], est_pos, velfix_function=None, signal='D1C', no_nans=False):
if velfix_function is None:
velfix_function = get_velfix_sympy_func()
def Fx_vel(vel):
vals, gradients = [], []
for meas in measurements:
if signal not in meas.observables or not np.isfinite(meas.observables[signal]):
if not no_nans:
vals.append(np.nan)
gradients.append(np.nan)
continue
sat_pos = meas.sat_pos_final if meas.corrected else meas.sat_pos
val, *gradient = velfix_function(est_pos[0], est_pos[1], est_pos[2],
sat_pos[0], sat_pos[1], sat_pos[2],
meas.sat_vel[0], meas.sat_vel[1], meas.sat_vel[2],
meas.observables[signal],
vel[0], vel[1], vel[2], vel[3])
vals.append(val)
gradients.append(gradient)
return np.asarray(vals), np.asarray(gradients)
return Fx_vel
-381
View File
@@ -1,381 +0,0 @@
from math import sqrt
from typing import Dict, List, Optional, Union
import numpy as np
import datetime
import struct
from . import constants
from .ephemeris import Ephemeris
from .lib.coordinates import LocalCoord
from .gps_time import GPSTime
from .helpers import ConstellationId, get_constellation_and_sv_id, get_nmea_id_from_constellation_and_svid, \
rinex3_obs_from_rinex2_obs
def array_from_normal_meas(meas):
return np.concatenate(([meas.get_nmea_id()],
[meas.recv_time_week],
[meas.recv_time_sec],
[meas.glonass_freq],
[meas.observables['C1C']],
[meas.observables_std['C1C']],
[meas.observables['D1C']],
[meas.observables_std['D1C']],
[meas.observables['S1C']],
[meas.observables['L1C']]))
def normal_meas_from_array(arr):
observables, observables_std = {}, {}
observables['C1C'] = arr[4]
observables_std['C1C'] = arr[5]
observables['D1C'] = arr[6]
observables_std['D1C'] = arr[7]
observables['S1C'] = arr[8]
observables['L1C'] = arr[9]
constellation_id, sv_id = get_constellation_and_sv_id(nmea_id=arr[0])
return GNSSMeasurement(constellation_id, sv_id, arr[1], arr[2],
observables, observables_std, arr[3])
class GNSSMeasurement:
PRN = 0
RECV_TIME_WEEK = 1
RECV_TIME_SEC = 2
GLONASS_FREQ = 3
PR = 4
PR_STD = 5
PRR = 6
PRR_STD = 7
SAT_POS = slice(8, 11)
SAT_VEL = slice(11, 14)
def __init__(self, constellation_id: ConstellationId, sv_id: int, recv_time_week: int, recv_time_sec: float, observables: Dict[str, float],
observables_std: Dict[str, float], glonass_freq: Union[int, float, None] = None):
# Metadata
# prn: unique satellite id
self.prn = "%s%02d" % (constellation_id.to_rinex_char(), sv_id) # satellite ID in rinex convention
self.constellation_id = constellation_id
self.sv_id = sv_id # satellite id per constellation
self.recv_time_week = recv_time_week
self.recv_time_sec = recv_time_sec
self.recv_time = GPSTime(recv_time_week, recv_time_sec)
self.glonass_freq = glonass_freq # glonass channel
# Measurements
self.observables = observables
self.observables_std = observables_std
# flags
self.processed = False
self.corrected = False
# sat info
self.sat_pos = np.array([np.nan, np.nan, np.nan])
self.sat_vel = np.array([np.nan, np.nan, np.nan])
self.sat_clock_err = np.nan
self.sat_ephemeris: Optional[Ephemeris] = None
self.sat_pos_final = np.array([np.nan, np.nan, np.nan]) # sat_pos in receiver time's ECEF frame instead of satellite time's ECEF frame
self.observables_final: Dict[str, float] = {}
def process(self, dog):
sat_time = self.recv_time - self.observables['C1C']/constants.SPEED_OF_LIGHT
sat_info = dog.get_sat_info(self.prn, sat_time)
if sat_info is None:
return False
self.sat_pos, self.sat_vel, self.sat_clock_err, _, self.sat_ephemeris = sat_info
self.processed = True
return True
def correct(self, est_pos, dog, correct_delay=True):
for obs in self.observables:
if obs[0] == 'C': # or obs[0] == 'L':
if correct_delay:
delay = dog.get_delay(self.prn, self.recv_time, est_pos, signal=obs)
else:
delay = 0.0
if delay is not None:
self.observables_final[obs] = (self.observables[obs] +
self.sat_clock_err*constants.SPEED_OF_LIGHT -
delay)
else:
self.observables_final[obs] = self.observables[obs]
if 'C1C' in self.observables_final and 'C2P' in self.observables_final:
self.observables_final['IOF'] = (((constants.GPS_L1**2)*self.observables_final['C1C'] -
(constants.GPS_L2**2)*self.observables_final['C2P'])/
(constants.GPS_L1**2 - constants.GPS_L2**2))
geometric_range = np.linalg.norm(self.sat_pos - est_pos)
theta_1 = constants.EARTH_ROTATION_RATE * geometric_range / constants.SPEED_OF_LIGHT
self.sat_pos_final = np.array([self.sat_pos[0] * np.cos(theta_1) + self.sat_pos[1] * np.sin(theta_1),
self.sat_pos[1] * np.cos(theta_1) - self.sat_pos[0] * np.sin(theta_1),
self.sat_pos[2]])
if 'C1C' in self.observables_final and np.isfinite(self.observables_final['C1C']):
self.corrected = True
return True
return False
def as_array(self, only_corrected=True):
observables = self.observables_final
sat_pos = self.sat_pos_final
if not self.corrected:
if only_corrected:
raise NotImplementedError('Only corrected measurements can be put into arrays')
else:
observables = self.observables
sat_pos = self.sat_pos
ret = np.array([self.get_nmea_id(), self.recv_time_week, self.recv_time_sec, self.glonass_freq,
observables['C1C'], self.observables_std['C1C'],
observables['D1C'], self.observables_std['D1C']])
return np.concatenate((ret, sat_pos, self.sat_vel))
def __repr__(self):
time = self.recv_time.as_datetime().strftime('%Y-%m-%dT%H:%M:%S.%f')
return f"<GNSSMeasurement from {self.prn} at {time}>"
def get_nmea_id(self):
return get_nmea_id_from_constellation_and_svid(self.constellation_id, self.sv_id)
def process_measurements(measurements: List[GNSSMeasurement], dog) -> List[GNSSMeasurement]:
proc_measurements = []
for meas in measurements:
if meas.process(dog):
proc_measurements.append(meas)
return proc_measurements
def correct_measurements(measurements: List[GNSSMeasurement], est_pos, dog, correct_delay=True) -> List[GNSSMeasurement]:
corrected_measurements = []
for meas in measurements:
if meas.correct(est_pos, dog, correct_delay=correct_delay):
corrected_measurements.append(meas)
return corrected_measurements
def group_measurements_by_epoch(measurements):
meas_filt_by_t = [[measurements[0]]]
for m in measurements[1:]:
if abs(m.recv_time - meas_filt_by_t[-1][-1].recv_time) > 1e-9:
meas_filt_by_t.append([])
meas_filt_by_t[-1].append(m)
return meas_filt_by_t
def group_measurements_by_sat(measurements):
measurements_by_sat = {}
sats = {m.prn for m in measurements}
for sat in sats:
measurements_by_sat[sat] = [m for m in measurements if m.prn == sat]
return measurements_by_sat
def gps_time_from_qcom_report(gnss_msg):
if gnss_msg.which() == 'measurementReport':
report = gnss_msg.measurementReport
constellation = ConstellationId.from_qcom_source(report.source)
if constellation in [ConstellationId.GPS, ConstellationId.SBAS]:
report_time = GPSTime(report.gpsWeek, report.milliseconds / 1000.0)
elif constellation == ConstellationId.GLONASS:
report_time = GPSTime.from_glonass(report.glonassCycleNumber,
report.glonassNumberOfDays,
report.milliseconds / 1000.0)
else:
raise NotImplementedError(f'Unknownconstellation {report.source}')
else:
report = gnss_msg.drMeasurementReport
constellation = ConstellationId.from_qcom_source(report.source)
if ConstellationId.from_qcom_source(report.source) in [ConstellationId.GPS, ConstellationId.SBAS]:
report_time = GPSTime(report.gpsWeek, report.gpsMilliseconds / 1000.0)
elif constellation == ConstellationId.GLONASS:
report_time = GPSTime.from_glonass(report.glonassYear,
report.glonassDay,
report.glonassMilliseconds / 1000.0)
else:
raise NotImplementedError(f'Unknownconstellation {report.source}')
return report_time
def get_measurements_from_qcom_reports(reports):
new_meas_dr = []
new_meas = []
for gnss_msg in reports:
if gnss_msg.which() == 'drMeasurementReport':
new_meas_dr.extend(read_raw_qcom(gnss_msg.drMeasurementReport))
else:
new_meas.extend(read_raw_qcom(gnss_msg.measurementReport))
sat_dict_dr = {meas.prn: meas for meas in new_meas_dr}
out_meas = []
for meas in new_meas:
if meas.prn in sat_dict_dr:
# Sometimes DR measurements are complete garbage, in those cases non-DR measurements are still sane, so cross-check
if abs(meas.observables['C1C'] - sat_dict_dr[meas.prn].observables['C1C']) < 1000:
meas.observables['C1C'] = sat_dict_dr[meas.prn].observables['C1C']
meas.observables_std['C1C'] = sat_dict_dr[meas.prn].observables_std['C1C']
out_meas.append(meas)
return out_meas
def read_raw_qcom(report):
dr = 'DrMeasurementReport' in str(report.schema)
# Only gps/sbas and glonass are supported
constellation_id = ConstellationId.from_qcom_source(report.source)
if constellation_id in [ConstellationId.GPS, ConstellationId.SBAS]: # gps/sbas
if dr:
recv_tow = report.gpsMilliseconds / 1000.0 # seconds
time_bias_ms = struct.unpack("f", struct.pack("I", report.gpsTimeBiasMs))[0]
else:
recv_tow = report.milliseconds / 1000.0 # seconds
time_bias_ms = report.timeBias
recv_time = GPSTime(report.gpsWeek, recv_tow)
elif constellation_id == ConstellationId.GLONASS:
if dr:
recv_tow = report.glonassMilliseconds / 1000.0 # seconds
recv_time = GPSTime.from_glonass(report.glonassYear, report.glonassDay, recv_tow)
time_bias_ms = report.glonassTimeBias
else:
recv_tow = report.milliseconds / 1000.0 # seconds
recv_time = GPSTime.from_glonass(report.glonassCycleNumber, report.glonassNumberOfDays, recv_tow)
time_bias_ms = report.timeBias
else:
raise NotImplementedError('Only GPS (0), SBAS (1) and GLONASS (6) are supported from qcom, not:', {report.source})
# logging.debug(recv_time, report.source, time_bias_ms, dr)
measurements = []
for i in report.sv:
# todo change svId to nmea_id in cereal message. Or better: change the publisher to publish correct svId's, since constellation id is also given
nmea_id = i.svId
if nmea_id == 255:
# TODO nmea_id is not valid. Fix publisher
continue
_, sv_id = get_constellation_and_sv_id(nmea_id)
if not i.measurementStatus.measurementNotUsable and i.measurementStatus.satelliteTimeIsKnown and i.measurementStatus.freshMeasurementIndicator:
observables, observables_std = {}, {}
if dr:
sat_tow = (i.filteredMeasurementIntegral + i.filteredMeasurementFraction + i.latency + time_bias_ms) / 1000
else:
sat_tow = (i.unfilteredMeasurementIntegral + i.unfilteredMeasurementFraction + i.latency + time_bias_ms) / 1000
observables['C1C'] = (recv_tow - sat_tow)*constants.SPEED_OF_LIGHT
observables_std['C1C'] = i.unfilteredTimeUncertainty * 1e-3 * constants.SPEED_OF_LIGHT # always use unfiltered std, filtered std is bigger?
if i.measurementStatus.fineOrCoarseVelocity:
# about 10x better, perhaps filtered with carrier phase?
observables['D1C'] = i.fineSpeed
observables_std['D1C'] = sqrt(i.fineSpeedUncertainty) # sqrt empirically makes performance much better, might be wrong
else:
observables['D1C'] = i.unfilteredSpeed
observables_std['D1C'] = i.unfilteredSpeedUncertainty
observables['S1C'] = (i.carrierNoise/100.) if i.carrierNoise != 0 else np.nan
observables['L1C'] = np.nan
# logging.debug(" %.5f %3d %10.2f %7.2f %7.2f %.2f %d" % (recv_time.tow, nmea_id,
# observables['C1C'], observables_std['C1C'],
# observables_std['D1C'], observables['S1C'], i.latency), i.observationState, i.measurementStatus.fineOrCoarseVelocity)
glonass_freq = (i.glonassFrequencyIndex - 7) if constellation_id == ConstellationId.GLONASS else np.nan
measurements.append(GNSSMeasurement(constellation_id, sv_id,
recv_time.week,
recv_time.tow,
observables,
observables_std,
glonass_freq))
return measurements
def read_raw_ublox(report) -> List[GNSSMeasurement]:
recv_tow = report.rcvTow # seconds
recv_week = report.gpsWeek
measurements = []
for i in report.measurements:
# only add Gps and Glonass fixes
if i.gnssId in [ConstellationId.GPS, ConstellationId.GLONASS]:
if i.svId > 32 or i.pseudorange > 2**32:
continue
observables = {}
observables_std = {}
if i.trackingStatus.pseudorangeValid and i.sigId == 0:
observables['C1C'] = i.pseudorange
# Empirically it seems obvious ublox's std is
# actually a variation
observables_std['C1C'] = sqrt(i.pseudorangeStdev)*10
if i.gnssId == ConstellationId.GLONASS:
glonass_freq = i.glonassFrequencyIndex - 7
observables['D1C'] = -(constants.SPEED_OF_LIGHT / (constants.GLONASS_L1 + glonass_freq * constants.GLONASS_L1_DELTA)) * i.doppler
else: # GPS
glonass_freq = np.nan
observables['D1C'] = -(constants.SPEED_OF_LIGHT / constants.GPS_L1) * i.doppler
observables_std['D1C'] = (constants.SPEED_OF_LIGHT / constants.GPS_L1) * i.dopplerStdev
observables['S1C'] = i.cno
if i.trackingStatus.carrierPhaseValid:
observables['L1C'] = i.carrierCycles
else:
observables['L1C'] = np.nan
measurements.append(GNSSMeasurement(ConstellationId(i.gnssId), i.svId, recv_week, recv_tow,
observables, observables_std, glonass_freq))
return measurements
def read_rinex_obs(obsdata) -> List[List[GNSSMeasurement]]:
measurements: List[List[GNSSMeasurement]] = []
obsdata_keys = list(obsdata.data.keys())
first_sat = obsdata_keys[0]
n = len(obsdata.data[first_sat]['Epochs'])
for i in range(n):
recv_time_datetime = obsdata.data[first_sat]['Epochs'][i]
recv_time_datetime = recv_time_datetime.astype(datetime.datetime)
recv_time = GPSTime.from_datetime(recv_time_datetime)
measurements.append([])
for sat_str in obsdata_keys:
if np.isnan(obsdata.data[sat_str]['C1'][i]):
continue
observables, observables_std = {}, {}
for obs in obsdata.data[sat_str]:
if obs == 'Epochs':
continue
rinex3_obs_key = rinex3_obs_from_rinex2_obs(obs)
observables[rinex3_obs_key] = obsdata.data[sat_str][obs][i]
observables_std[rinex3_obs_key] = 1.
constellation_id, sv_id = get_constellation_and_sv_id(int(sat_str))
measurements[-1].append(GNSSMeasurement(constellation_id, sv_id,
recv_time.week, recv_time.tow,
observables, observables_std))
return measurements
def get_Q(recv_pos, sat_positions):
local = LocalCoord.from_ecef(recv_pos)
sat_positions_rel = local.ecef2ned(sat_positions)
sat_distances = np.linalg.norm(sat_positions_rel, axis=1)
A = np.column_stack((sat_positions_rel[:,0]/sat_distances, # pylint: disable=unsubscriptable-object
sat_positions_rel[:,1]/sat_distances, # pylint: disable=unsubscriptable-object
sat_positions_rel[:,2]/sat_distances, # pylint: disable=unsubscriptable-object
-np.ones(len(sat_distances))))
if A.shape[0] < 4 or np.linalg.matrix_rank(A) < 4:
return np.inf*np.ones((4,4))
Q = np.linalg.inv(A.T.dot(A))
return Q
def get_DOP(recv_pos, sat_positions):
Q = get_Q(recv_pos, sat_positions)
return np.sqrt(np.trace(Q))
def get_HDOP(recv_pos, sat_positions):
Q = get_Q(recv_pos, sat_positions)
return np.sqrt(np.trace(Q[:2,:2]))
def get_VDOP(recv_pos, sat_positions):
Q = get_Q(recv_pos, sat_positions)
return np.sqrt(Q[2,2])
def get_TDOP(recv_pos, sat_positions):
Q = get_Q(recv_pos, sat_positions)
return np.sqrt(Q[3,3])
def get_PDOP(recv_pos, sat_positions):
Q = get_Q(recv_pos, sat_positions)
return np.sqrt(np.trace(Q[:3,:3]))
-251
View File
@@ -1,251 +0,0 @@
# Copyright (C) 2014 Swift Navigation Inc.
#
# This source is subject to the license found in the file 'LICENSE' which must
# be be distributed together with this source. All other rights reserved.
#
# THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
# EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
import datetime
import numpy as np
import logging
def floatornan(x):
if x == '' or x[-1] == ' ':
return np.NaN
return float(x)
def digitorzero(x):
if x == ' ' or x == '':
return 0
return int(x)
def padline(l, n=16):
x = len(l)
x_ = n * ((x + n - 1) // n)
padded = l + ' ' * (x_ - x)
while len(padded) < 70:
padded += ' ' * 16
return padded
TOTAL_SATS = 132 # Increased to support Galileo
class DownloadError(Exception):
pass
class RINEXFile:
def __init__(self, filename, rate=None):
self.rate = rate
try:
with open(filename) as f:
self._read_header(f)
self._read_data(f)
except TypeError:
logging.exception("TypeError, file likely not downloaded.")
raise DownloadError("file download failure")
except FileNotFoundError:
logging.exception("File not found in directory.")
raise DownloadError("file missing in download cache")
def _read_header(self, f):
version_line = padline(f.readline(), 80)
self.version = float(version_line[0:9])
if (self.version > 2.11):
raise ValueError(
f"RINEX file versions > 2.11 not supported (file version {self.version:f})")
self.filetype = version_line[20]
if self.filetype not in "ONGM": # Check valid file type
raise ValueError(f"RINEX file type '{self.filetype}' not supported")
if self.filetype != 'O':
raise ValueError("Only 'OBSERVATION DATA' RINEX files are currently supported")
self.gnss = version_line[40]
if self.gnss not in " GRSEM": # Check valid satellite system
raise ValueError(f"Satellite system '{self.filetype}' not supported")
if self.gnss == ' ':
self.gnss = 'G'
if self.gnss != 'G':
#raise ValueError("Only GPS data currently supported")
pass
self.comment = ""
while True: # Read the rest of the header
line = padline(f.readline(), 80)
label = line[60:80].rstrip()
if label == "END OF HEADER":
break
if label == "COMMENT":
self.comment += line[:60] + '\n'
if label == "MARKER NAME":
self.marker_name = line[:60].rstrip()
if self.marker_name == '':
self.marker_name = 'UNKNOWN'
if label == "# / TYPES OF OBSERV":
# RINEX files can have multiple line headers
# This code handles the case
try:
n_obs = int(line[0:6])
self.obs_types = []
except ValueError:
pass
if n_obs <= 9:
for i in range(0, n_obs):
self.obs_types.append(line[10 + 6 * i:12 + 6 * i])
if n_obs > 9:
for i in range(0, 9):
self.obs_types.append(line[10 + 6 * i:12 + 6 * i])
n_obs -= 9
def _read_next_non_comment(self, f):
line = f.readline()
while line and line.find('COMMENT') != -1:
line = f.readline()
return line
def _read_epoch_header(self, f):
epoch_hdr = self._read_next_non_comment(f)
if epoch_hdr == '':
return None
# ignore any line with these three strings
skippable = ('0.0000000 4 5', 'MARKER NUMBER', ' 4 1')
while any(skip in epoch_hdr for skip in skippable):
epoch_hdr = self._read_next_non_comment(f)
if epoch_hdr == '':
return None
year = int(epoch_hdr[1:3])
if year >= 80:
year += 1900
else:
year += 2000
month = int(epoch_hdr[4:6])
day = int(epoch_hdr[7:9])
hour = int(epoch_hdr[10:12])
minute = int(epoch_hdr[13:15])
second = int(epoch_hdr[15:18])
microsecond = int(
epoch_hdr[19:25]) # Discard the least sig. fig. (use microseconds only).
epoch = datetime.datetime(year, month, day, hour, minute, second, microsecond)
flag = int(epoch_hdr[28])
allowed_flags = {0, 3, 4}
if flag not in allowed_flags:
raise ValueError("Don't know how to handle epoch flag %d in epoch header:\n%s" %
(flag, epoch_hdr))
n_sats = int(epoch_hdr[29:32])
if flag > 1: # event flag: nsats is number of records
for i in range(n_sats):
f.readline()
return None
sats = []
for i in range(0, n_sats):
if ((i % 12) == 0) and (i > 0):
epoch_hdr = f.readline()
sats.append(epoch_hdr[(32 + (i % 12) * 3):(35 + (i % 12) * 3)])
return epoch, flag, sats
def _read_obs(self, f, n_sat, sat_map):
obs = np.empty((TOTAL_SATS, len(self.obs_types)), dtype=np.float64) * np.NaN
lli = np.zeros((TOTAL_SATS, len(self.obs_types)), dtype=np.uint8)
signal_strength = np.zeros((TOTAL_SATS, len(self.obs_types)), dtype=np.uint8)
for i in range(n_sat):
# Join together observations for a single satellite if split across lines.
obs_line = ''.join(
padline(f.readline()[:-1], 16) for _ in range((len(self.obs_types) + 4) // 5))
for j in range(len(self.obs_types)):
obs_record = obs_line[16 * j:16 * (j + 1)]
obs[int(sat_map[i]), j] = floatornan(obs_record[0:14])
lli[int(sat_map[i]), j] = digitorzero(obs_record[14:15])
signal_strength[int(sat_map[i]), j] = digitorzero(obs_record[15:16])
return obs, lli, signal_strength
def _skip_obs(self, f, n_sat):
for i in range(n_sat):
for _ in range((len(self.obs_types) + 4) // 5):
f.readline()
def _read_data_chunk(self, f, CHUNK_SIZE=10000):
obss = np.empty(
(CHUNK_SIZE, TOTAL_SATS, len(self.obs_types)), dtype=np.float64) * np.NaN
llis = np.zeros((CHUNK_SIZE, TOTAL_SATS, len(self.obs_types)), dtype=np.uint8)
signal_strengths = np.zeros(
(CHUNK_SIZE, TOTAL_SATS, len(self.obs_types)), dtype=np.uint8)
epochs = np.zeros(CHUNK_SIZE, dtype='datetime64[us]')
flags = np.zeros(CHUNK_SIZE, dtype=np.uint8)
i = 0
while True:
hdr = self._read_epoch_header(f)
if hdr is None:
break
# data faster than desired rate: ignore it
if self.rate and (hdr[0].microsecond or hdr[0].second % self.rate != 0):
self._skip_obs(f, len(hdr[2]))
continue
epoch, flags[i], sats = hdr
epochs[i] = np.datetime64(epoch)
sat_map = np.ones(len(sats)) * -1
for n, sat in enumerate(sats):
if sat[0] == 'G':
sat_map[n] = int(sat[1:]) - 1
if sat[0] == 'R':
sat_map[n] = int(sat[1:]) - 1 + 64
obss[i], llis[i], signal_strengths[i] = self._read_obs(f, len(sats), sat_map)
i += 1
if i >= CHUNK_SIZE:
break
return obss[:i], llis[:i], signal_strengths[:i], epochs[:i], flags[:i]
def _read_data(self, f):
self.data = {}
while True:
obss, llis, signal_strengths, epochs, flags = self._read_data_chunk(f)
if obss.shape[0] == 0:
break
for i, sv in enumerate(['%02d' % d for d in range(1, TOTAL_SATS+1)]):
if sv not in self.data:
self.data[sv] = {}
for j, obs_type in enumerate(self.obs_types):
if obs_type in self.data[sv]:
self.data[sv][obs_type] = np.append(self.data[sv][obs_type], obss[:, i, j])
else:
self.data[sv][obs_type] = obss[:, i, j]
if 'Epochs' in self.data[sv]:
self.data[sv]['Epochs'] = np.append(self.data[sv]['Epochs'], epochs)
else:
self.data[sv]['Epochs'] = epochs
for sat in list(self.data.keys()):
if np.all(np.isnan(self.data[sat]['C1'])):
del self.data[sat]
-32
View File
@@ -1,32 +0,0 @@
from numpy import cos, exp, pi
from .lib.coordinates import ecef2geodetic
def saast(pos, el, humi=0.75, temp0=15.0):
"""
Function from RTKlib: https://github.com/tomojitakasu/RTKLIB/blob/master/src/rtkcmn.c#L3362-3362
with no changes
:param time: time
:param pos: receiver position {ecef} m)
:param el: azimuth/elevation angle {az,el} (rad) -- we do not use az
:param humi: relative humidity
:param temp0: temperature (Celsius)
:return: tropospheric delay (m)
"""
pos_rad = ecef2geodetic(pos, radians=True)
if pos_rad[2] < -1E3 or 1E4 < pos_rad[2] or el <= 0:
return 0.0
# /* standard atmosphere */
hgt = 0.0 if pos_rad[2] < 0.0 else pos_rad[2]
pres = 1013.25 * pow(1.0 - 2.2557E-5 * hgt, 5.2568)
temp = temp0 - 6.5E-3 * hgt + 273.16
e = 6.108 * humi * exp((17.15 * temp - 4684.0) / (temp - 38.45))
# /* saastamoninen model */
z = pi / 2.0 - el
trph = 0.0022768 * pres / (
1.0 - 0.00266 * cos(2.0 * pos_rad[0]) - 0.00028 * hgt / 1E3) / cos(z)
trpw = 0.002277 * (1255.0 / temp + 0.05) * e / cos(z)
return trph + trpw
+3 -3
View File
@@ -14,10 +14,10 @@ function agnos_init {
echo -n openpilot > /data/params/d/GithubUsername
cat /usr/comma/setup_keys > /data/params/d/GithubSshKeys
fi
# wait longer for weston to come up
if [ -f "$BASEDIR/prebuilt" ]; then
sleep 3
sleep 5
fi
# TODO: move this to agnos
@@ -90,7 +90,7 @@ function launch {
# start manager
cd selfdrive/manager
./custom_dep.py && ./build.py && ./manager.py
./build.py && ./manager.py
# if broken, keep on screen error
while true; do sleep 1; done
+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="8.2"
export AGNOS_VERSION="9.1"
fi
if [ -z "$PASSIVE" ]; then
+7 -7
View File
@@ -54,7 +54,7 @@ public:
bool ignore_checksum = false;
bool ignore_counter = false;
bool parse(uint64_t sec, const std::vector<uint8_t> &dat);
bool parse(uint64_t nanos, const std::vector<uint8_t> &dat);
bool update_counter_generic(int64_t v, int cnt_size);
};
@@ -69,9 +69,9 @@ private:
public:
bool can_valid = false;
bool bus_timeout = false;
uint64_t first_sec = 0;
uint64_t last_sec = 0;
uint64_t last_nonempty_sec = 0;
uint64_t first_nanos = 0;
uint64_t last_nanos = 0;
uint64_t last_nonempty_nanos = 0;
uint64_t bus_timeout_threshold = 0;
uint64_t can_invalid_cnt = CAN_INVALID_CNT;
@@ -81,10 +81,10 @@ public:
#ifndef DYNAMIC_CAPNP
void update_string(const std::string &data, bool sendcan);
void update_strings(const std::vector<std::string> &data, std::vector<SignalValue> &vals, bool sendcan);
void UpdateCans(uint64_t sec, const capnp::List<cereal::CanData>::Reader& cans);
void UpdateCans(uint64_t nanos, const capnp::List<cereal::CanData>::Reader& cans);
#endif
void UpdateCans(uint64_t sec, const capnp::DynamicStruct::Reader& cans);
void UpdateValid(uint64_t sec);
void UpdateCans(uint64_t nanos, const capnp::DynamicStruct::Reader& cans);
void UpdateValid(uint64_t nanos);
void query_latest(std::vector<SignalValue> &vals, uint64_t last_ts = 0);
};
Binary file not shown.
+873 -197
View File
File diff suppressed because it is too large Load Diff
Binary file not shown.
+1071 -272
View File
File diff suppressed because it is too large Load Diff
Binary file not shown.
@@ -59,11 +59,9 @@ BO_ 500 DAS_3: 8 XXX
SG_ DISABLE_FUEL_SHUTOFF : 23|1@1+ (1,0) [0|0] "" XXX
SG_ GR_MAX_REQ : 32|4@1+ (1,0) [0|0] "" XXX
SG_ ACC_DECEL_REQ : 36|3@1+ (1,0) [0|0] "" XXX
SG_ STS : 46|2@1+ (1,0) [0|0] "" XXX
SG_ ACC_FAULTED : 47|1@0+ (1,0) [0|1] "" XXX
SG_ ACC_FAULTED : 46|2@1+ (1,0) [0|0] "" XXX
SG_ COLLISION_BRK_PREP : 48|1@1+ (1,0) [0|0] "" XXX
SG_ ACC_BRK_PREP : 49|1@1+ (1,0) [0|0] "" XXX
SG_ BRAKE_BOOL_1 : 36|1@0+ (1,0) [0|3] "" XXX
SG_ COUNTER : 55|4@0+ (1,0) [0|15] "" XXX
SG_ CHECKSUM : 63|8@0+ (1,0) [0|255] "" XXX
@@ -74,6 +72,7 @@ BO_ 501 DAS_4: 8 XXX
SG_ ACC_DISTANCE_CONFIG_2 : 41|2@0+ (1,0) [0|3] "" XXX
SG_ SPEED_DIGITAL : 63|8@0+ (1,0) [0|255] "mph" XXX
SG_ ACC_STATE : 38|3@0+ (1,0) [0|7] "" XXX
SG_ FCW_BRAKE_ENABLED : 29|1@0+ (1,0) [0|1] "" XXX
BO_ 544 EPS_2: 8 XXX
SG_ LKAS_STATE : 23|4@0+ (1,0) [0|15] "" XXX
@@ -103,12 +102,23 @@ BO_ 571 CRUISE_BUTTONS: 3 XXX
SG_ COUNTER : 15|4@0+ (1,0) [0|15] "" XXX
SG_ CHECKSUM : 23|8@0+ (1,0) [0|255] "" XXX
BO_ 625 DAS_5: 8 XXX
SG_ FCW_STATE : 2|1@1+ (1,0) [0|0] "" XXX
SG_ FCW_DISTANCE : 3|2@1+ (1,0) [0|0] "" XXX
SG_ ACCFCW_MESSAGE : 12|4@1+ (1,0) [0|0] "" XXX
SG_ SET_SPEED_KPH : 24|8@1+ (1,0) [0|250] "km/h" XXX
SG_ WHEEL_TORQUE_REQUEST : 38|15@0+ (1,-7767) [-7767|24999] "Nm" XXX
SG_ WHEEL_TORQUE_REQUEST_ACTIVE : 39|1@1+ (1,0) [0|0] "" XXX
SG_ COUNTER : 55|4@0+ (1,0) [0|15] "" XXX
SG_ CHECKSUM : 63|8@0+ (1,0) [0|255] "" XXX
BO_ 678 DAS_6: 8 XXX
SG_ LKAS_ICON_COLOR : 1|2@0+ (1,0) [0|3] "" XXX
SG_ LKAS_LANE_LINES : 19|4@0+ (1,0) [0|1] "" XXX
SG_ LKAS_ALERTS : 27|4@0+ (1,0) [0|1] "" XXX
SG_ CAR_MODEL : 15|8@0+ (1,0) [0|255] "" XXX
SG_ AUTO_HIGH_BEAM_ON : 47|1@1+ (1,0) [0|0] "" XXX
SG_ LKAS_DISABLED : 56|1@1+ (1,0) [0|0] "" XXX
BO_ 720 BSM_1: 6 XXX
SG_ RIGHT_STATUS : 5|1@0+ (1,0) [0|1] "" XXX
@@ -278,12 +288,6 @@ BO_ 324 SPEED_2: 8 XXX
BO_ 832 UNKNOWN_340: 8 XXX
SG_ SPEED_DIGITAL : 63|8@0+ (1,0) [0|255] "mph" XXX
BO_ 625 ACC_1: 8 XXX
SG_ SPEED : 31|8@0+ (1,0) [0|255] "km/h" XXX
SG_ ACCEL_PERHAPS : 39|16@0+ (1,0) [0|255] "" XXX
SG_ CHECKSUM : 63|8@0+ (1,0) [0|255] "" XXX
SG_ COUNTER : 55|4@0+ (1,0) [0|15] "" XXX
BO_ 268 ACC_10c: 8 XXX
SG_ BRAKE_PERHAPS : 48|1@0+ (1,0) [0|3] "" XXX
SG_ COUNTER : 55|4@0+ (1,0) [0|15] "" XXX
+13 -3
View File
@@ -61,11 +61,9 @@ BO_ 153 DAS_3: 8 XXX
SG_ DISABLE_FUEL_SHUTOFF : 23|1@1+ (1,0) [0|0] "" XXX
SG_ GR_MAX_REQ : 32|4@1+ (1,0) [0|0] "" XXX
SG_ ACC_DECEL_REQ : 36|3@1+ (1,0) [0|0] "" XXX
SG_ STS : 46|2@1+ (1,0) [0|0] "" XXX
SG_ ACC_FAULTED : 47|1@0+ (1,0) [0|1] "" XXX
SG_ ACC_FAULTED : 46|2@1+ (1,0) [0|0] "" XXX
SG_ COLLISION_BRK_PREP : 48|1@1+ (1,0) [0|0] "" XXX
SG_ ACC_BRK_PREP : 49|1@1+ (1,0) [0|0] "" XXX
SG_ BRAKE_BOOL_1 : 36|1@0+ (1,0) [0|3] "" XXX
SG_ COUNTER : 55|4@0+ (1,0) [0|15] "" XXX
SG_ CHECKSUM : 63|8@0+ (1,0) [0|255] "" XXX
@@ -76,6 +74,7 @@ BO_ 232 DAS_4: 8 XXX
SG_ ACC_DISTANCE_CONFIG_2 : 41|2@0+ (1,0) [0|3] "" XXX
SG_ SPEED_DIGITAL : 63|8@0+ (1,0) [0|255] "mph" XXX
SG_ ACC_STATE : 38|3@0+ (1,0) [0|7] "" XXX
SG_ FCW_BRAKE_ENABLED : 29|1@0+ (1,0) [0|1] "" XXX
BO_ 49 EPS_2: 8 XXX
SG_ LKAS_STATE : 23|4@0+ (1,0) [0|15] "" XXX
@@ -105,12 +104,23 @@ BO_ 177 CRUISE_BUTTONS: 3 XXX
SG_ COUNTER : 15|4@0+ (1,0) [0|15] "" XXX
SG_ CHECKSUM : 23|8@0+ (1,0) [0|255] "" XXX
BO_ 163 DAS_5: 8 XXX
SG_ FCW_STATE : 2|1@1+ (1,0) [0|0] "" XXX
SG_ FCW_DISTANCE : 3|2@1+ (1,0) [0|0] "" XXX
SG_ ACCFCW_MESSAGE : 12|4@1+ (1,0) [0|0] "" XXX
SG_ SET_SPEED_KPH : 24|8@1+ (1,0) [0|250] "km/h" XXX
SG_ WHEEL_TORQUE_REQUEST : 38|15@0+ (1,-7767) [-7767|24999] "Nm" XXX
SG_ WHEEL_TORQUE_REQUEST_ACTIVE : 39|1@1+ (1,0) [0|0] "" XXX
SG_ COUNTER : 55|4@0+ (1,0) [0|15] "" XXX
SG_ CHECKSUM : 63|8@0+ (1,0) [0|255] "" XXX
BO_ 250 DAS_6: 8 XXX
SG_ LKAS_ICON_COLOR : 1|2@0+ (1,0) [0|3] "" XXX
SG_ LKAS_LANE_LINES : 19|4@0+ (1,0) [0|1] "" XXX
SG_ LKAS_ALERTS : 27|4@0+ (1,0) [0|1] "" XXX
SG_ CAR_MODEL : 15|8@0+ (1,0) [0|255] "" XXX
SG_ AUTO_HIGH_BEAM_ON : 47|1@1+ (1,0) [0|0] "" XXX
SG_ LKAS_DISABLED : 56|1@1+ (1,0) [0|0] "" XXX
BO_ 720 BSM_1: 6 XXX
SG_ RIGHT_STATUS : 5|1@0+ (1,0) [0|1] "" XXX
+13 -3
View File
@@ -61,11 +61,9 @@ BO_ 500 DAS_3: 8 XXX
SG_ DISABLE_FUEL_SHUTOFF : 23|1@1+ (1,0) [0|0] "" XXX
SG_ GR_MAX_REQ : 32|4@1+ (1,0) [0|0] "" XXX
SG_ ACC_DECEL_REQ : 36|3@1+ (1,0) [0|0] "" XXX
SG_ STS : 46|2@1+ (1,0) [0|0] "" XXX
SG_ ACC_FAULTED : 47|1@0+ (1,0) [0|1] "" XXX
SG_ ACC_FAULTED : 46|2@1+ (1,0) [0|0] "" XXX
SG_ COLLISION_BRK_PREP : 48|1@1+ (1,0) [0|0] "" XXX
SG_ ACC_BRK_PREP : 49|1@1+ (1,0) [0|0] "" XXX
SG_ BRAKE_BOOL_1 : 36|1@0+ (1,0) [0|3] "" XXX
SG_ COUNTER : 55|4@0+ (1,0) [0|15] "" XXX
SG_ CHECKSUM : 63|8@0+ (1,0) [0|255] "" XXX
@@ -76,6 +74,7 @@ BO_ 501 DAS_4: 8 XXX
SG_ ACC_DISTANCE_CONFIG_2 : 41|2@0+ (1,0) [0|3] "" XXX
SG_ SPEED_DIGITAL : 63|8@0+ (1,0) [0|255] "mph" XXX
SG_ ACC_STATE : 38|3@0+ (1,0) [0|7] "" XXX
SG_ FCW_BRAKE_ENABLED : 29|1@0+ (1,0) [0|1] "" XXX
BO_ 544 EPS_2: 8 XXX
SG_ LKAS_STATE : 23|4@0+ (1,0) [0|15] "" XXX
@@ -105,12 +104,23 @@ BO_ 570 CRUISE_BUTTONS: 3 XXX
SG_ COUNTER : 15|4@0+ (1,0) [0|15] "" XXX
SG_ CHECKSUM : 23|8@0+ (1,0) [0|255] "" XXX
BO_ 625 DAS_5: 8 XXX
SG_ FCW_STATE : 2|1@1+ (1,0) [0|0] "" XXX
SG_ FCW_DISTANCE : 3|2@1+ (1,0) [0|0] "" XXX
SG_ ACCFCW_MESSAGE : 12|4@1+ (1,0) [0|0] "" XXX
SG_ SET_SPEED_KPH : 24|8@1+ (1,0) [0|250] "km/h" XXX
SG_ WHEEL_TORQUE_REQUEST : 38|15@0+ (1,-7767) [-7767|24999] "Nm" XXX
SG_ WHEEL_TORQUE_REQUEST_ACTIVE : 39|1@1+ (1,0) [0|0] "" XXX
SG_ COUNTER : 55|4@0+ (1,0) [0|15] "" XXX
SG_ CHECKSUM : 63|8@0+ (1,0) [0|255] "" XXX
BO_ 629 DAS_6: 8 XXX
SG_ LKAS_ICON_COLOR : 1|2@0+ (1,0) [0|3] "" XXX
SG_ LKAS_LANE_LINES : 19|4@0+ (1,0) [0|1] "" XXX
SG_ LKAS_ALERTS : 27|4@0+ (1,0) [0|1] "" XXX
SG_ CAR_MODEL : 15|8@0+ (1,0) [0|255] "" XXX
SG_ AUTO_HIGH_BEAM_ON : 47|1@1+ (1,0) [0|0] "" XXX
SG_ LKAS_DISABLED : 56|1@1+ (1,0) [0|0] "" XXX
BO_ 720 BSM_1: 6 XXX
SG_ RIGHT_STATUS : 5|1@0+ (1,0) [0|1] "" XXX
@@ -374,7 +374,6 @@ BO_ 1302 ODOMETER: 8 XXX
SG_ CHECKSUM : 59|4@0+ (1,0) [0|3] "" EON
CM_ SG_ 401 GEAR "10 = reverse, 11 = transition";
CM_ SG_ 450 EPB_STATE "3 \"engaged\" 2 \"disengaging\" 1 \"engaging\" 0 \"disengaged\"";
CM_ SG_ 806 REVERSE_LIGHT "Might be reverse gear selected and not the lights";
VAL_ 399 STEER_STATUS 7 "permanent_fault" 6 "tmp_fault" 5 "fault_1" 4 "no_torque_alert_2" 3 "low_speed_lockout" 2 "no_torque_alert_1" 0 "normal" ;
+4
View File
@@ -109,6 +109,10 @@ BO_ 1265 CLU11: 4 CLU
SG_ CF_Clu_AmpInfo : 25|1@1+ (1.0,0.0) [0.0|1.0] "" BCM
SG_ CF_Clu_AliveCnt1 : 28|4@1+ (1.0,0.0) [0.0|15.0] "" AHLS,EMS,EPB,LDWS_LKAS,MDPS,SCC
BO_ 1260 Sign_Detection: 8 XXX
SG_ SpeedLim_Nav_Cam : 40|8@1+ (1,0) [0|255] "km/h / mph" XXX
SG_ SpeedLim_Nav_Cam2 : 48|8@1+ (1,0) [0|255] "km/h / mph" XXX
BO_ 1492 TMU_GW_PE_01: 8 CLU
SG_ TMU_IVRActivity : 0|2@1+ (1.0,0.0) [0.0|3.0] "" DATC
SG_ TMU_PhoneActivity : 2|2@1+ (1.0,0.0) [0.0|3.0] "" DATC
+2 -2
View File
@@ -570,7 +570,7 @@ BO_ 401 STEERING_LTA: 8 XXX
SG_ CHECKSUM : 63|8@0+ (1,0) [0|255] "" XXX
SG_ SETME_X3 : 29|2@0+ (1,0) [0|3] "" XXX
SG_ PERCENTAGE : 39|8@0+ (1,0) [0|255] "" XXX
SG_ SETME_X64 : 47|8@0+ (1,0) [0|255] "" XXX
SG_ TORQUE_WIND_DOWN : 47|8@0+ (1,0) [0|255] "" XXX
SG_ ANGLE : 55|8@0- (0.5,0) [0|255] "" XXX
SG_ STEER_ANGLE_CMD : 15|16@0- (0.0573,0) [-540|540] "" XXX
SG_ STEER_REQUEST_2 : 25|1@0+ (1,0) [0|1] "" XXX
@@ -611,7 +611,7 @@ BO_ 1014 BSM: 8 XXX
SG_ APPROACHING_ENABLED : 15|1@0+ (1,0) [0|1] "" XXX
CM_ SG_ 401 PERCENTAGE "driver override percentage (0-100), very close to steeringPressed in OP";
CM_ SG_ 401 SETME_X64 "ramps to 0 smoothly then back on falling edge of STEER_REQUEST if BIT isn't 1";
CM_ SG_ 401 TORQUE_WIND_DOWN "used to wind down torque on user override";
CM_ SG_ 401 ANGLE "angle of car relative to lane center on LTA camera";
CM_ SG_ 401 STEER_ANGLE_CMD "desired angle, OEM steers up to 95 degrees, no angle limit but torque will bottom out";
CM_ SG_ 401 CLEAR_HOLD_STEERING_ALERT "set to 1 when user clears LKAS_HUD->LDA_ALERT ('Hold Steering') by applying torque to steering wheel";
+5 -5
View File
@@ -1,13 +1,14 @@
Programming
----
**Panda**
## Programming
```
./flash.py # flash application
./recover.py # flash bootstub
```
## Debugging
To print out the serial console from the STM32, run `tests/debug_console.py`
Troubleshooting
----
@@ -16,5 +17,4 @@ If panda is blinking fast with green LED, use `flash.py`.
Otherwise if LED is off and panda can't be seen with `lsusb` command, use [panda paw](https://comma.ai/shop/products/panda-paw) to go into DFU mode.
If your device has an internal panda and none of the above works, try running `../tests/reflash_internal_panda.py`.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1 -1
View File
@@ -1 +1 @@
const uint8_t gitversion[] = "DEV-bcce255c-DEBUG";
const uint8_t gitversion[] = "DEV-4ba36d72-DEBUG";
Binary file not shown.

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