Compare commits

..

33 Commits

Author SHA1 Message Date
Nigel Armstrong ad145da3bc Merge pull request #540 from commaai/devel
0.5.9 Release
2019-02-25 10:54:11 -08:00
rbiasini 2cee2e05ba Merge pull request #519 from commaai/devel
release 0.5.8
2019-01-31 17:01:04 -08:00
rbiasini 9ce3045f13 Merge pull request #470 from commaai/devel
0.5.7 release
2018-12-17 20:36:42 -07:00
rbiasini 9398a28be2 Merge pull request #448 from commaai/devel
0.5.6 release
2018-11-29 20:56:55 -08:00
rbiasini 9a42f2f1ad Merge pull request #434 from commaai/devel
calibration improvements and devel synch up
2018-11-13 18:50:56 -08:00
rbiasini 7c0202a101 Merge pull request #410 from commaai/devel
Improve Toyota radar filtering (#409)
2018-10-26 20:37:50 -07:00
rbiasini 18801659c5 Merge pull request #405 from commaai/devel
0.5.5 release
2018-10-25 17:34:53 -07:00
Willem Melching a488442402 Revert the changes to GM in 0.5.4 (#380) (#386)
* Revert 0.5.4 changes for GM for 18ers

* Redo the refactor of stock control msgs

* Fixed missing CONTROL_MSGS -> STOCK_CONTROL_MSGS

* Remove spacing

* Need candidate array idx
2018-10-03 21:03:09 +02:00
rbiasini ed6957540f Merge pull request #379 from commaai/devel
Release 0.5.4
2018-09-28 08:14:14 +02:00
rbiasini 999edf243e Merge pull request #359 from commaai/devel
0.5.3
2018-09-11 07:15:58 +02:00
rbiasini 63adcfc28c Merge pull request #329 from commaai/devel
0.5.2
2018-08-27 12:49:11 -07:00
Vehicle Researcher 8f22f52235 openpilot v0.5.1 release (#315)
Merge commit '2cfdc676101c387524246f789c8429647069b827' into release2
2018-08-27 12:21:14 -07:00
George Hotz 0ea21f3545 Merge pull request #293 from commaai/devel
0.5.0 release
2018-07-13 22:37:09 -07:00
George Hotz 27c7425b94 Merge pull request #277 from commaai/devel
openpilot 0.4.7.2
2018-06-28 11:22:35 -07:00
George Hotz 30b72e4be1 Merge pull request #267 from commaai/devel
openpilot 0.4.7.1
2018-06-19 09:18:12 -07:00
George Hotz afdda0e5fc Merge pull request #256 from commaai/devel
0.4.6 Release
2018-05-30 11:19:03 -07:00
George Hotz 88d1dd2bad Merge pull request #239 from commaai/devel
openpilot 0.4.5.1 release
2018-05-01 18:13:46 -07:00
George Hotz 3e491431a3 Merge pull request #226 from commaai/revert-220-devel
Revert "openpilot 0.4.3.1"
2018-03-26 15:18:53 -06:00
George Hotz f550656ee8 Revert "openpilot 0.4.3.1 (#220)"
This reverts commit 640ab12c72.
2018-03-26 14:13:40 -07:00
George Hotz 640ab12c72 openpilot 0.4.3.1 (#220)
* Honda Pilot 2017 Port (#161)

* Update README.md

* Update fingerprints.py

* Update carstate.py

* Update hondacan.py

* Update interface.py

* Update interface.py

* Update interface.py

* Update README.md

* Update README.md

* Update README.md

* Update fingerprints.py

* Update carstate.py

* Update hondacan.py

* Update interface.py

* Update carstate.py

* Update hondacan.py

* Update README.md

* Update fingerprints.py

* Update carstate.py

* Update carstate.py

* Update carstate.py

* Update hondacan.py

* Update interface.py

* Update carstate.py

* Update carstate.py

* Update Pilot Fingerprint

* Update fingerprints.py

* Give pilot its own definition and not use ILX

* add pilot argument

* Add Pilot interface

* Add pilot argument

* Update interface.py

* Parse Different gear on pilot

* Add steer max

* Fixed duplication of steer max value

* Adjust PID's for steering

* Update carcontroller.py

* Change Steer Ratio and wheelbase

* Update Steer fault values

Steer fault value of 3, does not seem to effect anything

* Update Kp,Ki Ratio

* Update interface.py

* Update readme for Pilot

* add pilot

* Update fingerprints.py

* Update carstate.py

* add signals

* add signal

* fix restricting video upload to wifi

* Dibs on SAFETY_GM numerical value

To match Panda repo.

* Safety Reference for Honda Bosch

* Update fingerprints.py (#210)

Consolidated my fingerprint and removed duplicates and ordered the fingerprint for the RAV4H. Double Checked.

* Interpolate ki/kp for steering PID loop (#200)

* Interpolate ki/kp for steering PID loop

Very much needed for the Volt port: car ping-pongs with low kp
on high speeeds, and the loop is unstable with high kp on
low speeds.

Also, removes "number or array?" logic from PIController,
now that all the callers use interpolation ofr ki/kp.

* Pass speed to steering PID loop for ki/kp interpolation

* Remove unused numbers import

* Slight changes to UI and Fingerprint for Odyssey Elite (#196)

* Adding back drive time to UI

* Add fingerprint for Odyssey Elite

* Removed extended fingerprint for Elite

* Revert "Adding back drive time to UI"

This reverts commit b9b02f7ff2511f28922f0bea47cd8c70bb9f4010.

* Squashed 'panda/' changes from 98f29a4..67d5208

67d5208 fix signedness issue in toyota safety
fe15d3f bump pandacan
11c2b08 add fault invalid
2c26e45 add sleep
27c7637 forgot the counter
3a6d7db don't hang
bfa7d2e canloader works
b259e2a can flasher is close to working
83f2edf isotp can support in softloader
7ae7c79 typo
e85cc47 forgot the selfs
190b4f6 start work on canflasher
5c655c9 add recover support
ae3457f usbflash is reliable
f7a0ab0 pedal usbflash works
585d0f9 add way to call isotp
be82899 despite it being bad code, move isotp
000715b start work on pedal canloader
626e312 pedal has a bootstub now
3662d1e redundant check
81e6b0d fix bug
083cd12 should have bounty to refactor that ish
b65d30c bad asserts
b2e6c3f isotp untested support for subaddr
30fd66a Merge pull request #93 from vntarasov/volt
06f5109 Merge pull request #94 from gregjhogan/can-printer-hex
c7d098c Merge pull request #95 from gregjhogan/setup-script
22fe250 Merge pull request #99 from gregjhogan/bit-transition-example
ba16ba3 Merge pull request #100 from gregjhogan/j2534-troubleshooting-instructions
ad08ea4 Merge pull request #90 from gregjhogan/can-forwarding
f3b6f5d added j2534 troubleshooting instructions
858d150 added script to find bits that transition from 0 to 1
c6acac8 added checking pedal interceptor message length
f7226ff added brake safety checks
d0c2634 added gas safety checks
d378e4a removed bosch safety forwarding restriction on 29 bit addresses
5c7ef9e added bosch safety hooks and forwarding
90c64b6 add note
23de8d4 Merge pull request #97 from commaai/pedal_improvements
0261641 added missing python packages
b92b235 fix bytearray encode issue
2434f1c Tweak Volt's brake pedal stickiness
e2f73d2 enable has a whole byte to itself
d5a9e1e correct checksum
f8ed9fa better names
986a14c don't alias pointers
9b8472e add watchdog support
8f0add9 handle faults
1d917f8 split gas set into 2 values, and have a fault state
1b77026 j2534 isn't alpha anymore
fbcc872 Merge pull request #92 from commaai/pedal
8a6f44b pedal is sending messages
08f464c python 3 bro is bad bro
9390961 kline checksum algo was broken...
3b7c33b add kline debug support
aa622bc init values
631ea9f better refactor
eb1fd75 add PEDAL adc sets
ccaa310 don't build with usb
8d4d763 debug console works
bd09883 comma pedal is building
75a29d5 Merge pull request #84 from gregjhogan/j2534-hds
eece37d only the panda has gmlan
9f43abe Merge pull request #89 from vntarasov/volt
5364d43 Merge pull request #88 from vntarasov/smaller-firmware
377a1ec bump version for descriptor fix
4fabdf0 Merge pull request #87 from gregjhogan/usb-multi-packet-control
8580773 fix sending WinUSB Extended Properties Feature Descriptor
6908feb Chevy Volt safety
786a004 Enable optimization to reduce firmware size
d70f43b hack to fix thinkpad
95ab1ae fixed flow control message padding
bbd04d1 updated installer
62216d0 single standalone DLL for J2534 driver
5c9138d fixed 11 bit address issue
f3b0ad2 fix LOOPBACK getting set when DATA_RATE is set
b750d36 updated README
a9a097f lowered CPU utilization
7c26a70 TIS needs unsupported protocols to return an error
42692b4 TIS doesn't like ChannelID being zero
cf126bb SET_CONFIG return error for reserved parameters
2e99dbf fix HDS issues
8203cc8 add is_grey
e946a54 add insecure_okay flag
4363b3e check webpage
4f59ded add secure mode note
6b11fb5 add autosecuring to tests
b27d185 Merge pull request #86 from commaai/better_pairing
4b53b42 elm wifi isn't an automated test
99f85cb Merge pull request #85 from gregjhogan/usb-wcid
0d38060 auto-install WinUSB device driver
c6653ca from python import
38cc0ee add wifi_secure_mode, boots in insecure mode

git-subtree-dir: panda
git-subtree-split: 67d52089a1300b86800d897f2b271e0a24cf6dd6

* Squashed 'opendbc/' changes from 81d9871..aa067f7

aa067f7 Chevy Volt tweaks (#83)
a60c6c4 Toyota: change signal name in EPS_STATUS msg
ce70b1a extra setme field toyota LKAS_HUD
df2a552 toyota missing ACC_CONTROL checksum
48bb293 Revert "Toyota Prius: added a comma specific message to control the speed sent to the EPS"
5f42439 Toyota Prius: added a comma specific message to control the speed sent to the EPS
6f5e8b6 Pedal Interceptor: fault state VAL moved to _comma
efd5f5c add setme to honda ACC_HUD
97fc335 add interceptor to civic
6f40f16 update generator script to allow for multiple imports
9ca956b add setme to toyota STEERING_IPAS
e5afa57 run generator for ipas scaling
8bd1182 Toyota IPAS: proper steer angle unit
f57511e acceleration pedal for gasPressed
c8d1dbc high beams also. likely dashboard message.
9f1c78b high beams for genericToggle
f037d42 turn signal lights (and thus hazard lights)
b35bb08 turn signals
78986cf Revert "turn signals"
ba946c9 turn signals
2af3ecc Speed, braking, and distance signals
f40ab87 Set packet lengths, adding steering rate, adjusted speed
cd59bfa units for speed_right
c2fcce2 speed of right vs left side of car
4ef5fae value table for gear status
97c48e2 tighten up speed bits. brake pressue max comment.
a0cbfd1 add gear status PRNDL
0c82865 initial signals for chrysler pacifica 2017 hybrid
5ed0540 add set me to toyota LKAS_HUD
aecac5d add set me fields to toyota ACC_HUD
5417013 update toyota ACC_CONTROL fields
e91e967 Comma Pedal: made GAS_COMMAND 6 bytes
d04434a Comma Pedal: added state byte and enable bit
c30b2cd Comma Pedal: sending 2 tracks on 0x200
8f72467 Volt doors and belts status (#70)
60f8b6c add set me to lkas hud honda
3c9e335 fix honda pcm gas message size
7ca471d Add 2018 Toyota CHR dbc (#78)
637fe00 set scaling to 1 for brake and gas which have no real unit
62a88d4 Volt: switch to parsing ACC buttons from powertrain CAN (#74)
3fdd47b Volt's gas pedal only and combined gas/acc (#76)
45ec9c9 Add 2017 Honda Ridgeline (#77)
cbd186a Add 2018 Camry Hybrid DBC's (#73)
974eeaf Toyota: re-generated the files after cfbc9ae363f98ef
19ea195 Toyota: more vals for LKA_STATE
cfbc9ae fixed inconsistent factor for speed in Honda dbc files
e7db803 convert all line endings to unix style

git-subtree-dir: opendbc
git-subtree-split: aa067f7079aa12617f7a37d85233e51af44e1bb2

* openpilot v0.4.3 release

* Squashed 'panda/' changes from 67d5208..3125232

3125232 bump version
703c0b4 Gas Interceptor: another fix to gas pressed logic
196d383 Interceptor: fixed gas pressed logic

git-subtree-dir: panda
git-subtree-split: 31252324d98e701c33cb6aeda20af6b549175764

* Squashed 'opendbc/' changes from aa067f7..91e882d

91e882d Updating bosch dbcs to use new format and bringing in new honda changes (#82)
9b32e2e Fix Checksum errors for CH-R (#86)

git-subtree-dir: opendbc
git-subtree-split: 91e882d4a04c129e12d39bcff0bbe56b75166e0f

* openpilot v0.4.3 release

* openpilot v0.4.3.1 release

* fix bug in canpacker for Toyotas with DSU connected (#221)

* update year on civic
2018-03-22 22:11:57 -07:00
George Hotz affc00df1f Merge pull request #188 from commaai/devel
0.4.2
2018-02-08 17:09:41 -08:00
ErichMoraga e343c95720 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:11:35 -08:00
George Hotz 89605ed88a Merge pull request #184 from commaai/devel
openpilot v0.4.1 hotfix
2018-02-02 19:46:57 -08:00
George Hotz 10cb834c39 Merge pull request #183 from commaai/devel
openpilot v0.4.1
2018-02-02 15:51:53 -08:00
George Hotz 675d9feb0b Merge pull request #176 from commaai/devel
openpilot v0.4.0.2
2018-01-22 09:55:06 -08:00
espes c2e120c362 Merge pull request #165 from commaai/devel
openpilot v0.4.0.1
2018-01-17 01:08:47 -08:00
George Hotz 5ae7119646 Merge pull request #154 from commaai/devel
openpilot v0.3.9
2017-12-07 19:22:41 -08:00
espes 5864323c7d Merge pull request #146 from commaai/devel
openpilot v0.3.8.2
2017-11-04 05:32:49 -07:00
espes 577608be57 Merge pull request #137 from commaai/devel
openpilot v0.3.7
2017-10-04 03:51:03 -07:00
espes 606c21bca4 Merge pull request #126 from commaai/devel
openpilot v0.3.6.1
2017-08-17 08:59:30 +02:00
espes cd25fac75d Merge pull request #123 from commaai/devel
openpilot v0.3.6
2017-08-11 09:00:23 +02:00
espes b111277f46 Merge pull request #121 from commaai/devel
openpilot v0.3.5 release
2017-07-31 09:02:27 +02:00
espes 0fba33b093 Merge pull request #120 from commaai/devel
openpilot 0.3.4
2017-07-29 07:41:31 +02:00
2561 changed files with 217619 additions and 421535 deletions
-25
View File
@@ -1,25 +0,0 @@
---
name: Bug report
about: Create a report to help us improve openpilot
title: ''
labels: 'bug'
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**How to reproduce or log data**
Steps to reproduce the behavior, or a explorer/cabana link to the exact drive and timestamp of when the bug occurred.
**Expected behavior**
A clear and concise description of what you expected to happen.
**Device/Version information (please complete the following information):**
- Device: [e.g. EON/EON Gold]
- Version: [e.g. 0.6.4], or commit hash when on devel
- Car make/model [e.g. Toyota Prius 2016]
**Additional context**
Add any other context about the problem here.
-21
View File
@@ -1,21 +0,0 @@
Choose one of the templates below:
# Fingerprint
This pull requests adds a fingerprint for <Make - Model - Year - Trim>.
This is an explorer link to a drive with the stock system enabled: ...
# Car support
This pull requests adds support for <Make - Model - Year - Trim>.
This is an explorer link to a drive with the stock system enabled: ...
This is an explorer link to a drive with openpilot system enabled: ...
# Feature
This pull requests adds feature X
## Description
Explain what the feature does
## Testing
Explain how the feature was tested. Either by the added unit tests, or what tests were performed while driving.
+4 -31
View File
@@ -1,16 +1,11 @@
venv/
.DS_Store
.tags
.ipynb_checkpoints
.idea
.overlay_init
.overlay_consistent
.sconsign.dblite
.vscode
model2.png
a.out
*.dylib
*.DSYM
*.d
*.pyc
@@ -18,11 +13,7 @@ a.out
.*.swp
.*.swo
.*.un~
*.tmp
*.o
*.o-*
*.os
*.os-*
*.so
*.a
*.clb
@@ -32,31 +23,13 @@ a.out
config.json
clcache
persist
board/obj/
selfdrive/boardd/boardd
selfdrive/logcatd/logcatd
selfdrive/mapd/default_speeds_by_region.json
selfdrive/proclogd/proclogd
selfdrive/ui/_ui
selfdrive/test/longitudinal_maneuvers/out
selfdrive/visiond/visiond
selfdrive/loggerd/loggerd
selfdrive/sensord/_gpsd
selfdrive/sensord/_sensord
selfdrive/camerad/camerad
selfdrive/modeld/_modeld
selfdrive/modeld/_dmonitoringmodeld
selfdrive/logcatd/logcatd
selfdrive/proclogd/proclogd
selfdrive/ui/ui
selfdrive/test/tests/plant/out
/src/
one
openpilot
notebooks
xx
panda_jungle
.coverage*
coverage.xml
htmlcov
pandaextra
+12
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'
-436
View File
@@ -1,436 +0,0 @@
dragonpilot 0.7.5.4
========================
* 加入 2018 skoda kodiaq 指紋v1。(感謝 @Gold 提供)
* Added 2018 skoda kodiaq FPv1. (Thanks to @Gold)
* 移除方向盤監控設定。(無法取消/關閉方向盤監控)
* Removed Steering monitor timer adjustment in code (timer in settings will no longer work.)
* Dynamic Follow 更新模型。(感謝 @ShaneSmiskol 提供代碼、 @cgw1968 測試)
* Updated Dynamic Follow model. (Special Thanks to @ShaneSmiskol for the feature and @cgw1968 for testing)
dragonpilot 0.7.5.3
========================
* Dynamic Follow 更新至 ShaneSmiskol:stock_additions 0.7.5 版。(感謝 @ShaneSmiskol 提供代碼、 @Wei 測試)
* Updated Dynamic Follow to ShaneSmiskol:stock_additions 0.7.5. (Special Thanks to @ShaneSmiskol for the feature and @Wei for testing)
* 優化 Lexus GSH 轉向。(感謝 @簡銘佑 測試)
* Optimize Lexus GSH steering. (Thanks to @簡銘佑)
* C2 支援自動關機「DragonAutoShutdownAt」參數。(感謝 @cgw1968 建議)
* C2 to support auto shutdown "DragonAutoShutDownAt" param. (Thanks to @cgw1968)
* 修正出現「pedalPressed」的錯誤。(感謝 @Wei 回報)
* Fixed issue showing "pedalPressed" error. (Thanks to @Wei)
* 將剎車狀熊顯示於 dp 資訊欄。
* Added brake indicator to dp infobar.
* 修正「溫度監控」燈示。
* Fixed "Temp monitor" indicator.
* 加入「方向燈取消控制」延遲控制設。(感謝 @wabes 建議)
* Added delay config to "Disable Lat Control on Blinker". (Thanks to @wabes)
* 加入巴西版 2020 Corolla Hybrid 指紋v2。(感謝 @berno22 提供)
* Added Brazil 2020 Corolla Hybrid FPv2. (Thanks to @berno22)
dragonpilot 0.7.5.2
========================
* 加入對 VW MQB/PQ 的支援。(感謝 @dingliangxue 移植)
* Added support to VW MQB/PQ platform. (Thanks to @dingliangxue)
* 修改成 3 小時後停止供電。(感謝 @Wei 建議)
* Updated to stop charging after 3 hrs. (Thanks to @Wei)
* 移除行車記錄下的「碰撞偵測」功能。
* Removed Impact Detection in Dashcam.
* 修正開啟「Noctua 風扇」模式導致的錯誤。(感謝 @阿濤 回報)
* Fixed a bug caused by enabling "Noctua Mod". (Thanks to @阿濤)
* 修正「位智模式」無法顯示警示的問題。(感謝 @axandres 回報)
* Fixed alert issue in waze mode. (Thanks to @axandres)
* 修正無法顯示更新中圖示的問題。
* Fixed unable to display "UPDATING" icon issue.
* 加入「允許多次自動換道」功能。(感謝 @阿濤 建議)
* Added "Allow Continuous Auto Lane Change" Toggle. (Thanks to @阿濤)
* 修正開機後設定頁面有時會錯誤的問題。(感謝 @salmankhan@Wei 回報)
* Fixed setting page crash issue. (Thanks to @salmankhan, @Wei)
* 修正熄火後一直出現更新訊息的錯誤。(感謝 @Sky Chang 回報)
* Fixed issue that keep showing update prompt. (Thanks to @Sky Chang)
dragonpilot 0.7.5.1
========================
* 修正因同時使用「社群功能」和「自定車型」造成的加減速問題。(特別感謝 @Wei@Sky Chang、@Han9365@鄧育林 的測試以及回報。)
* Fixed acceleration issue caused by used of both "Community Maintain Feature" and "Custom Car Model". (Special Thanks to @Wei, @Sky Chang, @Han9365, @鄧育林)
* 新增 DragonMaxSpeedLimit 設定值 (mph),當如果車速高於此值 op 將會停止操控。(感謝 @Anthony 建議)
* Added DragonMaxSpeedLimit parameter (mph), op will stop controlling when car speed is high than the value. (Thanks to @Anthony)
* 更新 appd 使用 cnpmjs 來下載 APKs。
* Updated appd to use cnpmjs to download APKs.
* 修正更新服務。(感謝 @Wei)
* Fixed Update Service. (Thanks to @Wei)
* 新增加拿大版 2018 Toyota Sienna LTD 指紋(v2)。(感謝 明峰 提供)
* Added Canada 2018 Toyota Sienna LTD fingerprint (v2). (Thanks to 明峰)
* 新增「通過移動網路上傳」開關
* Added Upload Over Mobile Network toggle.
* 新增「通過熱點上傳」開關
* Added Upload Over Hotspot toggle.
* 新增加拿大版 2018 Toyota Sienna LTD 指紋(v1)。(感謝 明峰 提供)
* Added Canada 2018 Toyota Sienna LTD fingerprint (v1). (Thanks to 明峰)
* 新增大陸版 Volkswagen Golf GTI 指紋 (v1)。(感謝 easyeiji 提供)
* Added China Volkswagen Golf GTI fingerprint (v1). (Thanks to easyeiji)
dragonpilot 0.7.5.0
========================
* 基於最新 openpilot 0.7.5 devel-staging.
* Based on latest openpilot 0.7.5 devel-staging.
* 更新 dp 圖示 (特別感謝 @wabes 的設計與提供)。
* Updated dp logo, special thanks to @wabes for the design.
* 簡/繁中文版和 i18n 整合成為單一版本。
* Merged zhs/zht/i18n versions into one.
* 新增大陸版 CAMRY HYBRID 指紋v2。(感謝 @杜子腾)
* Added China Camery Hybrid FPv2. (Thanks to @杜子腾)
* 新增台灣版 Altis HYBRID 指紋v1。(感謝 @Fish)
* Added Taiwan Altis Hybrid FPv1. (Thanks to @Fish)
* 新增行駛時關閉畫面功能。
* Added Screen off while driving feature.
* 新增倒車時關閉畫面功能。
* Added Screen off while reversing feature.
* 新增駕駛介面加入「加速模式」切換鈕。
* Added acceleration profile toggle onto driving UI.
* 新增自定車型功能,取代指紋暫存功能。
* Replaced fingerprint cache with custom car model selector.
* 新增可調亮度。
* Added Brightness changer.
* 新增部分德語支持。(特別感謝 @arne182 提供)
* Added partial de_DE language support (Thanks to @arne182)
* 新增停車碰撞偵測記錄功能。
* Added off road impact detection to dashcam.
2020-05-06
========================
* 更新 dp 圖示 (特別感謝 @wabes 的設計與提供)。
* 中文版整合進 i18n 版。
* 刪除指紋暫存功能。
* 新增 CAMERY HIBRID 指紋。(感謝 @杜子腾)
* 新增行駛時關閉畫面功能。
* 新增倒車時關閉畫面功能。
* 新增駕駛介面加入「加速模式」切換鈕。
* 新增自定義車型。
2020-04-16
========================
* [DEVEL] 加入台灣版 2016 Lexus IS200t 指紋。(感謝 Philip / Cody Dai)
* [DEVEL] 加入台灣版 2016 Toyota Prius 4.5 代指紋。(感謝 Philip)
* [DEVEL] 加入台灣版 201x Toyota RAV4 4WD 指紋。(感謝 Philip)
* [DEVEL] 加入台灣版 2020 Toyota Auris w/ LTA 指紋。(感謝 Philip)
* [DEVEL] 修正 commIssue 錯誤。(感謝 Kent 協助)
2020-04-13
========================
* [DEVEL] 加入可調整 Toyota Sng 起步反應值 (DragonToyotaSngResponse)。 (特別感謝 @Wei 提供 PR)
* [DEVEL] 駕駛介面加入「動態調整車距」按鈕。(感謝 @cgw1968-5779 建議)
* [DEVEL] 更新 update script。(感謝 深鯨希西 回報)
2020-04-10
========================
* [DEVEL] 更新 panda 至最新的 comma:master 分支。
* [DEVEL] 移除所有的第三方應用改為自動下載。
* [DEVEL] 移除「啟用原廠 DSU 模式」、「安全帶檢查」、「車門檢查」開關。
2020-03-31
========================
* [DEVEL] 更新至 2020-03-31 testing 分支。
2020-03-27
========================
* [DEVEL] 更新至最新的 testing 分支:
* 加入波蘭版 2015 Lexus NX200T 支援。(感謝 wabes 提供)
* 調整「啟用原廠 DSU 模式」為不再需要 AHB 。(Enable Stock DSU Mode no longer requires "AHB" toggle)
* 加入「安全帶檢查」、「車門檢查」、「檔位檢查」、「溫度檢查」開關。
* 加入曲率學習功能 - Curvature Learner 。(感謝 zorrobyte 提供)
* 加入大陸版 2018 Toyota Highlander 支援。(感謝 toyboxZ 提供)
* 加入大陸版 2018 Toyota Camry 2.0 支援。(感謝 Rming 提供)
* 加入韓文支持。(感謝 crwusiz 提供)
* 調整 OFFROAD 主頁翻譯將 "dragonpilot" 改回 "openpilot"。
2020-03-22
========================
* [DEVEL] 更新至最新的 testing 分支。
2020-03-17
========================
* [DEVEL] 更新至最新的 testing 分支 (commaai:devel-staging 0.7.4)。
* [DEVEL] 加入動態調整車距功能。(特別感謝 @ShaneSmiskol 提供 PR)
2020-03-14
========================
* [DEVEL] 更新 pt-Br (葡萄牙語) 翻譯。(感謝 berno22 提供)
* [DEVEL] 加入自動關機開關。(感謝 Rzxd 建議)
* [DEVEL] 調高 Toyota 扭力容錯值。
* [DEVEL] 優化讀取 dp 設定值。
* [DEVEL] 加入 2019 手動 Civic 指紋。感謝 (AlexNoop 提供)
* [DEVEL] dp 功能加入對 Subaru 車系的支援。
2020-03-06
========================
* [DEVEL] 加入葡萄牙語支持。(感謝 berno22 提供)
* [DEVEL] 加入大陸 2018 Camry、2020 RAV4 指紋。(感謝 笨木匠 提供)
* [DEVEL] 建立 devel-i18n 取代 devel-en。
* [DEVEL] devel-en is deprecated, please switch to devel-i18n instead.
2020-03-04
========================
* [DEVEL] 加入顯示駕駛監控畫面。
* [DEVEL] 加入加速模式選項。(特別感謝 @arne182, @cgw1968-5779 提供 PR)
* [DEVEL] 修正 shutdownd 在 comma two 可能會不正常關機的錯誤。(感謝 @Wei, @Rzxd 回報)
2020-02-25
========================
* [DEVEL] 更新至最新的 commaai:devel (0.7.3)。
2020-02-21
========================
* [DEVEL] 更新至最新的 commaai:devel (0.7.3)。
2020-02-14
========================
* [DEVEL] 更新至最新的 commaai:devel (0.7.2)。
* [DEVEL] 修正錯誤。
2020-02-08
========================
* [DEVEL] 更新至最新的 commaai:devel (0.7.2)。
* [DEVEL] dp 功能加入對現代 (Hyundai) 車系的支援。
* [DEVEL] 加入神盾測速照相自動啟動的開關。
* [DEVEL] 更新高德地圖至 v4.5.0.600053。
* [DEVEL] 使用 0.6.6 版的更新系統。
* [DEVEL] 修正急剎問題。(感謝 kumar 提供)
2020-01-31
========================
* [DEVEL] 移除行車介面電量、溫度顯示,(修正畫面當機、黑屏問題)
2020-01-29
========================
* [DEVEL] 修正行車介面錯誤。(感謝 深鲸希西 測試;eisenheim、HeatNation 反應)
2020-01-23
========================
* [DEVEL] 加入 Steer Ratio Learner 關閉。(感謝 eisenheim 建議)
* [DEVEL] 行車介面加入電量、溫度。(感謝 eisenheim 建議)
* [DEVEL] 優化 appd。
2020-01-19
========================
* [DEVEL] 更新至最新的 commaai:devel (0.7.1)。
* [DEVEL] 調整 appd 和 ALC 邏輯。
2020-01-14
========================
* [DEVEL] 加入開機啟動個人熱點。(感謝 eisenheim 建議)
2020-01-08
========================
* [DEVEL] 加入大陸版 2018 Lexus RX300 支援。(感謝 cafe 提供)
* [DEVEL] 加入 DragonBTG 設定。(感謝 CloudJ、低調哥、歐姓Altis車主 提供)
2019-12-31
========================
* [DEVEL-ZHS] 加回第三方應用。
2019-12-29
========================
* [DEVEL] 更新至最新的 commaai:devel (0.7.0)。
* [DEVEL] 輔助/自動變道改為可調整參數 (進階用戶)。(DragonAssistedLCMinMPH、DragonAutoLCMinMPH、DragonAutoLCDelay)
* [DEVEL-ZHS] 修正無法運行第三方應用錯誤。(感謝 深鲸希西 反應)
2019-12-18
========================
* [DEVEL] 修正自動換道邏輯。
* [DEVEL] 更新 offroad 翻譯。
* [DEVEL] 錯誤修正。
* [DEVEL] 移除美版 2017 Civic Hatchback 指紋。(與其它車型衝突)
2019-12-17
========================
* [DEVEL] 更新至最新的 commaai:devel (0.7.0)。
* [DEVEL] 加入輔助換道開關。(24mph / 40kph 以上)
* [DEVEL] 加入自動換道開關。(40mph / 65kph 以上)
* [DEVEL] 加入大陸版 2019 雷凌汽油版指紋。 (感謝 Shell 提供)
* [DEVEL] 加入大陸版 2019 卡羅拉汽油版指紋。 (感謝 Shell 提供)
* [DEVEL] 加入美版 2017 Civic Hatchback 指紋。(感謝 CFranHonda 提供)
2019-12-10
========================
* [DEVEL] 加入位智車機模式。 (Waze Mode)
2019-11-21
========================
* [DEVEL] 修正 offroad 翻譯。(感謝 鄧育林 回報)
* [DEVEL] 調整前車靜止移動偵測參數。
* [DEVEL] 前車靜止移動偵測可在未啟用 dp 時運作。
2019-11-18
========================
* [DEVEL] 修正 offroad 翻譯。(感謝 Cody、鄧育林 回報)
2019-11-18
========================
* [DEVEL] 修正 frame 翻譯。
2019-11-15
========================
* [DEVEL] 修正不會充電的錯誤。 (感謝 袁昊 反應)
2019-11-15
========================
* [DEVEL] 修正充電控制。 (感謝 KT 反應)
* [DEVEL] 更新 frame 翻譯,改為多語言版。 (感謝 深鲸希西、shaoching885、鄧育林 反應)
* [DEVEL] 更新至最新的 commaai:devel (0.6.6)。
2019-11-12
========================
* [DEVEL] 只顯示電量文字 (注意:有時不會更新,需要拔插 USB 線)
* [DEVEL] 自動偵測並鎖定硬體 (EON / UNO)。
2019-11-12
========================
* [DEVEL] 加入鎖定硬體 (EON / UNO) 的程式碼。
2019-11-11
========================
* [DEVEL] 更新高德地圖至 v4.3.0.600310 R2098NSLAE
* [DEVEL] 更新 MiXplorer 至 v6.40.3
* [DEVEL] 更新至最新的 commaai:devel (0.6.6)。
* [DEVEL] 前車靜止移動偵測加入偵測警示。
2019-11-07
========================
* [DEVEL] 讓 Bosch 系統顯示三角。 (感謝 ching885 回報)
* [DEVEL] 更新 offroad 多語言版簡體中文翻譯 (感謝 Rming 提供)
2019-11-06
========================
* [DEVEL] 修正 0.6.6 appd 和 dashcamd 錯誤。 (感謝 鄧育林 回報)
* [DEVEL] 更新至最新的 commaai:devel (0.6.6)。
2019-11-05
========================
* [DEVEL] 加入台灣 Lexus 2017 GS450h 支援。 (感謝 簡銘佑 提供指紋)
2019-11-01
========================
* [DEVEL] 新增神盾測速照相。 (感謝 Sky Chang 和 Wei Yi Chen)
* [DEVEL] 修正 offroad 翻譯。 (感謝 Leo Hsieh)
2019-11-01
========================
* [DEVEL] 移除 Miui 字型,縮小 dp 使用空間。
* [DEVEL] 更新 offroad 為多語言版
* [DEVEL] 更新至最新的 commaai:devel (0.6.5)。
2019-10-29
========================
* [DEVEL] 加入 SnG 補丁。(感謝 楊雅智)
2019-10-28
========================
* [DEVEL] 更新至最新的 commaai:devel (0.6.5)。
* [DEVEL] 調整 dragon_allow_gas 邏輯 (請回報任何問題,需更新 Panda 韌體)
2019-10-18
========================
* [DEVEL] 加入前車靜止移動偵測。(測試版,感謝 ucolchen)
* [DEVEL] 移除強迫網路連線提示。(感謝 Shell)
* [DEVEL] 修正 allow_gas 功能。
2019-10-18
========================
* [DEVEL] 加入彎道減速功能開關。
* [DEVEL] 強迫使用 dp 版 Panda 韌體。
* [DEVEL] 更新至最新的 commaai:devel (0.6.5)。
2019-10-17
========================
* [DEVEL] 加入「車型」顯示於 dp 設定畫面。
* [DEVEL] 修正充電控制讀取預設值的錯誤。
* [DEVEL] 修正無法顯示更新記錄的錯誤。
2019-10-16
========================
* [DEVEL] 刷新 Panda 韌體按鈕將會自動重啟 EON。(感謝 鄧育林 建議)
* [DEVEL] 下載更新記錄時使用 "no-cache" 標頭。
* [DEVEL] 更新高德地圖至 v4.3.0
* [DEVEL] 刪除 bs (Branch Switcher)
2019-10-14
========================
* [DEVEL] 啟用自動更新功能。(感謝 鄧育林 提供)
* [DEVEL] 清除不再使用的 dp params。
* [DEVEL] 加入數字電量指示。(感謝 鄧育林 建議)
* [DEVEL] 加入刷新 Panda 韌體按鈕。
2019-10-11
========================
* [DEVEL] 更新至最新的 commaai:devel (0.6.5)。
* [DEVEL] 加入台灣 2019 RAV4 汽油版指紋。 (感謝 Max Duan / CloudJ 提供)
2019-10-09
========================
* [DEVEL] 加入當 LatCtrl 關閉時,畫面顯示提示訊息。
2019-10-08
========================
* [DEVEL] 加回駕駛監控開關。
* [DEVEL] 加入 bs (branch switcher) 程式。
2019-10-07
========================
* [DEVEL] 加入台灣版 2019 RAV4H 油電版指紋。(感謝 Max Duan 提供)
2019-10-05
========================
* [DEVEL] 移除 curvature learner: 轉角明顯比原廠小。
* [DEVEL] 更新至最新的 commaai:devel (0.6.4)。
2019-09-30
========================
* [DEVEL] 更新 curvature learner 版本至 v4。
* [DEVEL] Lexus ISH 使用更精確的 EPS Steering Angle Sensor
2019-09-27
========================
* [DEVEL] 加入 Zorrobyte 的 curvature learner (https://github.com/zorrobyte/openpilot)
* [DEVEL] 加入可開關駕駛監控的程式碼。
* [DEVEL] 取消當 steering 出現錯誤時,自動切斷方向控制 2 秒的機制。
* [DEVEL] 讓行車介面的「方向盤」/「轉彎」圖示半透明化。
2019-09-26
========================
* [DEVEL] 修正當「啟用記錄服務」關閉時,make 會有問題的錯誤。 (感謝 shaoching885 和 afa 回報)
2019-09-24
========================
* [DEVEL] 行車介面加入可開關的「前車」、「路線」、「車道」設定。
* [DEVEL] 行車介面加入可開關的「方向燈號」提示。 (感謝 CloudJ 建議,程式碼來源: https://github.com/kegman/openpilot)
2019-09-23
========================
* [DEVEL] 優化讀取 params 的次數。
* [DEVEL] 加入可開關的車道偏移警示。
* [DEVEL] 修正充電控制邏輯。
* [DEVEL] 加入台灣 Prius 4.5 指紋。 (感謝 Lin Hsin Hung 提供)
2019-09-20
========================
* [DEVEL] 加入充電控制功能。 (感謝 loveloveses 和 KT 建議)
2019-09-16
========================
* [DEVEL] 加入台灣 CT200h 指紋。 (感謝 CloudJ 提供)
* [DEVEL] 加入美版 CT200h 移植。 (感謝 thomaspich 提供)
2019-09-13
========================
* [DEVEL] 行車介面加入可開關的「速度顯示」設定。
2019-09-09
========================
* [DEVEL] 加入 GreyPanda 模式。
2019-08-28
========================
* [DEVEL] 加入可調警示音量。
2019-08-27
========================
* [DEVEL] 自動關機改為可調時長。
-195
View File
@@ -1,195 +0,0 @@
dragonpilot 0.7.5
========================
* 移除方向盤監控設定。(無法取消/關閉方向盤監控)
* Removed Steering monitor timer adjustment in code (timer in settings will no longer work.)
* 優化 Lexus GSH 轉向。(感謝 @簡銘佑 測試)
* Optimize Lexus GSH steering. (Thanks to @簡銘佑)
* C2 支援自動關機「DragonAutoShutdownAt」參數。(感謝 @cgw1968 建議)
* C2 to support auto shutdown "DragonAutoShutDownAt" param. (Thanks to @cgw1968)
* 將剎車狀熊顯示於 dp 資訊欄。
* Added brake indicator to dp infobar.
* 加入「方向燈取消控制」延遲控制設。(感謝 @wabes 建議)
* Added delay config to "Disable Lat Control on Blinker". (Thanks to @wabes)
* 加入巴西版 2020 Corolla Hybrid 指紋v2。(感謝 @berno22 提供)
* Added Brazil 2020 Corolla Hybrid FPv2. (Thanks to @berno22)
* 加入對 VW MQB/PQ 的支援。(感謝 @dingliangxue 移植)
* Added support to VW MQB/PQ platform. (Thanks to @dingliangxue)
* 加入「允許多次自動換道」功能。(感謝 @阿濤 建議)
* Added "Allow Continuous Auto Lane Change" Toggle. (Thanks to @阿濤)
* 新增 DragonMaxSpeedLimit 設定值 (mph),當如果車速高於此值 op 將會停止操控。(感謝 @Anthony 建議)
* Added DragonMaxSpeedLimit parameter (mph), op will stop controlling when car speed is high than the value. (Thanks to @Anthony)
* 新增加拿大版 2018 Toyota Sienna LTD 指紋(v2)。(感謝 明峰 提供)
* Added Canada 2018 Toyota Sienna LTD fingerprint (v2). (Thanks to 明峰)
* 新增「通過移動網路上傳」開關
* Added Upload Over Mobile Network toggle.
* 新增「通過熱點上傳」開關
* Added Upload Over Hotspot toggle.
* 新增加拿大版 2018 Toyota Sienna LTD 指紋(v1)。(感謝 明峰 提供)
* Added Canada 2018 Toyota Sienna LTD fingerprint (v1). (Thanks to 明峰)
* 新增大陸版 Volkswagen Golf GTI 指紋 (v1)。(感謝 easyeiji 提供)
* Added China Volkswagen Golf GTI fingerprint (v1). (Thanks to easyeiji)
* 更新 dp 圖示 (特別感謝 @wabes 的設計與提供)。
* Updated dp logo, special thanks to @wabes for the design.
* 簡/繁中文版和 i18n 整合成為單一版本。
* Merged zhs/zht/i18n versions into one.
* 新增大陸版 CAMRY HYBRID 指紋v2。(感謝 @杜子腾)
* Added China Camery Hybrid FPv2. (Thanks to @杜子腾)
* 新增台灣版 Altis HYBRID 指紋v1。(感謝 @Fish)
* Added Taiwan Altis Hybrid FPv1. (Thanks to @Fish)
* 新增行駛時關閉畫面功能。
* Added Screen off while driving feature.
* 新增倒車時關閉畫面功能。
* Added Screen off while reversing feature.
* 新增駕駛介面加入「加速模式」切換鈕。
* Added acceleration profile toggle onto driving UI.
* 新增自定車型功能,取代指紋暫存功能。
* Replaced fingerprint cache with custom car model selector.
* 新增可調亮度。
* Added Brightness changer.
* 新增部分德語支持。(特別感謝 @arne182 提供)
* Added partial de_DE language support (Thanks to @arne182)
dragonpilot 0.7.4
========================
* [2020-04-10] 移除所有的第三方應用改為自動下載。
* [2020-04-10] 移除「啟用原廠 DSU 模式」、「安全帶檢查」、「車門檢查」開關。
* [2020-03-31] 還原部分修改代碼以達到 comma ai 安全準則。 (Reverted changes to panda safety code to comply with comma ai safety guideline.)
* [2020-03-31] 調整「啟用原廠 DSU 模式」為踩剎車時會暫時斷開控制 。(Enable Stock DSU Mode will temporary disable controls when brake is pressed.)
* [2020-03-27] 加入波蘭版 2015 Lexus NX200T 支援。(感謝 wabes 提供)
* [2020-03-27] 調整「啟用原廠 DSU 模式」為不再需要 AHB 。(Enable Stock DSU Mode no longer requires "AHB" toggle)
* [2020-03-27] 加入「安全帶檢查」、「車門檢查」、「檔位檢查」、「溫度檢查」開關。
* [2020-03-27] 加入曲率學習功能 - Curvature Learner 。(感謝 zorrobyte 提供)
* [2020-03-27] 加入大陸版 2018 Toyota Highlander 支援。(感謝 toyboxZ 提供)
* [2020-03-27] 加入大陸版 2018 Toyota Camry 2.0 支援。(感謝 Rming 提供)
* [2020-03-27] 加入韓文支持。(感謝 crwusiz 提供)
* [2020-03-27] 調整 OFFROAD 主頁翻譯將 "dragonpilot" 改回 "openpilot"。
dragonpilot 0.7.3
========================
* [2020-03-17] 加入動態調整車距功能。(特別感謝 @ShaneSmiskol 提供 PR)
* [2020-03-14] 更新 pt-Br (葡萄牙語) 翻譯。(感謝 berno22 提供)
* [2020-03-14] 加入自動關機開關。(感謝 Rzxd 建議)
* [2020-03-14] 調高 Toyota 扭力容錯值。
* [2020-03-14] 優化讀取 dp 設定值。
* [2020-03-14] 加入 2019 手動 Civic 指紋。感謝 (AlexNoop 提供)
* [2020-03-14] dp 功能加入對 Subaru 車系的支援。
* [2020-03-06] 加入葡萄牙語支持。(感謝 berno22 提供)
* [2020-03-06] 加入大陸 2018 Camry、2020 RAV4 指紋。(感謝 笨木匠 提供)
* [2020-03-04] 加入顯示駕駛監控畫面。
* [2020-03-04] 加入加速模式選項。(特別感謝 @arne182, @cgw1968-5779 提供 PR)
* [2020-03-04] 修正 shutdownd 在 comma two 可能會不正常關機的錯誤。(感謝 @Wei, @Rzxd 回報)
dragonpilot 0.7.2
========================
* [2020-02-08] dp 功能加入對現代 (Hyundai) 車系的支援。
* [2020-02-08] 加入神盾測速照相自動啟動的開關。
* [2020-02-08] 更新高德地圖至 v4.5.0.600053。
* [2020-02-08] 使用 0.6.6 版的更新系統。
* [2020-02-08] 修正急剎問題。(感謝 kumar 提供)
* [2020-01-31] 移除行車介面電量、溫度顯示,(修正畫面當機、黑屏問題)
* [2020-01-29] 修正行車介面錯誤。(感謝 深鲸希西 測試;eisenheim、HeatNation 反應)
* [2020-01-23] 加入 Steer Ratio Learner 關閉。(感謝 eisenheim 建議)
* [2020-01-23] 行車介面加入電量、溫度。(感謝 eisenheim 建議)
* [2020-01-23] 優化 appd。
dragonpilot 0.7.1
========================
* [2020-01-19] 調整 appd 和 ALC 邏輯。
* [2020-01-14] 加入開機啟動個人熱點。(感謝 eisenheim 建議)
* [2020-01-18] 加入大陸版 2018 Lexus RX300 支援。(感謝 cafe 提供)
* [2020-01-18] 加入 DragonBTG 設定。(感謝 CloudJ、低調哥、歐姓Altis車主 提供)
dragonpilot 0.7.0
========================
* [DEVEL] 更新至最新的 commaai:devel (0.7.0)。
* [2019-12-29] 輔助/自動變道改為可調整參數 (進階用戶)。(DragonAssistedLCMinMPH、DragonAutoLCMinMPH、DragonAutoLCDelay)
* [2019-12-29] 修正無法運行第三方應用錯誤。(感謝 深鲸希西 反應)
* [2019-12-18] 修正自動換道邏輯。
* [2019-12-18] 更新 offroad 翻譯。
* [2019-12-18] 錯誤修正。
* [2019-12-18] 移除美版 2017 Civic Hatchback 指紋。(與其它車型衝突)
* [2019-12-17] 加入輔助換道開關。(24mph / 40kph 以上)
* [2019-12-17] 加入自動換道開關。(40mph / 65kph 以上)
* [2019-12-17] 加入大陸版 2019 雷凌汽油版指紋。 (感謝 Shell 提供)
* [2019-12-17] 加入大陸版 2019 卡羅拉汽油版指紋。 (感謝 Shell 提供)
* [2019-12-17] 加入美版 2017 Civic Hatchback 指紋。(感謝 CFranHonda 提供)
* [2019-12-10] 加入位智車機模式。 (Waze Mode)
* [2019-11-21] 修正 offroad 翻譯。(感謝 鄧育林 回報)
* [2019-11-21] 調整前車靜止移動偵測參數。
* [2019-11-21] 前車靜止移動偵測可在未啟用 dp 時運作。
* [2019-11-18] 修正 offroad 翻譯。(感謝 Cody、鄧育林 回報)
* [2019-11-18] 修正 frame 翻譯。
dragonpilot 0.6.6
========================
* [2019-11-15] 修正不會充電的錯誤。 (感謝 袁昊 反應)
* [2019-11-15] 修正充電控制。 (感謝 KT 反應)
* [2019-11-15] 更新 frame 翻譯,改為多語言版。 (感謝 深鲸希西、shaoching885、鄧育林 反應)
* [2019-11-12] 只顯示電量文字 (注意:有時不會更新,需要拔插 USB 線)
* [2019-11-12] 自動偵測並鎖定硬體 (EON / UNO)。
* [2019-11-12] 加入鎖定硬體 (EON / UNO) 的程式碼。
* [2019-11-11] 更新高德地圖至 v4.3.0.600310 R2098NSLAE
* [2019-11-11] 更新 MiXplorer 至 v6.40.3
* [2019-11-11] 前車靜止移動偵測加入偵測警示。
* [2019-11-07] 讓 Bosch 系統顯示三角。 (感謝 ching885 回報)
* [2019-11-07] 更新 offroad 多語言版簡體中文翻譯 (感謝 Rming 提供)
* [2019-11-06] 修正 0.6.6 appd 和 dashcamd 錯誤。 (感謝 鄧育林 回報)
dragonpilot 0.6.5
========================
* [2019-11-05] 加入台灣 Lexus 2017 GS450h 支援。 (感謝 簡銘佑 提供指紋)
* [2019-11-01] 新增神盾測速照相。 (感謝 Sky Chang 和 Wei Yi Chen)
* [2019-11-01] 修正 offroad 翻譯。 (感謝 Leo Hsieh)
* [2019-11-01] 移除 Miui 字型,縮小 dp 使用空間。
* [2019-11-01] 更新 offroad 為多語言版
* [2019-10-29] 加入 SnG 補丁。(感謝 楊雅智)
* [2019-10-28] 調整 dragon_allow_gas 邏輯 (請回報任何問題,需更新 Panda 韌體)
* [2019-10-22] 移除強迫網路連線提示。(感謝 Shell)
* [2019-10-18] 加入前車靜止移動偵測。(測試版,感謝 ucolchen)
* [2019-10-18] 移除強迫網路連線提示。(感謝 Shell)
* [2019-10-18] 修正 allow_gas 功能。
* [2019-10-18] 加入彎道減速功能開關。
* [2019-10-18] 強迫使用 dp 版 Panda 韌體。
* [2019-10-17] 加入「車型」顯示於 dp 設定畫面。
* [2019-10-17] 修正充電控制讀取預設值的錯誤。
* [2019-10-17] 修正無法顯示更新記錄的錯誤。
* [2019-10-17] 刷新 Panda 韌體按鈕將會自動重啟 EON。(感謝 鄧育林 建議)
* [2019-10-17] 下載更新記錄時使用 "no-cache" 標頭。
* [2019-10-17] 更新高德地圖至 v4.3.0
* [2019-10-14] 啟用自動更新功能。(感謝 鄧育林 提供)
* [2019-10-14] 清除不再使用的 dp params。
* [2019-10-14] 加入數字電量指示。(感謝 鄧育林 建議)
* [2019-10-14] 加入刷新 Panda 韌體按鈕。
* [2019-10-11] 加入台灣 2019 RAV4 汽油版指紋。 (感謝 Max Duan / CloudJ 提供)
* [2019-10-11] 加入當 LatCtrl 關閉時,畫面顯示提示訊息。
dragonpilot 0.6.4
========================
* [2019-10-11] 加入台灣版 2019 RAV4H 油電版指紋。
* [2019-10-08] 加回駕駛監控開關。
* [2019-10-07] 加入台灣版 2019 RAV4H 油電版指紋。(感謝 Max Duan 提供)
* [2019-10-05] 移除 curvature learner: 轉角明顯比原廠小。
* [2019-09-30] 更新 curvature learner 版本至 v4。
* [2019-09-30] Lexus ISH 使用更精確的 EPS Steering Angle Sensor
* [2019-09-27] 加入 Zorrobyte 的 curvature learner (https://github.com/zorrobyte/openpilot)
* [2019-09-27] 加入可開關駕駛監控的程式碼。
* [2019-09-27] 取消當 steering 出現錯誤時,自動切斷方向控制 2 秒的機制。
* [2019-09-27] 讓行車介面的「方向盤」/「轉彎」圖示半透明化。
* [2019-09-26] 修正當「啟用記錄服務」關閉時,make 會有問題的錯誤。 (感謝 shaoching885 和 afa 回報)
* [2019-09-24] 行車介面加入可開關的「前車」、「路線」、「車道」設定。
* [2019-09-24] 行車介面加入可開關的「方向燈號」提示。 (感謝 CloudJ 建議,程式碼來源: https://github.com/kegman/openpilot)
* [2019-09-23] 優化讀取 params 的次數。
* [2019-09-23] 加入可開關的車道偏移警示。
* [2019-09-23] 修正充電控制邏輯。
* [2019-09-23] 加入台灣 Prius 4.5 指紋。 (感謝 Lin Hsin Hung 提供)
* [2019-09-20] 加入充電控制功能。 (感謝 loveloveses 和 KT 建議)
* [2019-09-16] 加入台灣 CT200h 指紋。 (感謝 CloudJ 提供)
* [2019-09-16] 加入美版 CT200h 移植。 (感謝 thomaspich 提供)
* [2019-09-13] 行車介面加入可開關的「速度顯示」設定。
* [2019-09-09] 加入 GreyPanda 模式。
* [2019-08-28] 加入可調警示音量。
* [2019-08-27] 自動關機改為可調時長。
dragonpilot 0.6.3
========================
* [2019-10-11] 加入台灣版 2019 RAV4H 油電版指紋。
-120
View File
@@ -1,120 +0,0 @@
2020-06-22 (0.7.5)
========================
* 移除方向盤監控設定。(無法取消/關閉方向盤監控)
* Removed Steering monitor timer adjustment in code (timer in settings will no longer work.)
2020-06-18 (0.7.5)
========================
* Dynamic Follow 更新模型。(感謝 @ShaneSmiskol 提供代碼、 @cgw1968 測試)
* Updated Dynamic Follow model. (Special Thanks to @ShaneSmiskol for the feature and @cgw1968 for testing)
2020-05-30 (0.7.5)
========================
* Dynamic Follow 更新至 ShaneSmiskol:stock_additions 0.7.5 版。(感謝 @ShaneSmiskol 提供代碼、 @Wei 測試)
* Updated Dynamic Follow to ShaneSmiskol:stock_additions 0.7.5. (Special Thanks to @ShaneSmiskol for the feature and @Wei for testing)
2020-05-28 (0.7.5)
========================
* 優化 Lexus GSH 轉向。(感謝 @簡銘佑 測試)
* Optimize Lexus GSH steering. (Thanks to @簡銘佑)
* C2 支援自動關機「DragonAutoShutdownAt」參數。(感謝 @cgw1968 建議)
* C2 to support auto shutdown "DragonAutoShutDownAt" param. (Thanks to @cgw1968)
* 修正出現「pedalPressed」的錯誤。(感謝 @Wei 回報)
* Fixed issue showing "pedalPressed" error. (Thanks to @Wei)
2020-05-26 (0.7.5)
========================
* 將剎車狀熊顯示於 dp 資訊欄。
* Added brake indicator to dp infobar.
* 修正「溫度監控」燈示。
* Fixed "Temp monitor" indicator.
* 加入「方向燈取消控制」延遲控制設。(感謝 @wabes 建議)
* Added delay config to "Disable Lat Control on Blinker". (Thanks to @wabes)
* 加入巴西版 2020 Corolla Hybrid 指紋v2。(感謝 @berno22 提供)
* Added Brazil 2020 Corolla Hybrid FPv2. (Thanks to @berno22)
2020-05-25 (0.7.5)
========================
* 加入對 VW MQB/PQ 的支援。(感謝 @dingliangxue 移植)
* Added support to VW MQB/PQ platform. (Thanks to @dingliangxue)
2020-05-21 (0.7.5)
========================
* 修改成 3 小時後停止供電。(感謝 @Wei 建議)
* Updated to stop charging after 3 hrs. (Thanks to @Wei)
* 移除行車記錄下的「碰撞偵測」功能。
* Removed Impact Detection in Dashcam.
* 修正開啟「Noctua 風扇」模式導致的錯誤。(感謝 @阿濤 回報)
* Fixed a bug caused by enabling "Noctua Mod". (Thanks to @阿濤)
* 修正「位智模式」無法顯示警示的問題。(感謝 @axandres 回報)
* Fixed alert issue in waze mode. (Thanks to @axandres)
* 修正無法顯示更新中圖示的問題。
* Fixed unable to display "UPDATING" icon issue.
2020-05-20 (0.7.5)
========================
* 加入「允許多次自動換道」功能。(感謝 @阿濤 建議)
* Added "Allow Continuous Auto Lane Change" Toggle. (Thanks to @阿濤)
* 修正開機後設定頁面有時會錯誤的問題。(感謝 @salmankhan@Wei 回報)
* Fixed setting page crash issue. (Thanks to @salmankhan, @Wei)
* 修正熄火後一直出現更新訊息的錯誤。(感謝 @Sky Chang 回報)
* Fixed issue that keep showing update prompt. (Thanks to @Sky Chang)
2020-05-19 (0.7.5)
========================
* 加入 DragonEnableAutoUpdate 預設值。
* Added DragonEnableAutoUpdate default value.
2020-05-18 (0.7.5)
========================
* 修正因同時使用「社群功能」和「自定車型」造成的加減速問題。(特別感謝 @Wei@Sky Chang、@Han9365@鄧育林 的測試以及回報。)
* Fixed acceleration issue caused by used of both "Community Maintain Feature" and "Custom Car Model"
2020-05-16 (0.7.5)
========================
* 新增 DragonMaxSpeedLimit 設定值 (mph),當如果車速高於此值 op 將會停止操控。(感謝 @Anthony 建議)
* Added DragonMaxSpeedLimit parameter (mph), op will stop controlling when car speed is high than the value. (Thanks to @Anthony)
* 更新 appd 使用 cnpmjs 來下載 APKs。
* Updated appd to use cnpmjs to download APKs.
* 修正更新服務。(感謝 @Wei)
* Fixed Update Service. (Thanks to @Wei)
* 新增加拿大版 2018 Toyota Sienna LTD 指紋(v2)。(感謝 明峰 提供)
* Added Canada 2018 Toyota Sienna LTD fingerprint (v2). (Thanks to 明峰)
2020-05-15 (0.7.5)
========================
* 新增「通過移動網路上傳」開關
* Added Upload Over Mobile Network toggle.
* 新增「通過熱點上傳」開關
* Added Upload Over Hotspot toggle.
* 新增加拿大版 2018 Toyota Sienna LTD 指紋(v1)。(感謝 明峰 提供)
* Added Canada 2018 Toyota Sienna LTD fingerprint (v1). (Thanks to 明峰)
* 新增大陸版 Volkswagen Golf GTI 指紋 (v1)。(感謝 easyeiji 提供)
* Added China Volkswagen Golf GTI fingerprint (v1). (Thanks to easyeiji)
2020-05-10
========================
* 基於最新 openpilot 0.7.5 devel-staging.
* Based on latest openpilot 0.7.5 devel-staging.
* 更新 dp 圖示 (特別感謝 @wabes 的設計與提供)。
* Updated dp logo, special thanks to @wabes for the design.
* 簡/繁中文版和 i18n 整合成為單一版本。
* Merged zhs/zht/i18n versions into one.
* 新增大陸版 CAMRY HYBRID 指紋v2。(感謝 @杜子腾)
* Added China Camry Hybrid FPv2. (Thanks to @杜子腾)
* 新增台灣版 Altis HYBRID 指紋v1。(感謝 @Fish)
* Added Taiwan Altis Hybrid FPv1. (Thanks to @Fish)
* 新增行駛時關閉畫面功能。
* Added Screen off while driving feature.
* 新增倒車時關閉畫面功能。
* Added Screen off while reversing feature.
* 新增駕駛介面加入「加速模式」切換鈕。
* Added acceleration profile toggle onto driving UI.
* 新增自定車型功能,取代指紋暫存功能。
* Replaced fingerprint cache with custom car model selector.
* 新增可調亮度。
* Added Brightness changer.
* 新增部分德語支持。(特別感謝 @arne182 提供)
* Added partial de_DE language support (Thanks to @arne182)
* 新增停車碰撞偵測記錄功能。
* Added off road impact detection to dashcam.
-32
View File
@@ -10,41 +10,9 @@ Most open source development activity is coordinated through our [Discord](https
* Make sure you have a [GitHub account](https://github.com/signup/free)
* Fork [our repositories](https://github.com/commaai) on GitHub
## Testing
### Local Testing
You can test your changes on your machine by running `run_docker_tests.sh`. This will run some automated tests in docker against your code.
### Automated Testing
All PRs are automatically checked by Github Actions. Check out `.github/workflows/` for what Github Actions runs. Any new tests sould be added to Github Actions.
### Code Style and Linting
Code is automatically checked for style by Github Actions as part of the automated tests. You can also run these tests yourself by running `pylint_openpilot.sh` and `flake8_openpilot.sh`.
## Car Ports (openpilot)
We've released a [Model Port guide](https://medium.com/@comma_ai/openpilot-port-guide-for-toyota-models-e5467f4b5fe6) for porting to Toyota/Lexus models.
If you port openpilot to a substantially new car brand, see this more generic [Brand Port guide](https://medium.com/@comma_ai/how-to-write-a-car-port-for-openpilot-7ce0785eda84). You might also be eligible for a bounty. See our bounties at [comma.ai/bounties.html](https://comma.ai/bounties.html)
## Pull Requests
Pull requests should be against the master branch. Before running master on in-car hardware, you'll need to clone the submodules too. That can be done by recursively cloning the repository:
```
git clone https://github.com/commaai/openpilot.git --recursive
```
Or alternatively, when on the master branch:
```
git submodule init
git submodule update
```
The reasons for having submodules on a dedicated repository and our new development philosophy can be found in our [post about externalization](https://medium.com/@comma_ai/a-2020-theme-externalization-13b33326d8b3).
Modules that are in seperate repositories include:
* apks
* cereal
* laika
* opendbc
* panda
+40
View File
@@ -0,0 +1,40 @@
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 \
libssl-dev \
ocl-icd-libopencl1 \
ocl-icd-opencl-dev \
opencl-headers
RUN pip install numpy==1.11.2 scipy==0.18.1 matplotlib==2.1.2
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
RUN make -C /tmp/openpilot/selfdrive/controls/lib/longitudinal_mpc clean
RUN make -C /tmp/openpilot/selfdrive/controls/lib/lateral_mpc clean
+9
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
+152 -262
View File
@@ -1,303 +1,162 @@
[![](https://i.imgur.com/UelUjKAh.png)](#)
[![](https://i.imgur.com/UetIFyH.jpg)](#)
Welcome to openpilot
======
[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 selected Honda, Toyota, Acura, Lexus, Chevrolet, Hyundai, Kia. It's about on par with Tesla Autopilot and GM Super Cruise, 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 to enable rapid prototyping. We look forward to your contributions - improving real vehicle automation has never been easier.
Table of Contents
=======================
* [What is openpilot?](#what-is-openpilot)
* [Integration with Stock Features](#integration-with-stock-features)
* [Supported Hardware](#supported-hardware)
* [Community](#community)
* [Hardware](#hardware)
* [Supported Cars](#supported-cars)
* [Community Maintained Cars and Features](#community-maintained-cars-and-features)
* [Installation Instructions](#installation-instructions)
* [Limitations of openpilot ALC and LDW](#limitations-of-openpilot-alc-and-ldw)
* [Limitations of openpilot ACC and FCW](#limitations-of-openpilot-acc-and-fcw)
* [Limitations of openpilot DM](#limitations-of-openpilot-dm)
* [User Data and comma Account](#user-data-and-comma-account)
* [Safety and Testing](#safety-and-testing)
* [Community Maintained Cars](#community-maintained-cars)
* [In Progress Cars](#in-progress-cars)
* [How can I add support for my car?](#how-can-i-add-support-for-my-car)
* [Directory structure](#directory-structure)
* [User Data / chffr Account / Crash Reporting](#user-data--chffr-account--crash-reporting)
* [Testing on PC](#testing-on-pc)
* [Community and Contributing](#community-and-contributing)
* [Directory Structure](#directory-structure)
* [Contributing](#contributing)
* [Licensing](#licensing)
---
What is openpilot?
Community
------
[openpilot](http://github.com/commaai/openpilot) is an open source driver assistance system. Currently, openpilot performs the functions of Adaptive Cruise Control (ACC), Automated Lane Centering (ALC), Forward Collision Warning (FCW) and Lane Departure Warning (LDW) for a growing variety of supported [car makes, models and model years](#supported-cars). In addition, while openpilot is engaged, a camera based Driver Monitoring (DM) feature alerts distracted and asleep drivers.
openpilot is developed by [comma.ai](https://comma.ai/) and users like you.
We have a [Twitter you should follow](https://twitter.com/comma_ai).
Also, we have a several thousand people community on [Discord](https://discord.comma.ai).
<table>
<tr>
<td><a href="https://www.youtube.com/watch?v=mgAbfr42oI8" title="YouTube" rel="noopener"><img src="https://i.imgur.com/kAtT6Ei.png"></a></td>
<td><a href="https://www.youtube.com/watch?v=394rJKeh76k" title="YouTube" rel="noopener"><img src="https://i.imgur.com/lTt8cS2.png"></a></td>
<td><a href="https://www.youtube.com/watch?v=1iNOc3cq8cs" title="YouTube" rel="noopener"><img src="https://i.imgur.com/ANnuSpe.png"></a></td>
<td><a href="https://www.youtube.com/watch?v=Vr6NgrB-zHw" title="YouTube" rel="noopener"><img src="https://i.imgur.com/Qypanuq.png"></a></td>
<td><a href="https://www.youtube.com/watch?v=ICOIin4p70w" title="YouTube" rel="noopener"><img src="https://i.imgur.com/gBTo7yB.png"></a></td>
<td><a href="https://www.youtube.com/watch?v=1zCtj3ckGFo" title="YouTube" rel="noopener"><img src="https://i.imgur.com/gNhhcep.png"></a></td>
<td><a href="https://www.youtube.com/watch?v=Qd2mjkBIRx0" title="YouTube" rel="noopener"><img src="https://i.imgur.com/tFnSexp.png"></a></td>
<td><a href="https://www.youtube.com/watch?v=ju12vlBm59E" title="YouTube" rel="noopener"><img src="https://i.imgur.com/3BKiJVy.png"></a></td>
</tr>
<tr>
<td><a href="https://www.youtube.com/watch?v=Ug41KIKF0oo" title="YouTube" rel="noopener"><img src="https://i.imgur.com/3caZ7xM.png"></a></td>
<td><a href="https://www.youtube.com/watch?v=NVR_CdG1FRg" title="YouTube" rel="noopener"><img src="https://i.imgur.com/bAZOwql.png"></a></td>
<td><a href="https://www.youtube.com/watch?v=tkEvIdzdfUE" title="YouTube" rel="noopener"><img src="https://i.imgur.com/EFINEzG.png"></a></td>
<td><a href="https://www.youtube.com/watch?v=_P-N1ewNne4" title="YouTube" rel="noopener"><img src="https://i.imgur.com/gAyAq22.png"></a></td>
<td><a href="https://www.youtube.com/watch?v=Z5VY5FzgNt4" title="YouTube" rel="noopener"><img src="https://i.imgur.com/3I9XOK2.png"></a></td>
<td><a href="https://www.youtube.com/watch?v=blnhZC7OmMg" title="YouTube" rel="noopener"><img src="https://i.imgur.com/f9IgX6s.png"></a></td>
<td><a href="https://www.youtube.com/watch?v=iRkz7FuJsA8" title="YouTube" rel="noopener"><img src="https://i.imgur.com/Vo5Zvmn.png"></a></td>
<td><a href="https://www.youtube.com/watch?v=IHjEqAKDqjM" title="YouTube" rel="noopener"><img src="https://i.imgur.com/V9Zd81n.png"></a></td>
</tr>
</table>
Integration with Stock Features
Hardware
------
In all supported cars:
* Stock Lane Keep Assist (LKA) and stock ALC are replaced by openpilot ALC, which only functions when openpilot is engaged by the user.
* Stock LDW is replaced by openpilot LDW.
At the moment openpilot supports the [EON Dashcam DevKit](https://comma.ai/shop/products/eon-dashcam-devkit). A [panda](https://shop.comma.ai/products/panda-obd-ii-dongle) and a [giraffe](https://comma.ai/shop/products/giraffe/) are recommended tools to interface the EON with the car. We'd like to support other platforms as well.
Additionally, on specific supported cars (see ACC column in [supported cars](#supported-cars)):
* Stock ACC is replaced by openpilot ACC.
* openpilot FCW operates in addition to stock FCW.
openpilot should preserve all other vehicle's stock features, including, but are not limited to: FCW, Automatic Emergency Braking (AEB), auto high-beam, blind spot warning, and side collision warning.
Supported Hardware
------
At the moment, openpilot supports the [EON DevKit](https://comma.ai/shop/products/eon-dashcam-devkit) and the [comma two](https://comma.ai/shop/products/comma-two-devkit). A [car harness](https://comma.ai/shop/products/car-harness) is recommended to connect the EON or comma two to the car. For experimental purposes, openpilot can also run on an Ubuntu computer with external [webcams](https://github.com/commaai/openpilot/tree/master/tools/webcam).
Install openpilot on a neo device by entering ``https://openpilot.comma.ai`` during NEOS setup.
Supported Cars
------
| Make | Model (US Market Reference) | Supported Package | ACC | No ACC accel below | No ALC below |
| ----------| ------------------------------| ------------------| -----------------| -------------------| ------------------|
| Acura | ILX 2016-18 | AcuraWatch Plus | openpilot | 25mph<sup>1</sup> | 25mph |
| Acura | RDX 2016-18 | AcuraWatch Plus | openpilot | 25mph<sup>1</sup> | 12mph |
| Honda | Accord 2018-19 | All | Stock | 0mph | 3mph |
| Honda | Accord Hybrid 2018-19 | All | Stock | 0mph | 3mph |
| Honda | Civic Hatchback 2017-19 | Honda Sensing | Stock | 0mph | 12mph |
| Honda | Civic Sedan/Coupe 2016-18 | Honda Sensing | openpilot | 0mph | 12mph |
| Honda | Civic Sedan/Coupe 2019-20 | Honda Sensing | Stock | 0mph | 2mph<sup>2</sup> |
| Honda | CR-V 2015-16 | Touring | openpilot | 25mph<sup>1</sup> | 12mph |
| Honda | CR-V 2017-19 | Honda Sensing | Stock | 0mph | 12mph |
| Honda | CR-V Hybrid 2017-2019 | Honda Sensing | Stock | 0mph | 12mph |
| Honda | Fit 2018-19 | Honda Sensing | openpilot | 25mph<sup>1</sup> | 12mph |
| Honda | HR-V 2019 | Honda Sensing | openpilot | 25mph<sup>1</sup> | 12mph |
| Honda | Insight 2019 | Honda Sensing | Stock | 0mph | 3mph |
| Honda | Odyssey 2018-20 | Honda Sensing | openpilot | 25mph<sup>1</sup> | 0mph |
| Honda | Passport 2019 | All | openpilot | 25mph<sup>1</sup> | 12mph |
| Honda | Pilot 2016-18 | Honda Sensing | openpilot | 25mph<sup>1</sup> | 12mph |
| Honda | Pilot 2019 | All | openpilot | 25mph<sup>1</sup> | 12mph |
| Honda | Ridgeline 2017-20 | Honda Sensing | openpilot | 25mph<sup>1</sup> | 12mph |
| Lexus | CT Hybrid 2017-18 | All | Stock<sup>3</sup>| 0mph | 0mph |
| Lexus | ES 2019 | All | openpilot | 0mph | 0mph |
| Lexus | ES Hybrid 2019 | All | openpilot | 0mph | 0mph |
| Lexus | IS 2017-2019 | All | Stock | 22mph | 0mph |
| Lexus | IS Hybrid 2017 | All | Stock | 0mph | 0mph |
| Lexus | NX Hybrid 2018 | All | Stock<sup>3</sup>| 0mph | 0mph |
| Lexus | RX 2016-17 | All | Stock<sup>3</sup>| 0mph | 0mph |
| Lexus | RX 2020 | All | openpilot | 0mph | 0mph |
| Lexus | RX Hybrid 2016-19 | All | Stock<sup>3</sup>| 0mph | 0mph |
| Toyota | Avalon 2016 | TSS-P | Stock<sup>3</sup>| 20mph<sup>1</sup> | 0mph |
| Toyota | Avalon 2017-18 | All | Stock<sup>3</sup>| 20mph<sup>1</sup> | 0mph |
| Toyota | Camry 2018-20 | All | Stock | 0mph<sup>4</sup> | 0mph |
| Toyota | Camry Hybrid 2018-19 | All | Stock | 0mph<sup>4</sup> | 0mph |
| Toyota | C-HR 2017-19 | All | Stock | 0mph | 0mph |
| Toyota | C-HR Hybrid 2017-19 | All | Stock | 0mph | 0mph |
| Toyota | Corolla 2017-19 | All | Stock<sup>3</sup>| 20mph<sup>1</sup> | 0mph |
| Toyota | Corolla 2020 | All | openpilot | 0mph | 0mph |
| Toyota | Corolla Hatchback 2019-20 | All | openpilot | 0mph | 0mph |
| Toyota | Corolla Hybrid 2020 | All | openpilot | 0mph | 0mph |
| Toyota | Highlander 2017-19 | All | Stock<sup>3</sup>| 0mph | 0mph |
| Toyota | Highlander Hybrid 2017-19 | All | Stock<sup>3</sup>| 0mph | 0mph |
| Toyota | Highlander 2020 | All | openpilot | 0mph | 0mph |
| Toyota | Highlander Hybrid 2020 | All | openpilot | 0mph | 0mph |
| Toyota | Prius 2016 | TSS-P | Stock<sup>3</sup>| 0mph | 0mph |
| Toyota | Prius 2017-19 | All | Stock<sup>3</sup>| 0mph | 0mph |
| Toyota | Prius Prime 2017-20 | All | Stock<sup>3</sup>| 0mph | 0mph |
| Toyota | Rav4 2016 | TSS-P | Stock<sup>3</sup>| 20mph<sup>1</sup> | 0mph |
| Toyota | Rav4 2017-18 | All | Stock<sup>3</sup>| 20mph<sup>1</sup> | 0mph |
| Toyota | Rav4 2019-20 | All | openpilot | 0mph | 0mph |
| Toyota | Rav4 Hybrid 2016 | TSS-P | Stock<sup>3</sup>| 0mph | 0mph |
| Toyota | Rav4 Hybrid 2017-18 | All | Stock<sup>3</sup>| 0mph | 0mph |
| Toyota | Rav4 Hybrid 2019-20 | All | openpilot | 0mph | 0mph |
| Toyota | Sienna 2018 | All | Stock<sup>3</sup>| 0mph | 0mph |
| Make | Model | Supported Package | Lateral | Longitudinal | No Accel Below | No Steer Below | Giraffe |
| ---------------------| -------------------------| ---------------------| --------| ---------------| -----------------| ---------------|-------------------|
| Acura | ILX 2016-17 | AcuraWatch Plus | Yes | Yes | 25mph<sup>1</sup>| 25mph | Nidec |
| Acura | RDX 2018 | AcuraWatch Plus | Yes | Yes | 25mph<sup>1</sup>| 12mph | Nidec |
| Buick<sup>3</sup> | Regal 2018 | Adaptive Cruise | Yes | Yes | 0mph | 7mph | Custom<sup>7</sup>|
| Chevrolet<sup>3</sup>| Malibu 2017 | Adaptive Cruise | Yes | Yes | 0mph | 7mph | Custom<sup>7</sup>|
| Chevrolet<sup>3</sup>| Volt 2017-18 | Adaptive Cruise | Yes | Yes | 0mph | 7mph | Custom<sup>7</sup>|
| Cadillac<sup>3</sup> | ATS 2018 | Adaptive Cruise | Yes | Yes | 0mph | 7mph | Custom<sup>7</sup>|
| Chrysler | Pacifica 2018 | Adaptive Cruise | Yes | Stock | 0mph | 9mph | FCA |
| Chrysler | Pacifica Hybrid 2017-18 | Adaptive Cruise | Yes | Stock | 0mph | 9mph | FCA |
| GMC<sup>3</sup> | Acadia Denali 2018 | Adaptive Cruise | Yes | Yes | 0mph | 7mph | Custom<sup>7</sup>|
| Holden<sup>3</sup> | Astra 2017 | Adaptive Cruise | Yes | Yes | 0mph | 7mph | Custom<sup>7</sup>|
| Honda | Accord 2018 | All | Yes | Stock | 0mph | 3mph | Bosch |
| Honda | Civic Sedan/Coupe 2016-18| Honda Sensing | Yes | Yes | 0mph | 12mph | Nidec |
| Honda | Civic Sedan/Coupe 2019 | Honda Sensing | Yes | Stock | 0mph | 2mph | Bosch |
| Honda | Civic Hatchback 2017-19 | Honda Sensing | Yes | Stock | 0mph | 12mph | Bosch |
| Honda | CR-V 2015-16 | Touring | Yes | Yes | 25mph<sup>1</sup>| 12mph | Nidec |
| Honda | CR-V 2017-18 | Honda Sensing | Yes | Stock | 0mph | 12mph | Bosch |
| Honda | Odyssey 2017-19 | Honda Sensing | Yes | Yes | 25mph<sup>1</sup>| 0mph | Inverted Nidec |
| Honda | Pilot 2016-18 | Honda Sensing | Yes | Yes | 25mph<sup>1</sup>| 12mph | Nidec |
| Honda | Pilot 2019 | All | Yes | Yes | 25mph<sup>1</sup>| 12mph | Inverted Nidec |
| Honda | Ridgeline 2017-19 | Honda Sensing | Yes | Yes | 25mph<sup>1</sup>| 12mph | Nidec |
| Hyundai | Santa Fe 2019 | All | Yes | Stock | 0mph | 0mph | Custom<sup>6</sup>|
| Hyundai | Elantra 2017 | SCC + LKAS | Yes | Stock | 19mph | 34mph | Custom<sup>6</sup>|
| Hyundai | Genesis 2018 | All | Yes | Stock | 19mph | 34mph | Custom<sup>6</sup>|
| Jeep | Grand Cherokee 2017-19 | Adaptive Cruise | Yes | Stock | 0mph | 9mph | FCA |
| Kia | Optima 2019 | SCC + LKAS | Yes | Stock | 0mph | 0mph | Custom<sup>6</sup>|
| Kia | Sorento 2018 | All | Yes | Stock | 0mph | 0mph | Custom<sup>6</sup>|
| Kia | Stinger 2018 | SCC + LKAS | Yes | Stock | 0mph | 0mph | Custom<sup>6</sup>|
| Lexus | RX Hybrid 2016-18 | All | Yes | Yes<sup>2</sup>| 0mph | 0mph | Toyota |
| Toyota | Camry 2018<sup>4</sup> | All | Yes | Stock | 0mph<sup>5</sup> | 0mph | Toyota |
| Toyota | C-HR 2017-18<sup>4</sup> | All | Yes | Stock | 0mph | 0mph | Toyota |
| Toyota | Corolla 2017-18 | All | Yes | Yes<sup>2</sup>| 20mph<sup>1</sup>| 0mph | Toyota |
| Toyota | Highlander 2017-18 | All | Yes | Yes<sup>2</sup>| 0mph | 0mph | Toyota |
| Toyota | Highlander Hybrid 2018 | All | Yes | Yes<sup>2</sup>| 0mph | 0mph | Toyota |
| Toyota | Prius 2016 | TSS-P | Yes | Yes<sup>2</sup>| 0mph | 0mph | Toyota |
| Toyota | Prius 2017-18 | All | Yes | Yes<sup>2</sup>| 0mph | 0mph | Toyota |
| Toyota | Prius Prime 2017-18 | All | Yes | Yes<sup>2</sup>| 0mph | 0mph | Toyota |
| Toyota | Rav4 2016 | TSS-P | Yes | Yes<sup>2</sup>| 20mph<sup>1</sup>| 0mph | Toyota |
| Toyota | Rav4 2017-18 | All | Yes | Yes<sup>2</sup>| 20mph<sup>1</sup>| 0mph | Toyota |
| Toyota | Rav4 Hybrid 2017-18 | All | Yes | Yes<sup>2</sup>| 0mph | 0mph | Toyota |
<sup>1</sup>[Comma Pedal](https://community.comma.ai/wiki/index.php/Comma_Pedal) is used to provide stop-and-go capability to some of the openpilot-supported cars that don't currently support stop-and-go. Here is how to [build a Comma Pedal](https://medium.com/@jfrux/comma-pedal-building-with-macrofab-6328bea791e8). ***NOTE: The Comma Pedal is not officially supported by [comma](https://comma.ai).*** <br />
<sup>2</sup>2019 Honda Civic 1.6L Diesel Sedan does not have ALC below 12mph. <br />
<sup>3</sup>When disconnecting the Driver Support Unit (DSU), openpilot ACC will replace stock ACC. For DSU locations, see [Toyota Wiki page](https://community.comma.ai/wiki/index.php/Toyota). ***NOTE: disconnecting the DSU disables Automatic Emergency Braking (AEB).*** <br />
<sup>4</sup>28mph for Camry 4CYL L, 4CYL LE and 4CYL SE which don't have Full-Speed Range Dynamic Radar Cruise Control. <br />
<sup>1</sup>[Comma Pedal](https://community.comma.ai/wiki/index.php/Comma_Pedal) is used to provide stop-and-go capability to some of the openpilot-supported cars that don't currently support stop-and-go. Here is how to [build a Comma Pedal](https://medium.com/@jfrux/comma-pedal-building-with-macrofab-6328bea791e8). ***NOTE: The Comma Pedal is not officially supported by [comma.ai](https://comma.ai)***
<sup>2</sup>When disconnecting the Driver Support Unit (DSU), otherwise longitudinal control is stock ACC. For DSU locations, see [Toyota Wiki page](https://community.comma.ai/wiki/index.php/Toyota)
<sup>3</sup>[GM installation guide](https://zoneos.com/volt/).
<sup>4</sup>It needs an extra 120Ohm resistor ([pic1](https://i.imgur.com/CmdKtTP.jpg), [pic2](https://i.imgur.com/s2etUo6.jpg)) on bus 3 and giraffe switches set to 01X1 (11X1 for stock LKAS), where X depends on if you have the [comma power](https://comma.ai/shop/products/power/).
<sup>5</sup>28mph for Camry 4CYL L, 4CYL LE and 4CYL SE which don't have Full-Speed Range Dynamic Radar Cruise Control.
<sup>6</sup>Open sourced [Hyundai Giraffe](https://github.com/commaai/neo/tree/master/giraffe/hyundai) is designed for the 2019 Sante Fe; pinout may differ for other Hyundais.
<sup>7</sup>Community built Giraffe, find more information [here](https://zoneos.com/shop/).
Community Maintained Cars and Features
Community Maintained Cars
------
| Make | Model (US Market Reference) | Supported Package | ACC | No ACC accel below | No ALC below |
| ----------| ------------------------------| ------------------| -----------------| -------------------| -------------|
| Buick | Regal 2018<sup>1</sup> | Adaptive Cruise | openpilot | 0mph | 7mph |
| Cadillac | ATS 2018<sup>1</sup> | Adaptive Cruise | openpilot | 0mph | 7mph |
| Chevrolet | Malibu 2017<sup>1</sup> | Adaptive Cruise | openpilot | 0mph | 7mph |
| Chevrolet | Volt 2017-18<sup>1</sup> | Adaptive Cruise | openpilot | 0mph | 7mph |
| Chrysler | Pacifica 2017-18 | Adaptive Cruise | Stock | 0mph | 9mph |
| Chrysler | Pacifica 2020 | Adaptive Cruise | Stock | 0mph | 39mph |
| Chrysler | Pacifica Hybrid 2017-18 | Adaptive Cruise | Stock | 0mph | 9mph |
| Chrysler | Pacifica Hybrid 2019-20 | Adaptive Cruise | Stock | 0mph | 39mph |
| Genesis | G80 2018<sup>2</sup> | All | Stock | 0mph | 0mph |
| Genesis | G90 2018<sup>2</sup> | All | Stock | 0mph | 0mph |
| GMC | Acadia Denali 2018<sup>3</sup>| Adaptive Cruise | openpilot | 0mph | 7mph |
| Holden | Astra 2017<sup>1</sup> | Adaptive Cruise | openpilot | 0mph | 7mph |
| Hyundai | Elantra 2017-19<sup>2</sup> | SCC + LKAS | Stock | 19mph | 34mph |
| Hyundai | Genesis 2015-16<sup>2</sup> | SCC + LKAS | Stock | 19mph | 37mph |
| Hyundai | Ioniq 2017<sup>2</sup> | SCC + LKAS | Stock | 0mph | 32mph |
| Hyundai | Ioniq 2019 EV<sup>2</sup> | SCC + LKAS | Stock | 0mph | 32mph |
| Hyundai | Kona 2017-19<sup>2</sup> | SCC + LKAS | Stock | 22mph | 0mph |
| Hyundai | Kona 2019 EV<sup>2</sup> | SCC + LKAS | Stock | 0mph | 0mph |
| Hyundai | Palisade 2020<sup>2</sup> | All | Stock | 0mph | 0mph |
| Hyundai | Santa Fe 2019<sup>2</sup> | All | Stock | 0mph | 0mph |
| Hyundai | Sonata 2020<sup>2</sup> | All | Stock | 0mph | 0mph |
| Jeep | Grand Cherokee 2016-18 | Adaptive Cruise | Stock | 0mph | 9mph |
| Jeep | Grand Cherokee 2019 | Adaptive Cruise | Stock | 0mph | 39mph |
| Kia | Forte 2018<sup>2</sup> | SCC + LKAS | Stock | 0mph | 0mph |
| Kia | Optima 2017<sup>2</sup> | SCC + LKAS/LDWS | Stock | 0mph | 32mph |
| Kia | Optima 2019<sup>2</sup> | SCC + LKAS | Stock | 0mph | 0mph |
| Kia | Sorento 2018<sup>2</sup> | SCC + LKAS | Stock | 0mph | 0mph |
| Kia | Stinger 2018<sup>2</sup> | SCC + LKAS | Stock | 0mph | 0mph |
| Nissan | Leaf 2019 | Propilot | Stock | 0mph | 0mph |
| Nissan | X-Trail 2018 | Propilot | Stock | 0mph | 0mph |
| Subaru | Crosstrek 2018-19 | EyeSight | Stock | 0mph | 0mph |
| Subaru | Impreza 2018-20 | EyeSight | Stock | 0mph | 0mph |
| Volkswagen| Golf 2016-19<sup>3</sup> | Driver Assistance | Stock | 0mph | 0mph |
| Make | Model | Supported Package | Lateral | Longitudinal | No Accel Below | No Steer Below | Giraffe |
| ---------------------| -------------------------| ---------------------| --------| ---------------| -----------------| ---------------|-------------------|
| Honda | Fit 2018 | Honda Sensing | Yes | Yes | 25mph<sup>1</sup>| 12mph | Inverted Nidec |
| Tesla | Model S 2012 | All | Yes | Not yet | Not applicable | 0mph | Custom<sup>9</sup>|
| Tesla | Model S 2013 | All | Yes | Not yet | Not applicable | 0mph | Custom<sup>9</sup>|
<sup>1</sup>Requires a [panda](https://comma.ai/shop/products/panda-obd-ii-dongle) and [community built giraffe](https://zoneos.com/volt/). ***NOTE: disconnecting the ASCM disables Automatic Emergency Braking (AEB).*** <br />
<sup>2</sup>Requires a [panda](https://comma.ai/shop/products/panda-obd-ii-dongle) and open sourced [Hyundai giraffe](https://github.com/commaai/neo/tree/master/giraffe/hyundai), designed for the 2019 Sante Fe; pinout may differ for other Hyundai and Kia models. <br />
<sup>3</sup>Requires a [custom connector](https://community.comma.ai/wiki/index.php/Volkswagen#Integration_at_R242_Camera) for the [car harness](https://comma.ai/shop/products/car-harness) <br />
[[Honda Fit Pull Request]](https://github.com/commaai/openpilot/pull/266). <br />
[[Tesla Model S Pull Request]](https://github.com/commaai/openpilot/pull/246) <br />
<sup>9</sup>Community built Giraffe, find more information here [Community Tesla Giraffe](https://github.com/jeankalud/neo/tree/tesla_giraffe/giraffe/tesla) <br />
Although it's not upstream, there's a community of people getting openpilot to run on Tesla's [here](https://tinkla.us/)
Community Maintained Cars are not confirmed by comma.ai to meet our [safety model](https://github.com/commaai/openpilot/blob/devel/SAFETY.md). Be extra cautious using them.
Community Maintained Cars and Features are not verified by comma to meet our [safety model](SAFETY.md). Be extra cautious using them. They are only available after enabling the toggle in `Settings->Developer->Enable Community Features`.
In Progress Cars
------
- All TSS-P Toyota with Steering Assist and LSS-P Lexus with Steering Assist or Lane Keep Assist.
- Only remaining Toyota cars with no port yet are the Avalon and the Sienna.
- All Hyundai with SmartSense.
- All Kia with SCC and LKAS.
- All Chrysler, Jeep, Fiat with Adaptive Cruise Control and LaneSense.
To promote a car from community maintained, it must meet a few requirements. We must own one from the brand, we must sell the harness for it, has full ISO26262 in both panda and openpilot, there must be a path forward for longitudinal control, it must have AEB still enabled, and it must support fingerprinting 2.0
Installation Instructions
How can I add support for my car?
------
Install openpilot on an EON or comma two by entering ``https://openpilot.comma.ai`` during the installer setup.
If your car has adaptive cruise control and lane keep assist, you are in luck. Using a [panda](https://comma.ai/shop/products/panda-obd-ii-dongle/) and [cabana](https://community.comma.ai/cabana/), you can understand how to make your car drive by wire.
Follow these [video instructions](https://youtu.be/3nlkomHathI) to properly mount the device on the windshield. Note: openpilot features an automatic pose calibration routine and openpilot performance should not be affected by small pitch and yaw misalignments caused by imprecise device mounting.
We've written guides for [Brand](https://medium.com/@comma_ai/how-to-write-a-car-port-for-openpilot-7ce0785eda84) and [Model](https://medium.com/@comma_ai/openpilot-port-guide-for-toyota-models-e5467f4b5fe6) ports. These guides might help you after you have the basics figured out.
Before placing the device on your windshield, check the state and local laws and ordinances where you drive. Some state laws prohibit or restrict the placement of objects on the windshield of a motor vehicle.
- BMW, Audi, Volvo, and Mercedes all use [FlexRay](https://en.wikipedia.org/wiki/FlexRay) and can be supported after [FlexRay support](https://github.com/commaai/openpilot/pull/463) is merged.
- We put time into a Ford port, but the steering has a 10 second cutout limitation that makes it unusable.
- The 2016-2017 Honda Accord uses a custom signaling protocol for steering that's unlikely to ever be upstreamed.
You will be able to engage openpilot after reviewing the onboarding screens and finishing the calibration procedure.
Limitations of openpilot ALC and LDW
------
openpilot ALC and openpilot LDW do not automatically drive the vehicle or reduce the amount of attention that must be paid to operate your vehicle. The driver must always keep control of the steering wheel and be ready to correct the openpilot ALC action at all times.
While changing lanes, openpilot is not capable of looking next to you or checking your blind spot. Only nudge the wheel to initiate a lane change after you have confirmed it's safe to do so.
Many factors can impact the performance of openpilot ALC and openpilot LDW, causing them to be unable to function as intended. These include, but are not limited to:
* Poor visibility (heavy rain, snow, fog, etc.) or weather conditions that may interfere with sensor operation.
* The road facing camera is obstructed, covered or damaged by mud, ice, snow, etc.
* Obstruction caused by applying excessive paint or adhesive products (such as wraps, stickers, rubber coating, etc.) onto the vehicle.
* The device is mounted incorrectly.
* When in sharp curves, like on-off ramps, intersections etc...; openpilot is designed to be limited in the amount of steering torque it can produce.
* In the presence of restricted lanes or construction zones.
* When driving on highly banked roads or in presence of strong cross-wind.
* Extremely hot or cold temperatures.
* Bright light (due to oncoming headlights, direct sunlight, etc.).
* Driving on hills, narrow, or winding roads.
The list above does not represent an exhaustive list of situations that may interfere with proper operation of openpilot components. It is the driver's responsibility to be in control of the vehicle at all times.
Limitations of openpilot ACC and FCW
------
openpilot ACC and openpilot FCW are not systems that allow careless or inattentive driving. It is still necessary for the driver to pay close attention to the vehicles surroundings and to be ready to re-take control of the gas and the brake at all times.
Many factors can impact the performance of openpilot ACC and openpilot FCW, causing them to be unable to function as intended. These include, but are not limited to:
* Poor visibility (heavy rain, snow, fog, etc.) or weather conditions that may interfere with sensor operation.
* The road facing camera or radar are obstructed, covered, or damaged by mud, ice, snow, etc.
* Obstruction caused by applying excessive paint or adhesive products (such as wraps, stickers, rubber coating, etc.) onto the vehicle.
* The device is mounted incorrectly.
* Approaching a toll booth, a bridge or a large metal plate.
* When driving on roads with pedestrians, cyclists, etc...
* In presence of traffic signs or stop lights, which are not detected by openpilot at this time.
* When the posted speed limit is below the user selected set speed. openpilot does not detect speed limits at this time.
* In presence of vehicles in the same lane that are not moving.
* When abrupt braking maneuvers are required. openpilot is designed to be limited in the amount of deceleration and acceleration that it can produce.
* When surrounding vehicles perform close cut-ins from neighbor lanes.
* Driving on hills, narrow, or winding roads.
* Extremely hot or cold temperatures.
* Bright light (due to oncoming headlights, direct sunlight, etc.).
* Interference from other equipment that generates radar waves.
The list above does not represent an exhaustive list of situations that may interfere with proper operation of openpilot components. It is the driver's responsibility to be in control of the vehicle at all times.
Limitations of openpilot DM
------
openpilot DM should not be considered an exact measurement of the alertness of the driver.
Many factors can impact the performance of openpilot DM, causing it to be unable to function as intended. These include, but are not limited to:
* Low light conditions, such as driving at night or in dark tunnels.
* Bright light (due to oncoming headlights, direct sunlight, etc.).
* The driver's face is partially or completely outside field of view of the driver facing camera.
* Right hand driving vehicles.
* The driver facing camera is obstructed, covered, or damaged.
The list above does not represent an exhaustive list of situations that may interfere with proper operation of openpilot components. A driver should not rely on openpilot DM to assess their level of attention.
User Data and comma Account
------
By default, openpilot uploads the driving data to our servers. You can also access your data by pairing with the comma connect app ([iOS](https://apps.apple.com/us/app/comma-connect/id1456551889), [Android](https://play.google.com/store/apps/details?id=ai.comma.connect&hl=en_US)). We use your data to train better models and improve openpilot for everyone.
openpilot is open source software: the user is free to disable data collection if they wish to do so.
openpilot logs the road facing camera, CAN, GPS, IMU, magnetometer, thermal sensors, crashes, and operating system logs.
The driver facing camera is only logged if you explicitly opt-in in settings. The microphone is not recorded.
By using openpilot, you agree to [our Privacy Policy](https://my.comma.ai/privacy). You understand that use of this software or its related services will generate certain types of user data, which may be logged and stored at the sole discretion of comma. By accepting this agreement, you grant an irrevocable, perpetual, worldwide right to comma for the use of this data.
Safety and Testing
----
* openpilot observes ISO26262 guidelines, see [SAFETY.md](SAFETY.md) for more detail.
* openpilot has software in the loop [tests](.github/workflows/test.yaml) that run on every commit.
* The safety model code lives in panda and is written in C, see [code rigor](https://github.com/commaai/panda#code-rigor) for more details.
* panda has software in the loop [safety tests](https://github.com/commaai/panda/tree/master/tests/safety).
* Internally, we have a hardware in the loop Jenkins test suite that builds and unit tests the various processes.
* panda has additional hardware in the loop [tests](https://github.com/commaai/panda/blob/master/Jenkinsfile).
* We run the latest openpilot in a testing closet containing 10 EONs continuously replaying routes.
Testing on PC
------
Check out the tools directory in master: lots of tools you can use to replay driving data, test and develop openpilot from your pc.
Community and Contributing
------
openpilot is developed by [comma](https://comma.ai/) and by users like you. We welcome both pull requests and issues on [GitHub](http://github.com/commaai/openpilot). Bug fixes and new car ports are encouraged.
You can add support for your car by following guides we have written for [Brand](https://medium.com/@comma_ai/how-to-write-a-car-port-for-openpilot-7ce0785eda84) and [Model](https://medium.com/@comma_ai/openpilot-port-guide-for-toyota-models-e5467f4b5fe6) ports. Generally, a car with adaptive cruise control and lane keep assist is a good candidate. [Join our Discord](https://discord.comma.ai) to discuss car ports: most car makes have a dedicated channel.
Want to get paid to work on openpilot? [comma is hiring](https://comma.ai/jobs/). We also have a [bounty program](https://comma.ai/bounties.html).
And [follow us on Twitter](https://twitter.com/comma_ai).
Directory Structure
Directory structure
------
.
├── apk # The apk files used for the UI
├── cereal # The messaging spec and libs used for all logs
├── cereal # The messaging spec used for all logs on EON
├── common # Library like functionality we've developed here
├── installer/updater # Manages auto-updates of openpilot
├── opendbc # Files showing how to interpret data from cars
├── panda # Code used to communicate on CAN
├── phonelibs # Libraries used on NEOS devices
├── pyextra # Libraries used on NEOS devices
├── panda # Code used to communicate on CAN and LIN
├── phonelibs # Libraries used on EON
├── pyextra # Libraries used on EON
└── selfdrive # Code needed to drive the car
├── assets # Fonts, images, and sounds for UI
├── athena # Allows communication with the app
├── assets # Fonts and images for UI
├── boardd # Daemon to talk to the board
├── camerad # Driver to capture images from the camera sensors
├── can # Helpers for parsing CAN messages
├── car # Car specific code to read states and control actuators
├── common # Shared C/C++ code for the daemons
├── controls # Perception, planning and controls
@@ -305,20 +164,56 @@ Directory Structure
├── locationd # Soon to be home of precise location
├── logcatd # Android logcat as a service
├── loggerd # Logger and uploader of car data
├── modeld # Driving and monitoring model runners
├── mapd # Fetches map data and computes next global path
├── orbd # Computes ORB features from frames
├── proclogd # Logs information from proc
├── sensord # IMU / GPS interface code
├── test # Unit tests, system tests and a car simulator
── ui # The UI
├── test # Car simulator running code through virtual maneuvers
── ui # The UI
└── visiond # Vision pipeline
To understand how the services interact, see `cereal/service_list.yaml`.
To understand how the services interact, see `selfdrive/service_list.yaml`
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.
The user facing camera is only logged if you explicitly opt-in in settings.
It does not log the microphone.
By using it, you agree to [our privacy policy](https://community.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.
Testing on PC
------
Check out [openpilot-tools](https://github.com/commaai/openpilot-tools): lots of tools you can use to replay driving data, test and develop openpilot from your pc.
Also, within openpilot there is a rudimentary infrastructure to run a basic simulation and generate a report of openpilot's behavior in different longitudinal control scenarios.
```bash
# Requires working docker
./run_docker_tests.sh
```
Contributing
------
We welcome both pull requests and issues on [github](http://github.com/commaai/openpilot). Bug fixes and new car ports encouraged.
We also have a [bounty program](https://comma.ai/bounties.html).
Want to get paid to work on openpilot? [comma.ai is hiring](https://comma.ai/jobs/)
Licensing
------
openpilot is released under the MIT license. Some parts of the software are released under other licenses as specified.
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.
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.
@@ -327,8 +222,3 @@ NO WARRANTY EXPRESSED OR IMPLIED.**
---
<img src="https://d1qb2nb5cznatu.cloudfront.net/startups/i/1061157-bc7e9bf3b246ece7322e6ffe653f6af8-medium_jpg.jpg?buster=1458363130" width="75"></img> <img src="https://cdn-images-1.medium.com/max/1600/1*C87EjxGeMPrkTuVRVWVg4w.png" width="225"></img>
[![Total alerts](https://img.shields.io/lgtm/alerts/g/commaai/openpilot.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/commaai/openpilot/alerts/)
[![Language grade: Python](https://img.shields.io/lgtm/grade/python/g/commaai/openpilot.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/commaai/openpilot/context:python)
[![Language grade: C/C++](https://img.shields.io/lgtm/grade/cpp/g/commaai/openpilot.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/commaai/openpilot/context:cpp)
[![codecov](https://codecov.io/gh/commaai/openpilot/branch/master/graph/badge.svg)](https://codecov.io/gh/commaai/openpilot)
+36
View File
@@ -0,0 +1,36 @@
Welcome to chffrplus
======
[chffrplus](https://github.com/commaai/chffrplus) is an open source dashcam.
This is the shipping reference software for the comma EON Dashcam DevKit. It keeps many of the niceities of [openpilot](https://github.com/commaai/openpilot), like high quality sensors, great camera, and good autostart and stop. Though unlike openpilot, it cannot control your car. chffrplus can interface with your car through a [panda](https://shop.comma.ai/products/panda-obd-ii-dongle), but just like our dashcam app [chffr](https://getchffr.com/), it is read only.
It integrates with the rest of the comma ecosystem, so you can view your drives on the [chffr](https://getchffr.com/) app for Android or iOS, and reverse engineer your car with [cabana](https://community.comma.ai/cabana/?demo=1).
Hardware
------
Right now chffrplus supports the [EON Dashcam DevKit](https://shop.comma.ai/products/eon-dashcam-devkit) for hardware to run on.
Install chffrplus on a EON device by entering ``https://chffrplus.comma.ai`` during NEOS setup.
User Data / chffr Account / Crash Reporting
------
By default chffrplus creates an account and includes a client for chffr, our dashcam app.
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.
Licensing
------
chffrplus is released under the MIT license.
+1 -193
View File
@@ -1,195 +1,3 @@
Version 0.7.5 (2020-05-13)
========================
* Right-Hand Drive support for both driving and driver monitoring!
* New driving model: improved at sharp turns and lead speed estimation
* New driver monitoring model: overall improvement on comma two
* Driver camera preview in settings to improve mounting position
* Added support for many Hyundai, Kia, Genesis models thanks to xx979xx!
* 2019 Nissan X-Trail and 2018 Nissan Leaf support thanks to avolmensky!
* Improved lateral tuning for 2020 Toyota Rav 4 (hybrid)
Version 0.7.4 (2020-03-20)
========================
* New driving model: improved lane changes and lead car detection
* Improved driver monitoring model: improve eye detection
* Improved calibration stability
* Improved lateral control on some 2019 and 2020 Toyota Prius
* Improved lateral control on VW Golf: 20% more steering torque
* Fixed bug where some 2017 and 2018 Toyota C-HR would use the wrong steering angle sensor
* Support for Honda Insight thanks to theantihero!
* Code cleanup in car abstraction layers and ui
Version 0.7.3 (2020-02-21)
========================
* Support for 2020 Highlander thanks to che220!
* Support for 2018 Lexus NX 300h thanks to kengggg!
* Speed up ECU firmware query
* Fix bug where manager would sometimes hang after shutting down the car
Version 0.7.2 (2020-02-07)
========================
* ECU firmware version based fingerprinting for Honda & Toyota
* New driving model: improved path prediction during turns and lane changes and better lead speed tracking
* Improve driver monitoring under extreme lighting and add low accuracy alert
* Support for 2019 Rav4 Hybrid thanks to illumiN8i!
* Support for 2016, 2017 and 2020 Lexus RX thanks to illumiN8i!
* Support for 2020 Chrysler Pacifica Hybrid thanks to adhintz!
Version 0.7.1 (2020-01-20)
========================
* comma two support!
* Lane Change Assist above 45 mph!
* Replace zmq with custom messaging library, msgq!
* Supercombo model: calibration and driving models are combined for better lead estimate
* More robust updater thanks to jyoung8607! Requires NEOS update
* Improve low speed ACC tuning
Version 0.7 (2019-12-13)
========================
* Move to SCons build system!
* Add Lane Departure Warning (LDW) for all supported vehicles!
* NEOS update: increase wifi speed thanks to jyoung8607!
* Adaptive driver monitoring based on scene
* New driving model trained end-to-end: improve lane lines and lead detection
* Smarter torque limit alerts for all cars
* Improve GM longitudinal control: proper computations for 15Hz radar
* Move GM port, Toyota with DSU removed, comma pedal in community features; toggle switch required
* Remove upload over cellular toggle: only upload qlog and qcamera files if not on wifi
* Refactor Panda code towards ISO26262 and SIL2 compliancy
* Forward stock FCW for Honda Nidec
* Volkswagen port now standard: comma Harness intercepts stock camera
Version 0.6.6 (2019-11-05)
========================
* Volkswagen support thanks to jyoung8607!
* Toyota Corolla Hybrid with TSS 2.0 support thanks to u8511049!
* Lexus ES with TSS 2.0 support thanks to energee!
* Fix GM ignition detection and lock safety mode not required anymore
* Log panda firmware and dongle ID thanks to martinl!
* New driving model: improve path prediction and lead detection
* New driver monitoring model, 4x smaller and running on DSP
* Display an alert and don't start openpilot if panda has wrong firmware
* Fix bug preventing EON from terminating processes after a drive
* Remove support for Toyota giraffe without the 120Ohm resistor
Version 0.6.5 (2019-10-07)
========================
* NEOS update: upgrade to Python3 and new installer!
* comma Harness support!
* New driving model: improve path prediction
* New driver monitoring model: more accurate face and eye detection
* Redesign offroad screen to display updates and alerts
* Increase maximum allowed acceleration
* Prevent car 12V battery drain by cutting off EON charge after 3 days of no drive
* Lexus CT Hybrid support thanks to thomaspich!
* Louder chime for critical alerts
* Add toggle to switch to dashcam mode
* Fix "invalid vehicle params" error on DSU-less Toyota
Version 0.6.4 (2019-09-08)
========================
* Forward stock AEB for Honda Nidec
* Improve lane centering on banked roads
* Always-on forward collision warning
* Always-on driver monitoring, except for right hand drive countries
* Driver monitoring learns the user's normal driving position
* Honda Fit support thanks to energee!
* Lexus IS support
Version 0.6.3 (2019-08-12)
========================
* Alert sounds from EON: requires NEOS update
* Improve driver monitoring: eye tracking and improved awareness logic
* Improve path prediction with new driving model
* Improve lane positioning with wide lanes and exits
* Improve lateral control on RAV4
* Slow down for turns using model
* Open sourced regression test to verify outputs against reference logs
* Open sourced regression test to sanity check all car models
Version 0.6.2 (2019-07-29)
========================
* New driving model!
* Improve lane tracking with double lines
* Strongly improve stationary vehicle detection
* Strongly reduce cases of braking due to false leads
* Better lead tracking around turns
* Improve cut-in prediction by using neural network
* Improve lateral control on Toyota Camry and C-HR thanks to zorrobyte!
* Fix unintended openpilot disengagements on Jeep thanks to adhintz!
* Fix delayed transition to offroad when car is turned off
Version 0.6.1 (2019-07-21)
========================
* Remote SSH with comma prime and [ssh.comma.ai](https://ssh.comma.ai)
* Panda code Misra-c2012 compliance, tested against cppcheck coverage
* Lockout openpilot after 3 terminal alerts for driver distracted or unresponsive
* Toyota Sienna support thanks to wocsor!
Version 0.6 (2019-07-01)
========================
* New model, with double the pixels and ten times the temporal context!
* Car should not take exits when in the right lane
* openpilot uses only ~65% of the CPU (down from 75%)
* Routes visible in connect/explorer after only 0.2% is uploaded (qlogs)
* loggerd and sensord are open source, every line of openpilot is now open
* Panda safety code is MISRA compliant and ships with a signed version on release2
* New NEOS is 500MB smaller and has a reproducible usr/pipenv
* Lexus ES Hybrid support thanks to wocsor!
* Improve tuning for supported Toyota with TSS 2.0
* Various other stability improvements
Version 0.5.13 (2019-05-31)
==========================
* Reduce panda power consumption by 70%, down to 80mW, when car is off (not for GM)
* Reduce EON power consumption by 40%, down to 1100mW, when car is off
* Reduce CPU utilization by 20% and improve stability
* Temporarily remove mapd functionalities to improve stability
* Add openpilot record-only mode for unsupported cars
* Synchronize controlsd to boardd to reduce latency
* Remove panda support for Subaru giraffe
Version 0.5.12 (2019-05-16)
==========================
* Improve lateral control for the Prius and Prius Prime
* Compress logs before writing to disk
* Remove old driving data when storage reaches 90% full
* Fix small offset in following distance
* Various small CPU optimizations
* Improve offroad power consumption: require NEOS Update
* Add default speed limits for Estonia thanks to martinl!
* Subaru Crosstrek support thanks to martinl!
* Toyota Avalon support thanks to njbrown09!
* Toyota Rav4 with TSS 2.0 support thanks to wocsor!
* Toyota Corolla with TSS 2.0 support thanks to wocsor!
Version 0.5.11 (2019-04-17)
========================
* Add support for Subaru
* Reduce panda power consumption by 60% when car is off
* Fix controlsd lag every 6 minutes. This would sometimes cause disengagements
* Fix bug in controls with new angle-offset learner in MPC
* Reduce cpu consumption of ubloxd by rewriting it in C++
* Improve driver monitoring model and face detection
* Improve performance of visiond and ui
* Honda Passport 2019 support
* Lexus RX Hybrid 2019 support thanks to schomems!
* Improve road selection heuristic in mapd
* Add Lane Departure Warning to dashboard for Toyota thanks to arne182
Version 0.5.10 (2019-03-19)
========================
* Self-tuning vehicle parameters: steering offset, tire stiffness and steering ratio
* Improve longitudinal control at low speed when lead vehicle harshly decelerates
* Fix panda bug going unexpectedly in DCP mode when EON is connected
* Reduce white panda power consumption by 500mW when EON is disconnected by turning off WIFI
* New Driver Monitoring Model
* Support QR codes for login using comma connect
* Refactor comma pedal FW and use CRC-8 checksum algorithm for safety. Reflashing pedal is required.
Please see `#hw-pedal` on [discord](discord.comma.ai) for assistance updating comma pedal.
* Additional speed limit rules for Germany thanks to arne182
* Allow negative speed limit offsets
Version 0.5.9 (2019-02-10)
========================
* Improve calibration using a dedicated neural network
@@ -200,7 +8,7 @@ Version 0.5.9 (2019-02-10)
* Kia Optima support thanks to emmertex!
* Buick Regal 2018 support thanks to HOYS!
* Comma pedal support for Toyota thanks to wocsor! Note: tuning needed and not maintained by comma
* Chrysler Pacifica and Jeep Grand Cherokee support thanks to adhintz!
* Chrysler Pacifica and Jeep Grand Cherokee suppor thanks to adhintz!
Version 0.5.8 (2019-01-17)
========================
+92 -17
View File
@@ -1,26 +1,16 @@
openpilot Safety
======
openpilot is an Adaptive Cruise Control (ACC) and Automated Lane Centering (ALC) system.
Like other ACC and ALC systems, openpilot is a failsafe passive system and it requires the
driver to be alert and to pay attention at all times.
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**.
In order to enforce driver alertness, openpilot includes a driver monitoring feature
that alerts the driver when distracted.
However, even with an attentive driver, we must make further efforts for the system to be
safe. We repeat, **driver alertness is necessary, but not sufficient, for openpilot to be
used safely** and openpilot is provided with no warranty of fitness for any purpose.
openpilot is developed in good faith to be compliant with FMVSS requirements and to follow
industry standards of safety for Level 2 Driver Assistance Systems. In particular, we observe
ISO26262 guidelines, including those from [pertinent documents](https://www.nhtsa.gov/sites/nhtsa.dot.gov/files/documents/13498a_812_573_alcsystemreport.pdf)
released by NHTSA. In addition, we impose strict coding guidelines (like [MISRA C : 2012](https://www.misra.org.uk/MISRAHome/MISRAC2012/tabid/196/Default.aspx))
on parts of openpilot that are safety relevant. We also perform software-in-the-loop,
hardware-in-the-loop and in-vehicle tests before each software release.
Following Hazard and Risk Analysis and FMEA, at a very high level, we have designed openpilot
ensuring two main safety requirements.
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.
@@ -28,7 +18,92 @@ ensuring two main safety requirements.
react. This means that while the system is engaged, the actuators are constrained
to operate within reasonable limits.
For vehicle specific implementation of the safety concept, refer to `panda/board/safety/`.
Following are details of the car specific safety implementations:
**Extra note**: comma.ai strongly discourages the use of openpilot forks with safety code either missing or
Honda/Acura
------
- While the system is engaged, gas, brake and steer commands 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 panda firmware and openpilot clip it to 1/4th of the max.
This is approximately 0.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 signals triggers a disengagement, which is enforced by the panda firmware and by openpilot. The
white led on the panda signifies if the panda 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 commands are subject to the same limits used by
the stock system.
- With the stock Driving Support Unit (DSU) connected (or in DSU-less models like Camry and C-HR),
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 between .3g of deceleration and .15g of acceleration
by the panda firmware and by openpilot. 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 panda firmware and by
openpilot to a value between -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 panda firmware and by
openpilot, 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 panda firmware and by openpilot 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 signals triggers a disengagement, which is enforced by the
panda firmware and by openpilot. 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 openpilot and the
panda firmware. The white led on the panda signifies if the panda is allowing control messages.
GM/Chevrolet
------
- While the system is engaged, gas, brake and steer commands are subject to the same limits used by
the stock system.
- The gas and regen are controlled by the 0x2CB message and it's limited by the panda firmware and by
openpilot to a value between 1404 and 3072. the minimum value correspond to a mild decel due to regen,
while 3072 correspond to approximately 0.18g of acceleration from stop.
- The friction brakes are controlled by the 0x315 message and its value is limited by the panda firmware
and openpilot to 350. This is approximately 0.3g of braking.
- Steering torque is controlled through the 0x180 CAN message and it's limited by the panda firmware and by
openpilot to a value between -255 and 255. In addition, the vehicle EPS unit will not fault when
commands outside these limits. A steering torque rate limit is enforced by the panda firmware and by
openpilot, so that the commanded steering torque must rise from 0 to max value no faster than
0.75s. Commanded steering torque is gradually limited by the panda firmware and by openpilot if the driver's
torque exceeds 12 units in the opposite dicrection to ensure limited applied torque against the
driver's will.
- Brake pedal and gas pedal potentiometer signals are contained in the 0xF1 and 0x1A1 CAN messages,
respectively. A rising edge of either signals triggers a disengagement, which is enforced by the
panda firmware and by openpilot. Additionally, the cruise control system disengages on the rising edge of
the brake pedal pressed signal. The regen paddle pressed signal is in the 0xBD message. When the
regen paddle is pressed, a disengagement is enforced by both the firmware and by openpilot.
- GM CAN uses both a counter and a checksum to ensure integrity and prevent
replay of the same message.
**Extra note"**: comma.ai strongly discourages the use of openpilot forks with safety code either missing or
not fully meeting the above requirements.
-248
View File
@@ -1,248 +0,0 @@
import os
import subprocess
import sys
import platform
AddOption('--test',
action='store_true',
help='build test files')
AddOption('--asan',
action='store_true',
help='turn on ASAN')
arch = subprocess.check_output(["uname", "-m"], encoding='utf8').rstrip()
if platform.system() == "Darwin":
arch = "Darwin"
if arch == "aarch64" and not os.path.isdir("/system"):
arch = "larch64"
webcam = bool(ARGUMENTS.get("use_webcam", 0))
if arch == "aarch64" or arch == "larch64":
lenv = {
"LD_LIBRARY_PATH": '/data/data/com.termux/files/usr/lib',
"PATH": os.environ['PATH'],
}
if arch == "aarch64":
# android
lenv["ANDROID_DATA"] = os.environ['ANDROID_DATA']
lenv["ANDROID_ROOT"] = os.environ['ANDROID_ROOT']
cpppath = [
"#phonelibs/opencl/include",
]
libpath = [
"/usr/lib",
"/data/data/com.termux/files/usr/lib",
"/system/vendor/lib64",
"/system/comma/usr/lib",
"#phonelibs/nanovg",
]
if arch == "larch64":
cpppath += ["#phonelibs/capnp-cpp/include"]
libpath += ["#phonelibs/snpe/larch64"]
libpath += ["#phonelibs/libyuv/larch64/lib"]
libpath += ["#external/capnparm/lib", "/usr/lib/aarch64-linux-gnu"]
cflags = ["-DQCOM2", "-mcpu=cortex-a57"]
cxxflags = ["-DQCOM2", "-mcpu=cortex-a57"]
rpath = ["/usr/local/lib"]
else:
libpath += ["#phonelibs/snpe/aarch64"]
libpath += ["#phonelibs/libyuv/lib"]
cflags = ["-DQCOM", "-mcpu=cortex-a57"]
cxxflags = ["-DQCOM", "-mcpu=cortex-a57"]
rpath = ["/system/vendor/lib64"]
else:
lenv = {
"PATH": "#external/bin:" + os.environ['PATH'],
}
cpppath = [
"#phonelibs/capnp-cpp/include",
"#phonelibs/zmq/x64/include",
"#external/tensorflow/include",
]
if arch == "Darwin":
libpath = [
"#phonelibs/capnp-cpp/mac/lib",
"#phonelibs/libyuv/mac/lib",
"#cereal",
"#selfdrive/common",
"/usr/local/lib",
"/System/Library/Frameworks/OpenGL.framework/Libraries",
]
else:
libpath = [
"#phonelibs/capnp-cpp/x64/lib",
"#phonelibs/snpe/x86_64-linux-clang",
"#phonelibs/zmq/x64/lib",
"#phonelibs/libyuv/x64/lib",
"#external/zmq/lib",
"#external/tensorflow/lib",
"#cereal",
"#selfdrive/common",
"/usr/lib",
"/usr/local/lib",
]
rpath = ["phonelibs/capnp-cpp/x64/lib",
"phonelibs/zmq/x64/lib",
"external/tensorflow/lib",
"cereal",
"selfdrive/common"]
# allows shared libraries to work globally
rpath = [os.path.join(os.getcwd(), x) for x in rpath]
cflags = []
cxxflags = []
ccflags_asan = ["-fsanitize=address", "-fno-omit-frame-pointer"] if GetOption('asan') else []
ldflags_asan = ["-fsanitize=address"] if GetOption('asan') else []
# change pythonpath to this
lenv["PYTHONPATH"] = Dir("#").path
env = Environment(
ENV=lenv,
CCFLAGS=[
"-g",
"-fPIC",
"-O2",
"-Werror=implicit-function-declaration",
"-Werror=incompatible-pointer-types",
"-Werror=int-conversion",
"-Werror=return-type",
"-Werror=format-extra-args",
] + cflags + ccflags_asan,
CPPPATH=cpppath + [
"#",
"#selfdrive",
"#phonelibs/bzip2",
"#phonelibs/libyuv/include",
"#phonelibs/openmax/include",
"#phonelibs/json11",
"#phonelibs/eigen",
"#phonelibs/curl/include",
#"#phonelibs/opencv/include", # use opencv4 instead
"#phonelibs/libgralloc/include",
"#phonelibs/android_frameworks_native/include",
"#phonelibs/android_hardware_libhardware/include",
"#phonelibs/android_system_core/include",
"#phonelibs/linux/include",
"#phonelibs/snpe/include",
"#phonelibs/nanovg",
"#selfdrive/common",
"#selfdrive/camerad",
"#selfdrive/camerad/include",
"#selfdrive/loggerd/include",
"#selfdrive/modeld",
"#cereal/messaging",
"#cereal",
"#opendbc/can",
],
CC='clang',
CXX='clang++',
LINKFLAGS=ldflags_asan,
RPATH=rpath,
CFLAGS=["-std=gnu11"] + cflags,
CXXFLAGS=["-std=c++14"] + cxxflags,
LIBPATH=libpath +
[
"#cereal",
"#selfdrive/common",
"#phonelibs",
]
)
if os.environ.get('SCONS_CACHE'):
CacheDir('/tmp/scons_cache')
node_interval = 5
node_count = 0
def progress_function(node):
global node_count
node_count += node_interval
sys.stderr.write("progress: %d\n" % node_count)
if os.environ.get('SCONS_PROGRESS'):
Progress(progress_function, interval=node_interval)
SHARED = False
def abspath(x):
if arch == 'aarch64':
pth = os.path.join("/data/pythonpath", x[0].path)
env.Depends(pth, x)
return File(pth)
else:
# rpath works elsewhere
return x[0].path.rsplit("/", 1)[1][:-3]
# still needed for apks
if arch == 'larch64':
zmq = 'zmq'
else:
zmq = FindFile("libzmq.a", libpath)
Export('env', 'arch', 'zmq', 'SHARED', 'webcam')
# cereal and messaging are shared with the system
SConscript(['cereal/SConscript'])
if SHARED:
cereal = abspath([File('cereal/libcereal_shared.so')])
messaging = abspath([File('cereal/libmessaging_shared.so')])
else:
cereal = [File('#cereal/libcereal.a')]
messaging = [File('#cereal/libmessaging.a')]
Export('cereal', 'messaging')
SConscript(['selfdrive/common/SConscript'])
Import('_common', '_visionipc', '_gpucommon', '_gpu_libs')
if SHARED:
common, visionipc, gpucommon = abspath(common), abspath(visionipc), abspath(gpucommon)
else:
common = [_common, 'json11']
visionipc = _visionipc
gpucommon = [_gpucommon] + _gpu_libs
Export('common', 'visionipc', 'gpucommon')
SConscript(['opendbc/can/SConscript'])
SConscript(['common/SConscript'])
SConscript(['common/kalman/SConscript'])
SConscript(['phonelibs/SConscript'])
if arch != "Darwin":
SConscript(['selfdrive/camerad/SConscript'])
SConscript(['selfdrive/modeld/SConscript'])
SConscript(['selfdrive/controls/lib/cluster/SConscript'])
SConscript(['selfdrive/controls/lib/lateral_mpc/SConscript'])
SConscript(['selfdrive/controls/lib/longitudinal_mpc/SConscript'])
SConscript(['selfdrive/controls/lib/longitudinal_mpc_model/SConscript'])
SConscript(['selfdrive/boardd/SConscript'])
SConscript(['selfdrive/proclogd/SConscript'])
SConscript(['selfdrive/ui/SConscript'])
SConscript(['selfdrive/loggerd/SConscript'])
if arch == "aarch64":
SConscript(['selfdrive/logcatd/SConscript'])
SConscript(['selfdrive/sensord/SConscript'])
SConscript(['selfdrive/clocksd/SConscript'])
SConscript(['selfdrive/locationd/SConscript'])
SConscript(['selfdrive/locationd/kalman/SConscript'])
SConscript(['tools/lib/index_log/SConscript'])
Binary file not shown.
Binary file not shown.
Binary file not shown.
-1
View File
@@ -1 +0,0 @@
.sconsign.dblite
-23
View File
@@ -1,23 +0,0 @@
name: Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-16.04
steps:
- uses: actions/checkout@v2
- name: Build docker image
run: docker build -t cereal .
- name: Unit Tests
run: |
docker run cereal bash -c "scons --test --asan -j$(nproc) && messaging/test_runner"
- name: Test ZMQ
run: |
docker run cereal bash -c "ZMQ=1 python -m unittest discover ."
- name: Test MSGQ
run: |
docker run cereal bash -c "MSGQ=1 python -m unittest discover ."
-11
View File
@@ -1,14 +1,3 @@
gen
node_modules
package-lock.json
*.pyc
__pycache__
.*.swp
.*.swo
libcereal*.a
libmessaging.*
libmessaging_shared.*
services.h
.sconsign.dblite
libcereal_shared.*
-19
View File
@@ -1,19 +0,0 @@
from ubuntu:16.04
RUN apt-get update && apt-get install -y libzmq3-dev clang wget git autoconf libtool curl make build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev llvm libncurses5-dev libncursesw5-dev xz-utils tk-dev libffi-dev liblzma-dev python-openssl
RUN curl -L https://github.com/pyenv/pyenv-installer/raw/master/bin/pyenv-installer | bash
ENV PATH="/root/.pyenv/bin:/root/.pyenv/shims:${PATH}"
RUN pyenv install 3.7.3
RUN pyenv global 3.7.3
RUN pyenv rehash
RUN pip3 install pyyaml==5.1.2 Cython==0.29.14 scons==3.1.1 pycapnp==0.6.4
WORKDIR /project/cereal
COPY install_capnp.sh .
RUN ./install_capnp.sh
ENV PYTHONPATH=/project
COPY . .
RUN scons -c && scons -j$(nproc)
+62
View File
@@ -0,0 +1,62 @@
PWD := $(shell pwd)
SRCS := log.capnp car.capnp
GENS := gen/cpp/car.capnp.c++ gen/cpp/log.capnp.c++
JS := gen/js/car.capnp.js gen/js/log.capnp.js
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/include/c++.capnp.h gen/c/include/java.capnp.h
ifeq ($(UNAME_M),x86_64)
ifneq (, $(shell which capnpc-java))
GENS += gen/java/Car.java gen/java/Log.java
else
$(warning capnpc-java not found, skipping java build)
endif
endif
endif
ifeq ($(UNAME_M),aarch64)
CAPNPC=PATH=$(PWD)/../phonelibs/capnp-cpp/aarch64/bin/:$$PATH capnpc
else
CAPNPC=capnpc
endif
.PHONY: all
all: $(GENS)
js: $(JS)
.PHONY: clean
clean:
rm -rf gen
rm -rf node_modules
rm -rf package-lock.json
gen/c/%.capnp.c: %.capnp
@echo "[ CAPNPC C ] $@"
mkdir -p gen/c/
$(CAPNPC) '$<' -o c:gen/c/
gen/js/%.capnp.js: %.capnp
@echo "[ CAPNPC JavaScript ] $@"
mkdir -p gen/js/
sh ./generate_javascript.sh
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/include/c++.capnp.h gen/c/include/java.capnp.h:
mkdir -p gen/c/include
touch '$@'
-41
View File
@@ -1,41 +0,0 @@
What is cereal?
----
cereal is both a messaging spec for robotics systems as well as generic high performance IPC pub sub messaging with a single publisher and multiple subscribers.
Imagine this use case:
* A sensor process reads gyro measurements directly from an IMU and publishes a sensorEvents packet
* A calibration process subscribes to the sensorEvents packet to use the IMU
* A localization process subscribes to the sensorEvents packet to use the IMU also
Messaging Spec
----
You'll find the message types in [log.capnp](log.capnp). It uses [Cap'n proto](https://capnproto.org/capnp-tool.html) and defines one struct called Event.
All Events have a logMonoTime and a valid. Then a big union defines the packet type.
Pub Sub Backends
----
cereal supports two backends, one based on [zmq](https://zeromq.org/), the other called msgq, a custom pub sub based on shared memory that doesn't require the bytes to pass through the kernel.
Example
---
```python
import cereal.messaging as messaging
# in subscriber
sm = messaging.SubMaster(['sensorEvents'])
while 1:
sm.update()
print(sm['sensorEvents'])
# in publisher
pm = messaging.PubMaster(['sensorEvents'])
dat = messaging.new_message('sensorEvents', size=1)
dat.sensorEvents[0] = {"gyro": {"v": [0.1, -0.1, 0.1]}}
pm.send('sensorEvents', dat)
```
-62
View File
@@ -1,62 +0,0 @@
Import('env', 'arch', 'zmq')
gen_dir = Dir('gen')
messaging_dir = Dir('messaging')
# TODO: remove src-prefix and cereal from command string. can we set working directory?
env.Command(["gen/c/include/c++.capnp.h", "gen/c/include/java.capnp.h"], [], "mkdir -p " + gen_dir.path + "/c/include && touch $TARGETS")
env.Command(
['gen/cpp/car.capnp.c++', 'gen/cpp/log.capnp.c++', 'gen/cpp/car.capnp.h', 'gen/cpp/log.capnp.h'],
['car.capnp', 'log.capnp'],
'capnpc $SOURCES --src-prefix=cereal -o c++:' + gen_dir.path + '/cpp/')
import shutil
if shutil.which('capnpc-java'):
env.Command(
['gen/java/Car.java', 'gen/java/Log.java'],
['car.capnp', 'log.capnp'],
'capnpc $SOURCES --src-prefix=cereal -o java:' + gen_dir.path + '/java/')
# TODO: remove non shared cereal and messaging
cereal_objects = env.SharedObject([
'gen/cpp/car.capnp.c++',
'gen/cpp/log.capnp.c++',
])
env.Library('cereal', cereal_objects)
env.SharedLibrary('cereal_shared', cereal_objects)
cereal_dir = Dir('.')
services_h = env.Command(
['services.h'],
['service_list.yaml', 'services.py'],
'python3 ' + cereal_dir.path + '/services.py > $TARGET')
messaging_objects = env.SharedObject([
'messaging/messaging.cc',
'messaging/impl_zmq.cc',
'messaging/impl_msgq.cc',
'messaging/msgq.cc',
])
messaging_lib = env.Library('messaging', messaging_objects)
Depends('messaging/impl_zmq.cc', services_h)
# note, this rebuilds the deps shared, zmq is statically linked to make APK happy
# TODO: get APK to load system zmq to remove the static link
shared_lib_shared_lib = [zmq, 'm', 'stdc++'] + ["gnustl_shared"] if arch == "aarch64" else [zmq]
env.SharedLibrary('messaging_shared', messaging_objects, LIBS=shared_lib_shared_lib)
env.Program('messaging/bridge', ['messaging/bridge.cc'], LIBS=[messaging_lib, 'zmq'])
Depends('messaging/bridge.cc', services_h)
# different target?
#env.Program('messaging/demo', ['messaging/demo.cc'], LIBS=[messaging_lib, 'zmq'])
env.Command(['messaging/messaging_pyx.so'],
[messaging_lib, 'messaging/messaging_pyx_setup.py', 'messaging/messaging_pyx.pyx', 'messaging/messaging.pxd'],
"cd " + messaging_dir.path + " && python3 messaging_pyx_setup.py build_ext --inplace")
if GetOption('test'):
env.Program('messaging/test_runner', ['messaging/test_runner.cc', 'messaging/msgq_tests.cc'], LIBS=[messaging_lib])
-49
View File
@@ -1,49 +0,0 @@
import os
import subprocess
zmq = 'zmq'
arch = subprocess.check_output(["uname", "-m"], encoding='utf8').rstrip()
cereal_dir = Dir('.')
cpppath = [
cereal_dir,
'/usr/lib/include',
]
AddOption('--test',
action='store_true',
help='build test files')
AddOption('--asan',
action='store_true',
help='turn on ASAN')
ccflags_asan = ["-fsanitize=address", "-fno-omit-frame-pointer"] if GetOption('asan') else []
ldflags_asan = ["-fsanitize=address"] if GetOption('asan') else []
env = Environment(
ENV=os.environ,
CC='clang',
CXX='clang++',
CCFLAGS=[
"-g",
"-fPIC",
"-O2",
"-Werror=implicit-function-declaration",
"-Werror=incompatible-pointer-types",
"-Werror=int-conversion",
"-Werror=return-type",
"-Werror=format-extra-args",
] + ccflags_asan,
LDFLAGS=ldflags_asan,
LINKFLAGS=ldflags_asan,
CFLAGS="-std=gnu11",
CXXFLAGS="-std=c++14",
CPPPATH=cpppath,
)
Export('env', 'zmq', 'arch')
SConscript(['SConscript'])
+76 -236
View File
@@ -22,7 +22,7 @@ struct CarEvent @0x9b1657f34caf3ad3 {
enum EventName @0xbaa8c5d505f727de {
# TODO: copy from error list
canError @0;
commIssue @0;
steerUnavailable @1;
brakeUnavailable @2;
gasUnavailable @3;
@@ -37,7 +37,7 @@ struct CarEvent @0x9b1657f34caf3ad3 {
buttonEnable @12;
pedalPressed @13;
cruiseDisabled @14;
radarCanError @15;
radarCommIssue @15;
dataNeeded @16;
speedTooLow @17;
outOfSpace @18;
@@ -49,7 +49,7 @@ struct CarEvent @0x9b1657f34caf3ad3 {
pcmDisable @24;
noTarget @25;
radarFault @26;
modelCommIssueDEPRECATED @27;
modelCommIssue @27;
brakeHold @28;
parkBrake @29;
manualRestart @30;
@@ -72,39 +72,6 @@ struct CarEvent @0x9b1657f34caf3ad3 {
calibrationProgress @47;
lowBattery @48;
invalidGiraffeHonda @49;
vehicleModelInvalid @50;
controlsFailed @51;
sensorDataInvalid @52;
commIssue @53;
tooDistracted @54;
posenetInvalid @55;
soundsUnavailable @56;
preLaneChangeLeft @57;
preLaneChangeRight @58;
laneChange @59;
invalidGiraffeToyota @60;
internetConnectivityNeeded @61;
communityFeatureDisallowed @62;
lowMemory @63;
stockAeb @64;
ldw @65;
carUnrecognized @66;
radarCommIssue @67;
driverMonitorLowAcc @68;
invalidLkasSetting @69;
speedTooHigh @70;
laneChangeBlocked @71;
relayMalfunction @72;
gasPressed @73;
stockFcw @74;
# dp
preLaneChangeLeftALC @75;
preLaneChangeRightALC @76;
laneChangeALC @77;
manualSteeringRequired @78;
manualSteeringRequiredBlinkersOn @79;
leadCarMoving @80;
leadCarDetected @81;
}
}
@@ -133,17 +100,10 @@ struct CarState {
brakeLights @19 :Bool;
# steering wheel
steeringAngle @7 :Float32; # deg
steeringRate @15 :Float32; # deg/s
steeringTorque @8 :Float32; # TODO: standardize units
steeringTorqueEps @27 :Float32; # TODO: standardize units
steeringPressed @9 :Bool; # if the user is using the steering wheel
steeringRateLimited @29 :Bool; # if the torque is limited by the rate limiter
steerWarning @35 :Bool; # temporary steer unavailble
steerError @36 :Bool; # permanent steer error
stockAeb @30 :Bool;
stockFcw @31 :Bool;
espDisabled @32 :Bool;
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;
@@ -160,21 +120,10 @@ struct CarState {
# lock info
doorOpen @24 :Bool;
seatbeltUnlatched @25 :Bool;
canValid @26 :Bool;
# clutch (manual transmission only)
clutchPressed @28 :Bool;
# dp
lkMode @37 :Bool;
# which packets this state came from
canMonoTimes @12: List(UInt64);
# blindspot sensors
leftBlindspot @33 :Bool; # Is there something blocking the left lane change
rightBlindspot @34 :Bool; # Is there something blocking the right lane change
struct WheelSpeeds {
# optional wheel speeds
fl @0 :Float32;
@@ -200,10 +149,9 @@ struct CarState {
sport @5;
low @6;
brake @7;
eco @8;
manumatic @9;
}
# send on change
struct ButtonEvent {
pressed @0 :Bool;
@@ -219,16 +167,13 @@ struct CarState {
altButton1 @6;
altButton2 @7;
altButton3 @8;
setCruise @9;
resumeCruise @10;
gapAdjustCruise @11;
}
}
}
# ******* radar state @ 20hz *******
struct RadarData @0x888ad6581cf0aacb {
struct RadarState {
errors @0 :List(Error);
points @1 :List(RadarPoint);
@@ -236,7 +181,7 @@ struct RadarData @0x888ad6581cf0aacb {
canMonoTimes @2 :List(UInt64);
enum Error {
canError @0;
commIssue @0;
fault @1;
wrongConfig @2;
}
@@ -301,8 +246,6 @@ struct CarControl {
audibleAlert @5: AudibleAlert;
rightLaneVisible @6: Bool;
leftLaneVisible @7: Bool;
rightLaneDepart @8: Bool;
leftLaneDepart @9: Bool;
enum VisualAlert {
# these are the choices from the Honda
@@ -314,7 +257,6 @@ struct CarControl {
wrongGear @4;
seatbeltUnbuckled @5;
speedTooHigh @6;
ldw @7;
}
enum AudibleAlert {
@@ -328,7 +270,6 @@ struct CarControl {
chimeWarning2 @5;
chimeWarningRepeat @6;
chimePrompt @7;
chimeWarning2Repeat @8;
}
}
}
@@ -337,190 +278,89 @@ struct CarControl {
struct CarParams {
carName @0 :Text;
carFingerprint @1 :Text;
radarNameDEPRECATED @1 :Text;
carFingerprint @2 :Text;
enableGasInterceptor @2 :Bool;
enableCruise @3 :Bool;
enableCamera @4 :Bool;
enableDsu @5 :Bool; # driving support unit
enableApgs @6 :Bool; # advanced parking guidance system
enableSteerDEPRECATED @3 :Bool;
enableGasInterceptor @4 :Bool;
enableBrakeDEPRECATED @5 :Bool;
enableCruise @6 :Bool;
enableCamera @26 :Bool;
enableDsu @27 :Bool; # driving support unit
enableApgs @28 :Bool; # advanced parking guidance system
minEnableSpeed @7 :Float32;
minSteerSpeed @8 :Float32;
safetyModel @9 :SafetyModel;
safetyModelPassive @42 :SafetyModel = silent;
safetyParam @10 :Int16;
minEnableSpeed @17 :Float32;
minSteerSpeed @49 :Float32;
safetyModel @18 :Int16;
safetyParam @41 :Int16;
steerMaxBP @11 :List(Float32);
steerMaxV @12 :List(Float32);
gasMaxBP @13 :List(Float32);
gasMaxV @14 :List(Float32);
brakeMaxBP @15 :List(Float32);
brakeMaxV @16 :List(Float32);
steerMaxBP @19 :List(Float32);
steerMaxV @20 :List(Float32);
gasMaxBP @21 :List(Float32);
gasMaxV @22 :List(Float32);
brakeMaxBP @23 :List(Float32);
brakeMaxV @24 :List(Float32);
# things about the car in the manual
mass @17 :Float32; # [kg] running weight
wheelbase @18 :Float32; # [m] distance from rear to front axle
centerToFront @19 :Float32; # [m] GC distance to front axle
steerRatio @20 :Float32; # [] ratio between front wheels and steering wheel angles
steerRatioRear @21 :Float32; # [] rear steering ratio wrt front steering (usually 0)
longPidDeadzoneBP @32 :List(Float32);
longPidDeadzoneV @33 :List(Float32);
# things we can derive
rotationalInertia @22 :Float32; # [kg*m2] body rotational inertia
tireStiffnessFront @23 :Float32; # [N/rad] front tire coeff of stiff
tireStiffnessRear @24 :Float32; # [N/rad] rear tire coeff of stiff
longitudinalTuning @25 :LongitudinalPIDTuning;
lateralParams @48 :LateralParams;
lateralTuning :union {
pid @26 :LateralPIDTuning;
indi @27 :LateralINDITuning;
lqr @40 :LateralLQRTuning;
}
steerLimitAlert @28 :Bool;
steerLimitTimer @47 :Float32; # time before steerLimitAlert is issued
vEgoStopping @29 :Float32; # Speed at which the car goes into stopping state
directAccelControl @30 :Bool; # Does the car have direct accel control or just gas/brake
stoppingControl @31 :Bool; # Does the car allows full control even at lows speeds when stopping
startAccel @32 :Float32; # Required acceleraton to overcome creep braking
steerRateCost @33 :Float32; # Lateral MPC cost on steering rate
steerControlType @34 :SteerControlType;
radarOffCan @35 :Bool; # True when radar objects aren't visible on CAN
steerActuatorDelay @36 :Float32; # Steering wheel actuator delay in seconds
openpilotLongitudinalControl @37 :Bool; # is openpilot doing the longitudinal control?
carVin @38 :Text; # VIN number queried during fingerprinting
isPandaBlack @39: Bool;
dashcamOnly @41: Bool;
transmissionType @43 :TransmissionType;
carFw @44 :List(CarFw);
radarTimeStep @45: Float32 = 0.05; # time delta between radar updates, 20Hz is very standard
communityFeature @46: Bool; # true if a community maintained feature is detected
fingerprintSource @49: FingerprintSource;
networkLocation @50 :NetworkLocation; # Where Panda/C2 is integrated into the car's CAN network
struct LateralParams {
torqueBP @0 :List(Int32);
torqueV @1 :List(Int32);
}
struct LateralPIDTuning {
kpBP @0 :List(Float32);
kpV @1 :List(Float32);
kiBP @2 :List(Float32);
kiV @3 :List(Float32);
kf @4 :Float32;
}
struct LongitudinalPIDTuning {
kpBP @0 :List(Float32);
kpV @1 :List(Float32);
kiBP @2 :List(Float32);
kiV @3 :List(Float32);
deadzoneBP @4 :List(Float32);
deadzoneV @5 :List(Float32);
}
struct LateralINDITuning {
outerLoopGain @0 :Float32;
innerLoopGain @1 :Float32;
timeConstant @2 :Float32;
actuatorEffectiveness @3 :Float32;
}
struct LateralLQRTuning {
scale @0 :Float32;
ki @1 :Float32;
dcGain @2 :Float32;
# State space system
a @3 :List(Float32);
b @4 :List(Float32);
c @5 :List(Float32);
k @6 :List(Float32); # LQR gain
l @7 :List(Float32); # Kalman gain
}
enum SafetyModel {
silent @0;
hondaNidec @1;
enum SafetyModels {
# does NOT match board setting
noOutput @0;
honda @1;
toyota @2;
elm327 @3;
gm @4;
hondaBoschGiraffe @5;
hondaBosch @5;
ford @6;
cadillac @7;
hyundai @8;
chrysler @9;
tesla @10;
subaru @11;
gmPassive @12;
mazda @13;
nissan @14;
volkswagen @15;
toyotaIpas @16;
allOutput @17;
gmAscm @18;
noOutput @19; # like silent but without silent CAN TXs
hondaBoschHarness @20;
volkswagenPq @21;
subaruLegacy @22; # pre-Global platform
}
# 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
steerKpBP @42 :List(Float32);
steerKpV @43 :List(Float32);
steerKiBP @44 :List(Float32);
steerKiV @45 :List(Float32);
steerKpDEPRECATED @15 :Float32;
steerKiDEPRECATED @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
steerControlType @46 :SteerControlType;
radarOffCan @47 :Bool; # True when radar objects aren't visible on CAN
steerActuatorDelay @48 :Float32; # Steering wheel actuator delay in seconds
openpilotLongitudinalControl @50 :Bool; # is openpilot doing the longitudinal control?
enum SteerControlType {
torque @0;
angle @1;
}
enum TransmissionType {
unknown @0;
automatic @1; # Traditional auto, including DSG
manual @2; # True "stick shift" only
direct @3; # Electric vehicle or other direct drive
}
struct CarFw {
ecu @0 :Ecu;
fwVersion @1 :Data;
address @2: UInt32;
subAddress @3: UInt8;
}
enum Ecu {
eps @0;
esp @1;
fwdRadar @2;
fwdCamera @3;
engine @4;
unknown @5;
transmission @8; # Transmission Control Module
srs @9; # airbag
gateway @10; # can gateway
hud @11; # heads up display
combinationMeter @12; # instrument cluster
# Toyota only
dsu @6;
apgs @7;
# Honda only
vsa @13; # Vehicle Stability Assist
programmedFuelInjection @14;
electricBrakeBooster @15;
shiftByWire @16;
}
enum FingerprintSource {
can @0;
fw @1;
fixed @2;
}
enum NetworkLocation {
fwdCamera @0; # Standard/default integration at LKAS camera
gateway @1; # Integration at vehicle's CAN gateway
}
}
-26
View File
@@ -1,26 +0,0 @@
#!/bin/bash
rm -r gen/ts
rm -r gen/js
mkdir gen/ts
mkdir gen/js
echo "Installing needed npm modules"
npm i capnpc-ts capnp-ts
capnpc -o node_modules/.bin/capnpc-ts:gen/ts log.capnp car.capnp
capnpc -o node_modules/.bin/capnpc-ts:gen/ts car.capnp
cat log.capnp | egrep '\([a-zA-Z]*\.[^\s]+\.[^s]+\)' | sed 's/^.*([a-zA-Z]*\.\([a-zA-Z.]*\)).*/\1/' | while read line
do
TOKEN=`echo $line | sed 's/\./_/g'`
ROOT=`echo $line | sed 's/\..*$//g'`
cat gen/ts/log.capnp.ts | grep '^import.*'${TOKEN}
if [[ "$?" == "1" ]]
then
sed -i 's/^\(import {.*\)'${ROOT}'\(,*\) \(.*\)$/\1'${ROOT}', '${TOKEN}'\2 \3/' ./gen/ts/log.capnp.ts
fi
done
tsc ./gen/ts/* --lib es2015 --outDir ./gen/js
-40
View File
@@ -1,40 +0,0 @@
set -e
echo "Installing capnp"
cd /tmp
VERSION=0.6.1
wget https://capnproto.org/capnproto-c++-${VERSION}.tar.gz
tar xvf capnproto-c++-${VERSION}.tar.gz
cd capnproto-c++-${VERSION}
CXXFLAGS="-fPIC" ./configure
make -j$(nproc)
make install
# manually build binaries statically
g++ -std=gnu++11 -I./src -I./src -DKJ_HEADER_WARNINGS -DCAPNP_HEADER_WARNINGS -DCAPNP_INCLUDE_DIR=\"/usr/local/include\" -pthread -O2 -DNDEBUG -pthread -pthread -o .libs/capnp src/capnp/compiler/module-loader.o src/capnp/compiler/capnp.o ./.libs/libcapnpc.a ./.libs/libcapnp.a ./.libs/libkj.a -lpthread -pthread
g++ -std=gnu++11 -I./src -I./src -DKJ_HEADER_WARNINGS -DCAPNP_HEADER_WARNINGS -DCAPNP_INCLUDE_DIR=\"/usr/local/include\" -pthread -O2 -DNDEBUG -pthread -pthread -o .libs/capnpc-c++ src/capnp/compiler/capnpc-c++.o ./.libs/libcapnp.a ./.libs/libkj.a -lpthread -pthread
g++ -std=gnu++11 -I./src -I./src -DKJ_HEADER_WARNINGS -DCAPNP_HEADER_WARNINGS -DCAPNP_INCLUDE_DIR=\"/usr/local/include\" -pthread -O2 -DNDEBUG -pthread -pthread -o .libs/capnpc-capnp src/capnp/compiler/capnpc-capnp.o ./.libs/libcapnp.a ./.libs/libkj.a -lpthread -pthread
cp .libs/capnp /usr/local/bin/
cp .libs/capnpc-c++ /usr/local/bin/
cp .libs/capnpc-capnp /usr/local/bin/
cp .libs/*.a /usr/local/lib
cd /tmp
echo "Installing c-capnp"
git clone https://github.com/commaai/c-capnproto.git
cd c-capnproto
git submodule update --init --recursive
autoreconf -f -i -s
CXXFLAGS="-fPIC" ./configure
make -j$(nproc)
make install
# manually build binaries statically
gcc -fPIC -o .libs/capnpc-c compiler/capnpc-c.o compiler/schema.capnp.o compiler/str.o ./.libs/libcapnp_c.a
cp .libs/capnpc-c /usr/local/bin/
cp .libs/*.a /usr/local/lib
+28 -372
View File
@@ -126,10 +126,6 @@ struct FrameData {
lensErr @13 :Float32;
lensTruePos @14 :Float32;
image @6 :Data;
gainFrac @15 :Float32;
focusVal @16 :List(Int16);
focusConf @17 :List(UInt8);
sharpnessScore @18 :List(UInt16);
frameType @7 :FrameType;
timestampSof @8 :UInt64;
@@ -141,7 +137,6 @@ struct FrameData {
unknown @0;
neo @1;
chffrAndroid @2;
front @3;
}
struct AndroidCaptureResult {
@@ -155,12 +150,6 @@ struct FrameData {
}
}
struct Thumbnail {
frameId @0 :UInt32;
timestampEof @1 :UInt64;
thumbnail @2 :Data;
}
struct GPSNMEAData {
timestamp @0 :Int64;
localWallTime @1 :UInt64;
@@ -273,7 +262,6 @@ struct ThermalData {
mem @4 :UInt16;
gpu @5 :UInt16;
bat @6 :UInt32;
pa0 @21 :UInt16;
# not thermal
freeSpace @7 :Float32;
@@ -282,9 +270,6 @@ struct ThermalData {
batteryCurrent @15 :Int32;
batteryVoltage @16 :Int32;
usbOnline @12 :Bool;
networkType @22 :NetworkType;
offroadPowerUsage @23 :UInt32; # Power usage since going offroad in uWh
networkStrength @24 :NetworkStrength;
fanSpeed @10 :UInt16;
started @11 :Bool;
@@ -294,103 +279,23 @@ struct ThermalData {
chargingError @17 :Bool;
chargingDisabled @18 :Bool;
memUsedPercent @19 :Int8;
cpuPerc @20 :Int8;
ipAddr @25 :Text; # dp
enum ThermalStatus {
green @0; # all processes run
yellow @1; # critical processes run (kill uploader), engage still allowed
red @2; # no engage, will disengage
danger @3; # immediate process shutdown
}
enum NetworkType {
none @0;
wifi @1;
cell2G @2;
cell3G @3;
cell4G @4;
cell5G @5;
}
enum NetworkStrength {
unknown @0;
poor @1;
moderate @2;
good @3;
great @4;
}
}
struct HealthData {
# from can health
voltage @0 :UInt32;
current @1 :UInt32;
ignitionLine @2 :Bool;
started @2 :Bool;
controlsAllowed @3 :Bool;
gasInterceptorDetected @4 :Bool;
startedSignalDetectedDeprecated @5 :Bool;
hasGps @6 :Bool;
canSendErrs @7 :UInt32;
canFwdErrs @8 :UInt32;
canRxErrs @19 :UInt32;
gmlanSendErrs @9 :UInt32;
hwType @10 :HwType;
fanSpeedRpm @11 :UInt16;
usbPowerMode @12 :UsbPowerMode;
ignitionCan @13 :Bool;
safetyModel @14 :Car.CarParams.SafetyModel;
faultStatus @15 :FaultStatus;
powerSaveEnabled @16 :Bool;
uptime @17 :UInt32;
faults @18 :List(FaultType);
enum FaultStatus {
none @0;
faultTemp @1;
faultPerm @2;
}
enum FaultType {
relayMalfunction @0;
unusedInterruptHandled @1;
interruptRateCan1 @2;
interruptRateCan2 @3;
interruptRateCan3 @4;
interruptRateTach @5;
interruptRateGmlan @6;
interruptRateInterrupts @7;
interruptRateSpiDma @8;
interruptRateSpiCs @9;
interruptRateUart1 @10;
interruptRateUart2 @11;
interruptRateUart3 @12;
interruptRateUart5 @13;
interruptRateUartDma @14;
interruptRateUsb @15;
interruptRateTim1 @16;
interruptRateTim3 @17;
registerDivergent @18;
# Update max fault type in boardd when adding faults
}
enum HwType {
unknown @0;
whitePanda @1;
greyPanda @2;
blackPanda @3;
pedal @4;
uno @5;
}
enum UsbPowerMode {
none @0;
client @1;
cdp @2;
dcp @3;
}
startedSignalDetected @5 :Bool;
isGreyPanda @6 :Bool;
}
struct LiveUI {
@@ -400,12 +305,12 @@ struct LiveUI {
awarenessStatus @3 :Float32;
}
struct RadarState @0x9a185389d6fdd05f {
struct Live20Data {
canMonoTimes @10 :List(UInt64);
mdMonoTime @6 :UInt64;
ftMonoTimeDEPRECATED @7 :UInt64;
controlsStateMonoTime @11 :UInt64;
radarErrors @12 :List(Car.RadarData.Error);
l100MonoTime @11 :UInt64;
radarErrors @12 :List(Car.RadarState.Error);
# all deprecated
warpMatrixDEPRECATED @0 :List(Float32);
@@ -432,8 +337,6 @@ struct RadarState @0x9a185389d6fdd05f {
fcw @10 :Bool;
status @11 :Bool;
aLeadTau @12 :Float32;
modelProb @13 :Float32;
radar @14 :Bool;
}
}
@@ -450,8 +353,6 @@ struct LiveCalibrationData {
# view_frame_from_road_frame
# ui's is inversed needs new
extrinsicMatrix @4 :List(Float32);
# the direction of travel vector in device frame
rpyCalib @7 :List(Float32);
}
struct LiveTracks {
@@ -467,15 +368,15 @@ struct LiveTracks {
oncoming @9 :Bool;
}
struct ControlsState @0x97ff69c53601abf1 {
struct Live100Data {
canMonoTimeDEPRECATED @16 :UInt64;
canMonoTimes @21 :List(UInt64);
radarStateMonoTimeDEPRECATED @17 :UInt64;
l20MonoTimeDEPRECATED @17 :UInt64;
mdMonoTimeDEPRECATED @18 :UInt64;
planMonoTime @28 :UInt64;
pathPlanMonoTime @50 :UInt64;
state @31 :OpenpilotState;
state @31 :ControlState;
vEgo @0 :Float32;
vEgoRaw @32 :Float32;
aEgoDEPRECATED @1 :Float32;
@@ -487,9 +388,9 @@ struct ControlsState @0x97ff69c53601abf1 {
ufAccelCmd @33 :Float32;
yActualDEPRECATED @6 :Float32;
yDesDEPRECATED @7 :Float32;
upSteerDEPRECATED @8 :Float32;
uiSteerDEPRECATED @9 :Float32;
ufSteerDEPRECATED @34 :Float32;
upSteer @8 :Float32;
uiSteer @9 :Float32;
ufSteer @34 :Float32;
aTargetMinDEPRECATED @10 :Float32;
aTargetMaxDEPRECATED @11 :Float32;
aTarget @35 :Float32;
@@ -516,10 +417,9 @@ struct ControlsState @0x97ff69c53601abf1 {
alertSize @39 :AlertSize;
alertBlinkingRate @42 :Float32;
alertType @44 :Text;
alertSoundDEPRECATED @45 :Text;
alertSound @56 :Car.CarControl.HUDControl.AudibleAlert;
alertSound @45 :Text;
awarenessStatus @26 :Float32;
angleModelBiasDEPRECATED @27 :Float32;
angleOffset @27 :Float32;
gpsPlannerActive @40 :Bool;
engageable @41 :Bool; # can OP be engaged?
driverMonitoringOn @43 :Bool;
@@ -528,16 +428,7 @@ struct ControlsState @0x97ff69c53601abf1 {
vCurvature @46 :Float32;
decelForTurn @47 :Bool;
decelForModel @54 :Bool;
canErrorCounter @57 :UInt32;
lateralControlState :union {
indiState @52 :LateralINDIState;
pidState @53 :LateralPIDState;
lqrState @55 :LateralLQRState;
}
enum OpenpilotState @0xdbe58b96d2d1ac61 {
enum ControlState {
disabled @0;
preEnabled @1;
enabled @2;
@@ -564,42 +455,6 @@ struct ControlsState @0x97ff69c53601abf1 {
full @3; # full screen
}
struct LateralINDIState {
active @0 :Bool;
steerAngle @1 :Float32;
steerRate @2 :Float32;
steerAccel @3 :Float32;
rateSetPoint @4 :Float32;
accelSetPoint @5 :Float32;
accelError @6 :Float32;
delayedOutput @7 :Float32;
delta @8 :Float32;
output @9 :Float32;
saturated @10 :Bool;
}
struct LateralPIDState {
active @0 :Bool;
steerAngle @1 :Float32;
steerRate @2 :Float32;
angleError @3 :Float32;
p @4 :Float32;
i @5 :Float32;
f @6 :Float32;
output @7 :Float32;
saturated @8 :Bool;
}
struct LateralLQRState {
active @0 :Bool;
steerAngle @1 :Float32;
i @2 :Float32;
output @3 :Float32;
lqrOutput @4 :Float32;
saturated @5 :Bool;
}
}
struct LiveEventData {
@@ -609,7 +464,6 @@ struct LiveEventData {
struct ModelData {
frameId @0 :UInt32;
timestampEof @9 :UInt64;
path @1 :PathData;
leftLane @2 :PathData;
@@ -618,29 +472,17 @@ struct ModelData {
freePath @6 :List(Float32);
settings @5 :ModelSettings;
leadFuture @7 :LeadData;
speed @8 :List(Float32);
meta @10 :MetaData;
longitudinal @11 :LongitudinalData;
struct PathData {
points @0 :List(Float32);
prob @1 :Float32;
std @2 :Float32;
stds @3 :List(Float32);
poly @4 :List(Float32);
}
struct LeadData {
dist @0 :Float32;
prob @1 :Float32;
std @2 :Float32;
relVel @3 :Float32;
relVelStd @4 :Float32;
relY @5 :Float32;
relYStd @6 :Float32;
relA @7 :Float32;
relAStd @8 :Float32;
}
struct ModelSettings {
@@ -652,21 +494,6 @@ struct ModelData {
yuvCorrection @5 :List(Float32);
inputTransform @6 :List(Float32);
}
struct MetaData {
engagedProb @0 :Float32;
desirePrediction @1 :List(Float32);
brakeDisengageProb @2 :Float32;
gasDisengageProb @3 :Float32;
steerOverrideProb @4 :Float32;
desireState @5 :List(Float32);
}
struct LongitudinalData {
distances @2 :List(Float32);
speeds @0 :List(Float32);
accelerations @1 :List(Float32);
}
}
struct CalibrationFeatures {
@@ -717,10 +544,8 @@ struct LogRotate {
struct Plan {
mdMonoTime @9 :UInt64;
radarStateMonoTime @10 :UInt64;
commIssue @31 :Bool;
eventsDEPRECATED @13 :List(Car.CarEvent);
l20MonoTime @10 :UInt64;
events @13 :List(Car.CarEvent);
# lateral, 3rd order polynomial
lateralValidDEPRECATED @0 :Bool;
@@ -757,10 +582,6 @@ struct Plan {
vCurvature @21 :Float32;
decelForTurn @22 :Bool;
mapValid @25 :Bool;
radarValid @28 :Bool;
radarCanError @30 :Bool;
processingDelay @29 :Float32;
struct GpsTrajectory {
@@ -773,7 +594,6 @@ struct Plan {
mpc1 @1;
mpc2 @2;
mpc3 @3;
model @4;
}
}
@@ -788,90 +608,8 @@ struct PathPlan {
rPoly @6 :List(Float32);
rProb @7 :Float32;
angleSteers @8 :Float32; # deg
rateSteers @13 :Float32; # deg/s
mpcSolutionValid @9 :Bool;
paramsValid @10 :Bool;
modelValidDEPRECATED @12 :Bool;
angleOffset @11 :Float32;
sensorValid @14 :Bool;
commIssue @15 :Bool;
posenetValid @16 :Bool;
desire @17 :Desire;
laneChangeState @18 :LaneChangeState;
laneChangeDirection @19 :LaneChangeDirection;
# dragonpilot
alcAllowed @20 :Bool;
enum Desire {
none @0;
turnLeft @1;
turnRight @2;
laneChangeLeft @3;
laneChangeRight @4;
keepLeft @5;
keepRight @6;
}
enum LaneChangeState {
off @0;
preLaneChange @1;
laneChangeStarting @2;
laneChangeFinishing @3;
}
enum LaneChangeDirection {
none @0;
left @1;
right @2;
}
}
struct LiveLocationKalman {
# More info on reference frames:
# https://github.com/commaai/openpilot/tree/master/common/transformations
positionECEF @0 : Measurement;
positionGeodetic @1 : Measurement;
velocityECEF @2 : Measurement;
velocityNED @3 : Measurement;
velocityDevice @4 : Measurement;
accelerationDevice @5: Measurement;
# These angles are all eulers and roll, pitch, yaw
# orientationECEF transforms to rot matrix: ecef_from_device
orientationECEF @6 : Measurement;
orientationNED @7 : Measurement;
angularVelocityDevice @8 : Measurement;
# orientationNEDCalibrated transforms to rot matrix: NED_from_calibrated
orientationNEDCalibrated @9 : Measurement;
# Calibrated frame is simply device frame
# aligned with the vehicle
velocityCalibrated @10 : Measurement;
accelerationCalibrated @11 : Measurement;
angularVelocityCalibrated @12 : Measurement;
gpsWeek @13 :Int32;
gpsTimeOfWeek @14 :Float64;
status @15 :Status;
unixTimestampMillis @16 :Int64;
enum Status {
uninitialized @0;
uncalibrated @1;
valid @2;
}
struct Measurement {
value @0 : List(Float64);
std @1 : List(Float64);
valid @2 : Bool;
}
angleSteers @8 :Float32;
valid @9 :Bool;
}
struct LiveLocationData {
@@ -1517,7 +1255,6 @@ struct UbloxGnss {
measurementReport @0 :MeasurementReport;
ephemeris @1 :Ephemeris;
ionoData @2 :IonoData;
hwStatus @3 :HwStatus;
}
struct MeasurementReport {
@@ -1641,30 +1378,9 @@ struct UbloxGnss {
healthValid @5 :Bool;
ionoCoeffsValid @6 :Bool;
}
struct HwStatus {
noisePerMS @0 :UInt16;
agcCnt @1 :UInt16;
aStatus @2 :AntennaSupervisorState;
aPower @3 :AntennaPowerStatus;
jamInd @4 :UInt8;
enum AntennaSupervisorState {
init @0;
dontknow @1;
ok @2;
short @3;
open @4;
}
enum AntennaPowerStatus {
off @0;
on @1;
dontknow @2;
}
}
}
struct Clocks {
bootTimeNanos @0 :UInt64;
monotonicNanos @1 :UInt64;
@@ -1800,14 +1516,11 @@ struct UiLayoutState {
activeApp @0 :App;
sidebarCollapsed @1 :Bool;
mapEnabled @2 :Bool;
mockEngaged @3 :Bool;
enum App {
home @0;
music @1;
nav @2;
settings @3;
none @4;
}
}
@@ -1873,40 +1586,10 @@ struct OrbKeyFrame {
descriptors @3 :Data;
}
struct DriverState {
struct DriverMonitoring {
frameId @0 :UInt32;
descriptorDEPRECATED @1 :List(Float32);
stdDEPRECATED @2 :Float32;
faceOrientation @3 :List(Float32);
facePosition @4 :List(Float32);
faceProb @5 :Float32;
leftEyeProb @6 :Float32;
rightEyeProb @7 :Float32;
leftBlinkProb @8 :Float32;
rightBlinkProb @9 :Float32;
irPwrDEPRECATED @10 :Float32;
faceOrientationStd @11 :List(Float32);
facePositionStd @12 :List(Float32);
}
struct DMonitoringState {
# TODO: deprecate old fields in controlsState
events @0 :List(Car.CarEvent);
faceDetected @1 :Bool;
isDistracted @2 :Bool;
awarenessStatus @3 :Float32;
isRHD @4 :Bool;
rhdChecked @5 :Bool;
posePitchOffset @6 :Float32;
posePitchValidCount @7 :UInt32;
poseYawOffset @8 :Float32;
poseYawValidCount @9 :UInt32;
stepChange @10 :Float32;
awarenessActive @11 :Float32;
awarenessPassive @12 :Float32;
isLowStd @13 :Bool;
hiStdCount @14 :UInt32;
isPreview @15 :Bool;
descriptor @1 :List(Float32);
std @2 :Float32;
}
struct Boot {
@@ -1919,13 +1602,6 @@ struct LiveParametersData {
valid @0 :Bool;
gyroBias @1 :Float32;
angleOffset @2 :Float32;
angleOffsetAverage @3 :Float32;
stiffnessFactor @4 :Float32;
steerRatio @5 :Float32;
sensorValid @6 :Bool;
yawRate @7 :Float32;
posenetSpeed @8 :Float32;
posenetValid @9 :Bool;
}
struct LiveMapData {
@@ -1949,8 +1625,6 @@ struct LiveMapData {
}
struct CameraOdometry {
frameId @4 :UInt32;
timestampEof @5 :UInt64;
trans @0 :List(Float32); # m/s in device frame
rot @1 :List(Float32); # rad/s in device frame
transStd @2 :List(Float32); # std m/s in device frame
@@ -1964,20 +1638,9 @@ struct KalmanOdometry {
rotStd @3 :List(Float32); # std rad/s in device frame
}
struct Sentinel {
enum SentinelType {
endOfSegment @0;
endOfRoute @1;
startOfSegment @2;
startOfRoute @3;
}
type @0 :SentinelType;
}
struct Event {
# in nanoseconds?
logMonoTime @0 :UInt64;
valid @67 :Bool = true;
union {
initData @1 :InitData;
@@ -1986,20 +1649,20 @@ struct Event {
sensorEventDEPRECATED @4 :SensorEventData;
can @5 :List(CanData);
thermal @6 :ThermalData;
controlsState @7 :ControlsState;
live100 @7 :Live100Data;
liveEventDEPRECATED @8 :List(LiveEventData);
model @9 :ModelData;
features @10 :CalibrationFeatures;
sensorEvents @11 :List(SensorEventData);
health @12 :HealthData;
radarState @13 :RadarState;
live20 @13 :Live20Data;
liveUIDEPRECATED @14 :LiveUI;
encodeIdx @15 :EncodeIndex;
liveTracks @16 :List(LiveTracks);
sendcan @17 :List(CanData);
logMessage @18 :Text;
liveCalibration @19 :LiveCalibrationData;
androidLog @20 :AndroidLogEntry;
androidLogEntry @20 :AndroidLogEntry;
gpsLocation @21 :GpsLocationData;
carState @22 :Car.CarState;
carControl @23 :Car.CarControl;
@@ -2030,7 +1693,7 @@ struct Event {
gpsLocationExternal @48 :GpsLocationData;
location @49 :LiveLocationData;
uiNavigationEvent @50 :UiNavigationEvent;
liveLocationKalmanDEPRECATED @51 :LiveLocationData;
liveLocationKalman @51 :LiveLocationData;
testJoystick @52 :Joystick;
orbOdometry @53 :OrbOdometry;
orbFeatures @54 :OrbFeatures;
@@ -2038,19 +1701,12 @@ struct Event {
orbKeyFrame @56 :OrbKeyFrame;
uiLayoutState @57 :UiLayoutState;
orbFeaturesSummary @58 :OrbFeaturesSummary;
driverState @59 :DriverState;
driverMonitoring @59 :DriverMonitoring;
boot @60 :Boot;
liveParameters @61 :LiveParametersData;
liveMapData @62 :LiveMapData;
cameraOdometry @63 :CameraOdometry;
pathPlan @64 :PathPlan;
kalmanOdometry @65 :KalmanOdometry;
thumbnail @66: Thumbnail;
carEvents @68: List(Car.CarEvent);
carParams @69: Car.CarParams;
frontFrame @70: FrameData;
dMonitoringState @71: DMonitoringState;
liveLocationKalman @72 :LiveLocationKalman;
sentinel @73 :Sentinel;
}
}
-53
View File
@@ -1,53 +0,0 @@
using Cxx = import "./include/c++.capnp";
$Cxx.namespace("cereal");
using Java = import "./include/java.capnp";
$Java.package("ai.comma.openpilot.cereal");
$Java.outerClassname("Map");
@0xa086df597ef5d7a0;
# Geometry
struct Point {
x @0: Float64;
y @1: Float64;
z @2: Float64;
}
struct PolyLine {
points @0: List(Point);
}
# Map features
struct Lane {
id @0 :Text;
leftBoundary @1 :LaneBoundary;
rightBoundary @2 :LaneBoundary;
leftAdjacentId @3 :Text;
rightAdjacentId @4 :Text;
inboundIds @5 :List(Text);
outboundIds @6 :List(Text);
struct LaneBoundary {
polyLine @0 :PolyLine;
startHeading @1 :Float32; # WRT north
}
}
# Map tiles
struct TileSummary {
version @0 :Text;
updatedAt @1 :UInt64; # Millis since epoch
level @2 :UInt8;
x @3 :UInt16;
y @4 :UInt16;
}
struct MapTile {
summary @0 :TileSummary;
lanes @1 :List(Lane);
}
-10
View File
@@ -1,10 +0,0 @@
demo
bridge
test_runner
*.o
*.os
*.d
*.a
*.so
messaging_pyx.cpp
build/
-225
View File
@@ -1,225 +0,0 @@
# must be build with scons
from .messaging_pyx import Context, Poller, SubSocket, PubSocket # pylint: disable=no-name-in-module, import-error
from .messaging_pyx import MultiplePublishersError, MessagingError # pylint: disable=no-name-in-module, import-error
import capnp
assert MultiplePublishersError
assert MessagingError
from cereal import log
from cereal.services import service_list
# sec_since_boot is faster, but allow to run standalone too
try:
from common.realtime import sec_since_boot
except ImportError:
import time
sec_since_boot = time.time
print("Warning, using python time.time() instead of faster sec_since_boot")
context = Context()
def new_message(service=None, size=None):
dat = log.Event.new_message()
dat.logMonoTime = int(sec_since_boot() * 1e9)
dat.valid = True
if service is not None:
if size is None:
dat.init(service)
else:
dat.init(service, size)
return dat
def pub_sock(endpoint):
sock = PubSocket()
sock.connect(context, endpoint)
return sock
def sub_sock(endpoint, poller=None, addr="127.0.0.1", conflate=False, timeout=None):
sock = SubSocket()
addr = addr.encode('utf8')
sock.connect(context, endpoint, addr, conflate)
if timeout is not None:
sock.setTimeout(timeout)
if poller is not None:
poller.registerSocket(sock)
return sock
def drain_sock_raw(sock, wait_for_one=False):
"""Receive all message currently available on the queue"""
ret = []
while 1:
if wait_for_one and len(ret) == 0:
dat = sock.receive()
else:
dat = sock.receive(non_blocking=True)
if dat is None:
break
ret.append(dat)
return ret
def drain_sock(sock, wait_for_one=False):
"""Receive all message currently available on the queue"""
ret = []
while 1:
if wait_for_one and len(ret) == 0:
dat = sock.receive()
else:
dat = sock.receive(non_blocking=True)
if dat is None: # Timeout hit
break
dat = log.Event.from_bytes(dat)
ret.append(dat)
return ret
# TODO: print when we drop packets?
def recv_sock(sock, wait=False):
"""Same as drain sock, but only returns latest message. Consider using conflate instead."""
dat = None
while 1:
if wait and dat is None:
rcv = sock.receive()
else:
rcv = sock.receive(non_blocking=True)
if rcv is None: # Timeout hit
break
dat = rcv
if dat is not None:
dat = log.Event.from_bytes(dat)
return dat
def recv_one(sock):
dat = sock.receive()
if dat is not None:
dat = log.Event.from_bytes(dat)
return dat
def recv_one_or_none(sock):
dat = sock.receive(non_blocking=True)
if dat is not None:
dat = log.Event.from_bytes(dat)
return dat
def recv_one_retry(sock):
"""Keep receiving until we get a message"""
while True:
dat = sock.receive()
if dat is not None:
return log.Event.from_bytes(dat)
# TODO: This does not belong in messaging
def get_one_can(logcan):
while True:
can = recv_one_retry(logcan)
if len(can.can) > 0:
return can
class SubMaster():
def __init__(self, services, ignore_alive=None, addr="127.0.0.1"):
self.poller = Poller()
self.frame = -1
self.updated = {s : False for s in services}
self.rcv_time = {s : 0. for s in services}
self.rcv_frame = {s : 0 for s in services}
self.alive = {s : False for s in services}
self.sock = {}
self.freq = {}
self.data = {}
self.logMonoTime = {}
self.valid = {}
if ignore_alive is not None:
self.ignore_alive = ignore_alive
else:
self.ignore_alive = []
for s in services:
if addr is not None:
self.sock[s] = sub_sock(s, poller=self.poller, addr=addr, conflate=True)
self.freq[s] = service_list[s].frequency
try:
data = new_message(s)
except capnp.lib.capnp.KjException:
# lists
data = new_message(s, 0)
self.data[s] = getattr(data, s)
self.logMonoTime[s] = 0
self.valid[s] = data.valid
def __getitem__(self, s):
return self.data[s]
def update(self, timeout=1000):
msgs = []
for sock in self.poller.poll(timeout):
msgs.append(recv_one_or_none(sock))
self.update_msgs(sec_since_boot(), msgs)
def update_msgs(self, cur_time, msgs):
# TODO: add optional input that specify the service to wait for
self.frame += 1
self.updated = dict.fromkeys(self.updated, False)
for msg in msgs:
if msg is None:
continue
s = msg.which()
self.updated[s] = True
self.rcv_time[s] = cur_time
self.rcv_frame[s] = self.frame
self.data[s] = getattr(msg, s)
self.logMonoTime[s] = msg.logMonoTime
self.valid[s] = msg.valid
for s in self.data:
# arbitrary small number to avoid float comparison. If freq is 0, we can skip the check
if self.freq[s] > 1e-5:
# alive if delay is within 10x the expected frequency
self.alive[s] = (cur_time - self.rcv_time[s]) < (10. / self.freq[s])
else:
self.alive[s] = True
def all_alive(self, service_list=None):
if service_list is None: # check all
service_list = self.alive.keys()
return all(self.alive[s] for s in service_list if s not in self.ignore_alive)
def all_valid(self, service_list=None):
if service_list is None: # check all
service_list = self.valid.keys()
return all(self.valid[s] for s in service_list)
def all_alive_and_valid(self, service_list=None):
if service_list is None: # check all
service_list = self.alive.keys()
return self.all_alive(service_list=service_list) and self.all_valid(service_list=service_list)
class PubMaster():
def __init__(self, services):
self.sock = {}
for s in services:
self.sock[s] = pub_sock(s)
def send(self, s, dat):
# accept either bytes or capnp builder
if not isinstance(dat, bytes):
dat = dat.to_bytes()
self.sock[s].send(dat)
-64
View File
@@ -1,64 +0,0 @@
#include <iostream>
#include <string>
#include <cassert>
#include <csignal>
#include <map>
typedef void (*sighandler_t)(int sig);
#include "services.h"
#include "impl_msgq.hpp"
#include "impl_zmq.hpp"
void sigpipe_handler(int sig) {
assert(sig == SIGPIPE);
std::cout << "SIGPIPE received" << std::endl;
}
static std::vector<std::string> get_services() {
std::vector<std::string> name_list;
for (const auto& it : services) {
std::string name = it.name;
if (name == "plusFrame" || name == "uiLayoutState") continue;
name_list.push_back(name);
}
return name_list;
}
int main(void){
signal(SIGPIPE, (sighandler_t)sigpipe_handler);
auto endpoints = get_services();
std::map<SubSocket*, PubSocket*> sub2pub;
Context *zmq_context = new ZMQContext();
Context *msgq_context = new MSGQContext();
Poller *poller = new MSGQPoller();
for (auto endpoint: endpoints){
SubSocket * msgq_sock = new MSGQSubSocket();
msgq_sock->connect(msgq_context, endpoint, "127.0.0.1", false);
poller->registerSocket(msgq_sock);
PubSocket * zmq_sock = new ZMQPubSocket();
zmq_sock->connect(zmq_context, endpoint);
sub2pub[msgq_sock] = zmq_sock;
}
while (true){
for (auto sub_sock : poller->poll(100)){
Message * msg = sub_sock->receive();
if (msg == NULL) continue;
sub2pub[sub_sock]->sendMessage(msg);
delete msg;
}
}
return 0;
}
File diff suppressed because it is too large Load Diff
-50
View File
@@ -1,50 +0,0 @@
#include <iostream>
#include <cstddef>
#include <chrono>
#include <thread>
#include <cassert>
#include "messaging.hpp"
#include "impl_zmq.hpp"
#define MSGS 1e5
int main() {
Context * c = Context::create();
SubSocket * sub_sock = SubSocket::create(c, "controlsState");
PubSocket * pub_sock = PubSocket::create(c, "controlsState");
char data[8];
Poller * poller = Poller::create({sub_sock});
auto start = std::chrono::steady_clock::now();
for (uint64_t i = 0; i < MSGS; i++){
*(uint64_t*)data = i;
pub_sock->send(data, 8);
auto r = poller->poll(100);
for (auto p : r){
Message * m = p->receive();
uint64_t ii = *(uint64_t*)m->getData();
assert(i == ii);
delete m;
}
}
auto end = std::chrono::steady_clock::now();
double elapsed = std::chrono::duration_cast<std::chrono::nanoseconds>(end - start).count() / 1e9;
double throughput = ((double) MSGS / (double) elapsed);
std::cout << throughput << " msg/s" << std::endl;
delete poller;
delete sub_sock;
delete pub_sock;
delete c;
return 0;
}
-30
View File
@@ -1,30 +0,0 @@
import time
from messaging_pyx import Context, Poller, SubSocket, PubSocket # pylint: disable=no-name-in-module, import-error
MSGS = 1e5
if __name__ == "__main__":
c = Context()
sub_sock = SubSocket()
pub_sock = PubSocket()
sub_sock.connect(c, "controlsState")
pub_sock.connect(c, "controlsState")
poller = Poller()
poller.registerSocket(sub_sock)
t = time.time()
for i in range(int(MSGS)):
bts = i.to_bytes(4, 'little')
pub_sock.send(bts)
for s in poller.poll(100):
dat = s.receive()
ii = int.from_bytes(dat, 'little')
assert(i == ii)
dt = time.time() - t
print("%.1f msg/s" % (MSGS / dt))
-195
View File
@@ -1,195 +0,0 @@
#include <cassert>
#include <cstring>
#include <iostream>
#include <cstdlib>
#include <csignal>
#include <cerrno>
#include "impl_msgq.hpp"
volatile sig_atomic_t msgq_do_exit = 0;
void sig_handler(int signal) {
assert(signal == SIGINT || signal == SIGTERM);
msgq_do_exit = 1;
}
MSGQContext::MSGQContext() {
}
MSGQContext::~MSGQContext() {
}
void MSGQMessage::init(size_t sz) {
size = sz;
data = new char[size];
}
void MSGQMessage::init(char * d, size_t sz) {
size = sz;
data = new char[size];
memcpy(data, d, size);
}
void MSGQMessage::takeOwnership(char * d, size_t sz) {
size = sz;
data = d;
}
void MSGQMessage::close() {
if (size > 0){
delete[] data;
}
size = 0;
}
MSGQMessage::~MSGQMessage() {
this->close();
}
int MSGQSubSocket::connect(Context *context, std::string endpoint, std::string address, bool conflate){
assert(context);
assert(address == "127.0.0.1");
q = new msgq_queue_t;
int r = msgq_new_queue(q, endpoint.c_str(), DEFAULT_SEGMENT_SIZE);
if (r != 0){
return r;
}
msgq_init_subscriber(q);
if (conflate){
q->read_conflate = true;
}
timeout = -1;
return 0;
}
Message * MSGQSubSocket::receive(bool non_blocking){
msgq_do_exit = 0;
void (*prev_handler_sigint)(int);
void (*prev_handler_sigterm)(int);
if (!non_blocking){
prev_handler_sigint = std::signal(SIGINT, sig_handler);
prev_handler_sigterm = std::signal(SIGTERM, sig_handler);
}
msgq_msg_t msg;
MSGQMessage *r = NULL;
int rc = msgq_msg_recv(&msg, q);
// Hack to implement blocking read with a poller. Don't use this
while (!non_blocking && rc == 0 && msgq_do_exit == 0){
msgq_pollitem_t items[1];
items[0].q = q;
int t = (timeout != -1) ? timeout : 100;
int n = msgq_poll(items, 1, t);
rc = msgq_msg_recv(&msg, q);
// The poll indicated a message was ready, but the receive failed. Try again
if (n == 1 && rc == 0){
continue;
}
if (timeout != -1){
break;
}
}
if (!non_blocking){
std::signal(SIGINT, prev_handler_sigint);
std::signal(SIGTERM, prev_handler_sigterm);
}
errno = msgq_do_exit ? EINTR : 0;
if (rc > 0){
if (msgq_do_exit){
msgq_msg_close(&msg); // Free unused message on exit
} else {
r = new MSGQMessage;
r->takeOwnership(msg.data, msg.size);
}
}
return (Message*)r;
}
void MSGQSubSocket::setTimeout(int t){
timeout = t;
}
MSGQSubSocket::~MSGQSubSocket(){
if (q != NULL){
msgq_close_queue(q);
delete q;
}
}
int MSGQPubSocket::connect(Context *context, std::string endpoint){
assert(context);
q = new msgq_queue_t;
msgq_new_queue(q, endpoint.c_str(), DEFAULT_SEGMENT_SIZE);
msgq_init_publisher(q);
return 0;
}
int MSGQPubSocket::sendMessage(Message *message){
msgq_msg_t msg;
msg.data = message->getData();
msg.size = message->getSize();
return msgq_msg_send(&msg, q);
}
int MSGQPubSocket::send(char *data, size_t size){
msgq_msg_t msg;
msg.data = data;
msg.size = size;
return msgq_msg_send(&msg, q);
}
MSGQPubSocket::~MSGQPubSocket(){
if (q != NULL){
msgq_close_queue(q);
delete q;
}
}
void MSGQPoller::registerSocket(SubSocket * socket){
assert(num_polls + 1 < MAX_POLLERS);
polls[num_polls].q = (msgq_queue_t*)socket->getRawSocket();
sockets.push_back(socket);
num_polls++;
}
std::vector<SubSocket*> MSGQPoller::poll(int timeout){
std::vector<SubSocket*> r;
msgq_poll(polls, num_polls, timeout);
for (size_t i = 0; i < num_polls; i++){
if (polls[i].revents){
r.push_back(sockets[i]);
}
}
return r;
}
-64
View File
@@ -1,64 +0,0 @@
#pragma once
#include "messaging.hpp"
#include "msgq.hpp"
#include <zmq.h>
#include <string>
#define MAX_POLLERS 128
class MSGQContext : public Context {
private:
void * context = NULL;
public:
MSGQContext();
void * getRawContext() {return context;}
~MSGQContext();
};
class MSGQMessage : public Message {
private:
char * data;
size_t size;
public:
void init(size_t size);
void init(char *data, size_t size);
void takeOwnership(char *data, size_t size);
size_t getSize(){return size;}
char * getData(){return data;}
void close();
~MSGQMessage();
};
class MSGQSubSocket : public SubSocket {
private:
msgq_queue_t * q = NULL;
int timeout;
public:
int connect(Context *context, std::string endpoint, std::string address, bool conflate=false);
void setTimeout(int timeout);
void * getRawSocket() {return (void*)q;}
Message *receive(bool non_blocking=false);
~MSGQSubSocket();
};
class MSGQPubSocket : public PubSocket {
private:
msgq_queue_t * q = NULL;
public:
int connect(Context *context, std::string endpoint);
int sendMessage(Message *message);
int send(char *data, size_t size);
~MSGQPubSocket();
};
class MSGQPoller : public Poller {
private:
std::vector<SubSocket*> sockets;
msgq_pollitem_t polls[MAX_POLLERS];
size_t num_polls = 0;
public:
void registerSocket(SubSocket *socket);
std::vector<SubSocket*> poll(int timeout);
~MSGQPoller(){};
};
-155
View File
@@ -1,155 +0,0 @@
#include <cassert>
#include <cstring>
#include <iostream>
#include <cstdlib>
#include <cerrno>
#include <zmq.h>
#include "services.h"
#include "impl_zmq.hpp"
static int get_port(std::string endpoint) {
int port = -1;
for (const auto& it : services) {
std::string name = it.name;
if (name == endpoint) {
port = it.port;
break;
}
}
assert(port >= 0);
return port;
}
ZMQContext::ZMQContext() {
context = zmq_ctx_new();
}
ZMQContext::~ZMQContext() {
zmq_ctx_term(context);
}
void ZMQMessage::init(size_t sz) {
size = sz;
data = new char[size];
}
void ZMQMessage::init(char * d, size_t sz) {
size = sz;
data = new char[size];
memcpy(data, d, size);
}
void ZMQMessage::close() {
if (size > 0){
delete[] data;
}
size = 0;
}
ZMQMessage::~ZMQMessage() {
this->close();
}
int ZMQSubSocket::connect(Context *context, std::string endpoint, std::string address, bool conflate){
sock = zmq_socket(context->getRawContext(), ZMQ_SUB);
if (sock == NULL){
return -1;
}
zmq_setsockopt(sock, ZMQ_SUBSCRIBE, "", 0);
if (conflate){
int arg = 1;
zmq_setsockopt(sock, ZMQ_CONFLATE, &arg, sizeof(int));
}
int reconnect_ivl = 500;
zmq_setsockopt(sock, ZMQ_RECONNECT_IVL_MAX, &reconnect_ivl, sizeof(reconnect_ivl));
full_endpoint = "tcp://" + address + ":";
full_endpoint += std::to_string(get_port(endpoint));
return zmq_connect(sock, full_endpoint.c_str());
}
Message * ZMQSubSocket::receive(bool non_blocking){
zmq_msg_t msg;
assert(zmq_msg_init(&msg) == 0);
int flags = non_blocking ? ZMQ_DONTWAIT : 0;
int rc = zmq_msg_recv(&msg, sock, flags);
Message *r = NULL;
if (rc >= 0){
// Make a copy to ensure the data is aligned
r = new ZMQMessage;
r->init((char*)zmq_msg_data(&msg), zmq_msg_size(&msg));
}
zmq_msg_close(&msg);
return r;
}
void ZMQSubSocket::setTimeout(int timeout){
zmq_setsockopt(sock, ZMQ_RCVTIMEO, &timeout, sizeof(int));
}
ZMQSubSocket::~ZMQSubSocket(){
zmq_close(sock);
}
int ZMQPubSocket::connect(Context *context, std::string endpoint){
sock = zmq_socket(context->getRawContext(), ZMQ_PUB);
if (sock == NULL){
return -1;
}
full_endpoint = "tcp://*:";
full_endpoint += std::to_string(get_port(endpoint));
return zmq_bind(sock, full_endpoint.c_str());
}
int ZMQPubSocket::sendMessage(Message *message){
return zmq_send(sock, message->getData(), message->getSize(), ZMQ_DONTWAIT);
}
int ZMQPubSocket::send(char *data, size_t size){
return zmq_send(sock, data, size, ZMQ_DONTWAIT);
}
ZMQPubSocket::~ZMQPubSocket(){
zmq_close(sock);
}
void ZMQPoller::registerSocket(SubSocket * socket){
assert(num_polls + 1 < MAX_POLLERS);
polls[num_polls].socket = socket->getRawSocket();
polls[num_polls].events = ZMQ_POLLIN;
sockets.push_back(socket);
num_polls++;
}
std::vector<SubSocket*> ZMQPoller::poll(int timeout){
std::vector<SubSocket*> r;
int rc = zmq_poll(polls, num_polls, timeout);
if (rc < 0){
return r;
}
for (size_t i = 0; i < num_polls; i++){
if (polls[i].revents){
r.push_back(sockets[i]);
}
}
return r;
}
-63
View File
@@ -1,63 +0,0 @@
#pragma once
#include "messaging.hpp"
#include <zmq.h>
#include <string>
#define MAX_POLLERS 128
class ZMQContext : public Context {
private:
void * context = NULL;
public:
ZMQContext();
void * getRawContext() {return context;}
~ZMQContext();
};
class ZMQMessage : public Message {
private:
char * data;
size_t size;
public:
void init(size_t size);
void init(char *data, size_t size);
size_t getSize(){return size;}
char * getData(){return data;}
void close();
~ZMQMessage();
};
class ZMQSubSocket : public SubSocket {
private:
void * sock;
std::string full_endpoint;
public:
int connect(Context *context, std::string endpoint, std::string address, bool conflate=false);
void setTimeout(int timeout);
void * getRawSocket() {return sock;}
Message *receive(bool non_blocking=false);
~ZMQSubSocket();
};
class ZMQPubSocket : public PubSocket {
private:
void * sock;
std::string full_endpoint;
public:
int connect(Context *context, std::string endpoint);
int sendMessage(Message *message);
int send(char *data, size_t size);
~ZMQPubSocket();
};
class ZMQPoller : public Poller {
private:
std::vector<SubSocket*> sockets;
zmq_pollitem_t polls[MAX_POLLERS];
size_t num_polls = 0;
public:
void registerSocket(SubSocket *socket);
std::vector<SubSocket*> poll(int timeout);
~ZMQPoller(){};
};
-117
View File
@@ -1,117 +0,0 @@
#include "messaging.hpp"
#include "impl_zmq.hpp"
#include "impl_msgq.hpp"
Context * Context::create(){
Context * c;
if (std::getenv("ZMQ")){
c = new ZMQContext();
} else {
c = new MSGQContext();
}
return c;
}
SubSocket * SubSocket::create(){
SubSocket * s;
if (std::getenv("ZMQ")){
s = new ZMQSubSocket();
} else {
s = new MSGQSubSocket();
}
return s;
}
SubSocket * SubSocket::create(Context * context, std::string endpoint){
SubSocket *s = SubSocket::create();
int r = s->connect(context, endpoint, "127.0.0.1");
if (r == 0) {
return s;
} else {
delete s;
return NULL;
}
}
SubSocket * SubSocket::create(Context * context, std::string endpoint, std::string address){
SubSocket *s = SubSocket::create();
int r = s->connect(context, endpoint, address);
if (r == 0) {
return s;
} else {
delete s;
return NULL;
}
}
SubSocket * SubSocket::create(Context * context, std::string endpoint, std::string address, bool conflate){
SubSocket *s = SubSocket::create();
int r = s->connect(context, endpoint, address, conflate);
if (r == 0) {
return s;
} else {
delete s;
return NULL;
}
}
PubSocket * PubSocket::create(){
PubSocket * s;
if (std::getenv("ZMQ")){
s = new ZMQPubSocket();
} else {
s = new MSGQPubSocket();
}
return s;
}
PubSocket * PubSocket::create(Context * context, std::string endpoint){
PubSocket *s = PubSocket::create();
int r = s->connect(context, endpoint);
if (r == 0) {
return s;
} else {
delete s;
return NULL;
}
}
Poller * Poller::create(){
Poller * p;
if (std::getenv("ZMQ")){
p = new ZMQPoller();
} else {
p = new MSGQPoller();
}
return p;
}
Poller * Poller::create(std::vector<SubSocket*> sockets){
Poller * p = Poller::create();
for (auto s : sockets){
p->registerSocket(s);
}
return p;
}
extern "C" Context * messaging_context_create() {
return Context::create();
}
extern "C" SubSocket * messaging_subsocket_create(Context* context, const char* endpoint) {
return SubSocket::create(context, std::string(endpoint));
}
extern "C" PubSocket * messaging_pubsocket_create(Context* context, const char* endpoint) {
return PubSocket::create(context, std::string(endpoint));
}
extern "C" Poller * messaging_poller_create(SubSocket** sockets, int size) {
std::vector<SubSocket*> socketsVec(sockets, sockets + size);
return Poller::create(socketsVec);
}
-56
View File
@@ -1,56 +0,0 @@
#pragma once
#include <cstddef>
#include <vector>
#include <string>
#define MSG_MULTIPLE_PUBLISHERS 100
class Context {
public:
virtual void * getRawContext() = 0;
static Context * create();
virtual ~Context(){};
};
class Message {
public:
virtual void init(size_t size) = 0;
virtual void init(char * data, size_t size) = 0;
virtual void close() = 0;
virtual size_t getSize() = 0;
virtual char * getData() = 0;
virtual ~Message(){};
};
class SubSocket {
public:
virtual int connect(Context *context, std::string endpoint, std::string address, bool conflate=false) = 0;
virtual void setTimeout(int timeout) = 0;
virtual Message *receive(bool non_blocking=false) = 0;
virtual void * getRawSocket() = 0;
static SubSocket * create();
static SubSocket * create(Context * context, std::string endpoint);
static SubSocket * create(Context * context, std::string endpoint, std::string address);
static SubSocket * create(Context * context, std::string endpoint, std::string address, bool conflate);
virtual ~SubSocket(){};
};
class PubSocket {
public:
virtual int connect(Context *context, std::string endpoint) = 0;
virtual int sendMessage(Message *message) = 0;
virtual int send(char *data, size_t size) = 0;
static PubSocket * create();
static PubSocket * create(Context * context, std::string endpoint);
virtual ~PubSocket(){};
};
class Poller {
public:
virtual void registerSocket(SubSocket *socket) = 0;
virtual std::vector<SubSocket*> poll(int timeout) = 0;
static Poller * create();
static Poller * create(std::vector<SubSocket*> sockets);
virtual ~Poller(){};
};
-39
View File
@@ -1,39 +0,0 @@
# distutils: language = c++
#cython: language_level=3
from libcpp.string cimport string
from libcpp.vector cimport vector
from libcpp cimport bool
cdef extern from "messaging.hpp":
cdef cppclass Context:
@staticmethod
Context * create()
cdef cppclass Message:
void init(size_t)
void init(char *, size_t)
void close()
size_t getSize()
char *getData()
cdef cppclass SubSocket:
@staticmethod
SubSocket * create()
int connect(Context *, string, string, bool)
Message * receive(bool)
void setTimeout(int)
cdef cppclass PubSocket:
@staticmethod
PubSocket * create()
int connect(Context *, string)
int sendMessage(Message *)
int send(char *, size_t)
cdef cppclass Poller:
@staticmethod
Poller * create()
void registerSocket(SubSocket *)
vector[SubSocket*] poll(int) nogil
-151
View File
@@ -1,151 +0,0 @@
# distutils: language = c++
# cython: c_string_encoding=ascii, language_level=3
import sys
from libcpp.string cimport string
from libcpp cimport bool
from libc cimport errno
from messaging cimport Context as cppContext
from messaging cimport SubSocket as cppSubSocket
from messaging cimport PubSocket as cppPubSocket
from messaging cimport Poller as cppPoller
from messaging cimport Message as cppMessage
class MessagingError(Exception):
pass
class MultiplePublishersError(MessagingError):
pass
cdef class Context:
cdef cppContext * context
def __cinit__(self):
self.context = cppContext.create()
def term(self):
del self.context
self.context = NULL
def __dealloc__(self):
pass
# Deleting the context will hang if sockets are still active
# TODO: Figure out a way to make sure the context is closed last
# del self.context
cdef class Poller:
cdef cppPoller * poller
cdef list sub_sockets
def __cinit__(self):
self.sub_sockets = []
self.poller = cppPoller.create()
def __dealloc__(self):
del self.poller
def registerSocket(self, SubSocket socket):
self.sub_sockets.append(socket)
self.poller.registerSocket(socket.socket)
def poll(self, timeout):
sockets = []
cdef int t = timeout
with nogil:
result = self.poller.poll(t)
for s in result:
socket = SubSocket()
socket.setPtr(s)
sockets.append(socket)
return sockets
cdef class SubSocket:
cdef cppSubSocket * socket
cdef bool is_owner
def __cinit__(self):
self.socket = cppSubSocket.create()
self.is_owner = True
if self.socket == NULL:
raise MessagingError
def __dealloc__(self):
if self.is_owner:
del self.socket
cdef setPtr(self, cppSubSocket * ptr):
if self.is_owner:
del self.socket
self.is_owner = False
self.socket = ptr
def connect(self, Context context, string endpoint, string address=b"127.0.0.1", bool conflate=False):
r = self.socket.connect(context.context, endpoint, address, conflate)
if r != 0:
if errno.errno == errno.EADDRINUSE:
raise MultiplePublishersError
else:
raise MessagingError
def setTimeout(self, int timeout):
self.socket.setTimeout(timeout)
def receive(self, bool non_blocking=False):
msg = self.socket.receive(non_blocking)
if msg == NULL:
# If a blocking read returns no message check errno if SIGINT was caught in the C++ code
if errno.errno == errno.EINTR:
print("SIGINT received, exiting")
sys.exit(1)
return None
else:
sz = msg.getSize()
m = msg.getData()[:sz]
del msg
return m
cdef class PubSocket:
cdef cppPubSocket * socket
def __cinit__(self):
self.socket = cppPubSocket.create()
if self.socket == NULL:
raise MessagingError
def __dealloc__(self):
del self.socket
def connect(self, Context context, string endpoint):
r = self.socket.connect(context.context, endpoint)
if r != 0:
if errno.errno == errno.EADDRINUSE:
raise MultiplePublishersError
else:
raise MessagingError
def send(self, string data):
length = len(data)
r = self.socket.send(<char*>data.c_str(), length)
if r != length:
if errno.errno == errno.EADDRINUSE:
raise MultiplePublishersError
else:
raise MessagingError
-57
View File
@@ -1,57 +0,0 @@
import os
import subprocess
import sysconfig
from distutils.core import Extension, setup # pylint: disable=import-error,no-name-in-module
from Cython.Build import cythonize
from Cython.Distutils import build_ext
def get_ext_filename_without_platform_suffix(filename):
name, ext = os.path.splitext(filename)
ext_suffix = sysconfig.get_config_var('EXT_SUFFIX')
if ext_suffix == ext:
return filename
ext_suffix = ext_suffix.replace(ext, '')
idx = name.find(ext_suffix)
if idx == -1:
return filename
else:
return name[:idx] + ext
class BuildExtWithoutPlatformSuffix(build_ext):
def get_ext_filename(self, ext_name):
filename = super().get_ext_filename(ext_name)
return get_ext_filename_without_platform_suffix(filename)
sourcefiles = ['messaging_pyx.pyx']
extra_compile_args = ["-std=c++11"]
libraries = ['zmq']
ARCH = subprocess.check_output(["uname", "-m"], encoding='utf8').rstrip() # pylint: disable=unexpected-keyword-arg
if ARCH == "aarch64" and os.path.isdir("/system"):
# android
extra_compile_args += ["-Wno-deprecated-register"]
libraries += ['gnustl_shared']
setup(name='CAN parser',
cmdclass={'build_ext': BuildExtWithoutPlatformSuffix},
ext_modules=cythonize(
Extension(
"messaging_pyx",
language="c++",
sources=sourcefiles,
extra_compile_args=extra_compile_args,
libraries=libraries,
extra_objects=[
os.path.join(os.path.dirname(os.path.realpath(__file__)), '../', 'libmessaging.a'),
]
)
),
nthreads=4,
)
-449
View File
@@ -1,449 +0,0 @@
#include <iostream>
#include <cassert>
#include <cerrno>
#include <cmath>
#include <cstring>
#include <cstdint>
#include <chrono>
#include <algorithm>
#include <cstdlib>
#include <csignal>
#include <random>
#include <poll.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/syscall.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include "msgq.hpp"
void sigusr2_handler(int signal) {
assert(signal == SIGUSR2);
}
uint64_t msgq_get_uid(void){
std::random_device rd("/dev/urandom");
std::uniform_int_distribution<uint64_t> distribution(0,std::numeric_limits<uint32_t>::max());
uint64_t uid = distribution(rd) << 32 | syscall(SYS_gettid);
return uid;
}
int msgq_msg_init_size(msgq_msg_t * msg, size_t size){
msg->size = size;
msg->data = new(std::nothrow) char[size];
return (msg->data == NULL) ? -1 : 0;
}
int msgq_msg_init_data(msgq_msg_t * msg, char * data, size_t size) {
int r = msgq_msg_init_size(msg, size);
if (r == 0)
memcpy(msg->data, data, size);
return r;
}
int msgq_msg_close(msgq_msg_t * msg){
if (msg->size > 0)
delete[] msg->data;
msg->size = 0;
return 0;
}
void msgq_reset_reader(msgq_queue_t * q){
int id = q->reader_id;
q->read_valids[id]->store(true);
q->read_pointers[id]->store(*q->write_pointer);
}
void msgq_wait_for_subscriber(msgq_queue_t *q){
while (*q->num_readers == 0){
;
}
return;
}
int msgq_new_queue(msgq_queue_t * q, const char * path, size_t size){
assert(size < 0xFFFFFFFF); // Buffer must be smaller than 2^32 bytes
std::signal(SIGUSR2, sigusr2_handler);
const char * prefix = "/dev/shm/";
char * full_path = new char[strlen(path) + strlen(prefix) + 1];
strcpy(full_path, prefix);
strcat(full_path, path);
auto fd = open(full_path, O_RDWR | O_CREAT, 0777);
delete[] full_path;
if (fd < 0)
return -1;
int rc = ftruncate(fd, size + sizeof(msgq_header_t));
if (rc < 0)
return -1;
char * mem = (char*)mmap(NULL, size + sizeof(msgq_header_t), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
close(fd);
if (mem == NULL)
return -1;
q->mmap_p = mem;
msgq_header_t *header = (msgq_header_t *)mem;
// Setup pointers to header segment
q->num_readers = reinterpret_cast<std::atomic<uint64_t>*>(&header->num_readers);
q->write_pointer = reinterpret_cast<std::atomic<uint64_t>*>(&header->write_pointer);
q->write_uid = reinterpret_cast<std::atomic<uint64_t>*>(&header->write_uid);
for (size_t i = 0; i < NUM_READERS; i++){
q->read_pointers[i] = reinterpret_cast<std::atomic<uint64_t>*>(&header->read_pointers[i]);
q->read_valids[i] = reinterpret_cast<std::atomic<uint64_t>*>(&header->read_valids[i]);
q->read_uids[i] = reinterpret_cast<std::atomic<uint64_t>*>(&header->read_uids[i]);
}
q->data = mem + sizeof(msgq_header_t);
q->size = size;
q->reader_id = -1;
q->endpoint = path;
q->read_conflate = false;
return 0;
}
void msgq_close_queue(msgq_queue_t *q){
if (q->mmap_p != NULL){
munmap(q->mmap_p, q->size + sizeof(msgq_header_t));
}
}
void msgq_init_publisher(msgq_queue_t * q) {
//std::cout << "Starting publisher" << std::endl;
uint64_t uid = msgq_get_uid();
*q->write_uid = uid;
*q->num_readers = 0;
for (size_t i = 0; i < NUM_READERS; i++){
*q->read_valids[i] = false;
*q->read_uids[i] = 0;
}
q->write_uid_local = uid;
}
static void thread_signal(uint32_t tid) {
#ifndef SYS_tkill
// TODO: this won't work for multithreaded programs
kill(tid, SIGUSR2);
#else
syscall(SYS_tkill, tid, SIGUSR2);
#endif
}
void msgq_init_subscriber(msgq_queue_t * q) {
assert(q != NULL);
assert(q->num_readers != NULL);
uint64_t uid = msgq_get_uid();
// Get reader id
while (true){
uint64_t cur_num_readers = *q->num_readers;
uint64_t new_num_readers = cur_num_readers + 1;
// No more slots available. Reset all subscribers to kick out inactive ones
if (new_num_readers > NUM_READERS){
std::cout << "Warning, evicting all subscribers!" << std::endl;
*q->num_readers = 0;
for (size_t i = 0; i < NUM_READERS; i++){
*q->read_valids[i] = false;
uint64_t old_uid = *q->read_uids[i];
*q->read_uids[i] = 0;
// Wake up reader in case they are in a poll
thread_signal(old_uid & 0xFFFFFFFF);
}
continue;
}
// Use atomic compare and swap to handle race condition
// where two subscribers start at the same time
if (std::atomic_compare_exchange_strong(q->num_readers,
&cur_num_readers,
new_num_readers)){
q->reader_id = cur_num_readers;
q->read_uid_local = uid;
// We start with read_valid = false,
// on the first read the read pointer will be synchronized with the write pointer
*q->read_valids[cur_num_readers] = false;
*q->read_pointers[cur_num_readers] = 0;
*q->read_uids[cur_num_readers] = uid;
break;
}
}
//std::cout << "New subscriber id: " << q->reader_id << " uid: " << q->read_uid_local << " " << q->endpoint << std::endl;
msgq_reset_reader(q);
}
int msgq_msg_send(msgq_msg_t * msg, msgq_queue_t *q){
// Die if we are no longer the active publisher
if (q->write_uid_local != *q->write_uid){
std::cout << "Killing old publisher: " << q->endpoint << std::endl;
errno = EADDRINUSE;
return -1;
}
uint64_t total_msg_size = ALIGN(msg->size + sizeof(int64_t));
// We need to fit at least three messages in the queue,
// then we can always safely access the last message
assert(3 * total_msg_size <= q->size);
uint64_t num_readers = *q->num_readers;
uint32_t write_cycles, write_pointer;
UNPACK64(write_cycles, write_pointer, *q->write_pointer);
char *p = q->data + write_pointer; // add base offset
// Check remaining space
// Always leave space for a wraparound tag for the next message, including alignment
int64_t remaining_space = q->size - write_pointer - total_msg_size - sizeof(int64_t);
if (remaining_space <= 0){
// Write -1 size tag indicating wraparound
*(int64_t*)p = -1;
// Invalidate all readers that are beyond the write pointer
// TODO: should we handle the case where a new reader shows up while this is running?
for (uint64_t i = 0; i < num_readers; i++){
uint64_t read_pointer = *q->read_pointers[i];
uint64_t read_cycles = read_pointer >> 32;
read_pointer &= 0xFFFFFFFF;
if ((read_pointer > write_pointer) && (read_cycles != write_cycles)) {
*q->read_valids[i] = false;
}
}
// Update global and local copies of write pointer and write_cycles
write_pointer = 0;
write_cycles = write_cycles + 1;
PACK64(*q->write_pointer, write_cycles, write_pointer);
// Set actual pointer to the beginning of the data segment
p = q->data;
}
// Invalidate readers that are in the area that will be written
uint64_t start = write_pointer;
uint64_t end = ALIGN(start + sizeof(int64_t) + msg->size);
for (uint64_t i = 0; i < num_readers; i++){
uint32_t read_cycles, read_pointer;
UNPACK64(read_cycles, read_pointer, *q->read_pointers[i]);
if ((read_pointer >= start) && (read_pointer < end) && (read_cycles != write_cycles)) {
*q->read_valids[i] = false;
}
}
// Write size tag
std::atomic<int64_t> *size_p = reinterpret_cast<std::atomic<int64_t>*>(p);
*size_p = msg->size;
// Copy data
memcpy(p + sizeof(int64_t), msg->data, msg->size);
__sync_synchronize();
// Update write pointer
uint32_t new_ptr = ALIGN(write_pointer + msg->size + sizeof(int64_t));
PACK64(*q->write_pointer, write_cycles, new_ptr);
// Notify readers
for (uint64_t i = 0; i < num_readers; i++){
uint64_t reader_uid = *q->read_uids[i];
thread_signal(reader_uid & 0xFFFFFFFF);
}
return msg->size;
}
int msgq_msg_ready(msgq_queue_t * q){
start:
int id = q->reader_id;
assert(id >= 0); // Make sure subscriber is initialized
if (q->read_uid_local != *q->read_uids[id]){
std::cout << q->endpoint << ": Reader was evicted, reconnecting" << std::endl;
msgq_init_subscriber(q);
goto start;
}
// Check valid
if (!*q->read_valids[id]){
msgq_reset_reader(q);
goto start;
}
uint32_t read_cycles, read_pointer;
UNPACK64(read_cycles, read_pointer, *q->read_pointers[id]);
uint32_t write_cycles, write_pointer;
UNPACK64(write_cycles, write_pointer, *q->write_pointer);
// Check if new message is available
return (read_pointer != write_pointer);
}
int msgq_msg_recv(msgq_msg_t * msg, msgq_queue_t * q){
start:
int id = q->reader_id;
assert(id >= 0); // Make sure subscriber is initialized
if (q->read_uid_local != *q->read_uids[id]){
std::cout << q->endpoint << ": Reader was evicted, reconnecting" << std::endl;
msgq_init_subscriber(q);
goto start;
}
// Check valid
if (!*q->read_valids[id]){
msgq_reset_reader(q);
goto start;
}
uint32_t read_cycles, read_pointer;
UNPACK64(read_cycles, read_pointer, *q->read_pointers[id]);
uint32_t write_cycles, write_pointer;
UNPACK64(write_cycles, write_pointer, *q->write_pointer);
char * p = q->data + read_pointer;
// Check if new message is available
if (read_pointer == write_pointer) {
msg->size = 0;
return 0;
}
// Read potential message size
std::atomic<int64_t> *size_p = reinterpret_cast<std::atomic<int64_t>*>(p);
std::int64_t size = *size_p;
// Check if the size that was read is valid
if (!*q->read_valids[id]){
msgq_reset_reader(q);
goto start;
}
// If size is -1 the buffer was full, and we need to wrap around
if (size == -1){
read_cycles++;
PACK64(*q->read_pointers[id], read_cycles, 0);
goto start;
}
// crashing is better than passing garbage data to the consumer
// the size will have weird value if it was overwritten by data accidentally
assert((uint64_t)size < q->size);
assert(size > 0);
uint32_t new_read_pointer = ALIGN(read_pointer + sizeof(std::int64_t) + size);
// If conflate is true, check if this is the latest message, else start over
if (q->read_conflate){
if (new_read_pointer != write_pointer){
// Update read pointer
PACK64(*q->read_pointers[id], read_cycles, new_read_pointer);
goto start;
}
}
// Copy message
if (msgq_msg_init_size(msg, size) < 0)
return -1;
__sync_synchronize();
memcpy(msg->data, p + sizeof(int64_t), size);
__sync_synchronize();
// Update read pointer
PACK64(*q->read_pointers[id], read_cycles, new_read_pointer);
// Check if the actual data that was copied is valid
if (!*q->read_valids[id]){
msgq_msg_close(msg);
msgq_reset_reader(q);
goto start;
}
return msg->size;
}
int msgq_poll(msgq_pollitem_t * items, size_t nitems, int timeout){
assert(timeout >= 0);
int num = 0;
// Check if messages ready
for (size_t i = 0; i < nitems; i++) {
items[i].revents = msgq_msg_ready(items[i].q);
if (items[i].revents) num++;
}
int ms = (timeout == -1) ? 100 : timeout;
struct timespec ts;
ts.tv_sec = ms / 1000;
ts.tv_nsec = (ms % 1000) * 1000 * 1000;
while (num == 0) {
int ret;
ret = nanosleep(&ts, &ts);
// Check if messages ready
for (size_t i = 0; i < nitems; i++) {
if (items[i].revents == 0 && msgq_msg_ready(items[i].q)){
num += 1;
items[i].revents = 1;
}
}
// exit if we had a timeout and the sleep finished
if (timeout != -1 && ret == 0){
break;
}
}
return num;
}
-66
View File
@@ -1,66 +0,0 @@
#pragma once
#include <cstdint>
#include <cstring>
#include <string>
#include <atomic>
#define DEFAULT_SEGMENT_SIZE (10 * 1024 * 1024)
#define NUM_READERS 8
#define ALIGN(n) ((n + (8 - 1)) & -8)
#define UNPACK64(higher, lower, input) do {uint64_t tmp = input; higher = tmp >> 32; lower = tmp & 0xFFFFFFFF;} while (0)
#define PACK64(output, higher, lower) output = ((uint64_t)higher << 32 ) | ((uint64_t)lower & 0xFFFFFFFF)
struct msgq_header_t {
uint64_t num_readers;
uint64_t write_pointer;
uint64_t write_uid;
uint64_t read_pointers[NUM_READERS];
uint64_t read_valids[NUM_READERS];
uint64_t read_uids[NUM_READERS];
};
struct msgq_queue_t {
std::atomic<uint64_t> *num_readers;
std::atomic<uint64_t> *write_pointer;
std::atomic<uint64_t> *write_uid;
std::atomic<uint64_t> *read_pointers[NUM_READERS];
std::atomic<uint64_t> *read_valids[NUM_READERS];
std::atomic<uint64_t> *read_uids[NUM_READERS];
char * mmap_p;
char * data;
size_t size;
int reader_id;
uint64_t read_uid_local;
uint64_t write_uid_local;
bool read_conflate;
std::string endpoint;
};
struct msgq_msg_t {
size_t size;
char * data;
};
struct msgq_pollitem_t {
msgq_queue_t *q;
int revents;
};
void msgq_wait_for_subscriber(msgq_queue_t *q);
void msgq_reset_reader(msgq_queue_t *q);
int msgq_msg_init_size(msgq_msg_t *msg, size_t size);
int msgq_msg_init_data(msgq_msg_t *msg, char * data, size_t size);
int msgq_msg_close(msgq_msg_t *msg);
int msgq_new_queue(msgq_queue_t * q, const char * path, size_t size);
void msgq_close_queue(msgq_queue_t *q);
void msgq_init_publisher(msgq_queue_t * q);
void msgq_init_subscriber(msgq_queue_t * q);
int msgq_msg_send(msgq_msg_t *msg, msgq_queue_t *q);
int msgq_msg_recv(msgq_msg_t *msg, msgq_queue_t *q);
int msgq_msg_ready(msgq_queue_t * q);
int msgq_poll(msgq_pollitem_t * items, size_t nitems, int timeout);
-56
View File
@@ -1,56 +0,0 @@
# MSGQ: A lock free single producer multi consumer message queue
[![Build Status](https://dev.azure.com/commaai/default/_apis/build/status/commaai.msgq?branchName=master)](https://dev.azure.com/commaai/default/_build/latest?definitionId=21&branchName=master)
## What is MSGQ?
MSGQ is a system to pass messages from a single producer to multiple consumers. All the consumers need to be able to receive all the messages. It is designed to be a high performance replacement for ZMQ-like SUB/PUB patterns. It uses a ring buffer in shared memory to efficiently read and write data. Each read requires a copy. Writing can be done without a copy, as long as the size of the data is known in advance.
## Storage
The storage for the queue consists of an area of metadata, and the actual buffer. The metadata contains:
1. A counter to the number of readers that are active
2. A pointer to the head of the queue for writing. From now on referred to as *write pointer*
3. A cycle counter for the writer. This counter is incremented when the writer wraps around
4. N pointers, pointing to the current read position for all the readers. From now on referred to as *read pointer*
5. N counters, counting the number of cycles for all the readers
6. N booleans, indicating validity for all the readers. From now on referred to as *validity flag*
The counter and the pointer are both 32 bit values, packed into 64 bit so they can be read and written atomically.
The data buffer is a ring buffer. All messages are prefixed by an 8 byte size field, followed by the data. A size of -1 indicates a wrap-around, and means the next message is stored at the beginning of the buffer.
## Writing
Writing involves the following steps:
1. Check if the area that is to be written overlaps with any of the read pointers, mark those readers as invalid by clearing the validity flag.
2. Write the message
3. Increase the write pointer by the size of the message
In case there is not enough space at the end of the buffer, a special empty message with a prefix of -1 is written. The cycle counter is incremented by one. In this case step 1 will check there are no read pointers pointing to the remainder of the buffer. Then another write cycle will start with the actual message.
There always needs to be 8 bytes of empty space at the end of the buffer. By doing this there is always space to write the -1.
## Reset reader
When the reader is lagging too much behind the read pointer becomes invalid and no longer points to the beginning of a valid message. To reset a reader to the current write pointer, the following steps are performed:
1. Set valid flag
2. Set read cycle counter to that of the writer
3. Set read pointer to write pointer
## Reading
Reading involves the following steps:
1. Read the size field at the current read pointer
2. Read the validity flag
3. Copy the data out of the buffer
4. Increase the read pointer by the size of the message
5. Check the validity flag again
Before starting the copy, the valid flag is checked. This is to prevent a race condition where the size prefix was invalid, and the read could read outside of the buffer. Make sure that step 1 and 2 are not reordered by your compiler or CPU.
If a writer overwrites the data while it's being copied out, the data will be invalid. Therefore the validity flag is also checked after reading it. The order of step 4 and 5 does not matter.
If at steps 2 or 5 the validity flag is not set, the reader is reset. Any data that was already read is discarded. After the reader is reset, the reading starts from the beginning.
If a message with size -1 is encountered, step 3 and 4 are replaced by increasing the cycle counter and setting the read pointer to the beginning of the buffer. After that another read is performed.
-395
View File
@@ -1,395 +0,0 @@
#include "catch2/catch.hpp"
#include "msgq.hpp"
TEST_CASE("ALIGN"){
REQUIRE(ALIGN(0) == 0);
REQUIRE(ALIGN(1) == 8);
REQUIRE(ALIGN(7) == 8);
REQUIRE(ALIGN(8) == 8);
REQUIRE(ALIGN(99999) == 100000);
}
TEST_CASE("msgq_msg_init_size"){
const size_t msg_size = 30;
msgq_msg_t msg;
msgq_msg_init_size(&msg, msg_size);
REQUIRE(msg.size == msg_size);
msgq_msg_close(&msg);
}
TEST_CASE("msgq_msg_init_data"){
const size_t msg_size = 30;
char * data = new char[msg_size];
for (size_t i = 0; i < msg_size; i++){
data[i] = i;
}
msgq_msg_t msg;
msgq_msg_init_data(&msg, data, msg_size);
REQUIRE(msg.size == msg_size);
REQUIRE(memcmp(msg.data, data, msg_size) == 0);
delete[] data;
msgq_msg_close(&msg);
}
TEST_CASE("msgq_init_subscriber"){
remove("/dev/shm/test_queue");
msgq_queue_t q;
msgq_new_queue(&q, "test_queue", 1024);
REQUIRE(*q.num_readers == 0);
q.reader_id = 1;
*q.read_valids[0] = false;
*q.read_pointers[0] = ((uint64_t)1 << 32);
*q.write_pointer = 255;
msgq_init_subscriber(&q);
REQUIRE(q.read_conflate == false);
REQUIRE(*q.read_valids[0] == true);
REQUIRE((*q.read_pointers[0] >> 32) == 0);
REQUIRE((*q.read_pointers[0] & 0xFFFFFFFF) == 255);
}
TEST_CASE("msgq_msg_send first message"){
remove("/dev/shm/test_queue");
msgq_queue_t q;
msgq_new_queue(&q, "test_queue", 1024);
msgq_init_publisher(&q);
REQUIRE(*q.write_pointer == 0);
size_t msg_size = 128;
SECTION("Aligned message size"){
}
SECTION("Unaligned message size"){
msg_size--;
}
char * data = new char[msg_size];
for (size_t i = 0; i < msg_size; i++){
data[i] = i;
}
msgq_msg_t msg;
msgq_msg_init_data(&msg, data, msg_size);
msgq_msg_send(&msg, &q);
REQUIRE(*(int64_t*)q.data == msg_size); // Check size tag
REQUIRE(*q.write_pointer == 128 + sizeof(int64_t));
REQUIRE(memcmp(q.data + sizeof(int64_t), data, msg_size) == 0);
delete[] data;
msgq_msg_close(&msg);
}
TEST_CASE("msgq_msg_send test wraparound"){
remove("/dev/shm/test_queue");
msgq_queue_t q;
msgq_new_queue(&q, "test_queue", 1024);
msgq_init_publisher(&q);
REQUIRE((*q.write_pointer & 0xFFFFFFFF) == 0);
REQUIRE((*q.write_pointer >> 32) == 0);
const size_t msg_size = 120;
msgq_msg_t msg;
msgq_msg_init_size(&msg, msg_size);
for (int i = 0; i < 8; i++) {
msgq_msg_send(&msg, &q);
}
// Check 8th message was written at the beginning
REQUIRE((*q.write_pointer & 0xFFFFFFFF) == msg_size + sizeof(int64_t));
// Check cycle count
REQUIRE((*q.write_pointer >> 32) == 1);
// Check wraparound tag
char * tag_location = q.data;
tag_location += 7 * (msg_size + sizeof(int64_t));
REQUIRE(*(int64_t*)tag_location == -1);
msgq_msg_close(&msg);
}
TEST_CASE("msgq_msg_recv test wraparound"){
remove("/dev/shm/test_queue");
msgq_queue_t q_pub, q_sub;
msgq_new_queue(&q_pub, "test_queue", 1024);
msgq_new_queue(&q_sub, "test_queue", 1024);
msgq_init_publisher(&q_pub);
msgq_init_subscriber(&q_sub);
REQUIRE((*q_pub.write_pointer >> 32) == 0);
REQUIRE((*q_sub.read_pointers[0] >> 32) == 0);
const size_t msg_size = 120;
msgq_msg_t msg1;
msgq_msg_init_size(&msg1, msg_size);
SECTION("Check cycle counter after reset") {
for (int i = 0; i < 8; i++) {
msgq_msg_send(&msg1, &q_pub);
}
msgq_msg_t msg2;
msgq_msg_recv(&msg2, &q_sub);
REQUIRE(msg2.size == 0); // Reader had to reset
msgq_msg_close(&msg2);
}
SECTION("Check cycle counter while keeping up with writer") {
for (int i = 0; i < 8; i++) {
msgq_msg_send(&msg1, &q_pub);
msgq_msg_t msg2;
msgq_msg_recv(&msg2, &q_sub);
REQUIRE(msg2.size > 0);
msgq_msg_close(&msg2);
}
}
REQUIRE((*q_sub.read_pointers[0] >> 32) == 1);
msgq_msg_close(&msg1);
}
TEST_CASE("msgq_msg_send test invalidation"){
remove("/dev/shm/test_queue");
msgq_queue_t q_pub, q_sub;
msgq_new_queue(&q_pub, "test_queue", 1024);
msgq_new_queue(&q_sub, "test_queue", 1024);
msgq_init_publisher(&q_pub);
msgq_init_subscriber(&q_sub);
*q_sub.write_pointer = (uint64_t)1 << 32;
REQUIRE(*q_sub.read_valids[0] == true);
SECTION("read pointer in tag"){
*q_sub.read_pointers[0] = 0;
}
SECTION("read pointer in data section"){
*q_sub.read_pointers[0] = 64;
}
SECTION("read pointer in wraparound section"){
*q_pub.write_pointer = ((uint64_t)1 << 32) | 1000; // Writer is one cycle ahead
*q_sub.read_pointers[0] = 1020;
}
msgq_msg_t msg;
msgq_msg_init_size(&msg, 128);
msgq_msg_send(&msg, &q_pub);
REQUIRE(*q_sub.read_valids[0] == false);
msgq_msg_close(&msg);
}
TEST_CASE("msgq_init_subscriber init 2 subscribers"){
remove("/dev/shm/test_queue");
msgq_queue_t q1, q2;
msgq_new_queue(&q1, "test_queue", 1024);
msgq_new_queue(&q2, "test_queue", 1024);
*q1.num_readers = 0;
REQUIRE(*q1.num_readers == 0);
REQUIRE(*q2.num_readers == 0);
msgq_init_subscriber(&q1);
REQUIRE(*q1.num_readers == 1);
REQUIRE(*q2.num_readers == 1);
REQUIRE(q1.reader_id == 0);
msgq_init_subscriber(&q2);
REQUIRE(*q1.num_readers == 2);
REQUIRE(*q2.num_readers == 2);
REQUIRE(q2.reader_id == 1);
}
TEST_CASE("Write 1 msg, read 1 msg", "[integration]"){
remove("/dev/shm/test_queue");
const size_t msg_size = 128;
msgq_queue_t writer, reader;
msgq_new_queue(&writer, "test_queue", 1024);
msgq_new_queue(&reader, "test_queue", 1024);
msgq_init_publisher(&writer);
msgq_init_subscriber(&reader);
// Build 128 byte message
msgq_msg_t outgoing_msg;
msgq_msg_init_size(&outgoing_msg, msg_size);
for (size_t i = 0; i < msg_size; i++){
outgoing_msg.data[i] = i;
}
REQUIRE(msgq_msg_send(&outgoing_msg, &writer) == msg_size);
msgq_msg_t incoming_msg1;
REQUIRE(msgq_msg_recv(&incoming_msg1, &reader) == msg_size);
REQUIRE(memcmp(incoming_msg1.data, outgoing_msg.data, msg_size) == 0);
// Verify that there are no more messages
msgq_msg_t incoming_msg2;
REQUIRE(msgq_msg_recv(&incoming_msg2, &reader) == 0);
msgq_msg_close(&outgoing_msg);
msgq_msg_close(&incoming_msg1);
msgq_msg_close(&incoming_msg2);
}
TEST_CASE("Write 2 msg, read 2 msg - conflate = false", "[integration]"){
remove("/dev/shm/test_queue");
const size_t msg_size = 128;
msgq_queue_t writer, reader;
msgq_new_queue(&writer, "test_queue", 1024);
msgq_new_queue(&reader, "test_queue", 1024);
msgq_init_publisher(&writer);
msgq_init_subscriber(&reader);
// Build 128 byte message
msgq_msg_t outgoing_msg;
msgq_msg_init_size(&outgoing_msg, msg_size);
for (size_t i = 0; i < msg_size; i++){
outgoing_msg.data[i] = i;
}
REQUIRE(msgq_msg_send(&outgoing_msg, &writer) == msg_size);
REQUIRE(msgq_msg_send(&outgoing_msg, &writer) == msg_size);
msgq_msg_t incoming_msg1;
REQUIRE(msgq_msg_recv(&incoming_msg1, &reader) == msg_size);
REQUIRE(memcmp(incoming_msg1.data, outgoing_msg.data, msg_size) == 0);
msgq_msg_t incoming_msg2;
REQUIRE(msgq_msg_recv(&incoming_msg2, &reader) == msg_size);
REQUIRE(memcmp(incoming_msg2.data, outgoing_msg.data, msg_size) == 0);
msgq_msg_close(&outgoing_msg);
msgq_msg_close(&incoming_msg1);
msgq_msg_close(&incoming_msg2);
}
TEST_CASE("Write 2 msg, read 2 msg - conflate = true", "[integration]"){
remove("/dev/shm/test_queue");
const size_t msg_size = 128;
msgq_queue_t writer, reader;
msgq_new_queue(&writer, "test_queue", 1024);
msgq_new_queue(&reader, "test_queue", 1024);
msgq_init_publisher(&writer);
msgq_init_subscriber(&reader);
reader.read_conflate = true;
// Build 128 byte message
msgq_msg_t outgoing_msg;
msgq_msg_init_size(&outgoing_msg, msg_size);
for (size_t i = 0; i < msg_size; i++){
outgoing_msg.data[i] = i;
}
REQUIRE(msgq_msg_send(&outgoing_msg, &writer) == msg_size);
REQUIRE(msgq_msg_send(&outgoing_msg, &writer) == msg_size);
msgq_msg_t incoming_msg1;
REQUIRE(msgq_msg_recv(&incoming_msg1, &reader) == msg_size);
REQUIRE(memcmp(incoming_msg1.data, outgoing_msg.data, msg_size) == 0);
// Verify that there are no more messages
msgq_msg_t incoming_msg2;
REQUIRE(msgq_msg_recv(&incoming_msg2, &reader) == 0);
msgq_msg_close(&outgoing_msg);
msgq_msg_close(&incoming_msg1);
msgq_msg_close(&incoming_msg2);
}
TEST_CASE("1 publisher, 1 slow subscriber", "[integration]"){
remove("/dev/shm/test_queue");
msgq_queue_t writer, reader;
msgq_new_queue(&writer, "test_queue", 1024);
msgq_new_queue(&reader, "test_queue", 1024);
msgq_init_publisher(&writer);
msgq_init_subscriber(&reader);
int n_received = 0;
int n_skipped = 0;
for (uint64_t i = 0; i < 1e5; i++) {
msgq_msg_t outgoing_msg;
msgq_msg_init_data(&outgoing_msg, (char*)&i, sizeof(uint64_t));
msgq_msg_send(&outgoing_msg, &writer);
msgq_msg_close(&outgoing_msg);
if (i % 10 == 0){
msgq_msg_t msg1;
msgq_msg_recv(&msg1, &reader);
if (msg1.size == 0){
n_skipped++;
} else {
n_received++;
}
msgq_msg_close(&msg1);
}
}
// TODO: verify these numbers by hand
REQUIRE(n_received == 8572);
REQUIRE(n_skipped == 1428);
}
TEST_CASE("1 publisher, 2 subscribers", "[integration]"){
remove("/dev/shm/test_queue");
msgq_queue_t writer, reader1, reader2;
msgq_new_queue(&writer, "test_queue", 1024);
msgq_new_queue(&reader1, "test_queue", 1024);
msgq_new_queue(&reader2, "test_queue", 1024);
msgq_init_publisher(&writer);
msgq_init_subscriber(&reader1);
msgq_init_subscriber(&reader2);
for (uint64_t i = 0; i < 1024 * 3; i++) {
msgq_msg_t outgoing_msg;
msgq_msg_init_data(&outgoing_msg, (char*)&i, sizeof(uint64_t));
msgq_msg_send(&outgoing_msg, &writer);
msgq_msg_t msg1, msg2;
msgq_msg_recv(&msg1, &reader1);
msgq_msg_recv(&msg2, &reader2);
REQUIRE(msg1.size == sizeof(uint64_t));
REQUIRE(msg2.size == sizeof(uint64_t));
REQUIRE(*(uint64_t*)msg1.data == i);
REQUIRE(*(uint64_t*)msg2.data == i);
msgq_msg_close(&outgoing_msg);
msgq_msg_close(&msg1);
msgq_msg_close(&msg2);
}
}
-14
View File
@@ -1,14 +0,0 @@
from messaging_pyx import Context, SubSocket, PubSocket # pylint: disable=no-name-in-module, import-error
if __name__ == "__main__":
c = Context()
pub_sock = PubSocket()
pub_sock.connect(c, "controlsState")
for i in range(int(1e10)):
print(i)
sub_sock = SubSocket()
sub_sock.connect(c, "controlsState")
pub_sock.send(b'a')
print(sub_sock.receive())
-2
View File
@@ -1,2 +0,0 @@
#define CATCH_CONFIG_MAIN
#include "catch2/catch.hpp"
-142
View File
@@ -1,142 +0,0 @@
import unittest
import time
import cereal.messaging as messaging
import concurrent.futures
def poller():
context = messaging.Context()
p = messaging.Poller()
sub = messaging.SubSocket()
sub.connect(context, 'controlsState')
p.registerSocket(sub)
socks = p.poll(10000)
r = [s.receive(non_blocking=True) for s in socks]
return r
class TestPoller(unittest.TestCase):
def test_poll_once(self):
context = messaging.Context()
pub = messaging.PubSocket()
pub.connect(context, 'controlsState')
with concurrent.futures.ThreadPoolExecutor() as e:
poll = e.submit(poller)
time.sleep(0.1) # Slow joiner syndrome
# Send message
pub.send("a")
# Wait for poll result
result = poll.result()
del pub
context.term()
self.assertEqual(result, [b"a"])
def test_poll_and_create_many_subscribers(self):
context = messaging.Context()
pub = messaging.PubSocket()
pub.connect(context, 'controlsState')
with concurrent.futures.ThreadPoolExecutor() as e:
poll = e.submit(poller)
time.sleep(0.1) # Slow joiner syndrome
c = messaging.Context()
for _ in range(10):
messaging.SubSocket().connect(c, 'controlsState')
time.sleep(0.1)
# Send message
pub.send("a")
# Wait for poll result
result = poll.result()
del pub
context.term()
self.assertEqual(result, [b"a"])
def test_multiple_publishers_exception(self):
context = messaging.Context()
with self.assertRaises(messaging.MultiplePublishersError):
pub1 = messaging.PubSocket()
pub1.connect(context, 'controlsState')
pub2 = messaging.PubSocket()
pub2.connect(context, 'controlsState')
pub1.send("a")
del pub1
del pub2
context.term()
def test_multiple_messages(self):
context = messaging.Context()
pub = messaging.PubSocket()
pub.connect(context, 'controlsState')
sub = messaging.SubSocket()
sub.connect(context, 'controlsState')
time.sleep(0.1) # Slow joiner
for i in range(100):
pub.send(str(i))
msg_seen = False
i = 0
while True:
r = sub.receive(non_blocking=True)
if r is not None:
self.assertEqual(str(i), r.decode('utf8'))
msg_seen = True
i += 1
if r is None and msg_seen: # ZMQ sometimes receives nothing on the first receive
break
del pub
del sub
context.term()
def test_conflate(self):
context = messaging.Context()
pub = messaging.PubSocket()
pub.connect(context, 'controlsState')
sub = messaging.SubSocket()
sub.connect(context, 'controlsState', conflate=True)
time.sleep(0.1) # Slow joiner
pub.send('a')
pub.send('b')
self.assertEqual(b'b', sub.receive())
del pub
del sub
context.term()
if __name__ == "__main__":
unittest.main()
-177
View File
@@ -1,177 +0,0 @@
# TODO: these port numbers are hardcoded in c, fix this
# LogRotate: 8001 is a PUSH PULL socket between loggerd and visiond
# all ZMQ pub sub: port, should_log, frequency, (qlog_decimation)
# frame syncing packet
frame: [8002, true, 20., 1]
# accel, gyro, and compass
sensorEvents: [8003, true, 100., 100]
# GPS data, also global timestamp
gpsNMEA: [8004, true, 9.] # 9 msgs each sec
# CPU+MEM+GPU+BAT temps
thermal: [8005, true, 2., 1]
# List(CanData), list of can messages
can: [8006, true, 100.]
controlsState: [8007, true, 100., 100]
#liveEvent: [8008, true, 0.]
model: [8009, true, 20., 5]
features: [8010, true, 0.]
health: [8011, true, 2., 1]
radarState: [8012, true, 20., 5]
#liveUI: [8014, true, 0.]
encodeIdx: [8015, true, 20.]
liveTracks: [8016, true, 20.]
sendcan: [8017, true, 100.]
logMessage: [8018, true, 0.]
liveCalibration: [8019, true, 4., 4]
androidLog: [8020, true, 0.]
carState: [8021, true, 100., 10]
# 8022 is reserved for sshd
carControl: [8023, true, 100., 10]
plan: [8024, true, 20.]
liveLocation: [8025, true, 0., 1]
gpsLocation: [8026, true, 1., 1]
ethernetData: [8027, true, 0.]
navUpdate: [8028, true, 0.]
qcomGnss: [8029, true, 0.]
lidarPts: [8030, true, 0.]
procLog: [8031, true, 0.5]
gpsLocationExternal: [8032, true, 10., 1]
ubloxGnss: [8033, true, 10.]
clocks: [8034, true, 1., 1]
liveMpc: [8035, false, 20.]
liveLongitudinalMpc: [8036, false, 20.]
navStatus: [8038, true, 0.]
gpsLocationTrimble: [8039, true, 0.]
trimbleGnss: [8041, true, 0.]
ubloxRaw: [8042, true, 20.]
gpsPlannerPoints: [8043, true, 0.]
gpsPlannerPlan: [8044, true, 0.]
applanixRaw: [8046, true, 0.]
orbLocation: [8047, true, 0.]
trafficEvents: [8048, true, 0.]
liveLocationTiming: [8049, true, 0.]
orbslamCorrection: [8050, true, 0.]
liveLocationCorrected: [8051, true, 0.]
orbObservation: [8052, true, 0.]
applanixLocation: [8053, true, 0.]
liveLocationKalman: [8054, true, 0., 1]
uiNavigationEvent: [8055, true, 0.]
orbOdometry: [8057, true, 0.]
orbFeatures: [8058, false, 0.]
orbKeyFrame: [8059, true, 0.]
uiLayoutState: [8060, true, 0.]
frontEncodeIdx: [8061, true, 5.]
orbFeaturesSummary: [8062, true, 0.]
driverState: [8063, true, 5., 1]
liveParameters: [8064, true, 10.]
liveMapData: [8065, true, 0.]
cameraOdometry: [8066, true, 20., 5]
pathPlan: [8067, true, 20.]
kalmanOdometry: [8068, true, 0.]
thumbnail: [8069, true, 0.2, 1]
carEvents: [8070, true, 1., 1]
carParams: [8071, true, 0.02, 1]
frontFrame: [8072, true, 10.]
dMonitoringState: [8073, true, 5., 1]
offroadLayout: [8074, false, 0.]
testModel: [8040, false, 0.]
testLiveLocation: [8045, false, 0.]
testJoystick: [8056, false, 0.]
# 8080 is reserved for slave testing daemon
# 8762 is reserved for logserver
# manager -- base process to manage starting and stopping of all others
# subscribes: thermal
# **** processes that communicate with the outside world ****
# thermald -- decides when to start and stop onroad
# subscribes: health, location
# publishes: thermal
# boardd -- communicates with the car
# subscribes: sendcan
# publishes: can, health, ubloxRaw
# sensord -- publishes IMU and Magnetometer
# publishes: sensorEvents
# gpsd -- publishes EON's gps
# publishes: gpsNMEA
# camerad -- publishes camera frames
# publishes: frame, frontFrame, thumbnail
# subscribes: driverState
# dmonitoringmodeld -- runs face detection on camera frames
# publishes: driverState
# **** stateful data transformers ****
# modeld -- runs & publishes the model
# publishes: model, cameraOdometry
# subscribes: liveCalibration, pathPlan
# plannerd -- decides where to drive the car
# subscribes: carState, model, radarState, controlsState, liveParameters
# publishes: plan, pathPlan, liveMpc, liveLongitudinalMpc
# controlsd -- drives the car by sending CAN messages to panda
# subscribes: can, thermal, health, plan, pathPlan, dMonitoringState, liveCalibration, model
# publishes: carState, carControl, sendcan, controlsState, carEvents, carParams
# dmonitoringd -- processes driver monitoring data and publishes driver awareness
# subscribes: driverState, liveCalibration, carState, model, gpsLocation
# publishes: dMonitoringState
# radard -- processes the radar and vision data
# subscribes: can, controlsState, model, liveParameters
# publishes: radarState, liveTracks
# params_learner -- learns vehicle params by observing the vehicle dynamics
# subscribes: controlsState, sensorEvents, cameraOdometry
# publishes: liveParameters
# calibrationd -- reads posenet and applies a temporal filter on the frame region to look at
# subscribes: cameraOdometry
# publishes: liveCalibration
# ubloxd -- read raw ublox data and converts them in readable format
# subscribes: ubloxRaw
# publishes: ubloxGnss
# **** LOGGING SERVICE ****
# loggerd
# subscribes: EVERYTHING
# **** NON VITAL SERVICES ****
# ui
# subscribes: thermal, model, controlsState, uiLayout, liveCalibration, radarState, liveMpc, plusFrame, liveMapData
# uploader
# communicates through file system with loggerd
# deleter
# communicates through file system with loggerd and uploader
# logmessaged -- central logging service, can log to cloud
# publishes: logMessage
# logcatd -- fetches logcat info from android
# publishes: androidLog
# proclogd -- fetches process information
# publishes: procLog
# tombstoned -- reports native crashes
# athenad -- on request, open a sub socket and return the value
# updated -- waits for network access and tries to update every hour
-33
View File
@@ -1,33 +0,0 @@
#!/usr/bin/env python3
import os
import yaml
class Service():
def __init__(self, port, should_log, frequency, decimation=None):
self.port = port
self.should_log = should_log
self.frequency = frequency
self.decimation = decimation
service_list_path = os.path.join(os.path.dirname(__file__), "service_list.yaml")
service_list = {}
with open(service_list_path, "r") as f:
for k, v in yaml.safe_load(f).items():
decimation = None
if len(v) == 4:
decimation = v[3]
service_list[k] = Service(v[0], v[1], v[2], decimation)
if __name__ == "__main__":
print("/* THIS IS AN AUTOGENERATED FILE, PLEASE EDIT service_list.yaml */")
print("#ifndef __SERVICES_H")
print("#define __SERVICES_H")
print("struct service { int port; bool should_log; int frequency; int decimation; char name[0x100]; };")
print("static struct service services[] = {")
for k, v in service_list.items():
print(' { .name = "%s", .port = %d, .should_log = %s, .frequency = %d, .decimation = %d },' % (k, v.port, "true" if v.should_log else "false", v.frequency, -1 if v.decimation is None else v.decimation))
print("};")
print("#endif")
-7
View File
@@ -1,7 +0,0 @@
coverage:
status:
project:
default:
informational: true
patch: off
-1
View File
@@ -1 +0,0 @@
*.cpp
-6
View File
@@ -1,6 +0,0 @@
Import('env')
# parser
env.Command(['common_pyx.so'],
['common_pyx_setup.py', 'clock.pyx'],
"cd common && python3 common_pyx_setup.py build_ext --inplace")
-281
View File
@@ -1,281 +0,0 @@
import os
import binascii
import itertools
import re
import struct
import subprocess
import random
from cereal import log
NetworkType = log.ThermalData.NetworkType
NetworkStrength = log.ThermalData.NetworkStrength
ANDROID = os.path.isfile('/EON')
def getprop(key):
if not ANDROID:
return ""
return subprocess.check_output(["getprop", key], encoding='utf8').strip()
def get_imei(slot):
slot = str(slot)
if slot not in ("0", "1"):
raise ValueError("SIM slot must be 0 or 1")
ret = parse_service_call_string(service_call(["iphonesubinfo", "3" ,"i32", str(slot)]))
if not ret:
# allow non android to be identified differently
ret = "%015d" % random.randint(0, 1<<32)
return ret
def get_serial():
ret = getprop("ro.serialno")
if ret == "":
ret = "cccccccc"
return ret
def get_subscriber_info():
ret = parse_service_call_string(service_call(["iphonesubinfo", "7"]))
if ret is None or len(ret) < 8:
return ""
return ret
def reboot(reason=None):
if reason is None:
reason_args = ["null"]
else:
reason_args = ["s16", reason]
subprocess.check_output([
"service", "call", "power", "16", # IPowerManager.reboot
"i32", "0", # no confirmation,
*reason_args,
"i32", "1" # wait
])
def service_call(call):
if not ANDROID:
return None
ret = subprocess.check_output(["service", "call", *call], encoding='utf8').strip()
if 'Parcel' not in ret:
return None
return parse_service_call_bytes(ret)
def parse_service_call_unpack(r, fmt):
try:
return struct.unpack(fmt, r)[0]
except Exception:
return None
def parse_service_call_string(r):
try:
r = r[8:] # Cut off length field
r = r.decode('utf_16_be')
# All pairs of two characters seem to be swapped. Not sure why
result = ""
for a, b, in itertools.zip_longest(r[::2], r[1::2], fillvalue='\x00'):
result += b + a
result = result.replace('\x00', '')
return result
except Exception:
return None
def parse_service_call_bytes(ret):
try:
r = b""
for hex_part in re.findall(r'[ (]([0-9a-f]{8})', ret):
r += binascii.unhexlify(hex_part)
return r
except Exception:
return None
def get_network_type():
if not ANDROID:
return NetworkType.none
wifi_check = parse_service_call_string(service_call(["connectivity", "2"]))
if wifi_check is None:
return NetworkType.none
elif 'WIFI' in wifi_check:
return NetworkType.wifi
else:
cell_check = parse_service_call_unpack(service_call(['phone', '59']), ">q")
# from TelephonyManager.java
cell_networks = {
0: NetworkType.none,
1: NetworkType.cell2G,
2: NetworkType.cell2G,
3: NetworkType.cell3G,
4: NetworkType.cell2G,
5: NetworkType.cell3G,
6: NetworkType.cell3G,
7: NetworkType.cell3G,
8: NetworkType.cell3G,
9: NetworkType.cell3G,
10: NetworkType.cell3G,
11: NetworkType.cell2G,
12: NetworkType.cell3G,
13: NetworkType.cell4G,
14: NetworkType.cell4G,
15: NetworkType.cell3G,
16: NetworkType.cell2G,
17: NetworkType.cell3G,
18: NetworkType.cell4G,
19: NetworkType.cell4G
}
return cell_networks.get(cell_check, NetworkType.none)
def get_network_strength(network_type):
network_strength = NetworkStrength.unknown
# from SignalStrength.java
def get_lte_level(rsrp, rssnr):
INT_MAX = 2147483647
if rsrp == INT_MAX:
lvl_rsrp = NetworkStrength.unknown
elif rsrp >= -95:
lvl_rsrp = NetworkStrength.great
elif rsrp >= -105:
lvl_rsrp = NetworkStrength.good
elif rsrp >= -115:
lvl_rsrp = NetworkStrength.moderate
else:
lvl_rsrp = NetworkStrength.poor
if rssnr == INT_MAX:
lvl_rssnr = NetworkStrength.unknown
elif rssnr >= 45:
lvl_rssnr = NetworkStrength.great
elif rssnr >= 10:
lvl_rssnr = NetworkStrength.good
elif rssnr >= -30:
lvl_rssnr = NetworkStrength.moderate
else:
lvl_rssnr = NetworkStrength.poor
return max(lvl_rsrp, lvl_rssnr)
def get_tdscdma_level(tdscmadbm):
lvl = NetworkStrength.unknown
if tdscmadbm > -25:
lvl = NetworkStrength.unknown
elif tdscmadbm >= -49:
lvl = NetworkStrength.great
elif tdscmadbm >= -73:
lvl = NetworkStrength.good
elif tdscmadbm >= -97:
lvl = NetworkStrength.moderate
elif tdscmadbm >= -110:
lvl = NetworkStrength.poor
return lvl
def get_gsm_level(asu):
if asu <= 2 or asu == 99:
lvl = NetworkStrength.unknown
elif asu >= 12:
lvl = NetworkStrength.great
elif asu >= 8:
lvl = NetworkStrength.good
elif asu >= 5:
lvl = NetworkStrength.moderate
else:
lvl = NetworkStrength.poor
return lvl
def get_evdo_level(evdodbm, evdosnr):
lvl_evdodbm = NetworkStrength.unknown
lvl_evdosnr = NetworkStrength.unknown
if evdodbm >= -65:
lvl_evdodbm = NetworkStrength.great
elif evdodbm >= -75:
lvl_evdodbm = NetworkStrength.good
elif evdodbm >= -90:
lvl_evdodbm = NetworkStrength.moderate
elif evdodbm >= -105:
lvl_evdodbm = NetworkStrength.poor
if evdosnr >= 7:
lvl_evdosnr = NetworkStrength.great
elif evdosnr >= 5:
lvl_evdosnr = NetworkStrength.good
elif evdosnr >= 3:
lvl_evdosnr = NetworkStrength.moderate
elif evdosnr >= 1:
lvl_evdosnr = NetworkStrength.poor
return max(lvl_evdodbm, lvl_evdosnr)
def get_cdma_level(cdmadbm, cdmaecio):
lvl_cdmadbm = NetworkStrength.unknown
lvl_cdmaecio = NetworkStrength.unknown
if cdmadbm >= -75:
lvl_cdmadbm = NetworkStrength.great
elif cdmadbm >= -85:
lvl_cdmadbm = NetworkStrength.good
elif cdmadbm >= -95:
lvl_cdmadbm = NetworkStrength.moderate
elif cdmadbm >= -100:
lvl_cdmadbm = NetworkStrength.poor
if cdmaecio >= -90:
lvl_cdmaecio = NetworkStrength.great
elif cdmaecio >= -110:
lvl_cdmaecio = NetworkStrength.good
elif cdmaecio >= -130:
lvl_cdmaecio = NetworkStrength.moderate
elif cdmaecio >= -150:
lvl_cdmaecio = NetworkStrength.poor
return max(lvl_cdmadbm, lvl_cdmaecio)
if network_type == NetworkType.none:
return network_strength
if network_type == NetworkType.wifi:
out = subprocess.check_output('dumpsys connectivity', shell=True).decode('utf-8')
network_strength = NetworkStrength.unknown
for line in out.split('\n'):
signal_str = "SignalStrength: "
if signal_str in line:
lvl_idx_start = line.find(signal_str) + len(signal_str)
lvl_idx_end = line.find(']', lvl_idx_start)
lvl = int(line[lvl_idx_start : lvl_idx_end])
if lvl >= -50:
network_strength = NetworkStrength.great
elif lvl >= -60:
network_strength = NetworkStrength.good
elif lvl >= -70:
network_strength = NetworkStrength.moderate
else:
network_strength = NetworkStrength.poor
return network_strength
else:
# check cell strength
out = subprocess.check_output('dumpsys telephony.registry', shell=True).decode('utf-8')
for line in out.split('\n'):
if "mSignalStrength" in line:
arr = line.split(' ')
ns = 0
if ("gsm" in arr[14]):
rsrp = int(arr[9])
rssnr = int(arr[11])
ns = get_lte_level(rsrp, rssnr)
if ns == NetworkStrength.unknown:
tdscmadbm = int(arr[13])
ns = get_tdscdma_level(tdscmadbm)
if ns == NetworkStrength.unknown:
asu = int(arr[1])
ns = get_gsm_level(asu)
else:
cdmadbm = int(arr[3])
cdmaecio = int(arr[4])
evdodbm = int(arr[5])
evdosnr = int(arr[7])
lvl_cdma = get_cdma_level(cdmadbm, cdmaecio)
lvl_edmo = get_evdo_level(evdodbm, evdosnr)
if lvl_edmo == NetworkStrength.unknown:
ns = lvl_cdma
elif lvl_cdma == NetworkStrength.unknown:
ns = lvl_edmo
else:
ns = min(lvl_cdma, lvl_edmo)
network_strength = max(network_strength, ns)
return network_strength
+1 -28
View File
@@ -1,34 +1,7 @@
import jwt
import requests
from datetime import datetime, timedelta
from common.basedir import PERSIST
from selfdrive.version import version
class Api():
def __init__(self, dongle_id):
self.dongle_id = dongle_id
with open(PERSIST+'/comma/id_rsa') as f:
self.private_key = f.read()
def get(self, *args, **kwargs):
return self.request('GET', *args, **kwargs)
def post(self, *args, **kwargs):
return self.request('POST', *args, **kwargs)
def request(self, method, endpoint, timeout=None, access_token=None, **params):
return api_get(endpoint, method=method, timeout=timeout, access_token=access_token, **params)
def get_token(self):
now = datetime.utcnow()
payload = {
'identity': self.dongle_id,
'nbf': now,
'iat': now,
'exp': now + timedelta(hours=1)
}
return jwt.encode(payload, self.private_key, algorithm='RS256').decode('utf8')
def api_get(endpoint, method='GET', timeout=None, access_token=None, **params):
backend = "https://api.commadotai.com/"
-97
View File
@@ -1,97 +0,0 @@
import os
import subprocess
import glob
import hashlib
import shutil
from common.basedir import BASEDIR
from selfdrive.swaglog import cloudlog
android_packages = ("ai.comma.plus.offroad",)
def get_installed_apks():
dat = subprocess.check_output(["pm", "list", "packages", "-f"], encoding='utf8').strip().split("\n")
ret = {}
for x in dat:
if x.startswith("package:"):
v,k = x.split("package:")[1].split("=")
ret[k] = v
return ret
def install_apk(path):
# can only install from world readable path
install_path = "/sdcard/%s" % os.path.basename(path)
shutil.copyfile(path, install_path)
ret = subprocess.call(["pm", "install", "-r", install_path])
os.remove(install_path)
return ret == 0
def start_offroad():
set_package_permissions()
system("am start -n ai.comma.plus.offroad/.MainActivity")
def set_package_permissions():
pm_grant("ai.comma.plus.offroad", "android.permission.ACCESS_FINE_LOCATION")
pm_grant("ai.comma.plus.offroad", "android.permission.READ_PHONE_STATE")
pm_grant("ai.comma.plus.offroad", "android.permission.READ_EXTERNAL_STORAGE")
appops_set("ai.comma.plus.offroad", "SU", "allow")
appops_set("ai.comma.plus.offroad", "WIFI_SCAN", "allow")
def appops_set(package, op, mode):
system(f"LD_LIBRARY_PATH= appops set {package} {op} {mode}")
def pm_grant(package, permission):
system(f"pm grant {package} {permission}")
def system(cmd):
try:
cloudlog.info("running %s" % cmd)
subprocess.check_output(cmd, stderr=subprocess.STDOUT, shell=True)
except subprocess.CalledProcessError as e:
cloudlog.event("running failed",
cmd=e.cmd,
output=e.output[-1024:],
returncode=e.returncode)
# *** external functions ***
def update_apks():
# install apks
installed = get_installed_apks()
install_apks = glob.glob(os.path.join(BASEDIR, "apk/*.apk"))
for apk in install_apks:
app = os.path.basename(apk)[:-4]
if app not in installed:
installed[app] = None
cloudlog.info("installed apks %s" % (str(installed), ))
for app in installed.keys():
apk_path = os.path.join(BASEDIR, "apk/"+app+".apk")
if not os.path.exists(apk_path):
continue
h1 = hashlib.sha1(open(apk_path, 'rb').read()).hexdigest()
h2 = None
if installed[app] is not None:
h2 = hashlib.sha1(open(installed[app], 'rb').read()).hexdigest()
cloudlog.info("comparing version of %s %s vs %s" % (app, h1, h2))
if h2 is None or h1 != h2:
cloudlog.info("installing %s" % app)
success = install_apk(apk_path)
if not success:
cloudlog.info("needing to uninstall %s" % app)
system("pm uninstall %s" % app)
success = install_apk(apk_path)
assert success
def pm_apply_packages(cmd):
for p in android_packages:
system("pm %s %s" % (cmd, p))
if __name__ == "__main__":
update_apks()
-7
View File
@@ -1,11 +1,4 @@
import os
BASEDIR = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), "../"))
from common.android import ANDROID
if ANDROID:
PERSIST = "/persist"
PARAMS = "/data/params"
else:
PERSIST = os.path.join(BASEDIR, "persist")
PARAMS = os.path.join(BASEDIR, "persist", "params")
-22
View File
@@ -1,22 +0,0 @@
from posix.time cimport clock_gettime, timespec, CLOCK_MONOTONIC_RAW, clockid_t
IF UNAME_SYSNAME == "Darwin":
# Darwin doesn't have a CLOCK_BOOTTIME
CLOCK_BOOTTIME = CLOCK_MONOTONIC_RAW
ELSE:
from posix.time cimport CLOCK_BOOTTIME
cdef double readclock(clockid_t clock_id):
cdef timespec ts
cdef double current
clock_gettime(clock_id, &ts)
current = ts.tv_sec + (ts.tv_nsec / 1000000000.)
return current
def monotonic_time():
return readclock(CLOCK_MONOTONIC_RAW)
def sec_since_boot():
return readclock(CLOCK_BOOTTIME)
-20
View File
@@ -1,20 +0,0 @@
from distutils.core import Extension, setup # pylint: disable=import-error,no-name-in-module
from Cython.Build import cythonize
from common.cython_hacks import BuildExtWithoutPlatformSuffix
sourcefiles = ['clock.pyx']
extra_compile_args = ["-std=c++11"]
setup(name='Common',
cmdclass={'build_ext': BuildExtWithoutPlatformSuffix},
ext_modules=cythonize(
Extension(
"common_pyx",
language="c++",
sources=sourcefiles,
extra_compile_args=extra_compile_args,
)
),
nthreads=4,
)
-23
View File
@@ -1,23 +0,0 @@
import os
import sysconfig
from Cython.Distutils import build_ext
def get_ext_filename_without_platform_suffix(filename):
name, ext = os.path.splitext(filename)
ext_suffix = sysconfig.get_config_var('EXT_SUFFIX')
if ext_suffix == ext:
return filename
ext_suffix = ext_suffix.replace(ext, '')
idx = name.find(ext_suffix)
if idx == -1:
return filename
else:
return name[:idx] + ext
class BuildExtWithoutPlatformSuffix(build_ext):
def get_ext_filename(self, ext_name):
filename = super().get_ext_filename(ext_name)
return get_ext_filename_without_platform_suffix(filename)
+47 -36
View File
@@ -7,9 +7,9 @@ from collections import namedtuple, defaultdict
def int_or_float(s):
# return number, trying to maintain int format
if s.isdigit():
return int(s, 10)
else:
try:
return int(s)
except ValueError:
return float(s)
DBCSignal = namedtuple(
@@ -17,11 +17,11 @@ DBCSignal = namedtuple(
"factor", "offset", "tmin", "tmax", "units"])
class dbc():
class dbc(object):
def __init__(self, fn):
self.name, _ = os.path.splitext(os.path.basename(fn))
with open(fn, encoding="ascii") as f:
self.txt = f.readlines()
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
@@ -41,7 +41,7 @@ class dbc():
self.def_vals = defaultdict(list)
# lookup to bit reverse each byte
self.bits_index = [(i & ~0b111) + ((-i-1) & 0b111) for i in range(64)]
self.bits_index = [(i & ~0b111) + ((-i-1) & 0b111) for i in xrange(64)]
for l in self.txt:
l = l.strip()
@@ -51,8 +51,7 @@ class dbc():
dat = bo_regexp.match(l)
if dat is None:
print("bad BO {0}".format(l))
print "bad BO", l
name = dat.group(2)
size = int(dat.group(3))
ids = int(dat.group(1), 0) # could be hex
@@ -68,9 +67,8 @@ class dbc():
if dat is None:
dat = sgm_regexp.match(l)
go = 1
if dat is None:
print("bad SG {0}".format(l))
print "bad SG", l
sgname = dat.group(1)
start_bit = int(dat.group(go+2))
@@ -92,22 +90,26 @@ class dbc():
dat = val_regexp.match(l)
if dat is None:
print("bad VAL {0}".format(l))
print "bad VAL", l
ids = int(dat.group(1), 0) # could be hex
sgname = dat.group(2)
defvals = dat.group(3)
defvals = defvals.replace("?",r"\?") #escape sequence in C++
defvals = defvals.replace("?","\?") #escape sequence in C++
defvals = defvals.split('"')[:-1]
# convert strings to UPPER_CASE_WITH_UNDERSCORES
defvals[1::2] = [d.strip().upper().replace(" ","_") for d in defvals[1::2]]
defs = defvals[1::2]
#cleanup, convert to UPPER_CASE_WITH_UNDERSCORES
for i,d in enumerate(defs):
d = defs[i].strip().upper()
defs[i] = d.replace(" ","_")
defvals[1::2] = defs
defvals = '"'+"".join(str(i) for i in defvals)+'"'
self.def_vals[ids].append((sgname, defvals))
for msg in self.msgs.values():
for msg in self.msgs.viewvalues():
msg[1].sort(key=lambda x: x.start_bit)
self.msg_name_to_address = {}
@@ -147,20 +149,22 @@ class dbc():
ival = dd.get(s.name)
if ival is not None:
b2 = s.size
if s.is_little_endian:
b1 = s.start_bit
else:
b1 = (s.start_bit // 8) * 8 + (-s.start_bit - 1) % 8
bo = 64 - (b1 + s.size)
ival = (ival / s.factor) - s.offset
ival = int(round(ival))
if s.is_signed and ival < 0:
ival = (1 << s.size) + ival
ival = (1 << b2) + ival
if s.is_little_endian:
shift = s.start_bit
else:
b1 = (s.start_bit // 8) * 8 + (-s.start_bit - 1) % 8
shift = 64 - (b1 + s.size)
mask = ((1 << s.size) - 1) << shift
dat = (ival & ((1 << s.size) - 1)) << shift
shift = b1 if s.is_little_endian else bo
mask = ((1 << b2) - 1) << shift
dat = (ival & ((1 << b2) - 1)) << shift
if s.is_little_endian:
mask = self.reverse_bytes(mask)
@@ -204,9 +208,9 @@ class dbc():
name = msg[0][0]
if debug:
print(name)
print name
st = x[2].ljust(8, b'\x00')
st = x[2].ljust(8, '\x00')
le, be = None, None
for s in msg[1]:
@@ -220,29 +224,35 @@ class dbc():
factor = s[5]
offset = s[6]
b2 = signal_size
if little_endian:
b1 = start_bit
else:
b1 = (start_bit // 8) * 8 + (-start_bit - 1) % 8
bo = 64 - (b1 + signal_size)
if little_endian:
if le is None:
le = struct.unpack("<Q", st)[0]
shift_amount = b1
tmp = le
shift_amount = start_bit
else:
if be is None:
be = struct.unpack(">Q", st)[0]
shift_amount = bo
tmp = be
b1 = (start_bit // 8) * 8 + (-start_bit - 1) % 8
shift_amount = 64 - (b1 + signal_size)
if shift_amount < 0:
continue
tmp = (tmp >> shift_amount) & ((1 << signal_size) - 1)
if signed and (tmp >> (signal_size - 1)):
tmp -= (1 << signal_size)
tmp = (tmp >> shift_amount) & ((1 << b2) - 1)
if signed and (tmp >> (b2 - 1)):
tmp -= (1 << b2)
tmp = tmp * factor + offset
# if debug:
# print("%40s %2d %2d %7.2f %s" % (s[0], s[1], s[2], tmp, s[-1]))
# print "%40s %2d %2d %7.2f %s" % (s[0], s[1], s[2], tmp, s[-1])
if arr is None:
out[s[0]] = tmp
@@ -257,6 +267,7 @@ class dbc():
if __name__ == "__main__":
from opendbc import DBC_PATH
import numpy as np
dbc_test = dbc(os.path.join(DBC_PATH, 'toyota_prius_2017_pt_generated.dbc'))
msg = ('STEER_ANGLE_SENSOR', {'STEER_ANGLE': -6.0, 'STEER_RATE': 4, 'STEER_FRACTION': -0.2})
@@ -266,7 +277,7 @@ if __name__ == "__main__":
dbc_test = dbc(os.path.join(DBC_PATH, 'hyundai_santa_fe_2019_ccan.dbc'))
decoded = dbc_test.decode((0x2b0, 0, "\xfa\xfe\x00\x07\x12"))
assert abs(decoded[1]['SAS_Angle'] - (-26.2)) < 0.001
assert np.isclose(decoded[1]['SAS_Angle'], -26.2)
msg = ('SAS11', {'SAS_Stat': 7.0, 'MsgCount': 0.0, 'SAS_Angle': -26.200000000000003, 'SAS_Speed': 0.0, 'CheckSum': 0.0})
encoded = dbc_test.encode(*msg)
-33
View File
@@ -1,33 +0,0 @@
#!/usr/bin/env python3.7
import subprocess
from common.params import Params
params = Params()
def get_last_modified():
return Params().get('DragonLastModified', encoding='utf-8')
def is_online():
return not subprocess.call(["ping", "-W", "4", "-c", "1", "117.28.245.92"])
def common_controller_update():
dragon_lat_ctrl = False if params.get("DragonLatCtrl", encoding='utf8') == "0" else True
if dragon_lat_ctrl:
dragon_enable_steering_on_signal = True if (params.get("DragonEnableSteeringOnSignal", encoding='utf8') == "1" and params.get("LaneChangeEnabled", encoding='utf8') == "0") else False
if dragon_enable_steering_on_signal:
try:
dragon_blinker_off_timer = float(params.get("DragonBlinkerOffTimer", encoding='utf8')) * 100
except (TypeError, ValueError):
dragon_blinker_off_timer = 0
else:
dragon_blinker_off_timer = 0
else:
dragon_enable_steering_on_signal = False
dragon_blinker_off_timer = 0
return dragon_lat_ctrl, dragon_enable_steering_on_signal, dragon_blinker_off_timer
def common_controller_ctrl(enabled, dragon_lat_ctrl, dragon_enable_steering_on_signal, blinker_on, steer_req):
if enabled:
if (dragon_enable_steering_on_signal and blinker_on) or not dragon_lat_ctrl:
steer_req = 0 if isinstance(steer_req, int) else False
return steer_req
+5 -18
View File
@@ -2,20 +2,12 @@ import os
import sys
import fcntl
import hashlib
import platform
from cffi import FFI
def suffix():
if platform.system() == "Darwin":
return ".dylib"
else:
return ".so"
TMPDIR = "/tmp/ccache"
def ffi_wrap(name, c_code, c_header, tmpdir="/tmp/ccache", cflags="", libraries=None):
if libraries is None:
libraries = []
cache = name + "_" + hashlib.sha1(c_code.encode('utf-8')).hexdigest()
def ffi_wrap(name, c_code, c_header, tmpdir=TMPDIR, cflags="", libraries=[]):
cache = name + "_" + hashlib.sha1(c_code).hexdigest()
try:
os.mkdir(tmpdir)
except OSError:
@@ -28,7 +20,7 @@ def ffi_wrap(name, c_code, c_header, tmpdir="/tmp/ccache", cflags="", libraries=
try:
mod = __import__(cache)
except Exception:
print("cache miss {0}".format(cache))
print "cache miss", cache
compile_code(cache, c_code, c_header, tmpdir, cflags, libraries)
mod = __import__(cache)
finally:
@@ -36,11 +28,7 @@ def ffi_wrap(name, c_code, c_header, tmpdir="/tmp/ccache", cflags="", libraries=
return mod.ffi, mod.lib
def compile_code(name, c_code, c_header, directory, cflags="", libraries=None):
if libraries is None:
libraries = []
def compile_code(name, c_code, c_header, directory, cflags="", libraries=[]):
ffibuilder = FFI()
ffibuilder.set_source(name, c_code, source_extension='.cpp', libraries=libraries)
ffibuilder.cdef(c_header)
@@ -48,7 +36,6 @@ def compile_code(name, c_code, c_header, directory, cflags="", libraries=None):
os.environ['CFLAGS'] = cflags
ffibuilder.compile(verbose=True, debug=False, tmpdir=directory)
def wrap_compiled(name, directory):
sys.path.append(directory)
mod = __import__(name)
-109
View File
@@ -1,109 +0,0 @@
import os
import shutil
import tempfile
from atomicwrites import AtomicWriter
def mkdirs_exists_ok(path):
try:
os.makedirs(path)
except OSError:
if not os.path.isdir(path):
raise
def rm_not_exists_ok(path):
try:
os.remove(path)
except OSError:
if os.path.exists(path):
raise
def rm_tree_or_link(path):
if os.path.islink(path):
os.unlink(path)
elif os.path.isdir(path):
shutil.rmtree(path)
def get_tmpdir_on_same_filesystem(path):
normpath = os.path.normpath(path)
parts = normpath.split("/")
if len(parts) > 1 and parts[1] == "scratch":
return "/scratch/tmp"
elif len(parts) > 2 and parts[2] == "runner":
return "/{}/runner/tmp".format(parts[1])
return "/tmp"
class AutoMoveTempdir():
def __init__(self, target_path, temp_dir=None):
self._target_path = target_path
self._path = tempfile.mkdtemp(dir=temp_dir)
@property
def name(self):
return self._path
def close(self):
os.rename(self._path, self._target_path)
def __enter__(self): return self
def __exit__(self, type, value, traceback):
if type is None:
self.close()
else:
shutil.rmtree(self._path)
class NamedTemporaryDir():
def __init__(self, temp_dir=None):
self._path = tempfile.mkdtemp(dir=temp_dir)
@property
def name(self):
return self._path
def close(self):
shutil.rmtree(self._path)
def __enter__(self): return self
def __exit__(self, type, value, traceback):
self.close()
def _get_fileobject_func(writer, temp_dir):
def _get_fileobject():
file_obj = writer.get_fileobject(dir=temp_dir)
os.chmod(file_obj.name, 0o644)
return file_obj
return _get_fileobject
def atomic_write_on_fs_tmp(path, **kwargs):
"""Creates an atomic writer using a temporary file in a temporary directory
on the same filesystem as path.
"""
# TODO(mgraczyk): This use of AtomicWriter relies on implementation details to set the temp
# directory.
writer = AtomicWriter(path, **kwargs)
return writer._open(_get_fileobject_func(writer, get_tmpdir_on_same_filesystem(path)))
def atomic_write_in_dir(path, **kwargs):
"""Creates an atomic writer using a temporary file in the same directory
as the destination file.
"""
writer = AtomicWriter(path, **kwargs)
return writer._open(_get_fileobject_func(writer, os.path.dirname(path)))
def atomic_write_in_dir_neos(path, contents, mode=None):
"""
Atomically writes contents to path using a temporary file in the same directory
as path. Useful on NEOS, where `os.link` (required by atomic_write_in_dir) is missing.
"""
f = tempfile.NamedTemporaryFile(delete=False, prefix=".tmp", dir=os.path.dirname(path))
f.write(contents)
f.flush()
if mode is not None:
os.fchmod(f.fileno(), mode)
os.fsync(f.fileno())
f.close()
os.rename(f.name, path)
+2 -1
View File
@@ -6,4 +6,5 @@ class FirstOrderFilter():
def update(self, x):
self.x = (1. - self.k) * self.x + self.k * x
return self.x
+64
View File
@@ -0,0 +1,64 @@
import os
from common.basedir import BASEDIR
def get_fingerprint_list():
# read all the folders in selfdrive/car and return a dict where:
# - keys are all the car models for which we have a fingerprint
# - values are lists dicts of messages that constitute the unique
# CAN fingerprint of each car model and all its variants
fingerprints = {}
for car_folder in [x[0] for x in os.walk(BASEDIR + '/selfdrive/car')]:
try:
car_name = car_folder.split('/')[-1]
values = __import__('selfdrive.car.%s.values' % car_name, fromlist=['FINGERPRINTS'])
if hasattr(values, 'FINGERPRINTS'):
car_fingerprints = values.FINGERPRINTS
else:
continue
for f, v in car_fingerprints.items():
fingerprints[f] = v
except (ImportError, IOError):
pass
return fingerprints
_FINGERPRINTS = get_fingerprint_list()
_DEBUG_ADDRESS = {1880: 8} # reserved for debug purposes
def is_valid_for_fingerprint(msg, car_fingerprint):
adr = msg.address
bus = msg.src
# ignore addresses that are more than 11 bits
return (adr in car_fingerprint and car_fingerprint[adr] == len(msg.dat)) or \
bus != 0 or adr >= 0x800
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]
for fingerprint in car_fingerprints:
fingerprint.update(_DEBUG_ADDRESS) # add alien debug address
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()
-1
View File
@@ -1 +0,0 @@
simple_kalman_impl.c
-6
View File
@@ -1,6 +0,0 @@
Import('env')
env.Command(['simple_kalman_impl.so'],
['simple_kalman_impl.pyx', 'simple_kalman_impl.pxd', 'simple_kalman_setup.py'],
"cd common/kalman && python3 simple_kalman_setup.py build_ext --inplace")
+253
View File
@@ -0,0 +1,253 @@
# pylint: skip-file
from __future__ import print_function
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
+23 -3
View File
@@ -1,3 +1,23 @@
# pylint: skip-file
from common.kalman.simple_kalman_impl import KF1D as KF1D
assert KF1D
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
-16
View File
@@ -1,16 +0,0 @@
cdef class KF1D:
cdef public:
double x0_0
double x1_0
double K0_0
double K1_0
double A0_0
double A0_1
double A1_0
double A1_1
double C0_0
double C0_1
double A_K_0
double A_K_1
double A_K_2
double A_K_3
-36
View File
@@ -1,36 +0,0 @@
# cython: language_level=3
cdef class KF1D:
def __init__(self, x0, A, C, K):
self.x0_0 = x0[0][0]
self.x1_0 = x0[1][0]
self.A0_0 = A[0][0]
self.A0_1 = A[0][1]
self.A1_0 = A[1][0]
self.A1_1 = A[1][1]
self.C0_0 = C[0]
self.C0_1 = C[1]
self.K0_0 = K[0][0]
self.K1_0 = K[1][0]
self.A_K_0 = self.A0_0 - self.K0_0 * self.C0_0
self.A_K_1 = self.A0_1 - self.K0_0 * self.C0_1
self.A_K_2 = self.A1_0 - self.K1_0 * self.C0_0
self.A_K_3 = self.A1_1 - self.K1_0 * self.C0_1
def update(self, meas):
cdef double x0_0 = self.A_K_0 * self.x0_0 + self.A_K_1 * self.x1_0 + self.K0_0 * meas
cdef double x1_0 = self.A_K_2 * self.x0_0 + self.A_K_3 * self.x1_0 + self.K1_0 * meas
self.x0_0 = x0_0
self.x1_0 = x1_0
return [self.x0_0, self.x1_0]
@property
def x(self):
return [[self.x0_0], [self.x1_0]]
@x.setter
def x(self, x):
self.x0_0 = x[0][0]
self.x1_0 = x[1][0]
-23
View File
@@ -1,23 +0,0 @@
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
-9
View File
@@ -1,9 +0,0 @@
from distutils.core import Extension, setup
from Cython.Build import cythonize
from common.cython_hacks import BuildExtWithoutPlatformSuffix
setup(name='Simple Kalman Implementation',
cmdclass={'build_ext': BuildExtWithoutPlatformSuffix},
ext_modules=cythonize(Extension("simple_kalman_impl", ["simple_kalman_impl.pyx"])))
-85
View File
@@ -1,85 +0,0 @@
import unittest
import random
import timeit
import numpy as np
from common.kalman.simple_kalman import KF1D
from common.kalman.simple_kalman_old import KF1D as KF1D_old
class TestSimpleKalman(unittest.TestCase):
def setUp(self):
dt = 0.01
x0_0 = 0.0
x1_0 = 0.0
A0_0 = 1.0
A0_1 = dt
A1_0 = 0.0
A1_1 = 1.0
C0_0 = 1.0
C0_1 = 0.0
K0_0 = 0.12287673
K1_0 = 0.29666309
self.kf_old = KF1D_old(x0=np.matrix([[x0_0], [x1_0]]),
A=np.matrix([[A0_0, A0_1], [A1_0, A1_1]]),
C=np.matrix([C0_0, C0_1]),
K=np.matrix([[K0_0], [K1_0]]))
self.kf = KF1D(x0=[[x0_0], [x1_0]],
A=[[A0_0, A0_1], [A1_0, A1_1]],
C=[C0_0, C0_1],
K=[[K0_0], [K1_0]])
def test_getter_setter(self):
self.kf.x = [[1.0], [1.0]]
self.assertEqual(self.kf.x, [[1.0], [1.0]])
def update_returns_state(self):
x = self.kf.update(100)
self.assertEqual(x, self.kf.x)
def test_old_equal_new(self):
for _ in range(1000):
v_wheel = random.uniform(0, 200)
x_old = self.kf_old.update(v_wheel)
x = self.kf.update(v_wheel)
# Compare the output x, verify that the error is less than 1e-4
self.assertAlmostEqual(x_old[0], x[0])
self.assertAlmostEqual(x_old[1], x[1])
def test_new_is_faster(self):
setup = """
import numpy as np
from common.kalman.simple_kalman import KF1D
from common.kalman.simple_kalman_old import KF1D as KF1D_old
dt = 0.01
x0_0 = 0.0
x1_0 = 0.0
A0_0 = 1.0
A0_1 = dt
A1_0 = 0.0
A1_1 = 1.0
C0_0 = 1.0
C0_1 = 0.0
K0_0 = 0.12287673
K1_0 = 0.29666309
kf_old = KF1D_old(x0=np.matrix([[x0_0], [x1_0]]),
A=np.matrix([[A0_0, A0_1], [A1_0, A1_1]]),
C=np.matrix([C0_0, C0_1]),
K=np.matrix([[K0_0], [K1_0]]))
kf = KF1D(x0=[[x0_0], [x1_0]],
A=[[A0_0, A0_1], [A1_0, A1_1]],
C=[C0_0, C0_1],
K=[[K0_0], [K1_0]])
"""
kf_speed = timeit.timeit("kf.update(1234)", setup=setup, number=10000)
kf_old_speed = timeit.timeit("kf_old.update(1234)", setup=setup, number=10000)
self.assertTrue(kf_speed < kf_old_speed / 4)
+22 -38
View File
@@ -1,11 +1,9 @@
import io
import os
import sys
import copy
import json
import socket
import logging
import traceback
from threading import local
from collections import OrderedDict
from contextlib import contextmanager
@@ -80,6 +78,28 @@ class SwagLogger(logging.Logger):
self.log_local = local()
self.log_local.ctx = {}
def findCaller(self, stack_info=None):
"""
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
@@ -120,42 +140,6 @@ class SwagLogger(logging.Logger):
else:
self.info(evt)
def findCaller(self, stack_info=False, stacklevel=1):
"""
Find the stack frame of the caller so that we can note the source
file name, line number and function name.
"""
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
orig_f = f
while f and stacklevel > 1:
f = f.f_back
stacklevel -= 1
if not f:
f = orig_f
rv = "(unknown file)", 0, "(unknown function)", None
while hasattr(f, "f_code"):
co = f.f_code
filename = os.path.normcase(co.co_filename)
if filename == _srcfile:
f = f.f_back
continue
sinfo = None
if stack_info:
sio = io.StringIO()
sio.write('Stack (most recent call last):\n')
traceback.print_stack(f, file=sio)
sinfo = sio.getvalue()
if sinfo[-1] == '\n':
sinfo = sinfo[:-1]
sio.close()
rv = (co.co_filename, f.f_lineno, co.co_name, sinfo)
break
return rv
if __name__ == "__main__":
log = SwagLogger()
-50
View File
@@ -1,50 +0,0 @@
def cputime_total(ct):
return ct.cpuUser + ct.cpuSystem + ct.cpuChildrenUser + ct.cpuChildrenSystem
def print_cpu_usage(first_proc, last_proc):
r = 0
procs = [
("selfdrive.controls.controlsd", 59.46),
("./_modeld", 48.94),
("./loggerd", 28.49),
("selfdrive.controls.plannerd", 19.77),
("selfdrive.controls.radard", 9.54),
("./_ui", 9.54),
("./camerad", 7.07),
("selfdrive.locationd.locationd", 7.13),
("./_sensord", 6.17),
("selfdrive.controls.dmonitoringd", 5.48),
("./boardd", 3.63),
("./_dmonitoringmodeld", 2.67),
("selfdrive.logmessaged", 2.71),
("selfdrive.thermald", 2.41),
("./paramsd", 2.18),
("selfdrive.locationd.calibrationd", 1.76),
("./proclogd", 1.54),
("./_gpsd", 0.09),
("./clocksd", 0.02),
("./ubloxd", 0.02),
("selfdrive.tombstoned", 0),
("./logcatd", 0),
("selfdrive.updated", 0),
]
dt = (last_proc.logMonoTime - first_proc.logMonoTime) / 1e9
print("------------------------------------------------")
for proc_name, normal_cpu_usage in procs:
try:
first = [p for p in first_proc.procLog.procs if proc_name in p.cmdline][0]
last = [p for p in last_proc.procLog.procs if proc_name in p.cmdline][0]
cpu_time = cputime_total(last) - cputime_total(first)
cpu_usage = cpu_time / dt * 100.
if cpu_usage > max(normal_cpu_usage * 1.1, normal_cpu_usage + 5.0):
print(f"Warning {proc_name} using more CPU than normal")
r = 1
print(f"{proc_name.ljust(35)} {cpu_usage:.2f}%")
except IndexError:
print(f"{proc_name.ljust(35)} NO METRICS FOUND")
print("------------------------------------------------")
return r
+1 -4
View File
@@ -12,10 +12,7 @@ def interp(x, xp, fp):
hi += 1
low = hi - 1
return fp[-1] if hi == N and xv > xp[low] else (
fp[0] if hi == 0 else
fp[0] if hi == 0 else
(xv - xp[low]) * (fp[hi] - fp[low]) / (xp[hi] - xp[low]) + fp[low])
return [get_interp(v) for v in x] if hasattr(
x, '__iter__') else get_interp(x)
def mean(x):
return sum(x) / len(x)
+47 -198
View File
@@ -1,4 +1,4 @@
#!/usr/bin/env python3
#!/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.
@@ -22,16 +22,12 @@ file in place without messing with <params_dir>/d.
"""
import time
import os
import string
import binascii
import errno
import sys
import shutil
import fcntl
import tempfile
import threading
from enum import Enum
from common.basedir import PARAMS
def mkdirs_exists_ok(path):
try:
@@ -40,167 +36,51 @@ def mkdirs_exists_ok(path):
if not os.path.isdir(path):
raise
class TxType(Enum):
PERSISTENT = 1
CLEAR_ON_MANAGER_START = 2
CLEAR_ON_PANDA_DISCONNECT = 3
CLEAR_ON_CAR_START = 3
class UnknownKeyName(Exception):
pass
keys = {
"AccessToken": [TxType.CLEAR_ON_MANAGER_START],
"AthenadPid": [TxType.PERSISTENT],
"CalibrationParams": [TxType.PERSISTENT],
"CarParams": [TxType.CLEAR_ON_MANAGER_START, TxType.CLEAR_ON_PANDA_DISCONNECT],
"CarParamsCache": [TxType.CLEAR_ON_MANAGER_START, TxType.CLEAR_ON_PANDA_DISCONNECT],
"CarVin": [TxType.CLEAR_ON_MANAGER_START, TxType.CLEAR_ON_PANDA_DISCONNECT],
"CommunityFeaturesToggle": [TxType.PERSISTENT],
"CompletedTrainingVersion": [TxType.PERSISTENT],
"ControlsParams": [TxType.PERSISTENT],
"DisablePowerDown": [TxType.PERSISTENT],
"DoUninstall": [TxType.CLEAR_ON_MANAGER_START],
"DongleId": [TxType.PERSISTENT],
"GitBranch": [TxType.PERSISTENT],
"GitCommit": [TxType.PERSISTENT],
"GitRemote": [TxType.PERSISTENT],
"GithubSshKeys": [TxType.PERSISTENT],
"HasAcceptedTerms": [TxType.PERSISTENT],
"HasCompletedSetup": [TxType.PERSISTENT],
"IsDriverViewEnabled": [TxType.CLEAR_ON_MANAGER_START],
"IsLdwEnabled": [TxType.PERSISTENT],
"IsGeofenceEnabled": [TxType.PERSISTENT],
"IsMetric": [TxType.PERSISTENT],
"IsOffroad": [TxType.CLEAR_ON_MANAGER_START],
"IsRHD": [TxType.PERSISTENT],
"IsTakingSnapshot": [TxType.CLEAR_ON_MANAGER_START],
"IsUpdateAvailable": [TxType.CLEAR_ON_MANAGER_START],
"IsUploadRawEnabled": [TxType.PERSISTENT],
"LastAthenaPingTime": [TxType.PERSISTENT],
"LastUpdateTime": [TxType.PERSISTENT],
"LimitSetSpeed": [TxType.PERSISTENT],
"LimitSetSpeedNeural": [TxType.PERSISTENT],
"LiveParameters": [TxType.PERSISTENT],
"LongitudinalControl": [TxType.PERSISTENT],
"OpenpilotEnabledToggle": [TxType.PERSISTENT],
"LaneChangeEnabled": [TxType.PERSISTENT],
"PandaFirmware": [TxType.CLEAR_ON_MANAGER_START, TxType.CLEAR_ON_PANDA_DISCONNECT],
"PandaFirmwareHex": [TxType.CLEAR_ON_MANAGER_START, TxType.CLEAR_ON_PANDA_DISCONNECT],
"PandaDongleId": [TxType.CLEAR_ON_MANAGER_START, TxType.CLEAR_ON_PANDA_DISCONNECT],
"Passive": [TxType.PERSISTENT],
"RecordFront": [TxType.PERSISTENT],
"ReleaseNotes": [TxType.PERSISTENT],
"ShouldDoUpdate": [TxType.CLEAR_ON_MANAGER_START],
"SpeedLimitOffset": [TxType.PERSISTENT],
"SubscriberInfo": [TxType.PERSISTENT],
"TermsVersion": [TxType.PERSISTENT],
"TrainingVersion": [TxType.PERSISTENT],
"UpdateAvailable": [TxType.CLEAR_ON_MANAGER_START],
"UpdateFailedCount": [TxType.CLEAR_ON_MANAGER_START],
"Version": [TxType.PERSISTENT],
"Offroad_ChargeDisabled": [TxType.CLEAR_ON_MANAGER_START, TxType.CLEAR_ON_PANDA_DISCONNECT],
"Offroad_ConnectivityNeeded": [TxType.CLEAR_ON_MANAGER_START],
"Offroad_ConnectivityNeededPrompt": [TxType.CLEAR_ON_MANAGER_START],
"Offroad_TemperatureTooHigh": [TxType.CLEAR_ON_MANAGER_START],
"Offroad_PandaFirmwareMismatch": [TxType.CLEAR_ON_MANAGER_START, TxType.CLEAR_ON_PANDA_DISCONNECT],
"Offroad_InvalidTime": [TxType.CLEAR_ON_MANAGER_START],
"Offroad_IsTakingSnapshot": [TxType.CLEAR_ON_MANAGER_START],
#dragonpilot config
"DragonEnableDashcam": [TxType.PERSISTENT],
"DragonEnableAutoShutdown": [TxType.PERSISTENT],
"DragonAutoShutdownAt": [TxType.PERSISTENT],
"DragonEnableSteeringOnSignal": [TxType.PERSISTENT],
"DragonEnableLogger": [TxType.PERSISTENT],
"DragonEnableUploader": [TxType.PERSISTENT],
"DragonNoctuaMode": [TxType.PERSISTENT],
"DragonCacheCar": [TxType.PERSISTENT],
"DragonCachedModel": [TxType.CLEAR_ON_MANAGER_START], # deprecated
"DragonCachedFP": [TxType.CLEAR_ON_MANAGER_START], # deprecated
"DragonCachedVIN": [TxType.CLEAR_ON_MANAGER_START], # deprecated
"DragonCachedCarFW": [TxType.CLEAR_ON_MANAGER_START], # deprecated
"DragonCachedSource": [TxType.CLEAR_ON_MANAGER_START], # deprecated
"DragonAllowGas": [TxType.PERSISTENT],
"DragonToyotaStockDSU": [TxType.PERSISTENT],
"DragonLatCtrl": [TxType.PERSISTENT],
"DragonUISpeed": [TxType.PERSISTENT],
"DragonUIEvent": [TxType.PERSISTENT],
"DragonUIMaxSpeed": [TxType.PERSISTENT],
"DragonUIFace": [TxType.PERSISTENT],
"DragonUIDev": [TxType.PERSISTENT],
"DragonUIDevMini": [TxType.PERSISTENT],
"DragonEnableTomTom": [TxType.PERSISTENT],
"DragonBootTomTom": [TxType.PERSISTENT],
"DragonRunTomTom": [TxType.PERSISTENT],
"DragonEnableAutonavi": [TxType.PERSISTENT],
"DragonBootAutonavi": [TxType.PERSISTENT],
"DragonRunAutonavi": [TxType.PERSISTENT],
"DragonEnableAegis": [TxType.PERSISTENT],
"DragonBootAegis": [TxType.PERSISTENT],
"DragonRunAegis": [TxType.PERSISTENT],
"DragonEnableMixplorer": [TxType.PERSISTENT],
"DragonRunMixplorer": [TxType.PERSISTENT],
"DragonSteeringMonitorTimer": [TxType.PERSISTENT],
"DragonCameraOffset": [TxType.PERSISTENT],
"DragonUIVolumeBoost": [TxType.PERSISTENT],
"DragonGreyPandaMode": [TxType.PERSISTENT],
"DragonDrivingUI": [TxType.PERSISTENT],
"DragonDisplaySteeringLimitAlert": [TxType.PERSISTENT],
"DragonChargingCtrl": [TxType.PERSISTENT],
"DragonCharging": [TxType.PERSISTENT],
"DragonDisCharging": [TxType.PERSISTENT],
"DragonToyotaLaneDepartureWarning": [TxType.PERSISTENT],
"DragonUILane": [TxType.PERSISTENT],
"DragonUILead": [TxType.PERSISTENT],
"DragonUIPath": [TxType.PERSISTENT],
"DragonUIBlinker": [TxType.PERSISTENT],
"DragonUIDMView": [TxType.PERSISTENT],
"DragonEnableDriverMonitoring": [TxType.PERSISTENT],
"DragonCarModel": [TxType.CLEAR_ON_MANAGER_START],
"DragonEnableSlowOnCurve": [TxType.PERSISTENT],
"DragonEnableLeadCarMovingAlert": [TxType.PERSISTENT],
"DragonToyotaSnGMod": [TxType.PERSISTENT],
"DragonWazeMode": [TxType.PERSISTENT],
"DragonRunWaze": [TxType.PERSISTENT],
"DragonEnableAutoLC": [TxType.PERSISTENT],
"DragonAssistedLCMinMPH": [TxType.PERSISTENT],
"DragonAutoLCMinMPH": [TxType.PERSISTENT],
"DragonAutoLCDelay": [TxType.PERSISTENT],
"DragonBTG": [TxType.PERSISTENT],
"DragonBootHotspot": [TxType.PERSISTENT],
"DragonAccelProfile": [TxType.PERSISTENT],
"DragonLastModified": [TxType.CLEAR_ON_MANAGER_START],
"DragonEnableRegistration": [TxType.PERSISTENT],
"DragonDynamicFollow": [TxType.PERSISTENT],
"DragonToyotaSngResponse": [TxType.PERSISTENT],
"DragonEnableGearCheck": [TxType.PERSISTENT],
"DragonEnableTempMonitor": [TxType.PERSISTENT],
"DragonAppAutoUpdate": [TxType.PERSISTENT],
"DragonUpdating": [TxType.CLEAR_ON_MANAGER_START],
"DragonCustomModel": [TxType.PERSISTENT],
"DragonSupportedCars": [TxType.PERSISTENT],
"DragonLocale": [TxType.PERSISTENT],
"DragonUIScreenOffReversing": [TxType.PERSISTENT],
"DragonEnableSRLearner": [TxType.PERSISTENT],
"DragonEnableSteerBoost": [TxType.PERSISTENT],
"DragonSteerBoostMin": [TxType.PERSISTENT],
"DragonSteerBoostMax": [TxType.PERSISTENT],
"DragonSteerBoostMinAt": [TxType.PERSISTENT],
"DragonSteerBoostMaxAt": [TxType.PERSISTENT],
"DragonDashcamHours": [TxType.PERSISTENT],
"DragonUIScreenOffDriving": [TxType.PERSISTENT],
"DragonEnableAutoUpdate": [TxType.PERSISTENT],
"DragonUIBrightness": [TxType.PERSISTENT],
"DragonEnableUploadOnMobile": [TxType.PERSISTENT],
"DragonEnableUploadOnHotspot": [TxType.PERSISTENT],
"DragonMaxSpeedLimit": [TxType.PERSISTENT],
"DragonEnableRating": [TxType.PERSISTENT],
"DragonEnableContALC": [TxType.PERSISTENT],
"DragonBlinkerOffTimer": [TxType.PERSISTENT],
}
# written: manager
# read: loggerd, uploaderd, offroad
"DongleId": TxType.PERSISTENT,
"AccessToken": TxType.PERSISTENT,
"Version": TxType.PERSISTENT,
"TrainingVersion": TxType.PERSISTENT,
"GitCommit": TxType.PERSISTENT,
"GitBranch": TxType.PERSISTENT,
"GitRemote": TxType.PERSISTENT,
# written: baseui
# read: ui, controls
"IsMetric": TxType.PERSISTENT,
"IsFcwEnabled": TxType.PERSISTENT,
"HasAcceptedTerms": TxType.PERSISTENT,
"CompletedTrainingVersion": TxType.PERSISTENT,
"IsUploadVideoOverCellularEnabled": TxType.PERSISTENT,
"IsDriverMonitoringEnabled": TxType.PERSISTENT,
"IsGeofenceEnabled": TxType.PERSISTENT,
"SpeedLimitOffset": TxType.PERSISTENT,
# written: visiond
# read: visiond, controlsd
"CalibrationParams": TxType.PERSISTENT,
"ControlsParams": TxType.PERSISTENT,
# written: controlsd
# read: radard
"CarParams": TxType.CLEAR_ON_CAR_START,
"Passive": TxType.PERSISTENT,
"DoUninstall": TxType.CLEAR_ON_MANAGER_START,
"ShouldDoUpdate": TxType.CLEAR_ON_MANAGER_START,
"IsUpdateAvailable": TxType.PERSISTENT,
"LongitudinalControl": TxType.PERSISTENT,
"LimitSetSpeed": TxType.PERSISTENT,
"RecordFront": TxType.PERSISTENT,
}
def fsync_dir(path):
fd = os.open(path, os.O_RDONLY)
@@ -210,7 +90,7 @@ def fsync_dir(path):
os.close(fd)
class FileLock():
class FileLock(object):
def __init__(self, path, create):
self._path = path
self._create = create
@@ -226,7 +106,7 @@ class FileLock():
self._fd = None
class DBAccessor():
class DBAccessor(object):
def __init__(self, path):
self._path = path
self._vals = None
@@ -396,9 +276,6 @@ def read_db(params_path, key):
return None
def write_db(params_path, key, value):
if isinstance(value, str):
value = value.encode('utf8')
prev_umask = os.umask(0)
lock = FileLock(params_path+"/.lock", True)
lock.acquire()
@@ -417,8 +294,8 @@ def write_db(params_path, key, value):
os.umask(prev_umask)
lock.release()
class Params():
def __init__(self, db=PARAMS):
class Params(object):
def __init__(self, db='/data/params'):
self.db = db
# create the database if it doesn't exist...
@@ -426,11 +303,6 @@ class Params():
with self.transaction(write=True):
pass
def clear_all(self):
shutil.rmtree(self.db, ignore_errors=True)
with self.transaction(write=True):
pass
def transaction(self, write=False):
if write:
return DBWriter(self.db)
@@ -440,20 +312,20 @@ class Params():
def _clear_keys_with_type(self, tx_type):
with self.transaction(write=True) as txn:
for key in keys:
if tx_type in keys[key]:
if keys[key] == tx_type:
txn.delete(key)
def manager_start(self):
self._clear_keys_with_type(TxType.CLEAR_ON_MANAGER_START)
def panda_disconnect(self):
self._clear_keys_with_type(TxType.CLEAR_ON_PANDA_DISCONNECT)
def car_start(self):
self._clear_keys_with_type(TxType.CLEAR_ON_CAR_START)
def delete(self, key):
with self.transaction(write=True) as txn:
txn.delete(key)
def get(self, key, block=False, encoding=None):
def get(self, key, block=False):
if key not in keys:
raise UnknownKeyName(key)
@@ -463,37 +335,14 @@ class Params():
break
# is polling really the best we can do?
time.sleep(0.05)
if ret is not None and encoding is not None:
ret = ret.decode(encoding)
return ret
def put(self, key, dat):
"""
Warning: This function blocks until the param is written to disk!
In very rare cases this can take over a second, and your code will hang.
Use the put_nonblocking helper function in time sensitive code, but
in general try to avoid writing params as much as possible.
"""
if key not in keys:
raise UnknownKeyName(key)
write_db(self.db, key, dat)
def put_nonblocking(key, val):
def f(key, val):
params = Params()
params.put(key, val)
t = threading.Thread(target=f, args=(key, val))
t.start()
return t
if __name__ == "__main__":
params = Params()
if len(sys.argv) > 2:
@@ -503,10 +352,10 @@ if __name__ == "__main__":
pp = params.get(k)
if pp is None:
print("%s is None" % k)
elif all(chr(c) in string.printable for c in pp):
elif all(ord(c) < 128 and ord(c) >= 32 for c in pp):
print("%s = %s" % (k, pp))
else:
print("%s = %s" % (k, binascii.hexlify(pp)))
print("%s = %s" % (k, pp.encode("hex")))
# Test multiprocess:
# seq 0 100000 | xargs -P20 -I{} python common/params.py DongleId {} && sleep 0.05
+3 -3
View File
@@ -1,6 +1,6 @@
import time
class Profiler():
class Profiler(object):
def __init__(self, enabled=False):
self.enabled = enabled
self.cp = {}
@@ -39,8 +39,8 @@ class Profiler():
print("******* Profiling *******")
for n, ms in sorted(self.cp.items(), key=lambda x: -x[1]):
if n in self.cp_ignored:
print("%30s: %9.2f percent: %3.0f IGNORED" % (n, ms*1000.0, ms/self.tot*100))
print("%30s: %7.2f percent: %3.0f IGNORED" % (n, ms*1000.0, ms/self.tot*100))
else:
print("%30s: %9.2f percent: %3.0f" % (n, ms*1000.0, ms/self.tot*100))
print("%30s: %7.2f percent: %3.0f" % (n, ms*1000.0, ms/self.tot*100))
print("Iter clock: %2.6f TOTAL: %2.2f" % (self.tot/self.iter, self.tot))
+48 -14
View File
@@ -2,25 +2,58 @@
import os
import time
import platform
import threading
import subprocess
import multiprocessing
from cffi import FFI
from common.common_pyx import sec_since_boot # pylint: disable=no-name-in-module, import-error
# time step for each process
DT_CTRL = 0.01 # controlsd
DT_MDL = 0.05 # model
DT_DMON = 0.1 # driver monitoring
DT_TRML = 0.5 # thermald and manager
ffi = FFI()
ffi.cdef("long syscall(long number, ...);")
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")
@@ -36,7 +69,7 @@ def set_realtime_priority(level):
return subprocess.call(['chrt', '-f', '-p', str(level), str(tid)])
class Ratekeeper():
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
@@ -66,9 +99,10 @@ class Ratekeeper():
lagged = False
remaining = self._next_frame_time - sec_since_boot()
self._next_frame_time += self._interval
if self._print_delay_threshold is not None and remaining < -self._print_delay_threshold:
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
-66
View File
@@ -1,66 +0,0 @@
import os
import subprocess
from common.basedir import BASEDIR
class Spinner():
def __init__(self):
try:
self.spinner_proc = subprocess.Popen(["./spinner"],
stdin=subprocess.PIPE,
cwd=os.path.join(BASEDIR, "selfdrive", "ui", "spinner"),
close_fds=True)
except OSError:
self.spinner_proc = None
def __enter__(self):
return self
def update(self, spinner_text):
if self.spinner_proc is not None:
self.spinner_proc.stdin.write(spinner_text.encode('utf8') + b"\n")
try:
self.spinner_proc.stdin.flush()
except BrokenPipeError:
pass
def close(self):
if self.spinner_proc is not None:
try:
self.spinner_proc.stdin.close()
except BrokenPipeError:
pass
self.spinner_proc.terminate()
self.spinner_proc = None
def __del__(self):
self.close()
def __exit__(self, type, value, traceback):
self.close()
class FakeSpinner():
def __init__(self):
pass
def __enter__(self):
return self
def update(self, _):
pass
def close(self):
pass
def __exit__(self, type, value, traceback):
pass
if __name__ == "__main__":
import time
with Spinner() as s:
s.update("Spinner text")
time.sleep(5.0)
print("gone")
time.sleep(5.0)
-73
View File
@@ -1,73 +0,0 @@
import numpy as np
class RunningStat():
# tracks realtime mean and standard deviation without storing any data
def __init__(self, priors=None, max_trackable=-1):
self.max_trackable = max_trackable
if priors is not None:
# initialize from history
self.M = priors[0]
self.S = priors[1]
self.n = priors[2]
self.M_last = self.M
self.S_last = self.S
else:
self.reset()
def reset(self):
self.M = 0.
self.S = 0.
self.M_last = 0.
self.S_last = 0.
self.n = 0
def push_data(self, new_data):
# short term memory hack
if self.max_trackable < 0 or self.n < self.max_trackable:
self.n += 1
if self.n == 0:
self.M_last = new_data
self.M = self.M_last
self.S_last = 0.
else:
self.M = self.M_last + (new_data - self.M_last) / self.n
self.S = self.S_last + (new_data - self.M_last) * (new_data - self.M);
self.M_last = self.M
self.S_last = self.S
def mean(self):
return self.M
def variance(self):
if self.n >= 2:
return self.S / (self.n - 1.)
else:
return 0
def std(self):
return np.sqrt(self.variance())
def params_to_save(self):
return [self.M, self.S, self.n]
class RunningStatFilter():
def __init__(self, raw_priors=None, filtered_priors=None, max_trackable=-1):
self.raw_stat = RunningStat(raw_priors, -1)
self.filtered_stat = RunningStat(filtered_priors, max_trackable)
def reset(self):
self.raw_stat.reset()
self.filtered_stat.reset()
def push_and_update(self, new_data):
_std_last = self.raw_stat.std()
self.raw_stat.push_data(new_data)
_delta_std = self.raw_stat.std() - _std_last
if _delta_std<=0:
self.filtered_stat.push_data(new_data)
else:
pass
# self.filtered_stat.push_data(self.filtered_stat.mean())
# class SequentialBayesian():
-83
View File
@@ -1,83 +0,0 @@
#!/usr/bin/env python3
import os
import time
import subprocess
from common.basedir import BASEDIR
class TextWindow():
def __init__(self, s):
try:
self.text_proc = subprocess.Popen(["./text", s],
stdin=subprocess.PIPE,
cwd=os.path.join(BASEDIR, "selfdrive", "ui", "text"),
close_fds=True)
except OSError:
self.text_proc = None
def get_status(self):
if self.text_proc is not None:
self.text_proc.poll()
return self.text_proc.returncode
return None
def __enter__(self):
return self
def close(self):
if self.text_proc is not None:
self.text_proc.terminate()
self.text_proc = None
def wait_for_exit(self):
while True:
if self.get_status() == 1:
return
time.sleep(0.1)
def __del__(self):
self.close()
def __exit__(self, type, value, traceback):
self.close()
class FakeTextWindow():
def __init__(self, s):
pass
def get_status(self):
return 1
def wait_for_exit(self):
return
def __enter__(self):
return self
def update(self, _):
pass
def __exit__(self, type, value, traceback):
pass
if __name__ == "__main__":
text = """Traceback (most recent call last):
File "./controlsd.py", line 608, in <module>
main()
File "./controlsd.py", line 604, in main
controlsd_thread(sm, pm, logcan)
File "./controlsd.py", line 455, in controlsd_thread
1/0
ZeroDivisionError: division by zero"""
print(text)
with TextWindow(text) as s:
for _ in range(100):
if s.get_status() == 1:
print("Got exit button")
break
time.sleep(0.1)
print("gone")
-28
View File
@@ -1,28 +0,0 @@
import signal
class TimeoutException(Exception):
pass
class Timeout:
"""
Timeout context manager.
For example this code will raise a TimeoutException:
with Timeout(seconds=5, error_msg="Sleep was too long"):
time.sleep(10)
"""
def __init__(self, seconds, error_msg=None):
if error_msg is None:
error_msg = 'Timed out after {} seconds'.format(seconds)
self.seconds = seconds
self.error_msg = error_msg
def handle_timeout(self, signume, frame):
raise TimeoutException(self.error_msg)
def __enter__(self):
signal.signal(signal.SIGALRM, self.handle_timeout)
signal.alarm(self.seconds)
def __exit__(self, exc_type, exc_val, exc_tb):
signal.alarm(0)
+29 -37
View File
@@ -1,5 +1,6 @@
import numpy as np
import common.transformations.orientation as orient
import cv2
FULL_FRAME_SIZE = (1164, 874)
W, H = FULL_FRAME_SIZE[0], FULL_FRAME_SIZE[1]
@@ -11,17 +12,6 @@ eon_intrinsics = np.array([
[ 0., FOCAL, H/2.],
[ 0., 0., 1.]])
leon_dcam_intrinsics = np.array([
[650, 0, 816//2],
[ 0, 650, 612//2],
[ 0, 0, 1]])
eon_dcam_intrinsics = np.array([
[860, 0, 1152//2],
[ 0, 860, 864//2],
[ 0, 0, 1]])
# aka 'K_inv' aka view_frame_from_camera_frame
eon_intrinsics_inv = np.linalg.inv(eon_intrinsics)
@@ -43,7 +33,6 @@ def get_calib_from_vp(vp):
roll_calib = 0
return roll_calib, pitch_calib, yaw_calib
# aka 'extrinsic_matrix'
# road : x->forward, y -> left, z->up
def get_view_frame_from_road_frame(roll, pitch, yaw, height):
@@ -61,13 +50,6 @@ def vp_from_ke(m):
"""
return (m[0, 0]/m[2,0], m[1,0]/m[2,0])
def vp_from_rpy(rpy):
e = get_view_frame_from_road_frame(rpy[0], rpy[1], rpy[2], 1.22)
ke = np.dot(eon_intrinsics, e)
return vp_from_ke(ke)
def roll_from_ke(m):
# note: different from calibration.h/RollAnglefromKE: i think that one's just wrong
return np.arctan2(-(m[1, 0] - m[1, 1] * m[2, 0] / m[2, 1]),
@@ -82,7 +64,7 @@ def normalize(img_pts, intrinsics=eon_intrinsics):
input_shape = img_pts.shape
img_pts = np.atleast_2d(img_pts)
img_pts = np.hstack((img_pts, np.ones((img_pts.shape[0],1))))
img_pts_normalized = img_pts.dot(intrinsics_inv.T)
img_pts_normalized = intrinsics_inv.dot(img_pts.T).T
img_pts_normalized[(img_pts < 0).any(axis=1)] = np.nan
return img_pts_normalized[:,:2].reshape(input_shape)
@@ -94,7 +76,7 @@ def denormalize(img_pts, intrinsics=eon_intrinsics):
input_shape = img_pts.shape
img_pts = np.atleast_2d(img_pts)
img_pts = np.hstack((img_pts, np.ones((img_pts.shape[0],1))))
img_pts_denormalized = img_pts.dot(intrinsics.T)
img_pts_denormalized = intrinsics.dot(img_pts.T).T
img_pts_denormalized[img_pts_denormalized[:,0] > W] = np.nan
img_pts_denormalized[img_pts_denormalized[:,0] < 0] = np.nan
img_pts_denormalized[img_pts_denormalized[:,1] > H] = np.nan
@@ -130,19 +112,29 @@ def img_from_device(pt_device):
return pt_img.reshape(input_shape)[:,:2]
def get_camera_frame_from_calib_frame(camera_frame_from_road_frame):
camera_frame_from_ground = camera_frame_from_road_frame[:, (0, 1, 3)]
calib_frame_from_ground = np.dot(eon_intrinsics,
get_view_frame_from_road_frame(0, 0, 0, 1.22))[:, (0, 1, 3)]
ground_from_calib_frame = np.linalg.inv(calib_frame_from_ground)
camera_frame_from_calib_frame = np.dot(camera_frame_from_ground, ground_from_calib_frame)
return camera_frame_from_calib_frame
def pretransform_from_calib(calib):
roll, pitch, yaw, height = calib
view_frame_from_road_frame = get_view_frame_from_road_frame(roll, pitch, yaw, height)
camera_frame_from_road_frame = np.dot(eon_intrinsics, view_frame_from_road_frame)
camera_frame_from_calib_frame = get_camera_frame_from_calib_frame(camera_frame_from_road_frame)
return np.linalg.inv(camera_frame_from_calib_frame)
def rotate_img(img, eulers, crop=None, intrinsics=eon_intrinsics):
size = img.shape[:2]
rot = orient.rot_from_euler(eulers)
quadrangle = np.array([[0, 0],
[size[1]-1, 0],
[0, size[0]-1],
[size[1]-1, size[0]-1]], dtype=np.float32)
quadrangle_norm = np.hstack((normalize(quadrangle, intrinsics=intrinsics), np.ones((4,1))))
warped_quadrangle_full = np.einsum('ij, kj->ki', intrinsics.dot(rot), quadrangle_norm)
warped_quadrangle = np.column_stack((warped_quadrangle_full[:,0]/warped_quadrangle_full[:,2],
warped_quadrangle_full[:,1]/warped_quadrangle_full[:,2])).astype(np.float32)
if crop:
W_border = (size[1] - crop[0])/2
H_border = (size[0] - crop[1])/2
outside_crop = (((warped_quadrangle[:,0] < W_border) |
(warped_quadrangle[:,0] >= size[1] - W_border)) &
((warped_quadrangle[:,1] < H_border) |
(warped_quadrangle[:,1] >= size[0] - H_border)))
if not outside_crop.all():
raise ValueError("warped image not contained inside crop")
else:
H_border, W_border = 0, 0
M = cv2.getPerspectiveTransform(quadrangle, warped_quadrangle)
img_warped = cv2.warpPerspective(img, M, size[::-1])
return img_warped[H_border: size[0] - H_border,
W_border: size[1] - W_border]
+1 -1
View File
@@ -65,7 +65,7 @@ def ecef2geodetic(ecef, radians=False):
geodetic = np.column_stack((lat, lon, h))
return geodetic.reshape(input_shape)
class LocalCoord():
class LocalCoord(object):
"""
Allows conversions to local frames. In this case NED.
That is: North East Down from the start position in
+15 -45
View File
@@ -1,8 +1,9 @@
import numpy as np
from common.transformations.camera import (FULL_FRAME_SIZE, eon_focal_length,
get_view_frame_from_road_frame,
vp_from_ke)
from common.transformations.camera import eon_focal_length, \
vp_from_ke, \
get_view_frame_from_road_frame, \
FULL_FRAME_SIZE
# segnet
@@ -30,40 +31,33 @@ model_intrinsics = np.array(
[ 0. , 0. , 1.]])
# MED model
MEDMODEL_INPUT_SIZE = (512, 256)
MEDMODEL_YUV_SIZE = (MEDMODEL_INPUT_SIZE[0], MEDMODEL_INPUT_SIZE[1] * 3 // 2)
MEDMODEL_CY = 47.6
medmodel_zoom = 1.
medmodel_intrinsics = np.array(
[[ eon_focal_length / medmodel_zoom, 0. , 0.5 * MEDMODEL_INPUT_SIZE[0]],
[ 0. , eon_focal_length / medmodel_zoom, MEDMODEL_CY],
[ 0. , 0. , 1.]])
# BIG model
BIGMODEL_INPUT_SIZE = (1024, 512)
BIGMODEL_INPUT_SIZE = (864, 288)
BIGMODEL_YUV_SIZE = (BIGMODEL_INPUT_SIZE[0], BIGMODEL_INPUT_SIZE[1] * 3 // 2)
bigmodel_zoom = 1.
bigmodel_intrinsics = np.array(
[[ eon_focal_length / bigmodel_zoom, 0. , 0.5 * BIGMODEL_INPUT_SIZE[0]],
[ 0. , eon_focal_length / bigmodel_zoom, 256+MEDMODEL_CY],
[ 0. , eon_focal_length / bigmodel_zoom, 0.2 * BIGMODEL_INPUT_SIZE[1]],
[ 0. , 0. , 1.]])
bigmodel_border = np.array([
[0,0,1],
[BIGMODEL_INPUT_SIZE[0], 0, 1],
[BIGMODEL_INPUT_SIZE[0], BIGMODEL_INPUT_SIZE[1], 1],
[0, BIGMODEL_INPUT_SIZE[1], 1],
])
model_frame_from_road_frame = np.dot(model_intrinsics,
get_view_frame_from_road_frame(0, 0, 0, model_height))
bigmodel_frame_from_road_frame = np.dot(bigmodel_intrinsics,
get_view_frame_from_road_frame(0, 0, 0, model_height))
medmodel_frame_from_road_frame = np.dot(medmodel_intrinsics,
get_view_frame_from_road_frame(0, 0, 0, model_height))
model_frame_from_bigmodel_frame = np.dot(model_intrinsics, np.linalg.inv(bigmodel_intrinsics))
medmodel_frame_from_bigmodel_frame = np.dot(medmodel_intrinsics, np.linalg.inv(bigmodel_intrinsics))
# 'camera from model camera'
def get_model_height_transform(camera_frame_from_road_frame, height):
@@ -108,16 +102,6 @@ def get_camera_frame_from_model_frame(camera_frame_from_road_frame, height=model
return np.dot(camera_from_model_camera, model_camera_from_model_frame)
def get_camera_frame_from_medmodel_frame(camera_frame_from_road_frame):
camera_frame_from_ground = camera_frame_from_road_frame[:, (0, 1, 3)]
medmodel_frame_from_ground = medmodel_frame_from_road_frame[:, (0, 1, 3)]
ground_from_medmodel_frame = np.linalg.inv(medmodel_frame_from_ground)
camera_frame_from_medmodel_frame = np.dot(camera_frame_from_ground, ground_from_medmodel_frame)
return camera_frame_from_medmodel_frame
def get_camera_frame_from_bigmodel_frame(camera_frame_from_road_frame):
camera_frame_from_ground = camera_frame_from_road_frame[:, (0, 1, 3)]
bigmodel_frame_from_ground = bigmodel_frame_from_road_frame[:, (0, 1, 3)]
@@ -126,17 +110,3 @@ def get_camera_frame_from_bigmodel_frame(camera_frame_from_road_frame):
camera_frame_from_bigmodel_frame = np.dot(camera_frame_from_ground, ground_from_bigmodel_frame)
return camera_frame_from_bigmodel_frame
def get_model_frame(snu_full, camera_frame_from_model_frame, size):
idxs = camera_frame_from_model_frame.dot(np.column_stack([np.tile(np.arange(size[0]), size[1]),
np.tile(np.arange(size[1]), (size[0],1)).T.flatten(),
np.ones(size[0] * size[1])]).T).T.astype(int)
calib_flat = snu_full[idxs[:,1], idxs[:,0]]
if len(snu_full.shape) == 3:
calib = calib_flat.reshape((size[1], size[0], 3))
elif len(snu_full.shape) == 2:
calib = calib_flat.reshape((size[1], size[0]))
else:
raise ValueError("shape of input img is weird")
return calib
+2 -2
View File
@@ -29,7 +29,7 @@ def euler2quat(eulers):
np.sin(gamma / 2) * np.sin(theta / 2) * np.cos(psi / 2)
quats = array([q0, q1, q2, q3]).T
for i in range(len(quats)):
for i in xrange(len(quats)):
if quats[i,0] < 0:
quats[i] = -quats[i]
return quats.reshape(output_shape)
@@ -99,7 +99,7 @@ def rot2quat(rots):
K3[:, 3, 2] = K3[:, 2, 3]
K3[:, 3, 3] = (rots[:, 0, 0] + rots[:, 1, 1] + rots[:, 2, 2]) / 3.0
q = np.empty((len(rots), 4))
for i in range(len(rots)):
for i in xrange(len(rots)):
_, eigvecs = linalg.eigh(K3[i].T)
eigvecs = eigvecs[:,3:]
q[i, 0] = eigvecs[-1]
-45
View File
@@ -1,45 +0,0 @@
import os
from cffi import FFI
# Workaround for the EON/termux build of Python having os.*xattr removed.
ffi = FFI()
ffi.cdef("""
int setxattr(const char *path, const char *name, const void *value, size_t size, int flags);
ssize_t getxattr(const char *path, const char *name, void *value, size_t size);
ssize_t listxattr(const char *path, char *list, size_t size);
int removexattr(const char *path, const char *name);
""")
libc = ffi.dlopen(None)
def setxattr(path, name, value, flags=0):
path = path.encode()
name = name.encode()
if libc.setxattr(path, name, value, len(value), flags) == -1:
raise OSError(ffi.errno, f"{os.strerror(ffi.errno)}: setxattr({path}, {name}, {value}, {flags})")
def getxattr(path, name, size=128):
path = path.encode()
name = name.encode()
value = ffi.new(f"char[{size}]")
l = libc.getxattr(path, name, value, size)
if l == -1:
# errno 61 means attribute hasn't been set
if ffi.errno == 61:
return None
raise OSError(ffi.errno, f"{os.strerror(ffi.errno)}: getxattr({path}, {name}, {size})")
return ffi.buffer(value)[:l]
def listxattr(path, size=128):
path = path.encode()
attrs = ffi.new(f"char[{size}]")
l = libc.listxattr(path, attrs, size)
if l == -1:
raise OSError(ffi.errno, f"{os.strerror(ffi.errno)}: listxattr({path}, {size})")
# attrs is b'\0' delimited values (so chop off trailing empty item)
return [a.decode() for a in ffi.buffer(attrs)[:l].split(b"\0")[0:-1]]
def removexattr(path, name):
path = path.encode()
name = name.encode()
if libc.removexattr(path, name) == -1:
raise OSError(ffi.errno, f"{os.strerror(ffi.errno)}: removexattr({path}, {name})")
-21
View File
@@ -1,21 +0,0 @@
The MIT License
Copyright (c) 2019-, Rick Lan, dragonpilot community, and a number of other of contributors.
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.
-92
View File
@@ -1,92 +0,0 @@
This Font Software is licensed under the SIL Open Font License,
Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font
creation efforts of academic and linguistic communities, and to
provide a free and open framework in which fonts may be shared and
improved in partnership with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply to
any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software
components as distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to,
deleting, or substituting -- in part or in whole -- any of the
components of the Original Version, by changing formats or by porting
the Font Software to a new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed,
modify, redistribute, and sell modified and unmodified copies of the
Font Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components, in
Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the
corresponding Copyright Holder. This restriction only applies to the
primary font name as presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created using
the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.
Binary file not shown.
Binary file not shown.
Binary file not shown.

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