Compare commits

...

122 Commits

Author SHA1 Message Date
Vehicle Researcher
28c0797d30 openpilot v0.4.2 release 2018-02-06 12:43:45 -08:00
Vehicle Researcher
a701aa7292 Merge opendbc subtree 2018-02-06 12:39:39 -08:00
Vehicle Researcher
433f934783 Merge panda subtree 2018-02-06 12:39:38 -08:00
Vehicle Researcher
db67cffb4d Squashed 'panda/' changes from b42db6d..98f29a4
98f29a4 v1.0.7 has working grey panda

git-subtree-dir: panda
git-subtree-split: 98f29a4a97af58aa4707bdaba948ac366ab2e6a0
2018-02-06 12:39:38 -08:00
vanillagorillaa
0dc6778548 Acura RDX 2018 AcuraWatch Plus Port (#162)
* Adding Acura RDX alpha support
2018-02-05 18:38:40 -08:00
ErichMoraga
c86b52698b Update fingerprints.py
Taiwanese Prius Prime fingerprint was identical to the regular prime (107 msgs.), but should really have 110.  I have the correct one in there now.
2018-02-05 14:16:58 -08:00
George Hotz
e5e5aa7ded openpilot v0.4.1 hotfix 2018-02-02 19:30:44 -08:00
George Hotz
4474b9b371 openpilot v0.4.1 tweaks 2018-01-30 21:34:01 -08:00
Vehicle Researcher
26e966852c openpilot v0.4.1 release 2018-01-30 12:58:14 -08:00
Vehicle Researcher
75ac92b90f Merge opendbc subtree 2018-01-30 12:54:13 -08:00
Vehicle Researcher
96f8e5158e Squashed 'panda/' changes from 2573d86..b42db6d
b42db6d Merge pull request #82 from commaai/uart_dma
fd68f86 smallr
be99ffc ok that doesn't hurt i think
a9f6bf0 this
8b7e849 working now
7fa4808 froze up, maybe thats the fix
1465aa4 ok, it's fixed
915cd84 ugh, ok, need that
fd05376 comment out debug
37c5263 big fifo
497f069 dma is all critical, no interrupts
7c34afe minor change
743d244 high baud rate works
5d2a4ba v1.0.6
fbf1390 Toyota Safety: fix in input param
6c01d09 Toyota: less torque error allowance to meet Corolla acceptable behavior
07c01b2 Toyota safety: using input param
4410a59 add safety param support
fc81fc1 uart dma in progress
65fb2b2 grey panda query, 1.0.5
f415c9a grey panda detection
b68957e add pandadebug support
b5e4962 leave msgs around in isotp
0acce2d add recvaddr support
3fc38f4 set bootmode with power
d4c052a make that work
21f8195 fix panda serial write
af74aa9 from python import

git-subtree-dir: panda
git-subtree-split: b42db6dc082fb13ef5ac63ed197a63e179651ef6
2018-01-30 12:54:12 -08:00
Vehicle Researcher
b68f3f7781 Merge panda subtree 2018-01-30 12:54:12 -08:00
George Hotz
36bef17224 Merge pull request #155 from slesinski/odyssey-port
Honda Odyssey 2018 EX-L with Honda Sensing
2018-01-18 21:49:14 -08:00
Ted Slesinski
715771bcff Unnecessary characters in comma's dongle id 2018-01-19 00:47:47 -05:00
Ted Slesinski
8e264baaa2 SteerRatio should be 14.35 2018-01-19 00:37:32 -05:00
Ted Slesinski
8ff147de6d Added the extra carstate reads 2018-01-19 00:34:02 -05:00
Ted Slesinski
71057c586f Tuning specific to odyssey 2018-01-19 00:34:02 -05:00
Ted Slesinski
fac22f4038 Gear shifter values like acura 2018-01-19 00:32:51 -05:00
Ted Slesinski
40094779d7 Car_gas 130 missing canbus, using 17c 2018-01-19 00:32:51 -05:00
Ted Slesinski
2552aa45c3 BRAKE_HOLD signal not ready yet 2018-01-19 00:32:51 -05:00
Ted Slesinski
c2972a80f9 Park Brake not yet in DBC 2018-01-19 00:32:51 -05:00
Ted Slesinski
791a440709 Wrong value for MAIN_ON 2018-01-19 00:32:51 -05:00
Ted Slesinski
13145dd9a7 Packet size off on a fingerprint id 2018-01-19 00:32:51 -05:00
Ted Slesinski
e9c477dcf2 Add hondacan changes 2018-01-19 00:30:33 -05:00
Ted Slesinski
8eebd19884 Add carcontroller changes 2018-01-19 00:30:33 -05:00
Ted Slesinski
a54b35a4d6 Add odyssey car params to interface 2018-01-19 00:30:33 -05:00
Ted Slesinski
8a6f7a5e78 Add carstate changes 2018-01-19 00:30:33 -05:00
Ted Slesinski
6752959d4a Add odyssey fingerprint 2018-01-19 00:30:33 -05:00
Vehicle Researcher
da52d065a4 openpilot v0.4.0.2 release 2018-01-18 15:46:12 -08:00
Vehicle Researcher
b731b7cf12 Merge opendbc subtree 2018-01-18 15:42:13 -08:00
Vehicle Researcher
5f014635e1 Squashed 'panda/' changes from c371fe6..2573d86
2573d86 docs say max is 4, respect the docs
864cd8f failing on some devices
54bcc67 Merge pull request #75 from gregjhogan/j2534-vs-2017-upgrade
1664270 Merge pull request #74 from gregjhogan/j2534-disconnect-fix
a7e3a8f bump panda version for serial bug
aa0cfad fix UART hang
09ab8f6 add sendaddr support to isotp
40a1883 fix up baud rate
65997ff add PandaSerial and location panda (aka pigeon) test
57d633c upgraded to VS 2017
35cc32a fixed pointer exception on disconnect

git-subtree-dir: panda
git-subtree-split: 2573d861e605a2dcf456a6421b31e83fdd9ca606
2018-01-18 15:42:12 -08:00
Vehicle Researcher
ef3d8314d3 Merge panda subtree 2018-01-18 15:42:12 -08:00
Vehicle Researcher
7ef3fd567f openpilot v0.4.0.1 tweaks 2018-01-16 23:26:39 -08:00
heatnation
b773e27ad1 Update fingerprints.py 2018-01-15 18:22:15 -08:00
Vehicle Researcher
a77c0a1098 openpilot v0.4.0.1 release 2017-12-23 17:15:27 -08:00
Vehicle Researcher
c7b5fb9116 Merge commit '57b9ddf20ef28d7a9b4fd57c08630281ef103422' as 'pyextra' 2017-12-23 17:10:45 -08:00
Vehicle Researcher
57b9ddf20e Squashed 'pyextra/' content from commit 4eda4dd
git-subtree-dir: pyextra
git-subtree-split: 4eda4dd765c2bc719da9064774de6b2c14c322d1
2017-12-23 17:10:45 -08:00
Vehicle Researcher
b8085e2c42 Merge commit 'ba97d0e83837b4c893edc609001dde7c41b8e24b' as 'opendbc' 2017-12-23 17:10:44 -08:00
Vehicle Researcher
c251b312d8 Squashed 'panda/' content from commit c371fe6
git-subtree-dir: panda
git-subtree-split: c371fe688dbad4c53635905d3471a01c185e811d
2017-12-23 17:10:42 -08:00
Vehicle Researcher
14fb17e22f Merge commit 'c251b312d87d26b5ed347b267f6f1570793f9b91' as 'panda' 2017-12-23 17:10:42 -08:00
Vehicle Researcher
a34c87ab46 remove submodules 2017-12-23 17:06:56 -08:00
Vehicle Researcher
1ad9cc8c67 openpilot v0.3.9 tweaks 2017-12-06 12:48:00 -08:00
Vehicle Researcher
5627d0d7fd openpilot v0.3.9 release 2017-11-22 04:30:24 -08:00
Vehicle Researcher
2cfdbefde8 update releases 2017-11-04 05:31:15 -07:00
Vehicle Researcher
7dabcdace8 openpilot v0.3.8.2 tweaks 2017-11-03 18:21:38 -07:00
Vehicle Researcher
187a70f760 openpilot v0.3.8.2 release 2017-10-31 02:27:39 -07:00
Vehicle Researcher
48303589e9 openpilot v0.3.7 tweaks 2017-10-03 23:46:23 -07:00
Vehicle Researcher
8385b27cad openpilot v0.3.7 tweaks 2017-10-03 00:35:46 -07:00
George Hotz
abd75aedd7 Bump panda version to fix old board updating 2017-09-30 23:30:38 -07:00
Vehicle Researcher
daf54ad54d openpilot v0.3.7 release 2017-09-30 19:05:03 -07:00
espes
94fe677f91 Fix rear view mirror setting 2017-08-28 22:24:11 -07:00
Vehicle Researcher
3de85098e5 openpilot v0.3.6.1 tweaks 2017-08-16 05:21:06 -07:00
Vehicle Researcher
5524dc8773 openpilot v0.3.6.1 release 2017-08-15 03:15:00 -07:00
Vehicle Researcher
19dd5f3e32 openpilot v0.3.6 tweaks 2017-08-10 20:38:56 -07:00
Vehicle Researcher
99cb610b12 openpilot v0.3.6 release 2017-08-09 17:41:38 -07:00
Vehicle Researcher
9d3963559a openpilot v0.3.5 release 2017-07-30 17:59:37 -07:00
Vehicle Researcher
1b8c44b506 openpilot v0.3.4 tweaks 2017-07-28 20:51:27 -07:00
Vehicle Researcher
6f46f988d9 openpilot v0.3.4 release 2017-07-28 03:23:57 -07:00
George Hotz
68485aa4e4 Merge pull request #116 from commaai/revert-114-new_panda_code
Revert "Pulled in new panda firmware and updated boardd to support the changes."
2017-07-17 23:17:13 -07:00
George Hotz
1581fdc198 Revert "Pulled in new panda firmware and updated boardd to support the changes." 2017-07-17 23:16:57 -07:00
George Hotz
317ae0fb37 Merge pull request #114 from diamondman/new_panda_code
Pulled in new panda firmware and updated boardd to support the changes.
2017-07-11 22:24:38 -07:00
Jessy Diamond Exum
5bf4196aed Removed unnecessary TODO 2017-07-11 22:01:04 -07:00
Jessy Diamond Exum
38aa03e0f7 Moved boardd loopback config to envvar. 2017-07-11 21:59:03 -07:00
Jessy Diamond Exum
9a9dc3ab23 Pulled in new panda firmware and updated boardd to support the changes. 2017-07-11 21:45:16 -07:00
George Hotz
e4aa959e2c Merge pull request #113 from pjlao307/update-alert-text
Update alert text
2017-07-07 10:25:59 -07:00
Joey Lao
2aa9a56f40 Update steering controls saturated message 2017-07-06 22:36:55 -07:00
pjlao307
721ed4ec0e Merge pull request #2 from commaai/release
Release
2017-07-03 11:15:42 -07:00
George Hotz
70be4ceab1 Merge pull request #109 from commaai/devel
openpilot 0.3.3
2017-06-30 18:23:10 -07:00
Vehicle Researcher
5cf91d0496 openpilot v0.3.3 release 2017-06-28 13:57:09 -07:00
George Hotz
6fee0bdb2d Merge pull request #102 from energee/devel-crv
Bounty: 2016 Honda CR-V Touring
2017-06-22 11:52:38 -07:00
Ted Slesinski
e40c161125 Addresses brake error review comment 2017-06-20 02:51:58 -04:00
Ted Slesinski
97eb55cc55 Fixes global saturation change 2017-06-20 02:47:47 -04:00
Ted Slesinski
65134be0d1 Adds correct value of 8 to gearshifter check array 2017-06-20 02:46:59 -04:00
Ted Slesinski
dbf71a23aa Init crv variable 2017-06-20 02:26:50 -04:00
George Hotz
7fec3db1d6 Merge pull request #103 from pjlao307/pjlao-update-ui
Update UI to make text more readable in all conditions as requested by community
2017-06-19 20:37:37 -07:00
Joey Lao
26b573c1d0 Make lead car text a little brighter 2017-06-12 16:39:10 -07:00
Vehicle Researcher
5ec1e7307e Revert last commit since KPH can get 3 digits long 2017-06-12 09:30:47 -07:00
Vehicle Researcher
8bc36b7f21 Adjust position of left speed to align with label (based on 2 digit speeds) 2017-06-12 09:03:49 -07:00
Vehicle Researcher
3b909eb693 More code cleanup 2017-06-12 08:41:11 -07:00
Vehicle Researcher
57e39c4472 Use color param in ui_draw_rounded_rect instead of hard coding 2017-06-12 08:27:57 -07:00
Vehicle Researcher
ff7672339c Add background to radar text. Code cleanup. 2017-06-12 08:19:47 -07:00
John Jones
6e824a2c22 missed one update in latcontrol 2017-06-11 21:33:44 -04:00
Vehicle Researcher
32fa49e093 Clean up code 2017-06-11 15:18:39 -07:00
Vehicle Researcher
2250eac58f Remove commented line 2017-06-11 15:16:46 -07:00
Vehicle Researcher
97be6b3a0e Update UI to make speed text more readable in all conditions as requested by community 2017-06-11 15:12:50 -07:00
John Jones
942655c947 adding steering change from video and removing integer div and adding ki/kp changes 2017-06-11 13:20:19 -04:00
Ted Slesinski
615db3f7fd Reverting steering to original value 2017-06-08 13:15:30 -04:00
Ted Slesinski
0bb75c5389 Syntax typo 2017-06-08 02:33:31 -04:00
Ted Slesinski
7b5ee81d2d Adds support for 2016 Honda CR-V Touring 2017-06-08 01:37:39 -04:00
Vehicle Researcher
7fe46f1e1d openpilot v0.3.2 release 2017-05-22 22:26:12 -07:00
George Hotz
50c0d1c9da Merge pull request #82 from energee/devel
DBC file for 2017 Honda CR-V
2017-05-22 09:00:44 -07:00
Ted Slesinski
6dbf544d06 Adds 2017 CR-V dbc file 2017-05-21 19:46:34 -04:00
Vehicle Researcher
41e3a0f699 openpilot v0.3.1 release 2017-05-17 00:40:33 -07:00
Vehicle Researcher
c5d8aec28b openpilot v0.3.0 release 2017-05-12 16:46:20 -07:00
Vehicle Researcher
4653a9aef0 openpilot v0.3.0-devel release 2017-05-11 12:41:17 -07:00
George Hotz
ab3492bb90 Merge pull request #93 from heidecjj/master
Bug fixes for testing suite
2017-05-02 23:34:32 -07:00
George Hotz
ed7cbb3866 Merge pull request #90 from heidecjj/patch-1
Update maneuver.py
2017-05-02 23:30:36 -07:00
Josh Heidecker
a30626cfe3 Fixed relative distance errors in testing 2017-05-02 22:01:03 -04:00
heidecjj
d2c087b3e2 Update maneuver.py
self.speed_lead_breakpoints was reading from "speed_lead_values" instead of "speed_lead_breakpoints"
2017-04-20 17:09:15 -04:00
George Hotz
0a747f991d Merge pull request #65 from jeankalud/master
Fixed little endian (and scaling/offset)
2017-03-01 16:09:46 -08:00
jeankalud
f5a1e86d85 Add files via upload
Removed unused debug strings
2017-03-01 18:13:37 -05:00
Vehicle Researcher
693bcb0f83 openpilot v0.2.9 release 2017-03-01 10:54:12 -08:00
jeankalud
0d0daed86e Add files via upload
Fixed little endian handling
Fixed offset / scaling handling
2017-03-01 11:02:46 -05:00
Vehicle Researcher
95a349abcc openpilot v0.2.8 release 2017-02-28 00:03:11 -08:00
Vehicle Researcher
c6ba5dc539 openpilot v0.2.7 release 2017-02-08 15:01:17 -08:00
Vehicle Researcher
6c3afeec0f openpilot v0.2.6 release 2017-01-31 01:33:55 -08:00
Vehicle Researcher
29c58b4588 openpilot v0.2.5 release 2017-01-30 14:10:01 -08:00
Vehicle Researcher
ecc565aa3f openpilot v0.2.4 release 2017-01-29 16:10:13 -08:00
George Hotz
db61810f98 Merge pull request #49 from mullakhmetov/master
Added context manager to file reading
2017-01-27 01:17:23 -08:00
Artur Mullakhmetov
48f203ad5b Added context manager to file reading 2017-01-27 11:33:27 +03:00
George Hotz
6ab4ac2dfb Merge pull request #47 from mullakhmetov/crossplatform-gettime
Refactor cross-platform libc usage
2017-01-25 09:19:22 -08:00
Artur Mullakhmetov
9cb3c7b6e6 Refactor cross-platform libc usage 2017-01-25 16:16:00 +03:00
Vehicle Researcher
adaa4ed350 openpilot v0.2.3 release 2017-01-11 14:30:55 -08:00
Vehicle Researcher
a64b9aa9b8 openpilot v0.2.2 release 2017-01-10 11:10:04 -08:00
George Hotz
0138eca61d Merge pull request #40 from TheMutley/master
DBC modified to match the Vector format
2017-01-09 20:47:52 -08:00
Mutley
139a40de29 DBC modified to match the Vector format 2017-01-05 16:55:54 -05:00
Vehicle Researcher
17d9becd3c openpilot v0.2.1 release 2016-12-14 21:29:12 -08:00
Vehicle Researcher
449b482cc3 openpilot v0.2 release 2016-12-12 20:18:19 -08:00
espes
a7e099c946 Update README.md 2016-11-30 14:31:28 -08:00
espes
610462be5a Merge pull request #2 from autti/ford-fusion
Ford Fusion 2017 dbc can file. refs #1.
2016-11-30 11:57:31 -08:00
Ariel Nuñez
207d32668f Added ford fusion dbc can file. refs #1.
Obtained from:

https://bitbucket.org/DataspeedInc/dbw_mkz_ros/downloads
2016-11-30 14:52:47 -05:00
Vehicle Researcher
e94a30bec0 openpilot release 2016-11-29 18:34:21 -08:00
612 changed files with 133113 additions and 38 deletions

28
.gitignore vendored
View File

@@ -1,2 +1,30 @@
.DS_Store
.tags
.ipynb_checkpoints
.idea
model2.png
*.DSYM
*.d
*.pyc
*.pyo
.*.swp
.*.swo
.*.un~
*.o
*.so
*.a
*.clb
*.class
*.pyxbldc
*.vcd
config.json
clcache
board/obj/
selfdrive/boardd/boardd
selfdrive/logcatd/logcatd
selfdrive/proclogd/proclogd
selfdrive/ui/ui
/src/

12
.travis.yml Normal file
View File

@@ -0,0 +1,12 @@
sudo: required
services:
- docker
install:
- docker build -t tmppilot -f Dockerfile.openpilot .
script:
- docker run --rm
-v "$(pwd)"/selfdrive/test/tests/plant/out:/tmp/openpilot/selfdrive/test/tests/plant/out
tmppilot /bin/sh -c 'cd /tmp/openpilot/selfdrive/test/tests/plant && OPTEST=1 ./test_longitudinal.py'

19
Dockerfile.openpilot Normal file
View File

@@ -0,0 +1,19 @@
FROM ubuntu:16.04
ENV PYTHONUNBUFFERED 1
RUN apt-get update && apt-get install -y build-essential clang vim screen wget bzip2 git libglib2.0-0 python-pip capnproto libcapnp-dev libzmq5-dev libffi-dev libusb-1.0-0
RUN pip install numpy==1.11.2 scipy==0.18.1 matplotlib
COPY requirements_openpilot.txt /tmp/
RUN pip install -r /tmp/requirements_openpilot.txt
ENV PYTHONPATH /tmp/openpilot:$PYTHONPATH
COPY ./common /tmp/openpilot/common
COPY ./cereal /tmp/openpilot/cereal
COPY ./opendbc /tmp/openpilot/opendbc
COPY ./selfdrive /tmp/openpilot/selfdrive
COPY ./phonelibs /tmp/openpilot/phonelibs
COPY ./pyextra /tmp/openpilot/pyextra
RUN mkdir -p /tmp/openpilot/selfdrive/test/out

7
LICENSE.openpilot Normal file
View File

@@ -0,0 +1,7 @@
Copyright (c) 2016, Comma.ai, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

9
Makefile Normal file
View File

@@ -0,0 +1,9 @@
code_dir := $(shell pwd)
# TODO: Add a global build system
.PHONY: all
all:
cd selfdrive && PYTHONPATH=$(code_dir) PREPAREONLY=1 ./manager.py

176
README.md
View File

@@ -1,53 +1,153 @@
opendbc
Welcome to openpilot
======
The project to democratize access to the decoder ring of your car.
[openpilot](http://github.com/commaai/openpilot) is an open source driving agent.
Currently it performs the functions of Adaptive Cruise Control (ACC) and Lane Keeping Assist System (LKAS) for Hondas, Acuras and Toyotas. It's about on par with Tesla Autopilot at launch, and better than [all other manufacturers](http://www.thedrive.com/tech/5707/the-war-for-autonomous-driving-part-iii-us-vs-germany-vs-japan).
The openpilot codebase has been written to be concise and enable rapid prototyping. We look forward to your contributions - improving real vehicle automation has never been easier.
### DBC file basics
Here are [some](https://www.youtube.com/watch?v=9OwTJFuDI7g) [videos](https://www.youtube.com/watch?v=64Wvt5pYQmE) [of](https://www.youtube.com/watch?v=6IW7Nejsr3A) [it](https://www.youtube.com/watch?v=-VN1YcC83nA) [running](https://www.youtube.com/watch?v=EQJZvVeihZk). And a really cool [tutorial](https://www.youtube.com/watch?v=PwOnsT2UW5o).
A DBC file encodes, in a humanly readable way, the information needed to understand a vehicle's CAN bus traffic. A vehicle might have multiple CAN buses and every CAN bus is represented by its own dbc file.
Wondering what's the DBC file format? [Here](http://www.socialledge.com/sjsu/index.php?title=DBC_Format) a good overview.
Hardware
------
### How to start reverse engineering cars
Right now openpilot supports the [NEO research platform](http://github.com/commaai/neo) and the [EON Dashcam DevKit](https://shop.comma.ai/products/eon-dashcam-devkit). We'd like to support other platforms as well.
[opendbc](https://github.com/commaai/opendbc) is integrated with [cabana](https://community.comma.ai/cabana/).
Install openpilot on a neo device by entering ``https://openpilot.comma.ai`` during NEOS setup.
Use [panda](https://github.com/commaai/panda) to connect your car to a computer.
Supported Cars
------
### DBC file preprocessor
- Acura ILX 2016 with AcuraWatch Plus
- Due to use of the cruise control for gas, it can only be enabled above 25 mph
DBC files for different models of the same brand have a lot of overlap. Therefore, we wrote a preprocessor to create DBC files from a brand DBC file and a model specific DBC file. The source DBC files can be found in the generator folder. After changing one of the files run the generator.py script to regenerate the output files. These output files will be placed in the root of the opendbc repository and are suffixed by _generated.
- Honda Civic 2016-2017 with Honda Sensing
- Due to limitations in steering firmware, steering is disabled below 12 mph
- Note that the hatchback model is not supported
### Good practices for contributing to opendbc
- Honda CR-V Touring 2015-2016
- Can only be enabled above 25 mph
- Comments: the best way to store comments is to add them directly to the DBC files. For example:
```
CM_ SG_ 490 LONG_ACCEL "wheel speed derivative, noisy and zero snapping";
```
is a comment that refers to signal `LONG_ACCEL` in message `490`. Using comments is highly recommended, especially for doubts and uncertainties. [cabana](https://community.comma.ai/cabana/) can easily display/add/edit comments to signals and messages.
- Honda Odyssey 2018 with Honda Sensing (alpha!)
- Can only be enabled above 25 mph
- Units: when applicable, it's recommended to convert signals into physical units, by using a proper signal factor. Using a SI unit is preferred, unless a non-SI unit rounds the signal factor much better.
For example:
```
SG_ VEHICLE_SPEED : 7|15@0+ (0.00278,0) [0|70] "m/s" PCM
```
is better than:
```
SG_ VEHICLE_SPEED : 7|15@0+ (0.00620,0) [0|115] "mph" PCM
```
However, the cleanest option is really:
```
SG_ VEHICLE_SPEED : 7|15@0+ (0.01,0) [0|250] "kph" PCM
```
- Acura RDX 2018 with AcuraWatch Plus (alpha!)
- Can only be enabled above 25 mph
- Signal's size: always use the smallest amount of bits possible. For example, let's say I'm reverse engineering the gas pedal position and I've determined that it's in a 3 bytes message. For 0% pedal position I read a message value of `0x00 0x00 0x00`, while for 100% of pedal position I read `0x64 0x00 0x00`: clearly, the gas pedal position is within the first byte of the message and I might be tempted to define the signal `GAS_POS` as:
```
SG_ GAS_POS : 7|8@0+ (1,0) [0|100] "%" PCM
```
However, I can't be sure that the very first bit of the message is referred to the pedal position: I haven't seen it changing! Therefore, a safer way of defining the signal is:
```
SG_ GAS_POS : 6|7@0+ (1,0) [0|100] "%" PCM
```
which leaves the first bit unallocated. This prevents from very erroneous reading of the gas pedal position, in case the first bit is indeed used for something else.
- Toyota RAV-4 2016+ non-hybrid with TSS-P
- By default it uses stock Toyota ACC for longitudinal control
- openpilot longitudinal control available after unplugging the [Driving Support ECU](https://community.comma.ai/wiki/index.php/Toyota#Rav4_.28for_openpilot.29) and can be enabled above 20 mph
- Toyota Prius 2017 (alpha!)
- By default it uses stock Toyota ACC for longitudinal control
- openpilot longitudinal control available after unplugging the [Driving Support ECU](https://community.comma.ai/wiki/index.php/Toyota#Prius_.28for_openpilot.29)
- Lateral control needs improvements
- Toyota RAV-4 2017 hybrid (alpha!)
- By default it uses stock Toyota ACC for longitudinal control
- openpilot longitudinal control available after unplugging the [Driving Support ECU](https://community.comma.ai/wiki/index.php/Toyota#Rav4_.28for_openpilot.29) and can do stop and go
- Toyota Corolla 2017 (alpha!)
- By default it uses stock Toyota ACC for longitudinal control
- openpilot longitudinal control available after unplugging the [Driving Support ECU](https://community.comma.ai/wiki/index.php/Toyota#Corolla_.28for_openpilot.29) and can be enabled above 20 mph
- Lexus RX 2017 hybrid (alpha!)
- By default it uses stock Lexus ACC for longitudinal control
- openpilot longitudinal control available after unplugging the [Driving Support ECU](https://community.comma.ai/wiki/index.php/Toyota#Lexus_RX_hybrid)
In Progress Cars
------
- All TSS-P Toyota with Steering Assist.
- 'Full Speed Range Dynamic Radar Cruise Control' is required to enable stop-and-go. Only the Prius, Camry and C-HR have this option.
- Even though the Tundra, Sequoia and the Land Cruiser have TSS-P, they don't have Steering Assist and are not supported.
- All LSS-P Lexus with Steering Assist or Lane Keep Assist.
- 'All-Speed Range Dynamic Radar Cruise Control' is required to enable stop-and-go. Only the GS, GSH, GS, F, RX, RXH, LX, NX, NXH, LC, LCH, LS, LSH have this option.
- Even though the LX have TSS-P, it does not have Steering Assist and is not supported.
Community WIP Cars
------
- [Chevy Volt 2016-2018 Premier with Driver Confidence II](https://github.com/commaai/openpilot/pull/104)
- [Classic Tesla Model S (pre-AP)](https://github.com/commaai/openpilot/pull/145)
- [Honda Pilot 2017 with Honda Sensing](https://github.com/commaai/openpilot/pull/161)
Directory structure
------
- cereal -- The messaging spec used for all logs on the phone
- common -- Library like functionality we've developed here
- opendbc -- Files showing how to interpret data from cars
- panda -- Code used to communicate on CAN and LIN
- phonelibs -- Libraries used on the phone
- selfdrive -- Code needed to drive the car
- assets -- Fonts for ui
- boardd -- Daemon to talk to the board
- car -- Code that talks to the car and implements CarInterface
- common -- Shared C/C++ code for the daemons
- controls -- Python controls (PID loops etc) for the car
- debug -- Tools to help you debug and do car ports
- logcatd -- Android logcat as a service
- loggerd -- Logger and uploader of car data
- proclogd -- Logs information from proc
- sensord -- IMU / GPS interface code
- test/plant -- Car simulator running code through virtual maneuvers
- ui -- The UI
- visiond -- embedded vision pipeline
To understand how the services interact, see `selfdrive/service_list.yaml`
Testing on PC
------
There is rudimentary infrastructure to run a basic simulation and generate a report of openpilot's behavior in different scenarios.
```bash
# Requires working docker
./run_docker_tests.sh
```
The results are written to `selfdrive/test/plant/out/index.html`
More extensive testing infrastructure and simulation environments are coming soon.
Adding Car Support
------
comma.ai offers [bounties](http://comma.ai/bounties.html) for adding additional car support.
CR-V Touring support came in through this program. Chevy Volt is close. Accord is close as well.
User Data / chffr Account / Crash Reporting
------
By default openpilot creates an account and includes a client for chffr, our dashcam app. We use your data to train better models and improve openpilot for everyone.
It's open source software, so you are free to disable it if you wish.
It logs the road facing camera, CAN, GPS, IMU, magnetometer, thermal sensors, crashes, and operating system logs.
It does not log the user facing camera or the microphone.
By using it, you agree to [our privacy policy](https://beta.comma.ai/privacy.html). 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.ai. By accepting this agreement, you grant an irrevocable, perpetual, worldwide right to comma.ai for the use of this data.
Contributing
------
We welcome both pull requests and issues on
[github](http://github.com/commaai/openpilot). See the TODO file for a list of
good places to start.
Want to get paid to work on openpilot? [comma.ai is hiring](http://comma.ai/positions.html)
Licensing
------
openpilot is released under the MIT license.
Any user of this software shall indemnify and hold harmless Comma.ai, Inc. and its directors, officers, employees, agents, stockholders, affiliates, subcontractors and customers from and against all allegations, claims, actions, suits, demands, damages, liabilities, obligations, losses, settlements, judgments, costs and expenses (including without limitation attorneys fees and costs) which arise out of, relate to or result from any use of this software by user.
**THIS IS ALPHA QUALITY SOFTWARE FOR RESEARCH PURPOSES ONLY. THIS IS NOT A PRODUCT.
YOU ARE RESPONSIBLE FOR COMPLYING WITH LOCAL LAWS AND REGULATIONS.
NO WARRANTY EXPRESSED OR IMPLIED.**

177
RELEASES.md Normal file
View File

@@ -0,0 +1,177 @@
Version 0.4.2 (2018-02-05)
==========================
* Add alpha support for 2017 Lexus RX Hybrid
* Add alpha support for 2018 ACURA RDX
* Updated fingerprint to include Toyota Rav4 SE and Prius Prime
* Bugfixes for Acura ILX and Honda Odyssey
Version 0.4.1 (2018-01-30)
==========================
* Add alpha support for 2017 Toyota Corolla
* Add alpha support for 2018 Honda Odyssey with Honda Sensing
* Add alpha support for Grey Panda
* Refactored car abstraction layer to make car ports easier
* Increased steering torque limit on Honda CR-V by 30%
Version 0.4.0.2 (2018-01-18)
==========================
* Add focus adjustment slider
* Minor bugfixes
Version 0.4.0.1 (2017-12-21)
==========================
* New UI to match chffrplus
* Improved lateral control tuning to fix oscillations on Civic
* Add alpha support for 2017 Toyota Rav4 Hybrid
* Reduced CPU usage
* Removed unnecessary utilization of fan at max speed
* Minor bug fixes
Version 0.3.9 (2017-11-21)
==========================
* Add alpha support for 2017 Toyota Prius
* Improved longitudinal control using model predictive control
* Enable Forward Collision Warning
* Acura ILX now maintains openpilot engaged at standstill when brakes are applied
Version 0.3.8.2 (2017-10-30)
==========================
* Add alpha support for 2017 Toyota RAV4
* Smoother lateral control
* Stay silent if stock system is connected through giraffe
* Minor bug fixes
Version 0.3.7 (2017-09-30)
==========================
* Improved lateral control using model predictive control
* Improved lane centering
* Improved GPS
* Reduced tendency of path deviation near right side exits
* Enable engagement while the accelerator pedal is pressed
* Enable engagement while the brake pedal is pressed, when stationary and with lead vehicle within 5m
* Disable engagement when park brake or brake hold are active
* Fixed sporadic longitudinal pulsing in Civic
* Cleanups to vehicle interface
Version 0.3.6.1 (2017-08-15)
============================
* Mitigate low speed steering oscillations on some vehicles
* Include board steering check for CR-V
Version 0.3.6 (2017-08-08)
==========================
* Fix alpha CR-V support
* Improved GPS
* Fix display of target speed not always matching HUD
* Increased acceleration after stop
* Mitigated some vehicles driving too close to the right line
Version 0.3.5 (2017-07-30)
==========================
* Fix bug where new devices would not begin calibration
* Minor robustness improvements
Version 0.3.4 (2017-07-28)
==========================
* Improved model trained on more data
* Much improved controls tuning
* Performance improvements
* Bugfixes and improvements to calibration
* Driving log can play back video
* Acura only: system now stays engaged below 25mph as long as brakes are applied
Version 0.3.3 (2017-06-28)
===========================
* Improved model trained on more data
* Alpha CR-V support thanks to energee and johnnwvs!
* Using the opendbc project for DBC files
* Minor performance improvements
* UI update thanks to pjlao307
* Power off button
* 6% more torque on the Civic
Version 0.3.2 (2017-05-22)
===========================
* Minor stability bugfixes
* Added metrics and rear view mirror disable to settings
* Update model with more crowdsourced data
Version 0.3.1 (2017-05-17)
===========================
* visiond stability bugfix
* Add logging for angle and flashing
Version 0.3.0 (2017-05-12)
===========================
* Add CarParams struct to improve the abstraction layer
* Refactor visiond IPC to support multiple clients
* Add raw GPS and beginning support for navigation
* Improve model in visiond using crowdsourced data
* Add improved system logging to diagnose instability
* Rewrite baseui in React Native
* Moved calibration to the cloud
Version 0.2.9 (2017-03-01)
===========================
* Retain compatibility with NEOS v1
Version 0.2.8 (2017-02-27)
===========================
* Fix bug where frames were being dropped in minute 71
Version 0.2.7 (2017-02-08)
===========================
* Better performance and pictures at night
* Fix ptr alignment issue in boardd
* Fix brake error light, fix crash if too cold
Version 0.2.6 (2017-01-31)
===========================
* Fix bug in visiond model execution
Version 0.2.5 (2017-01-30)
===========================
* Fix race condition in manager
Version 0.2.4 (2017-01-27)
===========================
* OnePlus 3T support
* Enable installation as NEOS app
* Various minor bugfixes
Version 0.2.3 (2017-01-11)
===========================
* Reduce space usage by 80%
* Add better logging
* Add Travis CI
Version 0.2.2 (2017-01-10)
===========================
* Board triggers started signal on CAN messages
* Improved autoexposure
* Handle out of space, improve upload status
Version 0.2.1 (2016-12-14)
===========================
* Performance improvements, removal of more numpy
* Fix boardd process priority
* Make counter timer reset on use of steering wheel
Version 0.2 (2016-12-12)
=========================
* Car/Radar abstraction layers have shipped, see cereal/car.capnp
* controlsd has been refactored
* Shipped plant model and testing maneuvers
* visiond exits more gracefully now
* Hardware encoder in visiond should always init
* ui now turns off the screen after 30 seconds
* Switch to openpilot release branch for future releases
* Added preliminary Docker container to run tests on PC
Version 0.1 (2016-11-29)
=========================
* Initial release of openpilot
* Adaptive cruise control is working
* Lane keep assist is working
* Support for Acura ILX 2016 with AcuraWatch Plus
* Support for Honda Civic 2016 Touring Edition

73
SAFETY.md Normal file
View File

@@ -0,0 +1,73 @@
openpilot Safety
======
openpilot is an Adaptive Cruise Control (ACC) and Lane Keeping Assist (LKA) system.
Like other ACC and LKA systems, openpilot requires the driver to be alert and to
pay attention at all times. We repeat, **driver alertness is necessary, but not
sufficient, for openpilot to be used safely**.
Even with an attentive driver, we must make further efforts for the system to be
safe. We have designed openpilot with two other safety considerations.
1. The driver must always be capable to immediately retake manual control of the vehicle,
by stepping on either pedal or by pressing the cancel button.
2. The vehicle must not alter its trajectory too quickly for the driver to safely
react. This means that while the system is engaged, the actuators are constrained
to operate within reasonable limits.
Following are details of the car specific safety implementations:
Honda/Acura
------
- While the system is engaged, gas, brake and steer limits are subject to the same limits used by
the stock system.
- Without an interceptor, the gas is controlled by the Powertrain Control Module (PCM).
The PCM limits acceleration to what is reasonable for a cruise control system. With an
interceptor, the gas is clipped to 60%.
- The brake is controlled by the 0x1FA CAN message. This message allows full
braking, although the board and the software clip it to 1/4th of the max.
This is around .3g of braking.
- Steering is controlled by the 0xE4 CAN message. The Electronic Power Steering (EPS)
controller in the car limits the torque to a very small amount, so regardless of the
message, the controller cannot jerk the wheel.
- Brake and gas pedal pressed signals are contained in the 0x17C CAN message. A rising edge of
either signal triggers a disengagement, which is enforced by the board and in software. The
green led on the board signifies if the board is allowing control messages.
- Honda CAN uses both a counter and a checksum to ensure integrity and prevent
replay of the same message.
Toyota/Lexus
------
- While the system is engaged, gas, brake and steer limits are subject to the same limits used by
the stock system.
- With the stock Driving Support Unit (DSU) enabled, the acceleration is controlled
by the stock system and is subject to the stock adaptive cruise control limits. Without the
stock DSU connected, the acceleration command is controlled by the 0x343 CAN message and its
value is limited by the board and the software to between .3g of deceleration and .15g of
acceleration. The acceleration command is ignored by the Engine Control Module (ECM) while the
cruise control system is disengaged.
- Steering torque is controlled through the 0x2E4 CAN message and it's limited by the board and in
software to a value of -1500 and 1500. In addition, the vehicle EPS unit will not respond to
commands outside these limits. A steering torque rate limit is enforced by the board and in
software so that the commanded steering torque must rise from 0 to max value no faster than
1.5s. Commanded steering torque is limited by the board and in software to be no more than 350
units above the actual EPS generated motor torque to ensure limited differences between
commanded and actual torques.
- Brake and gas pedal pressed signals are contained in the 0x224 and 0x1D2 CAN messages,
respectively. A rising edge of either signal triggers a disengagement, which is enforced by the
board and in software. Additionally, the cruise control system disengages on the rising edge of
the brake pedal pressed signal.
- The cruise control system state is contained in the 0x1D2 message. No control messages are
allowed if the cruise control system is not active. This is enforced by the software and the
board. The green led on the board signifies if the board is allowing control messages.

BIN
apk/ai.comma.plus.black.apk Normal file

Binary file not shown.

BIN
apk/ai.comma.plus.frame.apk Normal file

Binary file not shown.

Binary file not shown.

2
apk/external/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
src/*
out/*

BIN
apk/external/com.spotify.music.apkpatch vendored Normal file

Binary file not shown.

BIN
apk/external/com.waze.apkpatch vendored Normal file

Binary file not shown.

0
apk/external/out/.gitkeep vendored Normal file
View File

122
apk/external/patcher.py vendored Executable file
View File

@@ -0,0 +1,122 @@
#!/usr/bin/env python2.7
import os
import sys
import glob
import shutil
import urllib2
import hashlib
import subprocess
EXTERNAL_PATH = os.path.dirname(os.path.abspath(__file__))
if os.path.exists("/init.qcom.rc"):
# android
APKPATCH = os.path.join(EXTERNAL_PATH, 'tools/apkpatch_android')
SIGNAPK = os.path.join(EXTERNAL_PATH, 'tools/signapk_android')
else:
APKPATCH = os.path.join(EXTERNAL_PATH, 'tools/apkpatch')
SIGNAPK = os.path.join(EXTERNAL_PATH, 'tools/signapk')
APKS = {
'com.waze': {
'src': 'https://apkcache.s3.amazonaws.com/com.waze_1021278.apk',
'src_sha256': 'f00957e93e2389f9e30502ac54994b98ac769314b0963c263d4e8baa625ab0c2',
'patch': 'com.waze.apkpatch',
'out_sha256': '9ec8b0ea3c78c666342865b1bfb66e368a3f5c911df2ad12835206ec8b19f444'
},
'com.spotify.music': {
'src': 'https://apkcache.s3.amazonaws.com/com.spotify.music_24382006.apk',
'src_sha256': '0610fea68ee7ba5f8e4e0732ad429d729dd6cbb8bc21222c4c99db6cb09fbff4',
'patch': 'com.spotify.music.apkpatch',
'out_sha256': '5a3d6f478c7e40403a98ccc8906d7e0ae12b06543b41f5df52149dd09c647c11'
},
}
def sha256_path(path):
with open(path, 'rb') as f:
return hashlib.sha256(f.read()).hexdigest()
def remove(path):
try:
os.remove(path)
except OSError:
pass
def process(download, patch):
# clean up any junk apks
for out_apk in glob.glob(os.path.join(EXTERNAL_PATH, 'out/*.apk')):
app = os.path.basename(out_apk)[:-4]
if app not in APKS:
print "remove junk", out_apk
remove(out_apk)
complete = True
for k,v in APKS.iteritems():
apk_path = os.path.join(EXTERNAL_PATH, 'out', k+'.apk')
print "checking", apk_path
if os.path.exists(apk_path) and sha256_path(apk_path) == v['out_sha256']:
# nothing to do
continue
complete = False
remove(apk_path)
src_path = os.path.join(EXTERNAL_PATH, 'src', v['src_sha256'])
if not os.path.exists(src_path) or sha256_path(src_path) != v['src_sha256']:
if not download:
continue
print "downloading", v['src'], "to", src_path
# download it
resp = urllib2.urlopen(v['src'])
data = resp.read()
with open(src_path, 'wb') as src_f:
src_f.write(data)
if sha256_path(src_path) != v['src_sha256']:
print "download was corrupted..."
continue
if not patch:
continue
# ignoring lots of TOCTTOU here...
apk_temp = "/tmp/"+k+".patched"
remove(apk_temp)
apk_temp2 = "/tmp/"+k+".signed"
remove(apk_temp2)
try:
print "patching", v['patch']
subprocess.check_call([APKPATCH, 'apply', src_path, apk_temp, os.path.join(EXTERNAL_PATH, v['patch'])])
print "signing", apk_temp
subprocess.check_call([SIGNAPK,
os.path.join(EXTERNAL_PATH, 'tools/certificate.pem'), os.path.join(EXTERNAL_PATH, 'tools/key.pk8'),
apk_temp, apk_temp2])
out_sha256 = sha256_path(apk_temp2) if os.path.exists(apk_temp2) else None
if out_sha256 == v['out_sha256']:
print "done", apk_path
shutil.move(apk_temp2, apk_path)
else:
print "patch was corrupted", apk_temp2, out_sha256
finally:
remove(apk_temp)
remove(apk_temp2)
return complete
if __name__ == "__main__":
ret = True
if len(sys.argv) == 2 and sys.argv[1] == "download":
ret = process(True, False)
elif len(sys.argv) == 2 and sys.argv[1] == "patch":
ret = process(False, True)
else:
ret = process(True, True)
sys.exit(0 if ret else 1)

0
apk/external/src/.gitkeep vendored Normal file
View File

BIN
apk/external/tools/ApkPatch.android.jar vendored Normal file

Binary file not shown.

7
apk/external/tools/apkpatch_android vendored Executable file
View File

@@ -0,0 +1,7 @@
#!/system/bin/sh
DIR="$(cd "$(dirname "$0")" && pwd)"
export LD_LIBRARY_PATH=/system/lib64
export CLASSPATH="$DIR"/ApkPatch.android.jar
exec app_process "$DIR" ApkPatch "$@"

17
apk/external/tools/certificate.pem vendored Executable file
View File

@@ -0,0 +1,17 @@
-----BEGIN CERTIFICATE-----
MIICtTCCAh4CCQDm79UqF+Dc5zANBgkqhkiG9w0BAQUFADCBnjELMAkGA1UEBhMC
SUQxEzARBgNVBAgTCkphd2EgQmFyYXQxEDAOBgNVBAcTB0JhbmR1bmcxEjAQBgNV
BAoTCUxvbmRhdGlnYTETMBEGA1UECxMKQW5kcm9pZERldjEaMBgGA1UEAxMRTG9y
ZW5zaXVzIFcuIEwuIFQxIzAhBgkqhkiG9w0BCQEWFGxvcmVuekBsb25kYXRpZ2Eu
bmV0MB4XDTEwMDUwNTA5MjEzOFoXDTEzMDEyODA5MjEzOFowgZ4xCzAJBgNVBAYT
AklEMRMwEQYDVQQIEwpKYXdhIEJhcmF0MRAwDgYDVQQHEwdCYW5kdW5nMRIwEAYD
VQQKEwlMb25kYXRpZ2ExEzARBgNVBAsTCkFuZHJvaWREZXYxGjAYBgNVBAMTEUxv
cmVuc2l1cyBXLiBMLiBUMSMwIQYJKoZIhvcNAQkBFhRsb3JlbnpAbG9uZGF0aWdh
Lm5ldDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAy2oWtbdVXMHGiS6cA3qi
3VfZt5Vz9jTlux+TEcGx5h18ZKwclyo+z2B0L/p5bYdnrTdFEiD7IxvX+h3lu0JV
B9rdXZdyrzXNOw5YFrsn2k7hKvB8KEBaga1gZEwodlc6N14H3FbZdZkIA9V716Pu
e5CWBZ2VqU03lUJmKnpH8c8CAwEAATANBgkqhkiG9w0BAQUFAAOBgQBpNgXh8dw9
uMjZxzLUXovV5ptHd61jAcZlQlffqPsz6/2QNfIShVdGH9jkm0IudfKkbvvOKive
a77t9c4sDh2Sat2L/rx6BfTuS1+y9wFr1Ee8Rrr7wGHhRkx2qqGrXGVWqXn8aE3E
P6e7BTPF0ibS+tG8cdDPEisqGFxw36nTNQ==
-----END CERTIFICATE-----

BIN
apk/external/tools/key.pk8 vendored Executable file

Binary file not shown.

BIN
apk/external/tools/signapk.android.jar vendored Normal file

Binary file not shown.

7
apk/external/tools/signapk_android vendored Executable file
View File

@@ -0,0 +1,7 @@
#!/system/bin/sh
DIR="$(cd "$(dirname "$0")" && pwd)"
export LD_LIBRARY_PATH=/system/lib64
export CLASSPATH="$DIR"/signapk.android.jar
exec app_process "$DIR" com.android.signapk.SignApk "$@"

1
cereal/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
gen

52
cereal/Makefile Normal file
View File

@@ -0,0 +1,52 @@
PWD := $(shell pwd)
SRCS := log.capnp car.capnp
GENS := gen/cpp/car.capnp.c++ gen/cpp/log.capnp.c++
UNAME_M ?= $(shell uname -m)
# only generate C++ for docker tests
ifneq ($(OPTEST),1)
GENS += gen/c/car.capnp.c gen/c/log.capnp.c gen/c/c++.capnp.h gen/c/java.capnp.h
# Dont build java on the phone...
ifeq ($(UNAME_M),x86_64)
GENS += gen/java/Car.java gen/java/Log.java
endif
endif
ifeq ($(UNAME_M),aarch64)
CAPNPC=PATH=$(PWD)/../phonelibs/capnp-cpp/aarch64/bin/:$$PATH capnpc
else
CAPNPC=capnpc
endif
.PHONY: all
all: $(GENS)
.PHONY: clean
clean:
rm -rf gen
gen/c/%.capnp.c: %.capnp
@echo "[ CAPNPC C ] $@"
mkdir -p gen/c/
$(CAPNPC) '$<' -o c:gen/c/
gen/cpp/%.capnp.c++: %.capnp
@echo "[ CAPNPC C++ ] $@"
mkdir -p gen/cpp/
$(CAPNPC) '$<' -o c++:gen/cpp/
gen/java/Car.java gen/java/Log.java: $(SRCS)
@echo "[ CAPNPC java ] $@"
mkdir -p gen/java/
$(CAPNPC) $^ -o java:gen/java
# c-capnproto needs some empty headers
gen/c/c++.capnp.h gen/c/java.capnp.h:
mkdir -p gen/c/
touch '$@'

20
cereal/__init__.py Normal file
View File

@@ -0,0 +1,20 @@
import os
import capnp
CEREAL_PATH = os.path.dirname(os.path.abspath(__file__))
capnp.remove_import_hook()
if os.getenv("NEWCAPNP"):
import tempfile
import pyximport
importers = pyximport.install(build_dir=os.path.join(tempfile.gettempdir(), ".pyxbld"))
try:
import cereal.gen.cython.log_capnp_cython as log
import cereal.gen.cython.car_capnp_cython as car
finally:
pyximport.uninstall(*importers)
del importers
else:
log = capnp.load(os.path.join(CEREAL_PATH, "log.capnp"))
car = capnp.load(os.path.join(CEREAL_PATH, "car.capnp"))

26
cereal/c++.capnp Normal file
View File

@@ -0,0 +1,26 @@
# Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
# Licensed under the MIT License:
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
@0xbdf87d7bb8304e81;
$namespace("capnp::annotations");
annotation namespace(file): Text;
annotation name(field, enumerant, struct, enum, interface, method, param, group, union): Text;

321
cereal/car.capnp Normal file
View File

@@ -0,0 +1,321 @@
using Cxx = import "c++.capnp";
$Cxx.namespace("cereal");
using Java = import "java.capnp";
$Java.package("ai.comma.openpilot.cereal");
$Java.outerClassname("Car");
@0x8e2af1e708af8b8d;
# ******* events causing controls state machine transition *******
struct CarEvent @0x9b1657f34caf3ad3 {
name @0 :EventName;
enable @1 :Bool;
noEntry @2 :Bool;
warning @3 :Bool;
userDisable @4 :Bool;
softDisable @5 :Bool;
immediateDisable @6 :Bool;
preEnable @7 :Bool;
permanent @8 :Bool;
enum EventName @0xbaa8c5d505f727de {
# TODO: copy from error list
commIssue @0;
steerUnavailable @1;
brakeUnavailable @2;
gasUnavailable @3;
wrongGear @4;
doorOpen @5;
seatbeltNotLatched @6;
espDisabled @7;
wrongCarMode @8;
steerTempUnavailable @9;
reverseGear @10;
buttonCancel @11;
buttonEnable @12;
pedalPressed @13;
cruiseDisabled @14;
radarCommIssue @15;
dataNeeded @16;
speedTooLow @17;
outOfSpace @18;
overheat @19;
calibrationInProgress @20;
calibrationInvalid @21;
controlsMismatch @22;
pcmEnable @23;
pcmDisable @24;
noTarget @25;
radarFault @26;
modelCommIssue @27;
brakeHold @28;
parkBrake @29;
manualRestart @30;
lowSpeedLockout @31;
}
}
# ******* main car state @ 100hz *******
# all speeds in m/s
struct CarState {
errorsDEPRECATED @0 :List(CarEvent.EventName);
events @13 :List(CarEvent);
# car speed
vEgo @1 :Float32; # best estimate of speed
aEgo @16 :Float32; # best estimate of acceleration
vEgoRaw @17 :Float32; # unfiltered speed from CAN sensors
yawRate @22 :Float32; # best estimate of yaw rate
standstill @18 :Bool;
wheelSpeeds @2 :WheelSpeeds;
# gas pedal, 0.0-1.0
gas @3 :Float32; # this is user + computer
gasPressed @4 :Bool; # this is user pedal only
# brake pedal, 0.0-1.0
brake @5 :Float32; # this is user pedal only
brakePressed @6 :Bool; # this is user pedal only
brakeLights @19 :Bool;
# steering wheel
steeringAngle @7 :Float32; # deg
steeringRate @15 :Float32; # deg/s
steeringTorque @8 :Float32; # TODO: standardize units
steeringPressed @9 :Bool; # if the user is using the steering wheel
# cruise state
cruiseState @10 :CruiseState;
# gear
gearShifter @14 :GearShifter;
# button presses
buttonEvents @11 :List(ButtonEvent);
leftBlinker @20 :Bool;
rightBlinker @21 :Bool;
genericToggle @23 :Bool;
# lock info
doorOpen @24 :Bool;
seatbeltUnlatched @25 :Bool;
# which packets this state came from
canMonoTimes @12: List(UInt64);
struct WheelSpeeds {
# optional wheel speeds
fl @0 :Float32;
fr @1 :Float32;
rl @2 :Float32;
rr @3 :Float32;
}
struct CruiseState {
enabled @0 :Bool;
speed @1 :Float32;
available @2 :Bool;
speedOffset @3 :Float32;
standstill @4 :Bool;
}
enum GearShifter {
unknown @0;
park @1;
drive @2;
neutral @3;
reverse @4;
sport @5;
low @6;
brake @7;
}
# send on change
struct ButtonEvent {
pressed @0 :Bool;
type @1 :Type;
enum Type {
unknown @0;
leftBlinker @1;
rightBlinker @2;
accelCruise @3;
decelCruise @4;
cancel @5;
altButton1 @6;
altButton2 @7;
altButton3 @8;
}
}
}
# ******* radar state @ 20hz *******
struct RadarState {
errors @0 :List(Error);
points @1 :List(RadarPoint);
# which packets this state came from
canMonoTimes @2 :List(UInt64);
enum Error {
commIssue @0;
fault @1;
}
# similar to LiveTracks
# is one timestamp valid for all? I think so
struct RadarPoint {
trackId @0 :UInt64; # no trackId reuse
# these 3 are the minimum required
dRel @1 :Float32; # m from the front bumper of the car
yRel @2 :Float32; # m
vRel @3 :Float32; # m/s
# these are optional and valid if they are not NaN
aRel @4 :Float32; # m/s^2
yvRel @5 :Float32; # m/s
# some radars flag measurements VS estimates
measured @6 :Bool;
}
}
# ******* car controls @ 100hz *******
struct CarControl {
# must be true for any actuator commands to work
enabled @0 :Bool;
gasDEPRECATED @1 :Float32;
brakeDEPRECATED @2 :Float32;
steeringTorqueDEPRECATED @3 :Float32;
actuators @6 :Actuators;
cruiseControl @4 :CruiseControl;
hudControl @5 :HUDControl;
struct Actuators {
# range from 0.0 - 1.0
gas @0: Float32;
brake @1: Float32;
# range from -1.0 - 1.0
steer @2: Float32;
}
struct CruiseControl {
cancel @0: Bool;
override @1: Bool;
speedOverride @2: Float32;
accelOverride @3: Float32;
}
struct HUDControl {
speedVisible @0: Bool;
setSpeed @1: Float32;
lanesVisible @2: Bool;
leadVisible @3: Bool;
visualAlert @4: VisualAlert;
audibleAlert @5: AudibleAlert;
enum VisualAlert {
# these are the choices from the Honda
# map as good as you can for your car
none @0;
fcw @1;
steerRequired @2;
brakePressed @3;
wrongGear @4;
seatbeltUnbuckled @5;
speedTooHigh @6;
}
enum AudibleAlert {
# these are the choices from the Honda
# map as good as you can for your car
none @0;
beepSingle @1;
beepTriple @2;
beepRepeated @3;
chimeSingle @4;
chimeDouble @5;
chimeRepeated @6;
chimeContinuous @7;
}
}
}
# ****** car param ******
struct CarParams {
carName @0 :Text;
radarNameDEPRECATED @1 :Text;
carFingerprint @2 :Text;
enableSteer @3 :Bool;
enableGas @4 :Bool;
enableBrake @5 :Bool;
enableCruise @6 :Bool;
enableCamera @26 :Bool;
enableDsu @27 :Bool; # driving support unit
enableApgs @28 :Bool; # advanced parking guidance system
minEnableSpeed @17 :Float32;
safetyModel @18 :Int16;
safetyParam @41 :Int16;
steerMaxBP @19 :List(Float32);
steerMaxV @20 :List(Float32);
gasMaxBP @21 :List(Float32);
gasMaxV @22 :List(Float32);
brakeMaxBP @23 :List(Float32);
brakeMaxV @24 :List(Float32);
longPidDeadzoneBP @32 :List(Float32);
longPidDeadzoneV @33 :List(Float32);
enum SafetyModels {
# does NOT match board setting
noOutput @0;
honda @1;
toyota @2;
elm327 @3;
}
# things about the car in the manual
mass @7 :Float32; # [kg] running weight
wheelbase @8 :Float32; # [m] distance from rear to front axle
centerToFront @9 :Float32; # [m] GC distance to front axle
steerRatio @10 :Float32; # [] ratio between front wheels and steering wheel angles
steerRatioRear @11 :Float32; # [] rear steering ratio wrt front steering (usually 0)
# things we can derive
rotationalInertia @12 :Float32; # [kg*m2] body rotational inertia
tireStiffnessFront @13 :Float32; # [N/rad] front tire coeff of stiff
tireStiffnessRear @14 :Float32; # [N/rad] rear tire coeff of stiff
# Kp and Ki for the lateral control
steerKp @15 :Float32;
steerKi @16 :Float32;
steerKf @25 :Float32;
# Kp and Ki for the longitudinal control
longitudinalKpBP @36 :List(Float32);
longitudinalKpV @37 :List(Float32);
longitudinalKiBP @38 :List(Float32);
longitudinalKiV @39 :List(Float32);
steerLimitAlert @29 :Bool;
vEgoStopping @30 :Float32; # Speed at which the car goes into stopping state
directAccelControl @31 :Bool; # Does the car have direct accel control or just gas/brake
stoppingControl @34 :Bool; # Does the car allows full control even at lows speeds when stopping
startAccel @35 :Float32; # Required acceleraton to overcome creep braking
steerRateCost @40 :Float32; # Lateral MPC cost on steering rate
}

28
cereal/java.capnp Normal file
View File

@@ -0,0 +1,28 @@
# Copyright (c) 2013-2015 Sandstorm Development Group, Inc. and contributors
# Licensed under the MIT License:
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
@0xc5f1af96651f70ea;
annotation package @0x9ee4c8f803b3b596 (file) : Text;
# Name of the package, such as "org.example.foo", in which the generated code will reside.
annotation outerClassname @0x9b066bb4881f7cd3 (file) : Text;
# Name of the outer class that will wrap the generated code.

1433
cereal/log.capnp Normal file

File diff suppressed because it is too large Load Diff

0
common/__init__.py Normal file
View File

15
common/api/__init__.py Normal file
View File

@@ -0,0 +1,15 @@
import requests
from selfdrive.version import version
def api_get(endpoint, method='GET', timeout=None, access_token=None, **params):
backend = "https://api.commadotai.com/"
headers = {}
if access_token is not None:
headers['Authorization'] = "JWT "+access_token
headers['User-Agent'] = "openpilot-" + version
return requests.request(method, backend+endpoint, timeout=timeout, headers = headers, params=params)

4
common/basedir.py Normal file
View File

@@ -0,0 +1,4 @@
import os
BASEDIR = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), "../"))

220
common/dbc.py Executable file
View File

@@ -0,0 +1,220 @@
import re
import os
import struct
import bitstring
import sys
import numbers
from collections import namedtuple
def int_or_float(s):
# return number, trying to maintain int format
try:
return int(s)
except ValueError:
return float(s)
DBCSignal = namedtuple(
"DBCSignal", ["name", "start_bit", "size", "is_little_endian", "is_signed",
"factor", "offset", "tmin", "tmax", "units"])
class dbc(object):
def __init__(self, fn):
self.name, _ = os.path.splitext(os.path.basename(fn))
with open(fn) as f:
self.txt = f.read().split("\n")
self._warned_addresses = set()
# regexps from https://github.com/ebroecker/canmatrix/blob/master/canmatrix/importdbc.py
bo_regexp = re.compile("^BO\_ (\w+) (\w+) *: (\w+) (\w+)")
sg_regexp = re.compile("^SG\_ (\w+) : (\d+)\|(\d+)@(\d+)([\+|\-]) \(([0-9.+\-eE]+),([0-9.+\-eE]+)\) \[([0-9.+\-eE]+)\|([0-9.+\-eE]+)\] \"(.*)\" (.*)")
sgm_regexp = re.compile("^SG\_ (\w+) (\w+) *: (\d+)\|(\d+)@(\d+)([\+|\-]) \(([0-9.+\-eE]+),([0-9.+\-eE]+)\) \[([0-9.+\-eE]+)\|([0-9.+\-eE]+)\] \"(.*)\" (.*)")
# A dictionary which maps message ids to tuples ((name, size), signals).
# name is the ASCII name of the message.
# size is the size of the message in bytes.
# signals is a list signals contained in the message.
# signals is a list of DBCSignal in order of increasing start_bit.
self.msgs = {}
# lookup to bit reverse each byte
self.bits_index = [(i & ~0b111) + ((-i-1) & 0b111) for i in xrange(64)]
for l in self.txt:
l = l.strip()
if l.startswith("BO_ "):
# new group
dat = bo_regexp.match(l)
if dat is None:
print "bad BO", l
name = dat.group(2)
size = int(dat.group(3))
ids = int(dat.group(1), 0) # could be hex
if ids in self.msgs:
sys.exit("Duplicate address detected %d %s" % (ids, self.name))
self.msgs[ids] = ((name, size), [])
if l.startswith("SG_ "):
# new signal
dat = sg_regexp.match(l)
go = 0
if dat is None:
dat = sgm_regexp.match(l)
go = 1
if dat is None:
print "bad SG", l
sgname = dat.group(1)
start_bit = int(dat.group(go+2))
signal_size = int(dat.group(go+3))
is_little_endian = int(dat.group(go+4))==1
is_signed = dat.group(go+5)=='-'
factor = int_or_float(dat.group(go+6))
offset = int_or_float(dat.group(go+7))
tmin = int_or_float(dat.group(go+8))
tmax = int_or_float(dat.group(go+9))
units = dat.group(go+10)
self.msgs[ids][1].append(
DBCSignal(sgname, start_bit, signal_size, is_little_endian,
is_signed, factor, offset, tmin, tmax, units))
for msg in self.msgs.viewvalues():
msg[1].sort(key=lambda x: x.start_bit)
self.msg_name_to_address = {}
for address, m in self.msgs.items():
name = m[0][0]
self.msg_name_to_address[name] = address
def lookup_msg_id(self, msg_id):
if not isinstance(msg_id, numbers.Number):
msg_id = self.msg_name_to_address[msg_id]
return msg_id
def encode(self, msg_id, dd):
"""Encode a CAN message using the dbc.
Inputs:
msg_id: The message ID.
dd: A dictionary mapping signal name to signal data.
"""
msg_id = self.lookup_msg_id(msg_id)
# TODO: Stop using bitstring, which is super slow.
msg_def = self.msgs[msg_id]
size = msg_def[0][1]
bsf = bitstring.Bits(hex="00"*size)
for s in msg_def[1]:
ival = dd.get(s.name)
if ival is not None:
ival = (ival / s.factor) - s.offset
ival = int(round(ival))
# should pack this
if s.is_little_endian:
ss = s.start_bit
else:
ss = self.bits_index[s.start_bit]
if s.is_signed:
tbs = bitstring.Bits(int=ival, length=s.size)
else:
tbs = bitstring.Bits(uint=ival, length=s.size)
lpad = bitstring.Bits(bin="0b"+"0"*ss)
rpad = bitstring.Bits(bin="0b"+"0"*(8*size-(ss+s.size)))
tbs = lpad+tbs+rpad
bsf |= tbs
return bsf.tobytes()
def decode(self, x, arr=None, debug=False):
"""Decode a CAN message using the dbc.
Inputs:
x: A collection with elements (address, time, data), where address is
the CAN address, time is the bus time, and data is the CAN data as a
hex string.
arr: Optional list of signals which should be decoded and returned.
debug: True to print debugging statements.
Returns:
A tuple (name, data), where name is the name of the CAN message and data
is the decoded result. If arr is None, data is a dict of properties.
Otherwise data is a list of the same length as arr.
Returns (None, None) if the message could not be decoded.
"""
if arr is None:
out = {}
else:
out = [None]*len(arr)
msg = self.msgs.get(x[0])
if msg is None:
if x[0] not in self._warned_addresses:
#print("WARNING: Unknown message address {}".format(x[0]))
self._warned_addresses.add(x[0])
return None, None
name = msg[0][0]
if debug:
print name
blen = 8*len(x[2])
st = x[2].rjust(8, '\x00')
le, be = None, None
for s in msg[1]:
if arr is not None and s[0] not in arr:
continue
# big or little endian?
# see http://vi-firmware.openxcplatform.com/en/master/config/bit-numbering.html
if s[3] is False:
ss = self.bits_index[s[1]]
if be is None:
be = struct.unpack(">Q", st)[0]
x2_int = be
data_bit_pos = (blen - (ss + s[2]))
else:
if le is None:
le = struct.unpack("<Q", st)[0]
x2_int = le
ss = s[1]
data_bit_pos = ss
if data_bit_pos < 0:
continue
ival = (x2_int >> data_bit_pos) & ((1 << (s[2])) - 1)
if s[4] and (ival & (1<<(s[2]-1))): # signed
ival -= (1<<s[2])
# control the offset
ival = (ival * s[5]) + s[6]
#if debug:
# print "%40s %2d %2d %7.2f %s" % (s[0], s[1], s[2], ival, s[-1])
if arr is None:
out[s[0]] = ival
else:
out[arr.index(s[0])] = ival
return name, out
def get_signals(self, msg):
msg = self.lookup_msg_id(msg)
return [sgs.name for sgs in self.msgs[msg][1]]
if __name__ == "__main__":
from opendbc import DBC_PATH
dbc_test = dbc(os.path.join(DBC_PATH, sys.argv[1]))
print dbc_test.get_signals(0xe4)

104
common/fingerprints.py Normal file
View File

@@ -0,0 +1,104 @@
class HONDA:
CIVIC = "HONDA CIVIC 2016 TOURING"
ACURA_ILX = "ACURA ILX 2016 ACURAWATCH PLUS"
CRV = "HONDA CR-V 2016 TOURING"
ODYSSEY = "HONDA ODYSSEY 2018 EX-L"
ACURA_RDX = "ACURA RDX 2018 ACURAWATCH PLUS"
class TOYOTA:
PRIUS = "TOYOTA PRIUS 2017"
RAV4H = "TOYOTA RAV4 2017 HYBRID"
RAV4 = "TOYOTA RAV4 2017"
COROLLA = "TOYOTA COROLLA 2017"
LEXUS_RXH = "LEXUS RX HYBRID 2017"
_FINGERPRINTS = {
HONDA.ACURA_ILX: {
1024L: 5, 513L: 5, 1027L: 5, 1029L: 8, 929L: 4, 1057L: 5, 777L: 8, 1034L: 5, 1036L: 8, 398L: 3, 399L: 7, 145L: 8, 660L: 8, 985L: 3, 923L: 2, 542L: 7, 773L: 7, 800L: 8, 432L: 7, 419L: 8, 420L: 8, 1030L: 5, 422L: 8, 808L: 8, 428L: 8, 304L: 8, 819L: 7, 821L: 5, 57L: 3, 316L: 8, 545L: 4, 464L: 8, 1108L: 8, 597L: 8, 342L: 6, 983L: 8, 344L: 8, 804L: 8, 1039L: 8, 476L: 4, 892L: 8, 490L: 8, 1064L: 7, 882L: 2, 884L: 7, 887L: 8, 888L: 8, 380L: 8, 1365L: 5,
# sent messages
0xe4: 5, 0x1fa: 8, 0x200: 3, 0x30c: 8, 0x33d: 5,
},
HONDA.ACURA_RDX: {
57L: 3, 145L: 8, 229L: 4, 308L: 5, 316L: 8, 342L: 6, 344L: 8, 380L: 8, 392L: 6, 398L: 3, 399L: 6, 404L: 4, 420L: 8, 422L: 8, 426L: 8, 432L: 7, 464L: 8, 474L: 5, 476L: 4, 487L: 4, 490L: 8, 506L: 8, 542L: 7, 545L: 4, 597L: 8, 660L: 8, 773L: 7, 777L: 8, 780L: 8, 800L: 8, 804L: 8, 808L: 8, 819L: 7, 821L: 5, 829L: 5, 882L: 2, 884L: 7, 887L: 8, 888L: 8, 892L: 8, 923L: 2, 929L: 4, 963L: 8, 965L: 8, 966L: 8, 967L: 8, 983L: 8, 985L: 3, 1024L: 5, 1027L: 5, 1029L: 8, 1033L: 5, 1034L: 5, 1036L: 8, 1039L: 8, 1057L: 5, 1064L: 7, 1108L: 8, 1365L: 5, 1424L: 5, 1729L: 1
},
HONDA.CIVIC: {
1024L: 5, 513L: 5, 1027L: 5, 1029L: 8, 777L: 8, 1036L: 8, 1039L: 8, 1424L: 5, 401L: 8, 148L: 8, 662L: 4, 985L: 3, 795L: 8, 773L: 7, 800L: 8, 545L: 6, 420L: 8, 806L: 8, 808L: 8, 1322L: 5, 427L: 3, 428L: 8, 304L: 8, 432L: 7, 57L: 3, 450L: 8, 929L: 8, 330L: 8, 1302L: 8, 464L: 8, 1361L: 5, 1108L: 8, 597L: 8, 470L: 2, 344L: 8, 804L: 8, 399L: 7, 476L: 7, 1633L: 8, 487L: 4, 892L: 8, 490L: 8, 493L: 5, 884L: 8, 891L: 8, 380L: 8, 1365L: 5,
# sent messages
0xe4: 5, 0x1fa: 8, 0x200: 3, 0x30c: 8, 0x33d: 5, 0x35e: 8, 0x39f: 8,
},
HONDA.CRV: {
57L: 3, 145L: 8, 316L: 8, 340L: 8, 342L: 6, 344L: 8, 380L: 8, 398L: 3, 399L: 6, 401L: 8, 420L: 8, 422L: 8, 426L: 8, 432L: 7, 464L: 8, 474L: 5, 476L: 4, 487L: 4, 490L: 8, 493L: 3, 507L: 1, 542L: 7, 545L: 4, 597L: 8, 660L: 8, 661L: 4, 773L: 7, 777L: 8, 800L: 8, 804L: 8, 808L: 8, 882L: 2, 884L: 7, 888L: 8, 891L: 8, 892L: 8, 923L: 2, 929L: 8, 983L: 8, 985L: 3, 1024L: 5, 1027L: 5, 1029L: 8, 1033L: 5, 1036L: 8, 1039L: 8, 1057L: 5, 1064L: 7, 1108L: 8, 1125L: 8, 1296L: 8, 1365L: 5, 1424L: 5, 1600L: 5, 1601L: 8,
# sent messages
0x194: 4, 0x1fa: 8, 0x30c: 8, 0x33d: 5,
},
HONDA.ODYSSEY: {
57L: 3, 148L: 8, 228L: 5, 229L: 4, 316L: 8, 342L: 6, 344L: 8, 380L: 8, 399L: 7, 411L: 5, 419L: 8, 420L: 8, 427L: 3, 432L: 7, 450L: 8, 463L: 8, 464L: 8, 476L: 4, 490L: 8, 506L: 8, 542L: 7, 545L: 6, 597L: 8, 662L: 4, 773L: 7, 777L: 8, 780L: 8, 795L: 8, 800L: 8, 804L: 8, 806L: 8, 808L: 8, 817L: 4, 819L: 7, 821L: 5, 825L: 4, 829L: 5, 837L: 5, 856L: 7, 862L: 8, 871L: 8, 881L: 8, 882L: 4, 884L: 8, 891L: 8, 892L: 8, 905L: 8, 923L: 2, 927L: 8, 929L: 8, 963L: 8, 965L: 8, 966L: 8, 967L: 8, 983L: 8, 985L: 3, 1029L: 8, 1036L: 8, 1052L: 8, 1064L: 7, 1088L: 8, 1089L: 8, 1092L: 1, 1108L: 8, 1110L: 8, 1125L: 8, 1296L: 8, 1302L: 8, 1600L: 5, 1601L: 8, 1612L: 5, 1613L: 5, 1614L: 5, 1615L: 8, 1616L: 5, 1619L: 5, 1623L: 5, 1668L: 5
},
TOYOTA.RAV4: {
36L: 8, 37L: 8, 170L: 8, 180L: 8, 186L: 4, 426L: 6, 452L: 8, 464L: 8, 466L: 8, 467L: 8, 547L: 8, 548L: 8, 552L: 4, 562L: 4, 608L: 8, 610L: 5, 643L: 7, 705L: 8, 725L: 2, 740L: 5, 800L: 8, 835L: 8, 836L: 8, 849L: 4, 869L: 7, 870L: 7, 871L: 2, 896L: 8, 897L: 8, 900L: 6, 902L: 6, 905L: 8, 911L: 8, 916L: 3, 918L: 7, 921L: 8, 933L: 8, 944L: 8, 945L: 8, 951L: 8, 955L: 4, 956L: 8, 979L: 2, 998L: 5, 999L: 7, 1000L: 8, 1001L: 8, 1005L: 2, 1008L: 2, 1014L: 8, 1017L: 8, 1041L: 8, 1042L: 8, 1043L: 8, 1044L: 8, 1056L: 8, 1059L: 1, 1114L: 8, 1161L: 8, 1162L: 8, 1163L: 8, 1176L: 8, 1177L: 8, 1178L: 8, 1179L: 8, 1180L: 8, 1181L: 8, 1190L: 8, 1191L: 8, 1192L: 8, 1196L: 8, 1227L: 8, 1228L: 8, 1235L: 8, 1237L: 8, 1263L: 8, 1264L: 8, 1279L: 8, 1408L: 8, 1409L: 8, 1410L: 8, 1552L: 8, 1553L: 8, 1554L: 8, 1555L: 8, 1556L: 8, 1557L: 8, 1561L: 8, 1562L: 8, 1568L: 8, 1569L: 8, 1570L: 8, 1571L: 8, 1572L: 8, 1584L: 8, 1589L: 8, 1592L: 8, 1593L: 8, 1595L: 8, 1596L: 8, 1597L: 8, 1600L: 8, 1656L: 8, 1664L: 8, 1728L: 8, 1745L: 8, 1779L: 8, 1904L: 8, 1912L: 8, 1990L: 8, 1998L: 8
},
TOYOTA.RAV4H: {
36L: 8, 37L: 8, 170L: 8, 180L: 8, 186L: 4, 426L: 6, 452L: 8, 464L: 8, 466L: 8, 467L: 8, 547L: 8, 548L: 8, 552L: 4, 562L: 4, 608L: 8, 610L: 5, 643L: 7, 705L: 8, 725L: 2, 740L: 5, 800L: 8, 835L: 8, 836L: 8, 849L: 4, 869L: 7, 870L: 7, 871L: 2, 896L: 8, 897L: 8, 900L: 6, 902L: 6, 905L: 8, 911L: 8, 916L: 3, 918L: 7, 921L: 8, 933L: 8, 944L: 8, 945L: 8, 951L: 8, 955L: 8, 956L: 8, 979L: 2, 998L: 5, 999L: 7, 1000L: 8, 1001L: 8, 1008L: 2, 1014L: 8, 1017L: 8, 1041L: 8, 1042L: 8, 1043L: 8, 1044L: 8, 1056L: 8, 1059L: 1, 1114L: 8, 1161L: 8, 1162L: 8, 1163L: 8, 1176L: 8, 1177L: 8, 1178L: 8, 1179L: 8, 1180L: 8, 1181L: 8, 1190L: 8, 1191L: 8, 1192L: 8, 1196L: 8, 1227L: 8, 1228L: 8, 1235L: 8, 1237L: 8, 1263L: 8, 1279L: 8, 1408L: 8, 1409L: 8, 1410L: 8, 1552L: 8, 1553L: 8, 1554L: 8, 1555L: 8, 1556L: 8, 1557L: 8, 1561L: 8, 1562L: 8, 1568L: 8, 1569L: 8, 1570L: 8, 1571L: 8, 1572L: 8, 1584L: 8, 1589L: 8, 1592L: 8, 1593L: 8, 1595L: 8, 1596L: 8, 1597L: 8, 1600L: 8, 1656L: 8, 1664L: 8, 1728L: 8, 1745L: 8, 1779L: 8, 1904L: 8, 1912L: 8, 1990L: 8, 1998L: 8, 581L: 5, 296: 8, 560L: 7, 713L: 8, 550L: 8, 608L: 8, 37L: 8, 36L: 8, 950L: 8, 1198L: 8, 1197L: 8, 1199L: 8, 1212L: 8, 953L: 3, 1264L: 8, 1184L: 8, 1005L: 2, 1185L: 8, 1232L: 8, 1186L: 8
},
TOYOTA.PRIUS: [{
36L: 8, 37L: 8, 166L: 8, 170L: 8, 180L: 8, 295L: 8, 296L: 8, 426L: 6, 452L: 8, 466L: 8, 467L: 8, 550L: 8, 552L: 4, 560L: 7, 562L: 6, 581L: 5, 608L: 8, 610L: 8, 614L: 8, 643L: 7, 658L: 8, 713L: 8, 740L: 5, 742L: 8, 743L: 8, 800L: 8, 810L: 2, 814L: 8, 829L: 2, 830L: 7, 835L: 8, 836L: 8, 863L: 8, 869L: 7, 870L: 7, 871L: 2, 898L: 8, 900L: 6, 902L: 6, 905L: 8, 918L: 8, 921L: 8, 933L: 8, 944L: 8, 945L: 8, 950L: 8, 951L: 8, 953L: 8, 955L: 8, 956L: 8, 971L: 7, 975L: 5, 993L: 8, 998L: 5, 999L: 7, 1000L: 8, 1001L: 8, 1014L: 8, 1017L: 8, 1020L: 8, 1041L: 8, 1042L: 8, 1044L: 8, 1056L: 8, 1057L: 8, 1059L: 1, 1071L: 8, 1077L: 8, 1082L: 8, 1083L: 8, 1084L: 8, 1085L: 8, 1086L: 8, 1114L: 8, 1132L: 8, 1161L: 8, 1162L: 8, 1163L: 8, 1175L: 8, 1227L: 8, 1228L: 8, 1235L: 8, 1237L: 8, 1279L: 8, 1552L: 8, 1553L: 8, 1556L: 8, 1557L: 8, 1568L: 8, 1570L: 8, 1571L: 8, 1572L: 8, 1595L: 8, 1777L: 8, 1779L: 8, 1904L: 8, 1912L: 8, 1990L: 8, 1998L: 8
},
# Prius Prime
{
36L: 8, 37L: 8, 166L: 8, 170L: 8, 180L: 8, 295L: 8, 296L: 8, 426L: 6, 452L: 8, 466L: 8, 467L: 8, 550L: 8, 552L: 4, 560L: 7, 562L: 6, 581L: 5, 608L: 8, 610L: 8, 614L: 8, 643L: 7, 658L: 8, 713L: 8, 740L: 5, 742L: 8, 743L: 8, 800L: 8, 810L: 2, 814L: 8, 824L: 2, 829L: 2, 830L: 7, 835L: 8, 836L: 8, 863L: 8, 869L: 7, 870L: 7, 871L: 2,898L: 8, 900L: 6, 902L: 6, 905L: 8, 913L: 8, 918L: 8, 921L: 8, 933L: 8, 944L: 8, 945L: 8, 950L: 8, 951L: 8, 953L: 8, 955L: 8, 956L: 8, 971L: 7, 974L: 8, 975L: 5, 993L: 8, 998L: 5, 999L: 7, 1000L: 8, 1001L: 8, 1014L: 8, 1017L: 8, 1020L: 8, 1041L: 8, 1042L: 8, 1044L: 8, 1056L: 8, 1057L: 8, 1059L: 1, 1071L: 8, 1076L: 8, 1077L: 8, 1082L: 8, 1083L: 8, 1084L: 8, 1085L: 8, 1086L: 8, 1114L: 8, 1132L: 8, 1161L: 8, 1162L: 8, 1163L: 8, 1164L: 8, 1165L: 8, 1166L: 8, 1167L: 8, 1175L: 8, 1227L: 8, 1228L: 8, 1235L: 8, 1237L: 8, 1279L: 8, 1552L: 8, 1553L: 8, 1556L: 8, 1557L: 8, 1568L: 8, 1570L: 8, 1571L: 8, 1572L: 8, 1595L: 8, 1777L: 8, 1779L: 8, 1904L: 8, 1912L: 8, 1990L: 8, 1998L: 8
},
# Taiwanese Prius Prime
{
36L: 8, 37L: 8, 166L: 8, 170L: 8, 180L: 8, 295L: 8, 296L: 8, 426L: 6, 452L: 8, 466L: 8, 467L: 8, 550L: 8, 552L: 4, 560L: 7, 562L: 6, 581L: 5, 608L: 8, 610L: 8, 614L: 8, 643L: 7, 658L: 8, 713L: 8, 740L: 5, 742L: 8, 743L: 8, 800L: 8, 810L: 2, 814L: 8, 824L: 2, 829L: 2, 830L: 7, 835L: 8, 836L: 8, 845L: 5, 863L: 8, 869L: 7, 870L: 7, 871L: 2,898L: 8, 900L: 6, 902L: 6, 905L: 8, 913L: 8, 918L: 8, 921L: 8, 933L: 8, 944L: 8, 945L: 8, 950L: 8, 951L: 8, 953L: 8, 955L: 8, 956L: 8, 971L: 7, 974L: 8, 975L: 5, 993L: 8, 998L: 5, 999L: 7, 1000L: 8, 1001L: 8, 1005L: 2, 1014L: 8, 1017L: 8, 1020L: 8, 1041L: 8, 1042L: 8, 1044L: 8, 1056L: 8, 1057L: 8, 1059L: 1, 1071L: 8, 1076L: 8, 1077L: 8, 1082L: 8, 1083L: 8, 1084L: 8, 1085L: 8, 1086L: 8, 1114L: 8, 1132L: 8, 1161L: 8, 1162L: 8, 1163L: 8, 1164L: 8, 1165L: 8, 1166L: 8, 1167L: 8, 1175L: 8, 1227L: 8, 1228L: 8, 1235L: 8, 1237L: 8, 1264L: 8, 1279L: 8, 1552L: 8, 1553L: 8, 1556L: 8, 1557L: 8, 1568L: 8, 1570L: 8, 1571L: 8, 1572L: 8, 1595L: 8, 1777L: 8, 1779L: 8, 1904L: 8, 1912L: 8, 1990L: 8, 1998L: 8
}
],
TOYOTA.COROLLA: {
36: 8, 37: 8, 170: 8, 180: 8, 186: 4, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 547: 8, 548: 8, 552: 4, 608: 8, 610: 5, 643: 7, 705: 8, 740: 5, 800: 8, 835: 8, 836: 8, 849: 4, 869: 7, 870: 7, 871: 2, 896: 8, 897: 8, 900: 6, 902: 6, 905: 8, 911: 8, 916: 2, 921: 8, 933: 8, 944: 8, 945: 8, 951: 8, 955: 4, 956: 8, 979: 2, 992: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1017: 8, 1041: 8, 1042: 8, 1043: 8, 1044: 8, 1056: 8, 1059: 1, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1196: 8, 1227: 8, 1235: 8, 1279: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1561: 8, 1562: 8, 1568: 8, 1569: 8, 1570: 8, 1571: 8, 1572: 8, 1584: 8, 1589: 8, 1592: 8, 1596: 8, 1597: 8, 1600: 8, 1664: 8, 1728: 8, 1779: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8
},
TOYOTA.LEXUS_RXH: {
36: 8, 37: 8, 166: 8, 170: 8, 180: 8, 295: 8, 296: 8, 426: 6, 452: 8, 466: 8, 467: 8, 550: 8, 552: 4, 560: 7, 562: 6, 581: 5, 608: 8, 610: 5, 643: 7, 658: 8, 713: 8, 740: 5, 742: 8, 743: 8, 800: 8, 810: 2, 812: 3, 814: 8, 830: 7, 835: 8, 836: 8, 845: 5, 863: 8, 869: 7, 870: 7, 871: 2, 898: 8, 900: 6, 902: 6, 905: 8, 913: 8, 918: 8, 921: 8, 933: 8, 944: 8, 945: 8, 950: 8, 951: 8, 953: 8, 955: 8, 956: 8, 971: 7, 975: 6, 993: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1005: 2, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1059: 1, 1063: 8, 1071: 8, 1077: 8, 1082: 8, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1227: 8, 1228: 8, 1235: 8, 1237: 8, 1264: 8, 1279: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1575: 8, 1595: 8, 1777: 8, 1779: 8, 1808: 8, 1810: 8, 1816: 8, 1818: 8, 1840: 8, 1848: 8, 1904: 8, 1912: 8, 1940: 8, 1941: 8, 1948: 8, 1949: 8, 1952: 8, 1956: 8, 1960: 8, 1964: 8, 1986: 8, 1990: 8, 1994: 8, 1998: 8, 2004: 8, 2012: 8
},
}
# support additional internal only fingerprints
try:
from common.fingerprints_internal import add_additional_fingerprints
add_additional_fingerprints(_FINGERPRINTS)
except ImportError:
pass
def is_valid_for_fingerprint(msg, car_fingerprint):
adr = msg.address
return msg.src != 0 or (adr in car_fingerprint and car_fingerprint[adr] == len(msg.dat))
def eliminate_incompatible_cars(msg, candidate_cars):
"""Removes cars that could not have sent msg.
Inputs:
msg: A cereal/log CanData message from the car.
candidate_cars: A list of cars to consider.
Returns:
A list containing the subset of candidate_cars that could have sent msg.
"""
compatible_cars = []
for car_name in candidate_cars:
car_fingerprints = _FINGERPRINTS[car_name]
if not isinstance(car_fingerprints, list):
car_fingerprints = [car_fingerprints]
for fingerprint in car_fingerprints:
if is_valid_for_fingerprint(msg, fingerprint):
compatible_cars.append(car_name)
break
return compatible_cars
def all_known_cars():
"""Returns a list of all known car strings."""
return _FINGERPRINTS.keys()

View File

251
common/kalman/ekf.py Normal file
View File

@@ -0,0 +1,251 @@
import abc
import numpy as np
# The EKF class contains the framework for an Extended Kalman Filter, but must be subclassed to use.
# A subclass must implement:
# 1) calc_transfer_fun(); see bottom of file for more info.
# 2) __init__() to initialize self.state, self.covar, and self.process_noise appropriately
# Alternatively, the existing implementations of EKF can be used (e.g. EKF2D)
# Sensor classes are optionally used to pass measurement information into the EKF, to keep
# sensor parameters and processing methods for a each sensor together.
# Sensor classes have a read() method which takes raw sensor data and returns
# a SensorReading object, which can be passed to the EKF update() method.
# For usage, see run_ekf1d.py in selfdrive/new for a simple example.
# ekf.predict(dt) should be called between update cycles with the time since it was last called.
# Ideally, predict(dt) should be called at a relatively constant rate.
# update() should be called once per sensor, and can be called multiple times between predict steps.
# Access and set the state of the filter directly with ekf.state and ekf.covar.
class SensorReading:
# Given a perfect model and no noise, data = obs_model * state
def __init__(self, data, covar, obs_model):
self.data = data
self.obs_model = obs_model
self.covar = covar
def __repr__(self):
return "SensorReading(data={}, covar={}, obs_model={})".format(
repr(self.data), repr(self.covar), repr(self.obs_model))
# A generic sensor class that does no pre-processing of data
class SimpleSensor:
# obs_model can be
# a full observation model matrix, or
# an integer or tuple of indices into ekf.state, indicating which variables are being directly observed
# covar can be
# a full covariance matrix
# a float or tuple of individual covars for each component of the sensor reading
# dims is the number of states in the EKF
def __init__(self, obs_model, covar, dims):
# Allow for integer covar/obs_model
if not hasattr(obs_model, "__len__"):
obs_model = (obs_model, )
if not hasattr(covar, "__len__"):
covar = (covar, )
# Full observation model passed
if dims in np.array(obs_model).shape:
self.obs_model = np.asmatrix(obs_model)
self.covar = np.asmatrix(covar)
# Indices of unit observations passed
else:
self.obs_model = np.matlib.zeros((len(obs_model), dims))
self.obs_model[:, list(obs_model)] = np.identity(len(obs_model))
if np.asarray(covar).ndim == 2:
self.covar = np.asmatrix(covar)
elif len(covar) == len(obs_model):
self.covar = np.matlib.diag(covar)
else:
self.covar = np.matlib.identity(len(obs_model)) * covar
def read(self, data, covar=None):
if covar:
self.covar = covar
return SensorReading(data, self.covar, self.obs_model)
class EKF:
__metaclass__ = abc.ABCMeta
def __init__(self, debug=False):
self.DEBUG = debug
def __str__(self):
return "EKF(state={}, covar={})".format(self.state, self.covar)
# Measurement update
# Reading should be a SensorReading object with data, covar, and obs_model attributes
def update(self, reading):
# Potential improvements:
# deal with negative covars
# add noise to really low covars to ensure stability
# use mahalanobis distance to reject outliers
# wrap angles after state updates and innovation
# y = z - H*x
innovation = reading.data - reading.obs_model * self.state
if self.DEBUG:
print "reading:\n",reading.data
print "innovation:\n",innovation
# S = H*P*H' + R
innovation_covar = reading.obs_model * self.covar * reading.obs_model.T + reading.covar
# K = P*H'*S^-1
kalman_gain = self.covar * reading.obs_model.T * np.linalg.inv(
innovation_covar)
if self.DEBUG:
print "gain:\n", kalman_gain
print "innovation_covar:\n", innovation_covar
print "innovation: ", innovation
print "test: ", self.covar * reading.obs_model.T * (
reading.obs_model * self.covar * reading.obs_model.T + reading.covar *
0).I
# x = x + K*y
self.state += kalman_gain*innovation
# print "covar", np.diag(self.covar)
#self.state[(roll_vel, yaw_vel, pitch_vel),:] = reading.data
# Standard form: P = (I - K*H)*P
# self.covar = (self.identity - kalman_gain*reading.obs_model) * self.covar
# Use the Joseph form for numerical stability: P = (I-K*H)*P*(I - K*H)' + K*R*K'
aux_mtrx = (self.identity - kalman_gain * reading.obs_model)
self.covar = aux_mtrx * self.covar * aux_mtrx.T + kalman_gain * reading.covar * kalman_gain.T
if self.DEBUG:
print "After update"
print "state\n", self.state
print "covar:\n",self.covar
def update_scalar(self, reading):
# like update but knowing that measurement is a scalar
# this avoids matrix inversions and speeds up (surprisingly) drived.py a lot
# innovation = reading.data - np.matmul(reading.obs_model, self.state)
# innovation_covar = np.matmul(np.matmul(reading.obs_model, self.covar), reading.obs_model.T) + reading.covar
# kalman_gain = np.matmul(self.covar, reading.obs_model.T)/innovation_covar
# self.state += np.matmul(kalman_gain, innovation)
# aux_mtrx = self.identity - np.matmul(kalman_gain, reading.obs_model)
# self.covar = np.matmul(aux_mtrx, np.matmul(self.covar, aux_mtrx.T)) + np.matmul(kalman_gain, np.matmul(reading.covar, kalman_gain.T))
# written without np.matmul
es = np.einsum
ABC_T = "ij,jk,lk->il"
AB_T = "ij,kj->ik"
AB = "ij,jk->ik"
innovation = reading.data - es(AB, reading.obs_model, self.state)
innovation_covar = es(ABC_T, reading.obs_model, self.covar,
reading.obs_model) + reading.covar
kalman_gain = es(AB_T, self.covar, reading.obs_model) / innovation_covar
self.state += es(AB, kalman_gain, innovation)
aux_mtrx = self.identity - es(AB, kalman_gain, reading.obs_model)
self.covar = es(ABC_T, aux_mtrx, self.covar, aux_mtrx) + \
es(ABC_T, kalman_gain, reading.covar, kalman_gain)
# Prediction update
def predict(self, dt):
es = np.einsum
ABC_T = "ij,jk,lk->il"
AB = "ij,jk->ik"
# State update
transfer_fun, transfer_fun_jacobian = self.calc_transfer_fun(dt)
# self.state = np.matmul(transfer_fun, self.state)
# self.covar = np.matmul(np.matmul(transfer_fun_jacobian, self.covar), transfer_fun_jacobian.T) + self.process_noise * dt
# x = f(x, u), written in the form x = A(x, u)*x
self.state = es(AB, transfer_fun, self.state)
# P = J*P*J' + Q
self.covar = es(ABC_T, transfer_fun_jacobian, self.covar,
transfer_fun_jacobian) + self.process_noise * dt #!dt
#! Clip covariance to avoid explosions
self.covar = np.clip(self.covar,-1e10,1e10)
@abc.abstractmethod
def calc_transfer_fun(self, dt):
"""Return a tuple with the transfer function and transfer function jacobian
The transfer function and jacobian should both be a numpy matrix of size DIMSxDIMS
The transfer function matrix A should satisfy the state-update equation
x_(k+1) = A * x_k
The jacobian J is the direct jacobian A*x_k. For linear systems J=A.
Current implementations calculate A and J as functions of state. Control input
can be added trivially by adding a control parameter to predict() and calc_tranfer_update(),
and using it during calculation of A and J
"""
class FastEKF1D(EKF):
"""Fast version of EKF for 1D problems with scalar readings."""
def __init__(self, dt, var_init, Q):
super(FastEKF1D, self).__init__(False)
self.state = [0, 0]
self.covar = [var_init, var_init, 0]
# Process Noise
self.dtQ0 = dt * Q[0]
self.dtQ1 = dt * Q[1]
def update(self, reading):
raise NotImplementedError
def update_scalar(self, reading):
# TODO(mgraczyk): Delete this for speed.
# assert np.all(reading.obs_model == [1, 0])
rcov = reading.covar[0, 0]
x = self.state
S = self.covar
innovation = reading.data - x[0]
innovation_covar = S[0] + rcov
k0 = S[0] / innovation_covar
k1 = S[2] / innovation_covar
x[0] += k0 * innovation
x[1] += k1 * innovation
mk = 1 - k0
S[1] += k1 * (k1 * (S[0] + rcov) - 2 * S[2])
S[2] = mk * (S[2] - k1 * S[0]) + rcov * k0 * k1
S[0] = mk * mk * S[0] + rcov * k0 * k0
def predict(self, dt):
# State update
x = self.state
x[0] += dt * x[1]
# P = J*P*J' + Q
S = self.covar
S[0] += dt * (2 * S[2] + dt * S[1]) + self.dtQ0
S[2] += dt * S[1]
S[1] += self.dtQ1
# Clip covariance to avoid explosions
S = max(-1e10, min(S, 1e10))
def calc_transfer_fun(self, dt):
tf = np.identity(2)
tf[0, 1] = dt
tfj = tf
return tf, tfj

View File

@@ -0,0 +1,23 @@
import numpy as np
class KF1D:
# this EKF assumes constant covariance matrix, so calculations are much simpler
# the Kalman gain also needs to be precomputed using the control module
def __init__(self, x0, A, C, K):
self.x = x0
self.A = A
self.C = C
self.K = K
self.A_K = self.A - np.dot(self.K, self.C)
# K matrix needs to be pre-computed as follow:
# import control
# (x, l, K) = control.dare(np.transpose(self.A), np.transpose(self.C), Q, R)
# self.K = np.transpose(K)
def update(self, meas):
self.x = np.dot(self.A_K, self.x) + np.dot(self.K, meas)
return self.x

142
common/logging_extra.py Normal file
View File

@@ -0,0 +1,142 @@
import os
import sys
import copy
import json
import socket
import logging
from threading import local
from collections import OrderedDict
from contextlib import contextmanager
def json_handler(obj):
# if isinstance(obj, (datetime.date, datetime.time)):
# return obj.isoformat()
return repr(obj)
def json_robust_dumps(obj):
return json.dumps(obj, default=json_handler)
class NiceOrderedDict(OrderedDict):
def __str__(self):
return '{'+', '.join("%r: %r" % p for p in self.iteritems())+'}'
class SwagFormatter(logging.Formatter):
def __init__(self, swaglogger):
logging.Formatter.__init__(self, None, '%a %b %d %H:%M:%S %Z %Y')
self.swaglogger = swaglogger
self.host = socket.gethostname()
def format_dict(self, record):
record_dict = NiceOrderedDict()
if isinstance(record.msg, dict):
record_dict['msg'] = record.msg
else:
try:
record_dict['msg'] = record.getMessage()
except (ValueError, TypeError):
record_dict['msg'] = [record.msg]+record.args
record_dict['ctx'] = self.swaglogger.get_ctx()
if record.exc_info:
record_dict['exc_info'] = self.formatException(record.exc_info)
record_dict['level'] = record.levelname
record_dict['levelnum'] = record.levelno
record_dict['name'] = record.name
record_dict['filename'] = record.filename
record_dict['lineno'] = record.lineno
record_dict['pathname'] = record.pathname
record_dict['module'] = record.module
record_dict['funcName'] = record.funcName
record_dict['host'] = self.host
record_dict['process'] = record.process
record_dict['thread'] = record.thread
record_dict['threadName'] = record.threadName
record_dict['created'] = record.created
return record_dict
def format(self, record):
return json_robust_dumps(self.format_dict(record))
_tmpfunc = lambda: 0
_srcfile = os.path.normcase(_tmpfunc.__code__.co_filename)
class SwagLogger(logging.Logger):
def __init__(self):
logging.Logger.__init__(self, "swaglog")
self.global_ctx = {}
self.log_local = local()
self.log_local.ctx = {}
def findCaller(self):
"""
Find the stack frame of the caller so that we can note the source
file name, line number and function name.
"""
# f = currentframe()
f = sys._getframe(3)
#On some versions of IronPython, currentframe() returns None if
#IronPython isn't run with -X:Frames.
if f is not None:
f = f.f_back
rv = "(unknown file)", 0, "(unknown function)"
while hasattr(f, "f_code"):
co = f.f_code
filename = os.path.normcase(co.co_filename)
if filename in (logging._srcfile, _srcfile):
f = f.f_back
continue
rv = (co.co_filename, f.f_lineno, co.co_name)
break
return rv
def local_ctx(self):
try:
return self.log_local.ctx
except AttributeError:
self.log_local.ctx = {}
return self.log_local.ctx
def get_ctx(self):
return dict(self.local_ctx(), **self.global_ctx)
@contextmanager
def ctx(self, **kwargs):
old_ctx = self.local_ctx()
self.log_local.ctx = copy.copy(old_ctx) or {}
self.log_local.ctx.update(kwargs)
try:
yield
finally:
self.log_local.ctx = old_ctx
def bind(self, **kwargs):
self.local_ctx().update(kwargs)
def bind_global(self, **kwargs):
self.global_ctx.update(kwargs)
def event(self, event_name, *args, **kwargs):
evt = NiceOrderedDict()
evt['event'] = event_name
if args:
evt['args'] = args
evt.update(kwargs)
self.info(evt)
if __name__ == "__main__":
log = SwagLogger()
log.info("asdasd %s", "a")
log.info({'wut': 1})
with log.ctx():
log.bind(user="some user")
log.info("in req")
log.event("do_req")

29
common/numpy_fast.py Normal file
View File

@@ -0,0 +1,29 @@
def int_rnd(x):
return int(round(x))
def clip(x, lo, hi):
return max(lo, min(hi, x))
def interp(x, xp, fp):
N = len(xp)
if not hasattr(x, '__iter__'):
hi = 0
while hi < N and x > xp[hi]:
hi += 1
low = hi - 1
return fp[-1] if hi == N and x > xp[low] else (
fp[0] if hi == 0 else
(x - xp[low]) * (fp[hi] - fp[low]) / (xp[hi] - xp[low]) + fp[low])
result = []
for v in x:
hi = 0
while hi < N and v > xp[hi]:
hi += 1
low = hi - 1
result.append(fp[-1] if hi == N and v > xp[low] else (fp[
0] if hi == 0 else (v - xp[low]) * (fp[hi] - fp[low]) / (xp[hi] - xp[low]
) + fp[low]))
return result

330
common/params.py Executable file
View File

@@ -0,0 +1,330 @@
#!/usr/bin/env python
"""ROS has a parameter server, we have files.
The parameter store is a persistent key value store, implemented as a directory with a writer lock.
On Android, we store params under params_dir = /data/params. The writer lock is a file
"<params_dir>/.lock" taken using flock(), and data is stored in a directory symlinked to by
"<params_dir>/d".
Each key, value pair is stored as a file with named <key> with contents <value>, located in
<params_dir>/d/<key>
Readers of a single key can just open("<params_dir>/d/<key>") and read the file contents.
Readers who want a consistent snapshot of multiple keys should take the lock.
Writers should take the lock before modifying anything. Writers should also leave the DB in a
consistent state after a crash. The implementation below does this by copying all params to a temp
directory <params_dir>/<tmp>, then atomically symlinking <params_dir>/<d> to <params_dir>/<tmp>
before deleting the old <params_dir>/<d> directory.
Writers that only modify a single key can simply take the lock, then swap the corresponding value
file in place without messing with <params_dir>/d.
"""
import time
import os
import errno
import sys
import shutil
import fcntl
import tempfile
from enum import Enum
def mkdirs_exists_ok(path):
try:
os.makedirs(path)
except OSError:
if not os.path.isdir(path):
raise
class TxType(Enum):
PERSISTANT = 1
CLEAR_ON_MANAGER_START = 2
CLEAR_ON_CAR_START = 3
class UnknownKeyName(Exception):
pass
keys = {
# written: manager
# read: loggerd, uploaderd, baseui
"DongleId": TxType.PERSISTANT,
"AccessToken": TxType.PERSISTANT,
"Version": TxType.PERSISTANT,
"GitCommit": TxType.PERSISTANT,
"GitBranch": TxType.PERSISTANT,
"GitRemote": TxType.PERSISTANT,
# written: baseui
# read: ui, controls
"IsMetric": TxType.PERSISTANT,
"IsRearViewMirror": TxType.PERSISTANT,
"IsFcwEnabled": TxType.PERSISTANT,
"HasAcceptedTerms": TxType.PERSISTANT,
"IsUploadVideoOverCellularEnabled": TxType.PERSISTANT,
# written: visiond
# read: visiond, controlsd
"CalibrationParams": TxType.PERSISTANT,
# written: visiond
# read: visiond, ui
"CloudCalibration": TxType.PERSISTANT,
# written: controlsd
# read: radard
"CarParams": TxType.CLEAR_ON_CAR_START,
"Passive": TxType.PERSISTANT,
"DoUninstall": TxType.CLEAR_ON_MANAGER_START,
}
def fsync_dir(path):
fd = os.open(path, os.O_RDONLY)
try:
os.fsync(fd)
finally:
os.close(fd)
class FileLock(object):
def __init__(self, path, create):
self._path = path
self._create = create
self._fd = None
def acquire(self):
self._fd = os.open(self._path, os.O_CREAT if self._create else 0)
fcntl.flock(self._fd, fcntl.LOCK_EX)
def release(self):
if self._fd is not None:
os.close(self._fd)
self._fd = None
class DBAccessor(object):
def __init__(self, path):
self._path = path
self._vals = None
def keys(self):
self._check_entered()
return self._vals.keys()
def get(self, key):
self._check_entered()
try:
return self._vals[key]
except KeyError:
return None
def _get_lock(self, create):
lock = FileLock(os.path.join(self._path, ".lock"), create)
lock.acquire()
return lock
def _read_values_locked(self):
"""Callers should hold a lock while calling this method."""
vals = {}
try:
data_path = self._data_path()
keys = os.listdir(data_path)
for key in keys:
with open(os.path.join(data_path, key), "rb") as f:
vals[key] = f.read()
except (OSError, IOError) as e:
# Either the DB hasn't been created yet, or somebody wrote a bug and left the DB in an
# inconsistent state. Either way, return empty.
if e.errno == errno.ENOENT:
return {}
return vals
def _data_path(self):
return os.path.join(self._path, "d")
def _check_entered(self):
if self._vals is None:
raise Exception("Must call __enter__ before using DB")
class DBReader(DBAccessor):
def __enter__(self):
try:
lock = self._get_lock(False)
except OSError as e:
# Do not create lock if it does not exist.
if e.errno == errno.ENOENT:
self._vals = {}
return self
try:
# Read everything.
self._vals = self._read_values_locked()
return self
finally:
lock.release()
def __exit__(self, type, value, traceback): pass
class DBWriter(DBAccessor):
def __init__(self, path):
super(DBWriter, self).__init__(path)
self._lock = None
self._prev_umask = None
def put(self, key, value):
self._vals[key] = value
def delete(self, key):
self._vals.pop(key, None)
def __enter__(self):
mkdirs_exists_ok(self._path)
# Make sure we can write and that permissions are correct.
self._prev_umask = os.umask(0)
try:
os.chmod(self._path, 0o777)
self._lock = self._get_lock(True)
self._vals = self._read_values_locked()
except:
os.umask(self._prev_umask)
self._prev_umask = None
raise
return self
def __exit__(self, type, value, traceback):
self._check_entered()
try:
# data_path refers to the externally used path to the params. It is a symlink.
# old_data_path is the path currently pointed to by data_path.
# tempdir_path is a path where the new params will go, which the new data path will point to.
# new_data_path is a temporary symlink that will atomically overwrite data_path.
#
# The current situation is:
# data_path -> old_data_path
# We're going to write params data to tempdir_path
# tempdir_path -> params data
# Then point new_data_path to tempdir_path
# new_data_path -> tempdir_path
# Then atomically overwrite data_path with new_data_path
# data_path -> tempdir_path
old_data_path = None
new_data_path = None
tempdir_path = tempfile.mkdtemp(prefix=".tmp", dir=self._path)
try:
# Write back all keys.
os.chmod(tempdir_path, 0o777)
for k, v in self._vals.items():
with open(os.path.join(tempdir_path, k), "wb") as f:
f.write(v)
f.flush()
os.fsync(f.fileno())
fsync_dir(tempdir_path)
data_path = self._data_path()
try:
old_data_path = os.path.join(self._path, os.readlink(data_path))
except (OSError, IOError):
# NOTE(mgraczyk): If other DB implementations have bugs, this could cause
# copies to be left behind, but we still want to overwrite.
pass
new_data_path = "{}.link".format(tempdir_path)
os.symlink(os.path.basename(tempdir_path), new_data_path)
os.rename(new_data_path, data_path)
fsync_dir(self._path)
finally:
# If the rename worked, we can delete the old data. Otherwise delete the new one.
success = new_data_path is not None and os.path.exists(data_path) and (
os.readlink(data_path) == os.path.basename(tempdir_path))
if success:
if old_data_path is not None:
shutil.rmtree(old_data_path)
else:
shutil.rmtree(tempdir_path)
# Regardless of what happened above, there should be no link at new_data_path.
if new_data_path is not None and os.path.islink(new_data_path):
os.remove(new_data_path)
finally:
os.umask(self._prev_umask)
self._prev_umask = None
# Always release the lock.
self._lock.release()
self._lock = None
class JSDB(object):
def __init__(self, fn):
self._fn = fn
def begin(self, write=False):
if write:
return DBWriter(self._fn)
else:
return DBReader(self._fn)
class Params(object):
def __init__(self, db='/data/params'):
self.env = JSDB(db)
def _clear_keys_with_type(self, tx_type):
with self.env.begin(write=True) as txn:
for key in keys:
if keys[key] == tx_type:
txn.delete(key)
def manager_start(self):
self._clear_keys_with_type(TxType.CLEAR_ON_MANAGER_START)
def car_start(self):
self._clear_keys_with_type(TxType.CLEAR_ON_CAR_START)
def delete(self, key):
with self.env.begin(write=True) as txn:
txn.delete(key)
def get(self, key, block=False):
if key not in keys:
raise UnknownKeyName(key)
while 1:
with self.env.begin() as txn:
ret = txn.get(key)
if not block or ret is not None:
break
# is polling really the best we can do?
time.sleep(0.05)
return ret
def put(self, key, dat):
if key not in keys:
raise UnknownKeyName(key)
with self.env.begin(write=True) as txn:
txn.put(key, dat)
print "set", key
if __name__ == "__main__":
params = Params()
if len(sys.argv) > 2:
params.put(sys.argv[1], sys.argv[2])
else:
for k in keys:
pp = params.get(k)
if pp is None:
print k, "is None"
elif all(ord(c) < 128 and ord(c) >= 32 for c in pp):
print k, pp
else:
print k, pp.encode("hex")
# Test multiprocess:
# seq 0 100000 | xargs -P20 -I{} python common/params.py DongleId {} && sleep 0.05
# while python common/params.py DongleId; do sleep 0.05; done

47
common/profiler.py Normal file
View File

@@ -0,0 +1,47 @@
import time
class Profiler(object):
def __init__(self, enabled=False):
self.enabled = enabled
self.cp = {}
self.cp_ignored = []
self.iter = 0
self.start_time = time.clock()
self.last_time = self.start_time
self.tot = 0.
def reset(self, enabled=False):
self.enabled = enabled
self.cp = {}
self.cp_ignored = []
self.iter = 0
self.start_time = time.clock()
self.last_time = self.start_time
def checkpoint(self, name, ignore=False):
# ignore flag needed when benchmarking threads with ratekeeper
if not self.enabled:
return
tt = time.clock()
if name not in self.cp:
self.cp[name] = 0.
if ignore:
self.cp_ignored.append(name)
self.cp[name] += tt - self.last_time
if not ignore:
self.tot += tt - self.last_time
self.last_time = tt
def display(self):
if not self.enabled:
return
self.iter += 1
print "******* Profiling *******"
for n in self.cp:
ms = self.cp[n]
if n in self.cp_ignored:
print "%30s: %7.2f perc: %1.0f" % (n, ms*1000.0, ms/self.tot*100), " IGNORED"
else:
print "%30s: %7.2f perc: %1.0f" % (n, ms*1000.0, ms/self.tot*100)
print "Iter clock: %2.6f TOTAL: %2.2f" % (self.tot/self.iter, self.tot)

110
common/realtime.py Normal file
View File

@@ -0,0 +1,110 @@
"""Utilities for reading real time clocks and keeping soft real time constraints."""
import os
import time
import platform
import threading
import subprocess
import multiprocessing
from cffi import FFI
ffi = FFI()
ffi.cdef("""
typedef int clockid_t;
struct timespec {
long tv_sec; /* Seconds. */
long tv_nsec; /* Nanoseconds. */
};
int clock_gettime (clockid_t clk_id, struct timespec *tp);
long syscall(long number, ...);
"""
)
libc = ffi.dlopen(None)
# see <linux/time.h>
CLOCK_MONOTONIC_RAW = 4
CLOCK_BOOTTIME = 7
if platform.system() != 'Darwin' and hasattr(libc, 'clock_gettime'):
c_clock_gettime = libc.clock_gettime
tlocal = threading.local()
def clock_gettime(clk_id):
if not hasattr(tlocal, 'ts'):
tlocal.ts = ffi.new('struct timespec *')
ts = tlocal.ts
r = c_clock_gettime(clk_id, ts)
if r != 0:
raise OSError("clock_gettime")
return ts.tv_sec + ts.tv_nsec * 1e-9
else:
# hack. only for OS X < 10.12
def clock_gettime(clk_id):
return time.time()
def monotonic_time():
return clock_gettime(CLOCK_MONOTONIC_RAW)
def sec_since_boot():
return clock_gettime(CLOCK_BOOTTIME)
def set_realtime_priority(level):
if os.getuid() != 0:
print("not setting priority, not root")
return
if platform.machine() == "x86_64":
NR_gettid = 186
elif platform.machine() == "aarch64":
NR_gettid = 178
else:
raise NotImplementedError
tid = libc.syscall(NR_gettid)
return subprocess.call(['chrt', '-f', '-p', str(level), str(tid)])
class Ratekeeper(object):
def __init__(self, rate, print_delay_threshold=0.):
"""Rate in Hz for ratekeeping. print_delay_threshold must be nonnegative."""
self._interval = 1. / rate
self._next_frame_time = sec_since_boot() + self._interval
self._print_delay_threshold = print_delay_threshold
self._frame = 0
self._remaining = 0
self._process_name = multiprocessing.current_process().name
@property
def frame(self):
return self._frame
@property
def remaining(self):
return self._remaining
# Maintain loop rate by calling this at the end of each loop
def keep_time(self):
lagged = self.monitor_time()
if self._remaining > 0:
time.sleep(self._remaining)
return lagged
# this only monitor the cumulative lag, but does not enforce a rate
def monitor_time(self):
lagged = False
remaining = self._next_frame_time - sec_since_boot()
self._next_frame_time += self._interval
if remaining < -self._print_delay_threshold:
print("%s lagging by %.2f ms" % (self._process_name, -remaining * 1000))
lagged = True
self._frame += 1
self._remaining = remaining
return lagged
if __name__ == "__main__":
print sec_since_boot()

9
common/testing.py Normal file
View File

@@ -0,0 +1,9 @@
import os
from nose.tools import nottest
def phone_only(x):
if os.path.isfile("/init.qcom.rc"):
return x
else:
return nottest(x)

39
launch_openpilot.sh Executable file
View File

@@ -0,0 +1,39 @@
#!/usr/bin/bash
function launch {
# apply update
if [ "$(git rev-parse HEAD)" != "$(git rev-parse @{u})" ]; then
git reset --hard @{u} &&
git clean -xdf &&
exec "${BASH_SOURCE[0]}"
fi
# no cpu rationing for now
echo 0-3 > /dev/cpuset/background/cpus
echo 0-3 > /dev/cpuset/system-background/cpus
echo 0-3 > /dev/cpuset/foreground/boost/cpus
echo 0-3 > /dev/cpuset/foreground/cpus
echo 0-3 > /dev/cpuset/android/cpus
# wait for network
(cd selfdrive/ui/spinner && exec ./spinner 'waiting for network...') & spin_pid=$!
until ping -W 1 -c 1 8.8.8.8; do sleep 1; done
kill $spin_pid
# check if NEOS update is required
while [ "$(cat /VERSION)" -lt 4 ] && [ ! -e /data/media/0/noupdate ]; do
curl -o /tmp/updater https://neos.comma.ai/updater && chmod +x /tmp/updater && /tmp/updater
sleep 10
done
export PYTHONPATH="$PWD"
# start manager
cd selfdrive
./manager.py
# if broken, keep on screen error
while true; do sleep 1; done
}
launch

2
opendbc/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
*.pyc
.*.swp

53
opendbc/README.md Normal file
View File

@@ -0,0 +1,53 @@
opendbc
======
The project to democratize access to the decoder ring of your car.
### DBC file basics
A DBC file encodes, in a humanly readable way, the information needed to understand a vehicle's CAN bus traffic. A vehicle might have multiple CAN buses and every CAN bus is represented by its own dbc file.
Wondering what's the DBC file format? [Here](http://www.socialledge.com/sjsu/index.php?title=DBC_Format) a good overview.
### How to start reverse engineering cars
[opendbc](https://github.com/commaai/opendbc) is integrated with [cabana](https://community.comma.ai/cabana/).
Use [panda](https://github.com/commaai/panda) to connect your car to a computer.
### DBC file preprocessor
DBC files for different models of the same brand have a lot of overlap. Therefore, we wrote a preprocessor to create DBC files from a brand DBC file and a model specific DBC file. The source DBC files can be found in the generator folder. After changing one of the files run the generator.py script to regenerate the output files. These output files will be placed in the root of the opendbc repository and are suffixed by _generated.
### Good practices for contributing to opendbc
- Comments: the best way to store comments is to add them directly to the DBC files. For example:
```
CM_ SG_ 490 LONG_ACCEL "wheel speed derivative, noisy and zero snapping";
```
is a comment that refers to signal `LONG_ACCEL` in message `490`. Using comments is highly recommended, especially for doubts and uncertainties. [cabana](https://community.comma.ai/cabana/) can easily display/add/edit comments to signals and messages.
- Units: when applicable, it's recommended to convert signals into physical units, by using a proper signal factor. Using a SI unit is preferred, unless a non-SI unit rounds the signal factor much better.
For example:
```
SG_ VEHICLE_SPEED : 7|15@0+ (0.00278,0) [0|70] "m/s" PCM
```
is better than:
```
SG_ VEHICLE_SPEED : 7|15@0+ (0.00620,0) [0|115] "mph" PCM
```
However, the cleanest option is really:
```
SG_ VEHICLE_SPEED : 7|15@0+ (0.01,0) [0|250] "kph" PCM
```
- Signal's size: always use the smallest amount of bits possible. For example, let's say I'm reverse engineering the gas pedal position and I've determined that it's in a 3 bytes message. For 0% pedal position I read a message value of `0x00 0x00 0x00`, while for 100% of pedal position I read `0x64 0x00 0x00`: clearly, the gas pedal position is within the first byte of the message and I might be tempted to define the signal `GAS_POS` as:
```
SG_ GAS_POS : 7|8@0+ (1,0) [0|100] "%" PCM
```
However, I can't be sure that the very first bit of the message is referred to the pedal position: I haven't seen it changing! Therefore, a safer way of defining the signal is:
```
SG_ GAS_POS : 6|7@0+ (1,0) [0|100] "%" PCM
```
which leaves the first bit unallocated. This prevents from very erroneous reading of the gas pedal position, in case the first bit is indeed used for something else.

12
panda/.gitignore vendored Normal file
View File

@@ -0,0 +1,12 @@
*.pyc
.*.swp
.*.swo
*.o
a.out
*~
.#*
dist/
pandacan.egg-info/
board/obj/
examples/output.csv
.DS_Store

20
panda/.travis.yml Normal file
View File

@@ -0,0 +1,20 @@
language: python
cache:
directories:
- build/commaai/panda/boardesp/esp-open-sdk/crosstool-NG
addons:
apt:
packages:
- gcc-arm-none-eabi
- libnewlib-arm-none-eabi
- gperf
- texinfo
- help2man
script:
- python setup.py install
- pushd board && make bin && popd
- pushd boardesp && git clone --recursive https://github.com/pfalcon/esp-open-sdk.git && pushd esp-open-sdk && git checkout 03f5e898a059451ec5f3de30e7feff30455f7cec && LD_LIBRARY_PATH="" make STANDALONE=y && popd && popd
- pushd boardesp && make user1.bin && popd

7
panda/LICENSE Normal file
View File

@@ -0,0 +1,7 @@
Copyright (c) 2016, Comma.ai, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

89
panda/README.md Normal file
View File

@@ -0,0 +1,89 @@
Welcome to panda
======
[panda](http://github.com/commaai/panda) is the nicest universal car interface ever.
<a href="https://panda.comma.ai"><img src="https://github.com/commaai/panda/blob/master/panda.png">
<img src="https://github.com/commaai/panda/blob/master/buy.png"></a>
It supports 3x CAN, 2x LIN, and 1x GMLAN. It also charges a phone. On the computer side, it has both USB and Wi-Fi.
It uses an [STM32F413](http://www.st.com/en/microcontrollers/stm32f413-423.html?querycriteria=productId=LN2004) for low level stuff and an [ESP8266](https://en.wikipedia.org/wiki/ESP8266) for Wi-Fi. They are connected over high speed SPI, so the panda is actually capable of dumping the full contents of the busses over Wi-Fi, unlike every other dongle on amazon. ELM327 is weak, panda is strong.
It is 2nd gen hardware, reusing code and parts from the [NEO](https://github.com/commaai/neo) interface board.
[![Build Status](https://travis-ci.org/commaai/panda.svg?branch=master)](https://travis-ci.org/commaai/panda)
Usage
------
To install the library:
```
# pip install pandacan
```
See [this class](https://github.com/commaai/panda/blob/master/python/__init__.py#L80) for how to interact with the panda.
For example, to receive CAN messages:
```
>>> from panda import Panda
>>> panda = Panda()
>>> panda.can_recv()
```
And to send one on bus 0:
```
>>> panda.can_send(0x1aa, "message", 0)
```
More examples coming soon
Software interface support
------
As a universal car interface, it should support every reasonable software interface.
- User space ([done](https://github.com/commaai/panda/tree/master/python))
- socketcan in kernel ([alpha](https://github.com/commaai/panda/tree/master/drivers/linux))
- ELM327 ([done](https://github.com/commaai/panda/blob/master/boardesp/elm327.c))
- Windows J2534 ([alpha](https://github.com/commaai/panda/tree/master/drivers/windows))
Directory structure
------
- board -- Code that runs on the STM32
- boardesp -- Code that runs on the ESP8266
- drivers -- Drivers (not needed for use with python)
- python   -- Python userspace library for interfacing with the panda
- tests -- Tests and helper programs for panda
Programming (over USB)
------
[Programming the Board (STM32)](board/README.md)
[Programming the ESP](boardesp/README.md)
Debugging
------
To print out the serial console from the STM32, run tests/debug_console.py
To print out the serial console from the ESP8266, run PORT=1 tests/debug_console.py
Safety Model
------
When a panda powers up, by default it's in "SAFETY_NOOUTPUT" mode. While in no output mode, the buses are also forced to be silent. In order to send messages, you have to select a safety mode. Currently, setting safety modes is only supported over USB.
Safety modes can also optionally support "controls_allowed", which allows or blocks a subset of messages based on a piece of state in the board.
Hardware
------
Check out the hardware [guide](https://github.com/commaai/panda/blob/master/docs/guide.pdf)
Licensing
------
panda software is released under the MIT license unless otherwise specified.

31
panda/TODO Normal file
View File

@@ -0,0 +1,31 @@
** Projects **
== ELM327 Emulator ==
Write an elm327 emulator in boardesp/elm327.c and make it work with Torque
You'll find a start at this in the "elm327" branch.
== socketcan Kernel Driver ==
Write a kernel driver version of lib/panda.py that exposes the Panda on socketcan and makes it work with those tools.
You may want to switch to interrupt endpoint first. Should LIN be exposed as a serial interface?
== Windows J2534 DLL ==
Write a Windows DLL that exposes the J2534 API.
Will make the Panda work with car diagnostic software.
** Refactors **
== USB Interrupt Endpoint ==
Switch USB to use an interrupt endpoint instead of a bulk endpoint for can recv
== WebSocket Support ==
Add CAN streaming over WebSocket to the ELM code in addition to the UDP pipe.

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