Compare commits

..

158 Commits

Author SHA1 Message Date
Vehicle Researcher 9a9ff839a9 openpilot v0.4.4 release 2018-04-14 06:10:58 +00:00
Vehicle Researcher 4f7336f0e4 Merge opendbc subtree 2018-04-14 06:06:43 +00:00
Vehicle Researcher f66eb5a0a3 Squashed 'opendbc/' changes from a73f4e8..3d8a815
3d8a815 Toyota Prius: added AUTOPARK_STATUS msg
0894cbc Toyota: added comma specific message that copies 0x266 to be able to control steer angle even if park assist ecu is plugged in
b2af0fd Bosch: Adding minor changes to be compatible with 0.4.3.2+ (#89)

git-subtree-dir: opendbc
git-subtree-split: 3d8a815e1bbccd7cbfe7b5d0b97e8e8b9a9ce60e
2018-04-14 06:06:43 +00:00
Vehicle Researcher 94a27e351f Merge panda subtree 2018-04-14 06:06:42 +00:00
Vehicle Researcher e6e6ad2e1f Squashed 'panda/' changes from 3125232..2253dd3
2253dd3 fix volt ign detect
3b299d7 add ignition and refactor
af9af6d Merge pull request #110 from Jamezz/volt
13e850e more correct
f295063 add new define to tests
fec9758 gate that with debug
5516ebf one more ifdef
cac7b31 only panda has float
938d474 fpu enable
ffbf0c7 cleaner
de30f27 Revert "need f to not be double"
4142acf need f to not be double
3eb15c8 refactor to share code
a4c8b64 change to O2 to fix make recover
711fd11 Enable compiler optimizations, fix things it breaks
2e6f774 block IPAS in main toyota safety mode
e7a2b3a add ipas tests
894572c fix tests
367c9ad add safety toyota ipas
95919b9 Bounty: panda high quality CAN autobaud (#96)
6557cd2 Toyota Safety: allow controls only on rising edge of cruise_engaged
02c1ddf Revert "added steer override check when IPAS is in control (#106)"
9f925ba Fix the merge mess
23d3833 Merge from comma upstream
a0cc51a Undo safety mode override
ea1c1dc make wlan interface name generic
6dbd8c9 Implement WebUSB and upgrade WinUSB to 2.0 (#107)
4fc83a5 Add safety hook for ignition and have GM use gear selector to determine ignition
52b2ac0 switch from travis to circleci
48e2374 build panda esp image
065572a circleci build stm image
7a1f319 add panda python package test and fix safety test
021dde7 move saftey test helper files into safety folder
ce0545f add ci files
6a3307c no LIN over ELM
7d21acb added steer override check when IPAS is in control (#106)
1c88caf Safety code testing (#104)
f4efd1f Merge pull request #101 from adhintz/master
c02618b Merge pull request #102 from quillford/master
1ba5f8a added link to wiki for user scripts
de2b19e add support for multiple buses to can_unique and can_bittransition output data in sorted order.

git-subtree-dir: panda
git-subtree-split: 2253dd3c48e21abb82fe161d6f58237490111206
2018-04-14 06:06:42 +00:00
Ted Slesinski 28b8043c5b 2017 Honda Ridgeline (#198)
* Adds Honda Ridgeline

Replaced trim level placeholder

Adding 0x301 ridgeline message

(I restructured this slightly since we don't need to repeat `commands.append(make_can_msg(0x300, msg_0x300, idx, 1))` so many times

Updated dbc name

Use pedal_gas to detect gas pressed

Remove unnecessary signal check

Fix array notation

* Tire stiffness factor bumped to 1.5x

* Adds safety tests at line 133

* Revert "Adds safety tests at line 133"

This reverts commit 349edf5b1a879cac704db3786d0626211497bcb7.

* fix failing build due to syntax

* update variables for failing build

* Update interface.py

* Update Tire Slip Factor
2018-04-12 19:12:45 -07:00
Vehicle Researcher 78df63a6af openpilot v0.4.3.2 release 2018-03-31 07:54:47 +00:00
Vehicle Researcher a69dfe7b20 Squashed 'opendbc/' changes from 91e882d..a73f4e8
a73f4e8 Toyota: fixed LKA_STATE to be compatible with Corolla and properly generated CH-R dbc

git-subtree-dir: opendbc
git-subtree-split: a73f4e8b109f5ffbd7f93a19661dfefb81c26812
2018-03-31 07:29:19 +00:00
Vehicle Researcher d0c9cd28d1 Merge opendbc subtree 2018-03-31 07:29:19 +00:00
vanillagorillaa 9e1cabde36 update year on civic 2018-03-22 23:34:47 +01:00
Willem Melching c7cd8b4459 fix bug in canpacker for Toyotas with DSU connected (#221) 2018-03-22 15:13:23 -07:00
Vehicle Researcher 3d628a6fe2 openpilot v0.4.3.1 release 2018-03-19 23:40:24 -07:00
Vehicle Researcher 51fad4a6c6 openpilot v0.4.3 release 2018-03-18 10:36:29 -07:00
Vehicle Researcher 1a8883fb63 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
2018-03-18 10:32:25 -07:00
Vehicle Researcher a70a821d28 Merge opendbc subtree 2018-03-18 10:32:25 -07:00
Vehicle Researcher a8d110ad74 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
2018-03-18 10:32:24 -07:00
Vehicle Researcher 013351a2ee Merge panda subtree 2018-03-18 10:32:24 -07:00
George Hotz ad3f0a348a Merge pull request #192 from gregjhogan/wifi-only-upload-fix
fix restricting video upload to wifi
2018-03-17 12:01:42 -07:00
Vehicle Researcher 9a411ebf32 openpilot v0.4.3 release 2018-03-17 00:01:50 -07:00
Vehicle Researcher 4188b54c28 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
2018-03-16 23:57:47 -07:00
Vehicle Researcher 19010d3766 Merge opendbc subtree 2018-03-16 23:57:47 -07:00
Vehicle Researcher 02968cda63 Merge panda subtree 2018-03-16 23:57:46 -07:00
Vehicle Researcher 098e304118 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
2018-03-16 23:57:45 -07:00
Mark Krieger 650c45dcc5 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.
2018-03-16 21:28:50 -07:00
Vasily Tarasov 93f55f3ccf 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
2018-03-15 13:28:15 -07:00
arne182 569db3c1d2 Update fingerprints.py (#210)
Consolidated my fingerprint and removed duplicates and ordered the fingerprint for the RAV4H. Double Checked.
2018-03-09 13:34:39 -08:00
George Hotz 26d97d3374 Merge pull request #203 from energee/safety-honda-bosch
Safety Reference for Honda Bosch
2018-03-08 08:33:31 -08:00
Ted Slesinski 3acfa1b39b Safety Reference for Honda Bosch 2018-02-28 10:24:05 -05:00
George Hotz bbc67f8506 Merge pull request #202 from vntarasov/volt-gm-id
Dibs on SAFETY_GM numerical value
2018-02-27 22:58:02 -08:00
Vasily Tarasov 8343b56870 Dibs on SAFETY_GM numerical value
To match Panda repo.
2018-02-26 10:22:19 -08:00
Greg Hogan 008d900f81 fix restricting video upload to wifi 2018-02-10 09:31:56 -06:00
vanillagorillaa 32e5d6cd15 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
2018-02-09 12:50:37 -08:00
Vehicle Researcher 28c0797d30 openpilot v0.4.2 release 2018-02-06 12:43:45 -08:00
Vehicle Researcher 7ae657880d Squashed 'opendbc/' changes from 3ca654f..81d9871
81d9871 Lexus: added first draft of RX dbc file
cb352da fix toyota steering lka message length
d294f64 fix gas pedal message length rav4h
2d035de acura rdx remove double defined message
500a734 fix acura rdx dbc, import was missing

git-subtree-dir: opendbc
git-subtree-split: 81d9871dbe00ccfc5fe4418ea3577726fffa1def
2018-02-06 12:39:39 -08:00
Vehicle Researcher a701aa7292 Merge opendbc subtree 2018-02-06 12:39:39 -08:00
Vehicle Researcher db67cffb4d Squashed 'panda/' changes from b42db6d..98f29a4
98f29a4 v1.0.7 has working grey panda

git-subtree-dir: panda
git-subtree-split: 98f29a4a97af58aa4707bdaba948ac366ab2e6a0
2018-02-06 12:39:38 -08:00
Vehicle Researcher 433f934783 Merge panda subtree 2018-02-06 12:39:38 -08:00
vanillagorillaa 0dc6778548 Acura RDX 2018 AcuraWatch Plus Port (#162)
* Adding Acura RDX alpha support
2018-02-05 18:38:40 -08:00
ErichMoraga c86b52698b Update fingerprints.py
Taiwanese Prius Prime fingerprint was identical to the regular prime (107 msgs.), but should really have 110.  I have the correct one in there now.
2018-02-05 14:16:58 -08:00
George Hotz e5e5aa7ded openpilot v0.4.1 hotfix 2018-02-02 19:30:44 -08:00
George Hotz 4474b9b371 openpilot v0.4.1 tweaks 2018-01-30 21:34:01 -08:00
Vehicle Researcher 26e966852c openpilot v0.4.1 release 2018-01-30 12:58:14 -08:00
Vehicle Researcher 852166f5cc Squashed 'opendbc/' changes from 8753665..3ca654f
3ca654f move acura rdx to generator folder
1c7c490 move pilot touring to generated
89856dd fix bugs in some counter/checksum definitions
451a2b4 honda wheelspeed in kph to match toyota
290dd14 rename generic honda and toyota dbcs to include year
ccb8a14 readded gas interceptor to hondas so it does not break regression tests
66d256e readme explanation of preprocessor
6c8d9f7 regenerate new steer torque eps factor
beba6d5 move generated files to root folder
2b5b0aa Toyota: different factor for STEER_TORQUE_EPS
e41b174 fix typo
682f557 cleanup
1faf67c fix crv steering_control message
cce6c79 add odometer message to civic and odyssey
74cc834 fix PCM_SPEED factor
3f2baa5 fix honda dometer scaling
f6fd6b9 fix comments and values
f0ba5e2 whitespace consistency
8c77a5d dbc file preprocessor
10f8c6e consistent can message names for supported Hondas
af07d6a Topyota Corolla: added dbc file, seems the same as Rav4
a632fde Cleanup duplicate message names

git-subtree-dir: opendbc
git-subtree-split: 3ca654f88545d05bf23cb8ff945f06a28c32902e
2018-01-30 12:54:13 -08:00
Vehicle Researcher 75ac92b90f Merge opendbc subtree 2018-01-30 12:54:13 -08:00
Vehicle Researcher 96f8e5158e Squashed 'panda/' changes from 2573d86..b42db6d
b42db6d Merge pull request #82 from commaai/uart_dma
fd68f86 smallr
be99ffc ok that doesn't hurt i think
a9f6bf0 this
8b7e849 working now
7fa4808 froze up, maybe thats the fix
1465aa4 ok, it's fixed
915cd84 ugh, ok, need that
fd05376 comment out debug
37c5263 big fifo
497f069 dma is all critical, no interrupts
7c34afe minor change
743d244 high baud rate works
5d2a4ba v1.0.6
fbf1390 Toyota Safety: fix in input param
6c01d09 Toyota: less torque error allowance to meet Corolla acceptable behavior
07c01b2 Toyota safety: using input param
4410a59 add safety param support
fc81fc1 uart dma in progress
65fb2b2 grey panda query, 1.0.5
f415c9a grey panda detection
b68957e add pandadebug support
b5e4962 leave msgs around in isotp
0acce2d add recvaddr support
3fc38f4 set bootmode with power
d4c052a make that work
21f8195 fix panda serial write
af74aa9 from python import

git-subtree-dir: panda
git-subtree-split: b42db6dc082fb13ef5ac63ed197a63e179651ef6
2018-01-30 12:54:12 -08:00
Vehicle Researcher b68f3f7781 Merge panda subtree 2018-01-30 12:54:12 -08:00
George Hotz 36bef17224 Merge pull request #155 from slesinski/odyssey-port
Honda Odyssey 2018 EX-L with Honda Sensing
2018-01-18 21:49:14 -08:00
Ted Slesinski 715771bcff Unnecessary characters in comma's dongle id 2018-01-19 00:47:47 -05:00
Ted Slesinski 8e264baaa2 SteerRatio should be 14.35 2018-01-19 00:37:32 -05:00
Ted Slesinski 8ff147de6d Added the extra carstate reads 2018-01-19 00:34:02 -05:00
Ted Slesinski 71057c586f Tuning specific to odyssey 2018-01-19 00:34:02 -05:00
Ted Slesinski fac22f4038 Gear shifter values like acura 2018-01-19 00:32:51 -05:00
Ted Slesinski 40094779d7 Car_gas 130 missing canbus, using 17c 2018-01-19 00:32:51 -05:00
Ted Slesinski 2552aa45c3 BRAKE_HOLD signal not ready yet 2018-01-19 00:32:51 -05:00
Ted Slesinski c2972a80f9 Park Brake not yet in DBC 2018-01-19 00:32:51 -05:00
Ted Slesinski 791a440709 Wrong value for MAIN_ON 2018-01-19 00:32:51 -05:00
Ted Slesinski 13145dd9a7 Packet size off on a fingerprint id 2018-01-19 00:32:51 -05:00
Ted Slesinski e9c477dcf2 Add hondacan changes 2018-01-19 00:30:33 -05:00
Ted Slesinski 8eebd19884 Add carcontroller changes 2018-01-19 00:30:33 -05:00
Ted Slesinski a54b35a4d6 Add odyssey car params to interface 2018-01-19 00:30:33 -05:00
Ted Slesinski 8a6f7a5e78 Add carstate changes 2018-01-19 00:30:33 -05:00
Ted Slesinski 6752959d4a Add odyssey fingerprint 2018-01-19 00:30:33 -05:00
Vehicle Researcher da52d065a4 openpilot v0.4.0.2 release 2018-01-18 15:46:12 -08:00
Vehicle Researcher 255e45ca58 Squashed 'opendbc/' changes from 48968cc..8753665
8753665 Fix Chevy Volt actuator signal parsing (#66)
89963c9 Toyota: added auto high beam
b07a84d Add Honda Clarity Hybrid (#65)
ca352b3 add hyundai 2015 (#63)

git-subtree-dir: opendbc
git-subtree-split: 87536651c21daddba932f5d8668b52a0ece9082f
2018-01-18 15:42:13 -08:00
Vehicle Researcher b731b7cf12 Merge opendbc subtree 2018-01-18 15:42:13 -08:00
Vehicle Researcher 5f014635e1 Squashed 'panda/' changes from c371fe6..2573d86
2573d86 docs say max is 4, respect the docs
864cd8f failing on some devices
54bcc67 Merge pull request #75 from gregjhogan/j2534-vs-2017-upgrade
1664270 Merge pull request #74 from gregjhogan/j2534-disconnect-fix
a7e3a8f bump panda version for serial bug
aa0cfad fix UART hang
09ab8f6 add sendaddr support to isotp
40a1883 fix up baud rate
65997ff add PandaSerial and location panda (aka pigeon) test
57d633c upgraded to VS 2017
35cc32a fixed pointer exception on disconnect

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

https://bitbucket.org/DataspeedInc/dbw_mkz_ros/downloads
2016-11-30 14:52:47 -05:00
Vehicle Researcher e94a30bec0 openpilot release 2016-11-29 18:34:21 -08:00
4162 changed files with 131298 additions and 1106227 deletions
-3
View File
@@ -1,3 +0,0 @@
((c++-mode (flycheck-gcc-language-standard . "c++11")
(flycheck-clang-language-standard . "c++11")
))
-24
View File
@@ -1,24 +0,0 @@
.git
.DS_Store
notebooks
phone
massivemap
neos
installer
chffr/app2
chffr/backend/env
selfdrive/nav
selfdrive/baseui
chffr/lib/vidindex/vidindex
chffr/lib/index_log/index_log
selfdrive/test/simulator2
**/cache_data
xx/chffr/lib/index_log/index_log
xx/chffr/lib/vidindex/vidindex
xx/plus
xx/community
xx/projects
!xx/projects/eon_testing_master
!xx/projects/map3d
xx/ops
xx/junk
-11
View File
@@ -1,11 +0,0 @@
root = true
[*]
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
[{*.py, *.pyx, *pxd}]
charset = utf-8
indent_style = space
indent_size = 2
-27
View File
@@ -1,27 +0,0 @@
*.keras filter=lfs diff=lfs merge=lfs -text
*.dlc filter=lfs diff=lfs merge=lfs -text
*.pb filter=lfs diff=lfs merge=lfs -text
*.bin filter=lfs diff=lfs merge=lfs -text
*.apk filter=lfs diff=lfs merge=lfs -text
*.ipynb filter=nbstripout -diff
external/ffmpeg/bin/ffmpeg_cuda filter=lfs diff=lfs merge=lfs -text
models/segnet.keras filter=lfs diff=lfs merge=lfs -text
external/zmq/lib/libzmq.a filter=lfs diff=lfs merge=lfs -text
external/zmq/lib/libczmq.a filter=lfs diff=lfs merge=lfs -text
phonelibs/acado/x64/lib/libacado_toolkit.a filter=lfs diff=lfs merge=lfs -text
phonelibs/acado/x64/lib/libacado_toolkit_s.so.1.2.2beta filter=lfs diff=lfs merge=lfs -text
phonelibs/acado/x64/lib/libacado_casadi.a filter=lfs diff=lfs merge=lfs -text
phonelibs/acado/x64/lib/libacado_csparse.a filter=lfs diff=lfs merge=lfs -text
phonelibs/acado/x64/lib/libacado_qpoases.a filter=lfs diff=lfs merge=lfs -text
phonelibs/acado/aarch64/lib/libacado_toolkit.a filter=lfs diff=lfs merge=lfs -text
phonelibs/acado/aarch64/lib/libacado_toolkit_s.so.1.2.2beta filter=lfs diff=lfs merge=lfs -text
phonelibs/acado/aarch64/lib/libacado_casadi.a filter=lfs diff=lfs merge=lfs -text
phonelibs/acado/aarch64/lib/libacado_csparse.a filter=lfs diff=lfs merge=lfs -text
phonelibs/acado/aarch64/lib/libacado_qpoases.a filter=lfs diff=lfs merge=lfs -text
phonelibs/fastcv/aarch64/libfastcvopt.so filter=lfs diff=lfs merge=lfs -text
phonelibs/fastcv/aarch64/libfastcvadsp_stub.so filter=lfs diff=lfs merge=lfs -text
external/mac/MP4Box filter=lfs diff=lfs merge=lfs -text
models/segnet2.keras filter=lfs diff=lfs merge=lfs -text
external/opencl/*.deb filter=lfs diff=lfs merge=lfs -text
phonelibs/zmq/aarch64-linux/lib/libzmq.a filter=lfs diff=lfs merge=lfs -text
external/azcopy/azcopy filter=lfs diff=lfs merge=lfs -text
-25
View File
@@ -1,25 +0,0 @@
---
name: Bug report
about: Create a report to help us improve openpilot
title: ''
labels: ''
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.
-125
View File
@@ -1,125 +0,0 @@
name: Openpilot Tests
on: [push, pull_request]
env:
RUN: docker run --shm-size 1G --rm tmppilot /bin/sh -c
LOAD: docker load -i tmppilot.tar.gz/tmppilot.tar.gz
UNIT_TEST: cd /tmp/openpilot && python -m unittest discover
jobs:
build:
name: build
runs-on: ubuntu-16.04
steps:
- uses: actions/checkout@v2
- name: Checkout submodules
run: |
git submodule update --init
- run: |
docker pull $(grep -ioP '(?<=^from)\s+\S+' Dockerfile.openpilot) || true
docker pull docker.io/commaai/openpilot:latest || true
docker build --cache-from docker.io/commaai/openpilot:latest -t tmppilot -f Dockerfile.openpilot .
docker save tmppilot:latest | gzip > tmppilot.tar.gz
- uses: actions/upload-artifact@v1
with:
name: tmppilot.tar.gz
path: tmppilot.tar.gz
linter:
name: linter
runs-on: ubuntu-16.04
needs: build
steps:
- uses: actions/download-artifact@v1
with:
name: tmppilot.tar.gz
- name: Load image
run: $LOAD
- name: flake8
run: $RUN "cd /tmp/openpilot/ && ./flake8_openpilot.sh"
- name: pylint
run: $RUN "cd /tmp/openpilot/ && ./pylint_openpilot.sh"
unit_tests:
name: unit tests
runs-on: ubuntu-16.04
needs: build
steps:
- uses: actions/download-artifact@v1
with:
name: tmppilot.tar.gz
- name: Load image
run: $LOAD
- name: Run unit tests
run: |
$RUN cd /tmp/openpilot/selfdrive/test/test_fingerprints.py
$RUN "$UNIT_TEST common"
$RUN "$UNIT_TEST opendbc/can"
$RUN "$UNIT_TEST selfdrive/boardd"
$RUN "$UNIT_TEST selfdrive/controls"
$RUN "$UNIT_TEST selfdrive/loggerd"
$RUN "$UNIT_TEST selfdrive/car"
$RUN "$UNIT_TEST selfdrive/locationd"
$RUN "$UNIT_TEST selfdrive/athena"
process_replay:
name: process replay
runs-on: ubuntu-16.04
needs: build
timeout-minutes: 30
steps:
- uses: actions/download-artifact@v1
with:
name: tmppilot.tar.gz
- name: Load image
run: $LOAD
- name: Run replay
run: |
CONTAINER_NAME="tmppilot_${GITHUB_SHA}"
docker run --shm-size 1G --name ${CONTAINER_NAME} tmppilot /bin/sh -c "cd /tmp/openpilot/selfdrive/test/process_replay && CI=1 ./test_processes.py"
docker cp $CONTAINER_NAME:/tmp/openpilot/selfdrive/test/process_replay/diff.txt diff.txt
docker rm $CONTAINER_NAME
- uses: actions/upload-artifact@v1
if: always()
with:
name: process_replay_diff.txt
path: diff.txt
test_longitudinal:
name: longitudinal
runs-on: ubuntu-16.04
needs: build
timeout-minutes: 30
steps:
- uses: actions/download-artifact@v1
with:
name: tmppilot.tar.gz
- name: Load image
run: $LOAD
- name: Test longitudinal
run: |
CONTAINER_NAME="tmppilot_${GITHUB_SHA}"
docker run --shm-size 1G --name ${CONTAINER_NAME} tmppilot /bin/sh -c "cd /tmp/openpilot/selfdrive/test/longitudinal_maneuvers && OPTEST=1 ./test_longitudinal.py"
mkdir out
docker cp $CONTAINER_NAME:/tmp/openpilot/selfdrive/test/longitudinal_maneuvers/out/longitudinal/ out/
docker rm $CONTAINER_NAME
- uses: actions/upload-artifact@v1
if: always()
with:
name: longitudinal
path: out
test_car_models:
name: test car models
runs-on: ubuntu-16.04
needs: build
timeout-minutes: 30
steps:
- uses: actions/download-artifact@v1
with:
name: tmppilot.tar.gz
- name: Load image
run: $LOAD
- name: Test car models
run: $RUN "mkdir -p /data/params && cd /tmp/openpilot/selfdrive/test/ && ./test_car_models.py"
+1 -30
View File
@@ -1,16 +1,9 @@
venv/
.DS_Store
.tags
.ipynb_checkpoints
.idea
.overlay_init
.overlay_consistent
.sconsign.dblite
.vscode
model2.png
a.out
*.dylib
*.DSYM
*.d
*.pyc
@@ -18,9 +11,7 @@ a.out
.*.swp
.*.swo
.*.un~
*.tmp
*.o
*.os
*.so
*.a
*.clb
@@ -30,30 +21,10 @@ 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/ui/ui
/src/
one
openpilot
notebooks
xx
panda_jungle
.coverage*
htmlcov
pandaextra
-16
View File
@@ -1,16 +0,0 @@
[submodule "panda"]
path = panda
url = ../../commaai/panda.git
[submodule "opendbc"]
path = opendbc
url = ../../commaai/opendbc.git
[submodule "laika_repo"]
path = laika_repo
url = ../../commaai/laika.git
[submodule "apks"]
path = apks
url = ../../commaai/openpilot-apks.git
[submodule "cereal"]
path = cereal
url = ../../commaai/cereal.git
-585
View File
@@ -1,585 +0,0 @@
[MASTER]
# A comma-separated list of package or module names from where C extensions may
# be loaded. Extensions are loading into the active Python interpreter and may
# run arbitrary code
extension-pkg-whitelist=scipy
# Add files or directories to the blacklist. They should be base names, not
# paths.
ignore=CVS
# Add files or directories matching the regex patterns to the blacklist. The
# regex matches against base names, not paths.
ignore-patterns=
# Python code to execute, usually for sys.path manipulation such as
# pygtk.require().
#init-hook=
# Use multiple processes to speed up Pylint.
jobs=4
# List of plugins (as comma separated values of python modules names) to load,
# usually to register additional checkers.
load-plugins=
# Pickle collected data for later comparisons.
persistent=yes
# Specify a configuration file.
#rcfile=
# When enabled, pylint would attempt to guess common misconfiguration and emit
# user-friendly hints instead of false-positive error messages
suggestion-mode=yes
# Allow loading of arbitrary C extensions. Extensions are imported into the
# active Python interpreter and may run arbitrary code.
unsafe-load-any-extension=no
[MESSAGES CONTROL]
# Only show warnings with the listed confidence levels. Leave empty to show
# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED
confidence=
# Disable the message, report, category or checker with the given id(s). You
# can either give multiple identifiers separated by comma (,) or put this
# option multiple times (only on the command line, not in the configuration
# file where it should appear only once).You can also use "--disable=all" to
# disable everything first and then reenable specific checks. For example, if
# you want to run only the similarities checker, you can use "--disable=all
# --enable=similarities". If you want to run only the classes checker, but have
# no Warning level messages displayed, use"--disable=all --enable=classes
# --disable=W"
disable=print-statement,
parameter-unpacking,
unpacking-in-except,
old-raise-syntax,
backtick,
long-suffix,
old-ne-operator,
old-octal-literal,
import-star-module-level,
non-ascii-bytes-literal,
raw-checker-failed,
bad-inline-option,
locally-disabled,
locally-enabled,
file-ignored,
suppressed-message,
useless-suppression,
deprecated-pragma,
apply-builtin,
basestring-builtin,
buffer-builtin,
cmp-builtin,
coerce-builtin,
execfile-builtin,
file-builtin,
long-builtin,
raw_input-builtin,
reduce-builtin,
standarderror-builtin,
unicode-builtin,
xrange-builtin,
coerce-method,
delslice-method,
getslice-method,
setslice-method,
no-absolute-import,
old-division,
dict-iter-method,
dict-view-method,
next-method-called,
metaclass-assignment,
indexing-exception,
raising-string,
reload-builtin,
oct-method,
hex-method,
nonzero-method,
cmp-method,
input-builtin,
round-builtin,
intern-builtin,
unichr-builtin,
map-builtin-not-iterating,
zip-builtin-not-iterating,
range-builtin-not-iterating,
filter-builtin-not-iterating,
using-cmp-argument,
eq-without-hash,
div-method,
idiv-method,
rdiv-method,
exception-message-attribute,
invalid-str-codec,
sys-max-int,
bad-python3-import,
deprecated-string-function,
deprecated-str-translate-call,
deprecated-itertools-function,
deprecated-types-field,
next-method-defined,
dict-items-not-iterating,
dict-keys-not-iterating,
dict-values-not-iterating,
bad-indentation,
line-too-long,
missing-docstring,
multiple-statements,
bad-continuation,
invalid-name,
too-many-arguments,
too-many-locals,
superfluous-parens,
bad-whitespace,
too-many-instance-attributes,
wrong-import-position,
ungrouped-imports,
wrong-import-order,
protected-access,
trailing-whitespace,
too-many-branches,
too-few-public-methods,
too-many-statements,
trailing-newlines,
attribute-defined-outside-init,
too-many-return-statements,
too-many-public-methods,
unused-argument,
old-style-class,
no-init,
len-as-condition,
unneeded-not,
no-self-use,
multiple-imports,
no-else-return,
logging-not-lazy,
fixme,
redefined-outer-name,
unused-variable,
unsubscriptable-object,
expression-not-assigned,
too-many-boolean-expressions,
consider-using-ternary,
invalid-unary-operand-type,
relative-import,
deprecated-lambda
# Enable the message, report, category or checker with the given id(s). You can
# either give multiple identifier separated by comma (,) or put this option
# multiple time (only on the command line, not in the configuration file where
# it should appear only once). See also the "--disable" option for examples.
enable=c-extension-no-member
[REPORTS]
# Python expression which should return a note less than 10 (10 is the highest
# note). You have access to the variables errors warning, statement which
# respectively contain the number of errors / warnings messages and the total
# number of statements analyzed. This is used by the global evaluation report
# (RP0004).
evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
# Template used to display messages. This is a python new-style format string
# used to format the message information. See doc for all details
#msg-template=
# Set the output format. Available formats are text, parseable, colorized, json
# and msvs (visual studio).You can also give a reporter class, eg
# mypackage.mymodule.MyReporterClass.
output-format=text
# Tells whether to display a full report or only the messages
reports=no
# Activate the evaluation score.
score=yes
[REFACTORING]
# Maximum number of nested blocks for function / method body
max-nested-blocks=5
# Complete name of functions that never returns. When checking for
# inconsistent-return-statements if a never returning function is called then
# it will be considered as an explicit return statement and no message will be
# printed.
never-returning-functions=optparse.Values,sys.exit
[LOGGING]
# Logging modules to check that the string format arguments are in logging
# function parameter format
logging-modules=logging
[SPELLING]
# Limits count of emitted suggestions for spelling mistakes
max-spelling-suggestions=4
# Spelling dictionary name. Available dictionaries: none. To make it working
# install python-enchant package.
spelling-dict=
# List of comma separated words that should not be checked.
spelling-ignore-words=
# A path to a file that contains private dictionary; one word per line.
spelling-private-dict-file=
# Tells whether to store unknown words to indicated private dictionary in
# --spelling-private-dict-file option instead of raising a message.
spelling-store-unknown-words=no
[MISCELLANEOUS]
# List of note tags to take in consideration, separated by a comma.
notes=FIXME,
XXX,
TODO
[SIMILARITIES]
# Ignore comments when computing similarities.
ignore-comments=yes
# Ignore docstrings when computing similarities.
ignore-docstrings=yes
# Ignore imports when computing similarities.
ignore-imports=no
# Minimum lines number of a similarity.
min-similarity-lines=4
[TYPECHECK]
# List of decorators that produce context managers, such as
# contextlib.contextmanager. Add to this list to register other decorators that
# produce valid context managers.
contextmanager-decorators=contextlib.contextmanager
# List of members which are set dynamically and missed by pylint inference
# system, and so shouldn't trigger E1101 when accessed. Python regular
# expressions are accepted.
generated-members=capnp.* cereal.* pygame.* zmq.* setproctitle.* smbus2.* usb1.* serial.* cv2.*
# Tells whether missing members accessed in mixin class should be ignored. A
# mixin class is detected if its name ends with "mixin" (case insensitive).
ignore-mixin-members=yes
# This flag controls whether pylint should warn about no-member and similar
# checks whenever an opaque object is returned when inferring. The inference
# can return multiple potential results while evaluating a Python object, but
# some branches might not be evaluated, which results in partial inference. In
# that case, it might be useful to still emit no-member and other checks for
# the rest of the inferred objects.
ignore-on-opaque-inference=yes
# List of class names for which member attributes should not be checked (useful
# for classes with dynamically set attributes). This supports the use of
# qualified names.
ignored-classes=optparse.Values,thread._local,_thread._local
# List of module names for which member attributes should not be checked
# (useful for modules/projects where namespaces are manipulated during runtime
# and thus existing member attributes cannot be deduced by static analysis. It
# supports qualified module names, as well as Unix pattern matching.
ignored-modules=flask setproctitle usb1 flask.ext.socketio smbus2 usb1.*
# Show a hint with possible names when a member name was not found. The aspect
# of finding the hint is based on edit distance.
missing-member-hint=yes
# The minimum edit distance a name should have in order to be considered a
# similar match for a missing member name.
missing-member-hint-distance=1
# The total number of similar names that should be taken in consideration when
# showing a hint for a missing member.
missing-member-max-choices=1
[VARIABLES]
# List of additional names supposed to be defined in builtins. Remember that
# you should avoid to define new builtins when possible.
additional-builtins=
# Tells whether unused global variables should be treated as a violation.
allow-global-unused-variables=yes
# List of strings which can identify a callback function by name. A callback
# name must start or end with one of those strings.
callbacks=cb_,
_cb
# A regular expression matching the name of dummy variables (i.e. expectedly
# not used).
dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_
# Argument names that match this expression will be ignored. Default to name
# with leading underscore
ignored-argument-names=_.*|^ignored_|^unused_
# Tells whether we should check for unused import in __init__ files.
init-import=no
# List of qualified module names which can have objects that can redefine
# builtins.
redefining-builtins-modules=six.moves,past.builtins,future.builtins
[FORMAT]
# Expected format of line ending, e.g. empty (any line ending), LF or CRLF.
expected-line-ending-format=
# Regexp for a line that is allowed to be longer than the limit.
ignore-long-lines=^\s*(# )?<?https?://\S+>?$
# Number of spaces of indent required inside a hanging or continued line.
indent-after-paren=4
# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
# tab).
indent-string=' '
# Maximum number of characters on a single line.
max-line-length=100
# Maximum number of lines in a module
max-module-lines=1000
# List of optional constructs for which whitespace checking is disabled. `dict-
# separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}.
# `trailing-comma` allows a space between comma and closing bracket: (a, ).
# `empty-line` allows space-only lines.
no-space-check=trailing-comma,
dict-separator
# Allow the body of a class to be on the same line as the declaration if body
# contains single statement.
single-line-class-stmt=no
# Allow the body of an if to be on the same line as the test if there is no
# else.
single-line-if-stmt=no
[BASIC]
# Naming style matching correct argument names
argument-naming-style=snake_case
# Regular expression matching correct argument names. Overrides argument-
# naming-style
#argument-rgx=
# Naming style matching correct attribute names
attr-naming-style=snake_case
# Regular expression matching correct attribute names. Overrides attr-naming-
# style
#attr-rgx=
# Bad variable names which should always be refused, separated by a comma
bad-names=foo,
bar,
baz,
toto,
tutu,
tata
# Naming style matching correct class attribute names
class-attribute-naming-style=any
# Regular expression matching correct class attribute names. Overrides class-
# attribute-naming-style
#class-attribute-rgx=
# Naming style matching correct class names
class-naming-style=PascalCase
# Regular expression matching correct class names. Overrides class-naming-style
#class-rgx=
# Naming style matching correct constant names
const-naming-style=UPPER_CASE
# Regular expression matching correct constant names. Overrides const-naming-
# style
#const-rgx=
# Minimum line length for functions/classes that require docstrings, shorter
# ones are exempt.
docstring-min-length=-1
# Naming style matching correct function names
function-naming-style=snake_case
# Regular expression matching correct function names. Overrides function-
# naming-style
#function-rgx=
# Good variable names which should always be accepted, separated by a comma
good-names=i,
j,
k,
ex,
Run,
_
# Include a hint for the correct naming format with invalid-name
include-naming-hint=no
# Naming style matching correct inline iteration names
inlinevar-naming-style=any
# Regular expression matching correct inline iteration names. Overrides
# inlinevar-naming-style
#inlinevar-rgx=
# Naming style matching correct method names
method-naming-style=snake_case
# Regular expression matching correct method names. Overrides method-naming-
# style
#method-rgx=
# Naming style matching correct module names
module-naming-style=snake_case
# Regular expression matching correct module names. Overrides module-naming-
# style
#module-rgx=
# Colon-delimited sets of names that determine each other's naming style when
# the name regexes allow several styles.
name-group=
# Regular expression which should only match function or class names that do
# not require a docstring.
no-docstring-rgx=^_
# List of decorators that produce properties, such as abc.abstractproperty. Add
# to this list to register other decorators that produce valid properties.
property-classes=abc.abstractproperty
# Naming style matching correct variable names
variable-naming-style=snake_case
# Regular expression matching correct variable names. Overrides variable-
# naming-style
#variable-rgx=
[DESIGN]
# Maximum number of arguments for function / method
max-args=5
# Maximum number of attributes for a class (see R0902).
max-attributes=7
# Maximum number of boolean expressions in a if statement
max-bool-expr=5
# Maximum number of branch for function / method body
max-branches=12
# Maximum number of locals for function / method body
max-locals=15
# Maximum number of parents for a class (see R0901).
max-parents=7
# Maximum number of public methods for a class (see R0904).
max-public-methods=20
# Maximum number of return / yield for function / method body
max-returns=6
# Maximum number of statements in function / method body
max-statements=50
# Minimum number of public methods for a class (see R0903).
min-public-methods=2
[CLASSES]
# List of method names used to declare (i.e. assign) instance attributes.
defining-attr-methods=__init__,
__new__,
setUp
# List of member names, which should be excluded from the protected access
# warning.
exclude-protected=_asdict,
_fields,
_replace,
_source,
_make
# List of valid names for the first argument in a class method.
valid-classmethod-first-arg=cls
# List of valid names for the first argument in a metaclass class method.
valid-metaclass-classmethod-first-arg=mcs
[IMPORTS]
# Allow wildcard imports from modules that define __all__.
allow-wildcard-with-all=no
# Analyse import fallback blocks. This can be used to support both Python 2 and
# 3 compatible code, which means that the block might have code that exists
# only in one or another interpreter, leading to false positives when analysed.
analyse-fallback-blocks=no
# Deprecated modules which should not be used, separated by a comma
deprecated-modules=regsub,
TERMIOS,
Bastion,
rexec
# Create a graph of external dependencies in the given file (report RP0402 must
# not be disabled)
ext-import-graph=
# Create a graph of every (i.e. internal and external) dependencies in the
# given file (report RP0402 must not be disabled)
import-graph=
# Create a graph of internal dependencies in the given file (report RP0402 must
# not be disabled)
int-import-graph=
# Force import order to recognize a module as part of the standard
# compatibility libraries.
known-standard-library=
# Force import order to recognize a module as part of a third party library.
known-third-party=enchant
[EXCEPTIONS]
# Exceptions that will emit a warning when being caught. Defaults to
# "Exception"
overgeneral-exceptions=Exception
+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'
+5 -27
View File
@@ -2,39 +2,17 @@
Our software is open source so you can solve your own problems without needing help from others. And if you solve a problem and are so kind, you can upstream it for the rest of the world to use.
Most open source development activity is coordinated through our [Discord](https://discord.comma.ai). A lot of documentation is available on our [medium](https://medium.com/@comma_ai/)
Most open source development activity is coordinated through our [slack](https://slack.comma.ai). A lot of documentation is available on our [medium](https://medium.com/@comma_ai/)
## Getting Started
* Join our [Discord](https://discord.comma.ai)
* Join our slack [slack.comma.ai](https://slack.comma.ai)
* 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 travis. Check out `.travis.yml` for what travis runs. Any new tests sould be added to travis.
### Code Style and Linting
Code is automatically check for style by travis as part of the automated tests. You can also run these yourself by running `check_code_quality.sh`.
* Fork the repository on GitHub
## 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.
We've released a guide for porting to Toyota cars [here](https://medium.com/@comma_ai/openpilot-port-guide-for-toyota-models-e5467f4b5fe6)
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)
If you port openpilot to a substantially new car, you might 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 run
```
git submodule init
git submodule update
```
in order to pull down the submodules, such as `panda` and `opendbc`.
+5 -74
View File
@@ -1,88 +1,19 @@
FROM ubuntu:16.04
ENV PYTHONUNBUFFERED 1
RUN apt-get update && apt-get install -y \
autoconf \
build-essential \
bzip2 \
clang \
cmake \
curl \
ffmpeg \
git \
libarchive-dev \
libbz2-dev \
libcurl4-openssl-dev \
libeigen3-dev \
libffi-dev \
libglew-dev \
libgles2-mesa-dev \
libglfw3-dev \
libglib2.0-0 \
liblzma-dev \
libmysqlclient-dev \
libomp-dev \
libopencv-dev \
libssl-dev \
libsqlite3-dev \
libtool \
libusb-1.0-0-dev \
libzmq5-dev \
locales \
ocl-icd-libopencl1 \
ocl-icd-opencl-dev \
opencl-headers \
python-dev \
python-pip \
screen \
sudo \
vim \
wget
RUN apt-get update && apt-get install -y build-essential clang vim screen wget bzip2 git libglib2.0-0 python-pip capnproto libcapnp-dev libzmq5-dev libffi-dev libusb-1.0-0
RUN pip install numpy==1.11.2 scipy==0.18.1 matplotlib
COPY requirements_openpilot.txt /tmp/
RUN pip install -r /tmp/requirements_openpilot.txt
RUN sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && locale-gen
ENV LANG en_US.UTF-8
ENV LANGUAGE en_US:en
ENV LC_ALL en_US.UTF-8
ENV PYTHONPATH /tmp/openpilot:$PYTHONPATH
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 pip install pipenv==2018.11.26
COPY Pipfile /tmp/
COPY Pipfile.lock /tmp/
RUN python --version
RUN cd /tmp && pipenv install --system --deploy
# Install subset of dev dependencies needed for CI
RUN pip install matplotlib==3.1.1 dictdiffer==0.8.0 fastcluster==1.1.25 aenum==2.2.1 scipy==1.3.1 lru-dict==1.1.6 tenacity==5.1.1 azure-common==1.1.23 azure-nspkg==3.0.2 azure-storage-blob==2.1.0 azure-storage-common==2.1.0 azure-storage-nspkg==3.1.0 pycurl==7.43.0.3
ENV PATH="/tmp/openpilot/external/bin:${PATH}"
ENV PYTHONPATH /tmp/openpilot:${PYTHONPATH}
RUN mkdir -p /tmp/openpilot
COPY ./flake8_openpilot.sh /tmp/openpilot/
COPY ./pylint_openpilot.sh /tmp/openpilot/
COPY ./.pylintrc /tmp/openpilot/
COPY ./release /tmp/openpilot/release
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
COPY ./panda /tmp/openpilot/panda
COPY ./external /tmp/openpilot/external
COPY ./tools /tmp/openpilot/tools
COPY SConstruct /tmp/openpilot/SConstruct
RUN mkdir -p /tmp/openpilot/selfdrive/test/out
RUN cd /tmp/openpilot && scons -j$(nproc)
Vendored
-23
View File
@@ -1,23 +0,0 @@
pipeline {
agent {
docker {
image 'python:3.7.3'
args '--user=root'
}
}
stages {
stage('EON Build/Test') {
steps {
lock(resource: "", label: 'eon', inversePrecedence: true, variable: 'eon_name', quantity: 1){
timeout(time: 30, unit: 'MINUTES') {
dir(path: 'release') {
sh 'pip install paramiko'
sh 'python remote_build.py'
}
}
}
}
}
}
}
+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
-130
View File
@@ -1,130 +0,0 @@
[[source]]
name = "pypi"
url = "https://pypi.org/simple"
verify_ssl = true
[dev-packages]
opencv-python= "==3.4.2.17"
PyQt5 = "*"
ipython = "*"
networkx = "==2.3"
azure-core = "==1.1.1"
azure-common = "==1.1.24"
azure-nspkg = "==3.0.2"
azure-storage-blob = "==2.1.0"
azure-storage-common = "==2.1.0"
azure-storage-nspkg = "==3.1.0"
boto = "*"
"boto3" = "*"
control = "*"
datadog = "*"
dlib = "*"
elasticsearch = "*"
future = "*"
futures = "*"
pycocotools = {git = "https://github.com/cocodataset/cocoapi.git",subdirectory = "PythonAPI"}
gunicorn = "*"
"h5py" = "*"
hexdump = "*"
"html5lib" = "*"
imageio = "*"
ipykernel = "*"
joblib = "*"
json-logging-py = "*"
jupyter = "*"
libarchive = "*"
lru-dict = "*"
"mpld3" = "*"
msgpack-python = "*"
nbstripout = "*"
numpy = "*"
osmium = "*"
pbr = "*"
percache = "*"
pprofile = "*"
pycurl = "*"
git-pylint-commit-hook = "*"
pymongo = "*"
"pynmea2" = "*"
pypolyline = "*"
python-logstash = "*"
redis = "*"
"s2sphere" = "*"
scikit-image = "*"
"subprocess32" = "*"
tenacity = "*"
tensorflow-gpu = "==2.0"
PyJWT = "==1.4.1"
PyMySQL = "==0.9.2"
Werkzeug = "*"
"backports.lzma" = "*"
Flask-Cors = "*"
Flask-SocketIO = "*"
"GeoAlchemy2" = "*"
Pygments = "*"
PyNaCl = "*"
"PySDL2" = "*"
reverse_geocoder = "*"
Shapely = "*"
SQLAlchemy = "*"
scipy = "*"
fastcluster = "*"
backports-abc = "*"
pygame = "*"
simplejson = "*"
python-logstash-async = "*"
seaborn = "*"
pyproj = "*"
mock = "*"
matplotlib = "*"
dictdiffer = "*"
aenum = "*"
coverage = "*"
azure-cli-core = "*"
paramiko = "*"
aiohttp = "*"
[packages]
overpy = {git = "https://github.com/commaai/python-overpy.git",ref = "f86529af402d4642e1faeb146671c40284007323"}
atomicwrites = "*"
cffi = "*"
crcmod = "*"
hexdump = "*"
libusb1 = "*"
numpy = "*"
psutil = "*"
pycapnp = "*"
cryptography = "*"
pyserial = "*"
python-dateutil = "*"
pyzmq = "*"
raven = "*"
requests = "*"
setproctitle = "*"
six = "*"
smbus2 = "*"
sympy = "*"
tqdm = "*"
Cython = "*"
PyYAML = "*"
websocket_client = "*"
Logentries = {git = "https://github.com/commaai/le_python.git",ref = "feaeacb48f7f4bdb02c0a8fc092326d4e101b7f2"}
urllib3 = "*"
chardet = "*"
idna = "*"
gunicorn = "*"
utm = "*"
json-rpc = "*"
Flask = "*"
PyJWT = "*"
"Jinja2" = "*"
nose = "*"
flake8 = "*"
pylint = "*"
pycryptodome = "*"
pillow = "*"
scons = "*"
cysignals = "*"
[requires]
python_version = "3.7.3"
Generated
-2970
View File
File diff suppressed because it is too large Load Diff
+117 -266
View File
@@ -1,306 +1,157 @@
[![](https://i.imgur.com/UelUjKAh.png)](#)
Welcome to openpilot
======
Table of Contents
=======================
[openpilot](http://github.com/commaai/openpilot) is an open source driving agent.
* [What is openpilot?](#what-is-openpilot)
* [Integration with Stock Features](#integration-with-stock-features)
* [Supported Hardware](#supported-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)
* [Testing on PC](#testing-on-pc)
* [Community and Contributing](#community-and-contributing)
* [Directory Structure](#directory-structure)
* [Licensing](#licensing)
Currently it performs the functions of Adaptive Cruise Control (ACC) and Lane Keeping Assist System (LKAS) for Hondas, Acuras and Toyotas. It's about on par with Tesla Autopilot at launch, and better than [all other manufacturers](http://www.thedrive.com/tech/5707/the-war-for-autonomous-driving-part-iii-us-vs-germany-vs-japan).
---
The openpilot codebase has been written to be concise and enable rapid prototyping. We look forward to your contributions - improving real vehicle automation has never been easier.
What is openpilot?
Here are [some](https://www.youtube.com/watch?v=9OwTJFuDI7g) [videos](https://www.youtube.com/watch?v=64Wvt5pYQmE) [of](https://www.youtube.com/watch?v=6IW7Nejsr3A) [it](https://www.youtube.com/watch?v=-VN1YcC83nA) [running](https://www.youtube.com/watch?v=EQJZvVeihZk). And a really cool [tutorial](https://www.youtube.com/watch?v=PwOnsT2UW5o).
Hardware
------
[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.
Right now openpilot supports the [EON Dashcam DevKit](https://shop.comma.ai/products/eon-dashcam-devkit). We'd like to support other platforms as well.
<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>
</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>
</tr>
</table>
Integration with Stock Features
------
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.
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. In the future, we'd like to support other platforms as well, like gaming PCs.
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>5</sup> | 25mph |
| Acura | RDX 2016-18 | AcuraWatch Plus | openpilot | 25mph<sup>5</sup> | 12mph |
| Chrysler | Pacifica 2017-18 | Adaptive Cruise | Stock | 0mph | 9mph |
| Chrysler | Pacifica Hybrid 2017-18 | Adaptive Cruise | Stock | 0mph | 9mph |
| Chrysler | Pacifica Hybrid 2019-20 | Adaptive Cruise | Stock | 0mph | 39mph |
| 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 | Honda Sensing | Stock | 0mph | 2mph |
| Honda | CR-V 2015-16 | Touring | openpilot | 25mph<sup>5</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>5</sup> | 12mph |
| Honda | Odyssey 2018-20 | Honda Sensing | openpilot | 25mph<sup>5</sup> | 0mph |
| Honda | Passport 2019 | All | openpilot | 25mph<sup>5</sup> | 12mph |
| Honda | Pilot 2016-18 | Honda Sensing | openpilot | 25mph<sup>5</sup> | 12mph |
| Honda | Pilot 2019 | All | openpilot | 25mph<sup>5</sup> | 12mph |
| Honda | Ridgeline 2017-19 | Honda Sensing | openpilot | 25mph<sup>5</sup> | 12mph |
| Hyundai | Elantra 2017-19<sup>1</sup> | SCC + LKAS | Stock | 19mph | 34mph |
| Hyundai | Genesis 2018<sup>1</sup> | All | Stock | 19mph | 34mph |
| Hyundai | Santa Fe 2019<sup>1</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 | Optima 2019<sup>1</sup> | SCC + LKAS | Stock | 0mph | 0mph |
| Kia | Sorento 2018<sup>1</sup> | All | Stock | 0mph | 0mph |
| Kia | Stinger 2018<sup>1</sup> | SCC + LKAS | Stock | 0mph | 0mph |
| Lexus | CT Hybrid 2017-18 | All | Stock<sup>4</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 | RX 2016-17 | All | Stock<sup>4</sup>| 0mph | 0mph |
| Lexus | RX 2020 | All | openpilot | 0mph | 0mph |
| Lexus | RX Hybrid 2016-19 | All | Stock<sup>4</sup>| 0mph | 0mph |
| Subaru | Crosstrek 2018-19 | EyeSight | Stock | 0mph | 0mph |
| Subaru | Impreza 2019-20 | EyeSight | Stock | 0mph | 0mph |
| Toyota | Avalon 2016 | TSS-P | Stock<sup>4</sup>| 20mph<sup>5</sup> | 0mph |
| Toyota | Avalon 2017-18 | All | Stock<sup>4</sup>| 20mph<sup>5</sup> | 0mph |
| Toyota | Camry 2018-19 | All | Stock | 0mph<sup>2</sup> | 0mph |
| Toyota | Camry Hybrid 2018-19 | All | Stock | 0mph<sup>2</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>4</sup>| 20mph<sup>5</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>4</sup>| 0mph | 0mph |
| Toyota | Highlander Hybrid 2017-19 | All | Stock<sup>4</sup>| 0mph | 0mph |
| Toyota | Prius 2016 | TSS-P | Stock<sup>4</sup>| 0mph | 0mph |
| Toyota | Prius 2017-19 | All | Stock<sup>4</sup>| 0mph | 0mph |
| Toyota | Prius Prime 2017-20 | All | Stock<sup>4</sup>| 0mph | 0mph |
| Toyota | Rav4 2016 | TSS-P | Stock<sup>4</sup>| 20mph<sup>5</sup> | 0mph |
| Toyota | Rav4 2017-18 | All | Stock<sup>4</sup>| 20mph<sup>5</sup> | 0mph |
| Toyota | Rav4 2019 | All | openpilot | 0mph | 0mph |
| Toyota | Rav4 Hybrid 2016 | TSS-P | Stock<sup>4</sup>| 0mph | 0mph |
| Toyota | Rav4 Hybrid 2017-18 | All | Stock<sup>4</sup>| 0mph | 0mph |
| Toyota | Rav4 Hybrid 2019-20 | All | openpilot | 0mph | 0mph |
| Toyota | Sienna 2018 | All | Stock<sup>4</sup>| 0mph | 0mph |
| Volkswagen| Golf 2016-19<sup>3</sup> | Driver Assistance | Stock | 0mph | 0mph |
- Acura ILX 2016 with AcuraWatch Plus
- Due to use of the cruise control for gas, it can only be enabled above 25 mph
<sup>1</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>2</sup>28mph for Camry 4CYL L, 4CYL LE and 4CYL SE which don't have Full-Speed Range Dynamic Radar Cruise Control. <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 Civic 2016-2018 with Honda Sensing
- Due to limitations in steering firmware, steering is disabled below 12 mph
- Note that the hatchback model is not supported
Community Maintained Cars and Features
- Honda CR-V Touring 2015-2016
- Can only be enabled above 25 mph
- Honda Odyssey 2018 with Honda Sensing (alpha!)
- Can only be enabled above 25 mph
- Acura RDX 2018 with AcuraWatch Plus (alpha!)
- Can only be enabled above 25 mph
- Honda Pilot 2017 with Honda Sensing (alpha!)
- Can only be enabled above 27 mph
- Honda Ridgeline 2017 with Honda Sensing (alpha!)
- Can only be enabled above 27 mph
- Toyota RAV-4 2016+ non-hybrid with TSS-P
- By default it uses stock Toyota ACC for longitudinal control
- openpilot longitudinal control available after unplugging the [Driving Support ECU](https://community.comma.ai/wiki/index.php/Toyota#Rav4_.28for_openpilot.29) and can be enabled above 20 mph
- Toyota Prius 2017 (alpha!)
- By default it uses stock Toyota ACC for longitudinal control
- openpilot longitudinal control available after unplugging the [Driving Support ECU](https://community.comma.ai/wiki/index.php/Toyota#Prius_.28for_openpilot.29)
- Lateral control needs improvements
- Toyota RAV-4 2017 hybrid (alpha!)
- By default it uses stock Toyota ACC for longitudinal control
- openpilot longitudinal control available after unplugging the [Driving Support ECU](https://community.comma.ai/wiki/index.php/Toyota#Rav4_.28for_openpilot.29) and can do stop and go
- Toyota Corolla 2017 (alpha!)
- By default it uses stock Toyota ACC for longitudinal control
- openpilot longitudinal control available after unplugging the [Driving Support ECU](https://community.comma.ai/wiki/index.php/Toyota#Corolla_.28for_openpilot.29) and can be enabled above 20 mph
- Lexus RX 2017 hybrid (alpha!)
- By default it uses stock Lexus ACC for longitudinal control
- openpilot longitudinal control available after unplugging the [Driving Support ECU](https://community.comma.ai/wiki/index.php/Toyota#Lexus_RX_hybrid)
In Progress Cars
------
- All TSS-P Toyota with Steering Assist.
- 'Full Speed Range Dynamic Radar Cruise Control' is required to enable stop-and-go. Only the Prius, Camry and C-HR have this option.
- Even though the Tundra, Sequoia and the Land Cruiser have TSS-P, they don't have Steering Assist and are not supported.
- All LSS-P Lexus with Steering Assist or Lane Keep Assist.
- 'All-Speed Range Dynamic Radar Cruise Control' is required to enable stop-and-go. Only the GS, GSH, GS, F, RX, RXH, LX, NX, NXH, LC, LCH, LS, LSH have this option.
- Even though the LX have TSS-P, it does not have Steering Assist and is not supported.
Community WIP Cars
------
| Make | Model (US Market Reference) | Supported Package | ACC | No ACC accel below | No ALC below |
| ----------| ------------------------------| ------------------| -----------------| -------------------| -------------|
| Buick | Regal 2018<sup>6</sup> | Adaptive Cruise | openpilot | 0mph | 7mph |
| Cadillac | ATS 2018<sup>6</sup> | Adaptive Cruise | openpilot | 0mph | 7mph |
| Chevrolet | Malibu 2017<sup>6</sup> | Adaptive Cruise | openpilot | 0mph | 7mph |
| Chevrolet | Volt 2017-18<sup>6</sup> | Adaptive Cruise | openpilot | 0mph | 7mph |
| GMC | Acadia Denali 2018<sup>6</sup>| Adaptive Cruise | openpilot | 0mph | 7mph |
| Holden | Astra 2017<sup>6</sup> | Adaptive Cruise | openpilot | 0mph | 7mph |
- [Chevy Volt 2016-2018 Premier with Driver Confidence II](https://github.com/commaai/openpilot/pull/104)
<sup>4</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>5</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>6</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 />
- [Classic Tesla Model S (pre-AP)](https://github.com/commaai/openpilot/pull/145)
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`.
Installation Instructions
Directory structure
------
Install openpilot on a EON by entering ``https://openpilot.comma.ai`` during the installer setup.
- cereal -- The messaging spec used for all logs on the phone
- common -- Library like functionality we've developed here
- opendbc -- Files showing how to interpret data from cars
- panda -- Code used to communicate on CAN and LIN
- phonelibs -- Libraries used on the phone
- selfdrive -- Code needed to drive the car
- assets -- Fonts for ui
- boardd -- Daemon to talk to the board
- car -- Code that talks to the car and implements CarInterface
- common -- Shared C/C++ code for the daemons
- controls -- Python controls (PID loops etc) for the car
- debug -- Tools to help you debug and do car ports
- logcatd -- Android logcat as a service
- loggerd -- Logger and uploader of car data
- proclogd -- Logs information from proc
- sensord -- IMU / GPS interface code
- test/plant -- Car simulator running code through virtual maneuvers
- ui -- The UI
- visiond -- embedded vision pipeline
Follow this [video instructions](https://youtu.be/3nlkomHathI) to properly mount the EON 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 EON mounting.
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.
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 EON 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 EON 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 measurements of the status of 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 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](run_docker_tests.sh) 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.
To understand how the services interact, see `selfdrive/service_list.yaml`
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.
There is rudimentary infrastructure to run a basic simulation and generate a report of openpilot's behavior in different scenarios.
Community and Contributing
```bash
# Requires working docker
./run_docker_tests.sh
```
The results are written to `selfdrive/test/plant/out/index.html`
More extensive testing infrastructure and simulation environments are coming soon.
Adding Car Support
------
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.
comma.ai offers [bounties](http://comma.ai/bounties.html) for adding additional car support.
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.
CR-V Touring support came in through this program. Chevy Volt is close. Accord is close as well.
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
User Data / chffr Account / Crash Reporting
------
.
├── apk # The apk files used for the UI
├── cereal # The messaging spec and libs 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 EON
├── pyextra # Libraries used on EON
└── selfdrive # Code needed to drive the car
├── assets # Fonts and images for UI
├── athena # Allows communication with the app
├── boardd # Daemon to talk to the board
├── camerad # Driver to capture images from the camera sensors
├── car # Car specific code to read states and control actuators
├── common # Shared C/C++ code for the daemons
├── controls # Perception, planning and controls
├── debug # Tools to help you debug and do car ports
├── 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
├── proclogd # Logs information from proc
├── sensord # IMU / GPS interface code
├── tests # Unit tests, system tests and a car simulator
└── ui # The UI
To understand how the services interact, see `cereal/service_list.yaml`.
By default openpilot creates an account and includes a client for chffr, our dashcam app. We use your data to train better models and improve openpilot for everyone.
It's open source software, so you are free to disable it if you wish.
It logs the road facing camera, CAN, GPS, IMU, magnetometer, thermal sensors, crashes, and operating system logs.
It does not log the user facing camera or the microphone.
By using it, you agree to [our privacy policy](https://beta.comma.ai/privacy.html). You understand that use of this software or its related services will generate certain types of user data, which may be logged and stored at the sole discretion of comma.ai. By accepting this agreement, you grant an irrevocable, perpetual, worldwide right to comma.ai for the use of this data.
Contributing
------
We welcome both pull requests and issues on
[github](http://github.com/commaai/openpilot). See the TODO file for a list of
good places to start.
Want to get paid to work on openpilot? [comma.ai is hiring](http://comma.ai/positions.html)
Licensing
------
openpilot is released under the MIT license. Some parts of the software are released under other licenses as specified.
openpilot is released under the MIT license.
Any user of this software shall indemnify and hold harmless comma.ai, Inc. and its directors, officers, employees, agents, stockholders, affiliates, subcontractors and customers from and against all allegations, claims, actions, suits, demands, damages, liabilities, obligations, losses, settlements, judgments, costs and expenses (including without limitation attorneys fees and costs) which arise out of, relate to or result from any use of this software by user.
Any user of this software shall indemnify and hold harmless Comma.ai, Inc. and its directors, officers, employees, agents, stockholders, affiliates, subcontractors and customers from and against all allegations, claims, actions, suits, demands, damages, liabilities, obligations, losses, settlements, judgments, costs and expenses (including without limitation attorneys fees and costs) which arise out of, relate to or result from any use of this software by user.
**THIS IS ALPHA QUALITY SOFTWARE FOR RESEARCH PURPOSES ONLY. THIS IS NOT A PRODUCT.
YOU ARE RESPONSIBLE FOR COMPLYING WITH LOCAL LAWS AND REGULATIONS.
NO WARRANTY EXPRESSED OR IMPLIED.**
---
<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>
+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.
-295
View File
@@ -1,298 +1,3 @@
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
* Abstract planner in its own process to remove lags in controls process
* Improve speed limits with country/region defaults by road type
* Reduce mapd data usage with gzip thanks to eFiniLan
* Zip log files in the background to reduce disk usage
* 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!
Version 0.5.8 (2019-01-17)
========================
* Open sourced visiond
* Auto-slowdown for upcoming turns
* Chrysler/Jeep/Fiat support thanks to adhintz!
* Honda Civic 2019 support thanks to csouers!
* Improve use of car display in Toyota thanks to arne182!
* No data upload when connected to Android or iOS hotspots and "Enable Upload Over Cellular" setting is off
* EON stops charging when 12V battery drops below 11.8V
Version 0.5.7 (2018-12-06)
========================
* Speed limit from OpenStreetMap added to UI
* Highlight speed limit when speed exceeds road speed limit plus a delta
* Option to limit openpilot max speed to road speed limit plus a delta
* Cadillac ATS support thanks to vntarasov!
* GMC Acadia support thanks to CryptoKylan!
* Decrease GPU power consumption
* NEOSv8 autoupdate
Version 0.5.6 (2018-11-16)
========================
* Refresh settings layout and add feature descriptions
* In Honda, keep stock camera on for logging and extra stock features; new openpilot giraffe setting is 0111!
* In Toyota, option to keep stock camera on for logging and extra stock features (e.g. AHB); 120Ohm resistor required on giraffe.
* Improve camera calibration stability
* More tuning to Honda positive accelerations
* Reduce brake pump use on Hondas
* Chevrolet Malibu support thanks to tylergets!
* Holden Astra support thanks to AlexHill!
Version 0.5.5 (2018-10-20)
========================
* Increase allowed Honda positive accelerations
* Fix sporadic unexpected braking when passing semi-trucks in Toyota
* Fix gear reading bug in Hyundai Elantra thanks to emmertex!
Version 0.5.4 (2018-09-25)
========================
* New Driving Model
* New Driver Monitoring Model
* Improve longitudinal mpc in mid-low speed braking
* Honda Accord hybrid support thanks to energee!
* Ship mpc binaries and sensibly reduce build time
* Calibration more stable
* More Hyundai and Kia cars supported thanks to emmertex!
* Various GM Volt improvements thanks to vntarasov!
Version 0.5.3 (2018-09-03)
========================
* Hyundai Santa Fe support!
* Honda Pilot 2019 support thanks to energee!
* Toyota Highlander support thanks to daehahn!
* Improve steering tuning for Honda Odyssey
Version 0.5.2 (2018-08-16)
========================
* New calibration: more accurate, a lot faster, open source!
* Enable orbd
* Add little endian support to CAN packer
* Fix fingerprint for Honda Accord 1.5T
* Improve driver monitoring model
Version 0.5.1 (2018-08-01)
========================
* Fix radar error on Civic sedan 2018
* Improve thermal management logic
* Alpha Toyota C-HR and Camry support!
* Auto-switch Driver Monitoring to 3 min counter when inaccurate
Version 0.5 (2018-07-11)
========================
* Driver Monitoring (beta) option in settings!
* Make visiond, loggerd and UI use less resources
* 60 FPS UI
* Better car parameters for most cars
* New sidebar with stats
* Remove Waze and Spotify to free up system resources
* Remove rear view mirror option
* Calibration 3x faster
Version 0.4.7.2 (2018-06-25)
==========================
* Fix loggerd lag issue
* No longer prompt for updates
* Mitigate right lane hugging for properly mounted EON (procedure on wiki)
Version 0.4.7.1 (2018-06-18)
==========================
* Fix Acura ILX steer faults
* Fix bug in mock car
Version 0.4.7 (2018-06-15)
==========================
* New model!
* GM Volt (and CT6 lateral) support!
* Honda Bosch lateral support!
* Improve actuator modeling to reduce lateral wobble
* Minor refactor of car abstraction layer
* Hack around orbd startup issue
Version 0.4.6 (2018-05-18)
==========================
* NEOSv6 required! Will autoupdate
* Stability improvements
* Fix all memory leaks
* Update C++ compiler to clang6
* Improve front camera exposure
Version 0.4.5 (2018-04-27)
==========================
* Release notes added to the update popup
* Improve auto shut-off logic to disallow empty battery
* Added onboarding instructions
* Include orbd, the first piece of new calibration algorithm
* Show remaining upload data instead of file numbers
* Fix UI bugs
* Fix memory leaks
Version 0.4.4 (2018-04-13)
==========================
* EON are flipped! Flip your EON's mount!
+61 -22
View File
@@ -1,26 +1,13 @@
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.
Even with an attentive driver, we must make further efforts for the system to be
safe. We have designed openpilot with two other safety considerations.
1. The driver must always be capable to immediately retake manual control of the vehicle,
by stepping on either pedal or by pressing the cancel button.
@@ -28,7 +15,59 @@ 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
not fully meeting the above requirements.
Honda/Acura
------
- While the system is engaged, gas, brake and steer limits are subject to the same limits used by
the stock system.
- Without an interceptor, the gas is controlled by the Powertrain Control Module (PCM).
The PCM limits acceleration to what is reasonable for a cruise control system. With an
interceptor, the gas is clipped to 60%.
- The brake is controlled by the 0x1FA CAN message. This message allows full
braking, although the board and the software clip it to 1/4th of the max.
This is around .3g of braking.
- Steering is controlled by the 0xE4 CAN message. The Electronic Power Steering (EPS)
controller in the car limits the torque to a very small amount, so regardless of the
message, the controller cannot jerk the wheel.
- Brake and gas pedal pressed signals are contained in the 0x17C CAN message. A rising edge of
either signal triggers a disengagement, which is enforced by the board and in software. The
green led on the board signifies if the board is allowing control messages.
- Honda CAN uses both a counter and a checksum to ensure integrity and prevent
replay of the same message.
Toyota/Lexus
------
- While the system is engaged, gas, brake and steer limits are subject to the same limits used by
the stock system.
- With the stock Driving Support Unit (DSU) enabled, the acceleration is controlled
by the stock system and is subject to the stock adaptive cruise control limits. Without the
stock DSU connected, the acceleration command is controlled by the 0x343 CAN message and its
value is limited by the board and the software to between .3g of deceleration and .15g of
acceleration. The acceleration command is ignored by the Engine Control Module (ECM) while the
cruise control system is disengaged.
- Steering torque is controlled through the 0x2E4 CAN message and it's limited by the board and in
software to a value of -1500 and 1500. In addition, the vehicle EPS unit will not respond to
commands outside these limits. A steering torque rate limit is enforced by the board and in
software so that the commanded steering torque must rise from 0 to max value no faster than
1.5s. Commanded steering torque is limited by the board and in software to be no more than 350
units above the actual EPS generated motor torque to ensure limited differences between
commanded and actual torques.
- Brake and gas pedal pressed signals are contained in the 0x224 and 0x1D2 CAN messages,
respectively. A rising edge of either signal triggers a disengagement, which is enforced by the
board and in software. Additionally, the cruise control system disengages on the rising edge of
the brake pedal pressed signal.
- The cruise control system state is contained in the 0x1D2 message. No control messages are
allowed if the cruise control system is not active. This is enforced by the software and the
board. The green led on the board signifies if the board is allowing control messages.
-232
View File
@@ -1,232 +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":
lenv = {
"LD_LIBRARY_PATH": '/data/data/com.termux/files/usr/lib',
"PATH": os.environ['PATH'],
"ANDROID_DATA": os.environ['ANDROID_DATA'],
"ANDROID_ROOT": os.environ['ANDROID_ROOT'],
}
cpppath = [
"#phonelibs/opencl/include",
]
libpath = [
"#phonelibs/snpe/aarch64-android-clang3.8",
"/usr/lib",
"/data/data/com.termux/files/usr/lib",
"/system/vendor/lib64",
"/system/comma/usr/lib",
"#phonelibs/nanovg",
"#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/capnp-c/include",
"#phonelibs/zmq/x64/include",
"#external/tensorflow/include",
]
if arch == "Darwin":
libpath = [
"#phonelibs/capnp-cpp/mac/lib",
"#phonelibs/capnp-c/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/capnp-c/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/json/src",
"#phonelibs/json11",
"#phonelibs/eigen",
"#phonelibs/curl/include",
"#phonelibs/opencv/include",
"#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]
#zmq = 'zmq'
# still needed for apks
zmq = FindFile("libzmq.a", libpath)
Export('env', 'arch', 'zmq', 'SHARED')
# 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, 'json']
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/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'])
# TODO: finish cereal, dbcbuilder, MPC
-3
View File
@@ -1,3 +0,0 @@
Place apks here that you want to be installed with the name <app>.apk
These won't be committed into one, but for now baseui will ship with openpilot.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+2
View File
@@ -0,0 +1,2 @@
src/*
out/*
Binary file not shown.
BIN
View File
Binary file not shown.
Vendored Executable
+122
View File
@@ -0,0 +1,122 @@
#!/usr/bin/env python2.7
import os
import sys
import glob
import shutil
import urllib2
import hashlib
import subprocess
EXTERNAL_PATH = os.path.dirname(os.path.abspath(__file__))
if os.path.exists("/init.qcom.rc"):
# android
APKPATCH = os.path.join(EXTERNAL_PATH, 'tools/apkpatch_android')
SIGNAPK = os.path.join(EXTERNAL_PATH, 'tools/signapk_android')
else:
APKPATCH = os.path.join(EXTERNAL_PATH, 'tools/apkpatch')
SIGNAPK = os.path.join(EXTERNAL_PATH, 'tools/signapk')
APKS = {
'com.waze': {
'src': 'https://apkcache.s3.amazonaws.com/com.waze_1021278.apk',
'src_sha256': 'f00957e93e2389f9e30502ac54994b98ac769314b0963c263d4e8baa625ab0c2',
'patch': 'com.waze.apkpatch',
'out_sha256': 'fee880a91a44c738442cd05fd1b6d9b5817cbf755aa61c86325ada2bc443d5cf'
},
'com.spotify.music': {
'src': 'https://apkcache.s3.amazonaws.com/com.spotify.music_24382006.apk',
'src_sha256': '0610fea68ee7ba5f8e4e0732ad429d729dd6cbb8bc21222c4c99db6cb09fbff4',
'patch': 'com.spotify.music.apkpatch',
'out_sha256': '5a3d6f478c7e40403a98ccc8906d7e0ae12b06543b41f5df52149dd09c647c11'
},
}
def sha256_path(path):
with open(path, 'rb') as f:
return hashlib.sha256(f.read()).hexdigest()
def remove(path):
try:
os.remove(path)
except OSError:
pass
def process(download, patch):
# clean up any junk apks
for out_apk in glob.glob(os.path.join(EXTERNAL_PATH, 'out/*.apk')):
app = os.path.basename(out_apk)[:-4]
if app not in APKS:
print "remove junk", out_apk
remove(out_apk)
complete = True
for k,v in APKS.iteritems():
apk_path = os.path.join(EXTERNAL_PATH, 'out', k+'.apk')
print "checking", apk_path
if os.path.exists(apk_path) and sha256_path(apk_path) == v['out_sha256']:
# nothing to do
continue
complete = False
remove(apk_path)
src_path = os.path.join(EXTERNAL_PATH, 'src', v['src_sha256'])
if not os.path.exists(src_path) or sha256_path(src_path) != v['src_sha256']:
if not download:
continue
print "downloading", v['src'], "to", src_path
# download it
resp = urllib2.urlopen(v['src'])
data = resp.read()
with open(src_path, 'wb') as src_f:
src_f.write(data)
if sha256_path(src_path) != v['src_sha256']:
print "download was corrupted..."
continue
if not patch:
continue
# ignoring lots of TOCTTOU here...
apk_temp = "/tmp/"+k+".patched"
remove(apk_temp)
apk_temp2 = "/tmp/"+k+".signed"
remove(apk_temp2)
try:
print "patching", v['patch']
subprocess.check_call([APKPATCH, 'apply', src_path, apk_temp, os.path.join(EXTERNAL_PATH, v['patch'])])
print "signing", apk_temp
subprocess.check_call([SIGNAPK,
os.path.join(EXTERNAL_PATH, 'tools/certificate.pem'), os.path.join(EXTERNAL_PATH, 'tools/key.pk8'),
apk_temp, apk_temp2])
out_sha256 = sha256_path(apk_temp2) if os.path.exists(apk_temp2) else None
if out_sha256 == v['out_sha256']:
print "done", apk_path
shutil.move(apk_temp2, apk_path)
else:
print "patch was corrupted", apk_temp2, out_sha256
finally:
remove(apk_temp)
remove(apk_temp2)
return complete
if __name__ == "__main__":
ret = True
if len(sys.argv) == 2 and sys.argv[1] == "download":
ret = process(True, False)
elif len(sys.argv) == 2 and sys.argv[1] == "patch":
ret = process(False, True)
else:
ret = process(True, True)
sys.exit(0 if ret else 1)
Binary file not shown.
+7
View File
@@ -0,0 +1,7 @@
#!/system/bin/sh
DIR="$(cd "$(dirname "$0")" && pwd)"
export LD_LIBRARY_PATH=/system/lib64
export CLASSPATH="$DIR"/ApkPatch.android.jar
exec app_process "$DIR" ApkPatch "$@"
+17
View File
@@ -0,0 +1,17 @@
-----BEGIN CERTIFICATE-----
MIICtTCCAh4CCQDm79UqF+Dc5zANBgkqhkiG9w0BAQUFADCBnjELMAkGA1UEBhMC
SUQxEzARBgNVBAgTCkphd2EgQmFyYXQxEDAOBgNVBAcTB0JhbmR1bmcxEjAQBgNV
BAoTCUxvbmRhdGlnYTETMBEGA1UECxMKQW5kcm9pZERldjEaMBgGA1UEAxMRTG9y
ZW5zaXVzIFcuIEwuIFQxIzAhBgkqhkiG9w0BCQEWFGxvcmVuekBsb25kYXRpZ2Eu
bmV0MB4XDTEwMDUwNTA5MjEzOFoXDTEzMDEyODA5MjEzOFowgZ4xCzAJBgNVBAYT
AklEMRMwEQYDVQQIEwpKYXdhIEJhcmF0MRAwDgYDVQQHEwdCYW5kdW5nMRIwEAYD
VQQKEwlMb25kYXRpZ2ExEzARBgNVBAsTCkFuZHJvaWREZXYxGjAYBgNVBAMTEUxv
cmVuc2l1cyBXLiBMLiBUMSMwIQYJKoZIhvcNAQkBFhRsb3JlbnpAbG9uZGF0aWdh
Lm5ldDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAy2oWtbdVXMHGiS6cA3qi
3VfZt5Vz9jTlux+TEcGx5h18ZKwclyo+z2B0L/p5bYdnrTdFEiD7IxvX+h3lu0JV
B9rdXZdyrzXNOw5YFrsn2k7hKvB8KEBaga1gZEwodlc6N14H3FbZdZkIA9V716Pu
e5CWBZ2VqU03lUJmKnpH8c8CAwEAATANBgkqhkiG9w0BAQUFAAOBgQBpNgXh8dw9
uMjZxzLUXovV5ptHd61jAcZlQlffqPsz6/2QNfIShVdGH9jkm0IudfKkbvvOKive
a77t9c4sDh2Sat2L/rx6BfTuS1+y9wFr1Ee8Rrr7wGHhRkx2qqGrXGVWqXn8aE3E
P6e7BTPF0ibS+tG8cdDPEisqGFxw36nTNQ==
-----END CERTIFICATE-----
Vendored Executable
BIN
View File
Binary file not shown.
Binary file not shown.
+7
View File
@@ -0,0 +1,7 @@
#!/system/bin/sh
DIR="$(cd "$(dirname "$0")" && pwd)"
export LD_LIBRARY_PATH=/system/lib64
export CLASSPATH="$DIR"/signapk.android.jar
exec app_process "$DIR" com.android.signapk.SignApk "$@"
Submodule apks deleted from d4f4f07a15
Submodule cereal deleted from ab32956aaf
+1
View File
@@ -0,0 +1 @@
gen
+52
View File
@@ -0,0 +1,52 @@
PWD := $(shell pwd)
SRCS := log.capnp car.capnp mapd.capnp
GENS := gen/cpp/car.capnp.c++ gen/cpp/log.capnp.c++ gen/cpp/mapd.capnp.c++
UNAME_M ?= $(shell uname -m)
# only generate C++ for docker tests
ifneq ($(OPTEST),1)
GENS += gen/c/car.capnp.c gen/c/log.capnp.c gen/c/mapd.capnp.c gen/c/c++.capnp.h gen/c/java.capnp.h
# Dont build java on the phone...
ifeq ($(UNAME_M),x86_64)
GENS += gen/java/Car.java gen/java/Log.java
endif
endif
ifeq ($(UNAME_M),aarch64)
CAPNPC=PATH=$(PWD)/../phonelibs/capnp-cpp/aarch64/bin/:$$PATH capnpc
else
CAPNPC=capnpc
endif
.PHONY: all
all: $(GENS)
.PHONY: clean
clean:
rm -rf gen
gen/c/%.capnp.c: %.capnp
@echo "[ CAPNPC C ] $@"
mkdir -p gen/c/
$(CAPNPC) '$<' -o c:gen/c/
gen/cpp/%.capnp.c++: %.capnp
@echo "[ CAPNPC C++ ] $@"
mkdir -p gen/cpp/
$(CAPNPC) '$<' -o c++:gen/cpp/
gen/java/Car.java gen/java/Log.java: $(SRCS)
@echo "[ CAPNPC java ] $@"
mkdir -p gen/java/
$(CAPNPC) $^ -o java:gen/java
# c-capnproto needs some empty headers
gen/c/c++.capnp.h gen/c/java.capnp.h:
mkdir -p gen/c/
touch '$@'
+9
View File
@@ -0,0 +1,9 @@
import os
import capnp
CEREAL_PATH = os.path.dirname(os.path.abspath(__file__))
capnp.remove_import_hook()
log = capnp.load(os.path.join(CEREAL_PATH, "log.capnp"))
car = capnp.load(os.path.join(CEREAL_PATH, "car.capnp"))
mapd = capnp.load(os.path.join(CEREAL_PATH, "mapd.capnp"))
+332
View File
@@ -0,0 +1,332 @@
using Cxx = import "c++.capnp";
$Cxx.namespace("cereal");
using Java = import "java.capnp";
$Java.package("ai.comma.openpilot.cereal");
$Java.outerClassname("Car");
@0x8e2af1e708af8b8d;
# ******* events causing controls state machine transition *******
struct CarEvent @0x9b1657f34caf3ad3 {
name @0 :EventName;
enable @1 :Bool;
noEntry @2 :Bool;
warning @3 :Bool;
userDisable @4 :Bool;
softDisable @5 :Bool;
immediateDisable @6 :Bool;
preEnable @7 :Bool;
permanent @8 :Bool;
enum EventName @0xbaa8c5d505f727de {
# TODO: copy from error list
commIssue @0;
steerUnavailable @1;
brakeUnavailable @2;
gasUnavailable @3;
wrongGear @4;
doorOpen @5;
seatbeltNotLatched @6;
espDisabled @7;
wrongCarMode @8;
steerTempUnavailable @9;
reverseGear @10;
buttonCancel @11;
buttonEnable @12;
pedalPressed @13;
cruiseDisabled @14;
radarCommIssue @15;
dataNeeded @16;
speedTooLow @17;
outOfSpace @18;
overheat @19;
calibrationInProgress @20;
calibrationInvalid @21;
controlsMismatch @22;
pcmEnable @23;
pcmDisable @24;
noTarget @25;
radarFault @26;
modelCommIssue @27;
brakeHold @28;
parkBrake @29;
manualRestart @30;
lowSpeedLockout @31;
plannerError @32;
ipasOverride @33;
debugAlert @34;
}
}
# ******* main car state @ 100hz *******
# all speeds in m/s
struct CarState {
errorsDEPRECATED @0 :List(CarEvent.EventName);
events @13 :List(CarEvent);
# car speed
vEgo @1 :Float32; # best estimate of speed
aEgo @16 :Float32; # best estimate of acceleration
vEgoRaw @17 :Float32; # unfiltered speed from CAN sensors
yawRate @22 :Float32; # best estimate of yaw rate
standstill @18 :Bool;
wheelSpeeds @2 :WheelSpeeds;
# gas pedal, 0.0-1.0
gas @3 :Float32; # this is user + computer
gasPressed @4 :Bool; # this is user pedal only
# brake pedal, 0.0-1.0
brake @5 :Float32; # this is user pedal only
brakePressed @6 :Bool; # this is user pedal only
brakeLights @19 :Bool;
# steering wheel
steeringAngle @7 :Float32; # deg
steeringRate @15 :Float32; # deg/s
steeringTorque @8 :Float32; # TODO: standardize units
steeringPressed @9 :Bool; # if the user is using the steering wheel
# cruise state
cruiseState @10 :CruiseState;
# gear
gearShifter @14 :GearShifter;
# button presses
buttonEvents @11 :List(ButtonEvent);
leftBlinker @20 :Bool;
rightBlinker @21 :Bool;
genericToggle @23 :Bool;
# lock info
doorOpen @24 :Bool;
seatbeltUnlatched @25 :Bool;
# which packets this state came from
canMonoTimes @12: List(UInt64);
struct WheelSpeeds {
# optional wheel speeds
fl @0 :Float32;
fr @1 :Float32;
rl @2 :Float32;
rr @3 :Float32;
}
struct CruiseState {
enabled @0 :Bool;
speed @1 :Float32;
available @2 :Bool;
speedOffset @3 :Float32;
standstill @4 :Bool;
}
enum GearShifter {
unknown @0;
park @1;
drive @2;
neutral @3;
reverse @4;
sport @5;
low @6;
brake @7;
}
# send on change
struct ButtonEvent {
pressed @0 :Bool;
type @1 :Type;
enum Type {
unknown @0;
leftBlinker @1;
rightBlinker @2;
accelCruise @3;
decelCruise @4;
cancel @5;
altButton1 @6;
altButton2 @7;
altButton3 @8;
}
}
}
# ******* radar state @ 20hz *******
struct RadarState {
errors @0 :List(Error);
points @1 :List(RadarPoint);
# which packets this state came from
canMonoTimes @2 :List(UInt64);
enum Error {
commIssue @0;
fault @1;
}
# similar to LiveTracks
# is one timestamp valid for all? I think so
struct RadarPoint {
trackId @0 :UInt64; # no trackId reuse
# these 3 are the minimum required
dRel @1 :Float32; # m from the front bumper of the car
yRel @2 :Float32; # m
vRel @3 :Float32; # m/s
# these are optional and valid if they are not NaN
aRel @4 :Float32; # m/s^2
yvRel @5 :Float32; # m/s
# some radars flag measurements VS estimates
measured @6 :Bool;
}
}
# ******* car controls @ 100hz *******
struct CarControl {
# must be true for any actuator commands to work
enabled @0 :Bool;
active @7 :Bool;
gasDEPRECATED @1 :Float32;
brakeDEPRECATED @2 :Float32;
steeringTorqueDEPRECATED @3 :Float32;
actuators @6 :Actuators;
cruiseControl @4 :CruiseControl;
hudControl @5 :HUDControl;
struct Actuators {
# range from 0.0 - 1.0
gas @0: Float32;
brake @1: Float32;
# range from -1.0 - 1.0
steer @2: Float32;
steerAngle @3: Float32;
}
struct CruiseControl {
cancel @0: Bool;
override @1: Bool;
speedOverride @2: Float32;
accelOverride @3: Float32;
}
struct HUDControl {
speedVisible @0: Bool;
setSpeed @1: Float32;
lanesVisible @2: Bool;
leadVisible @3: Bool;
visualAlert @4: VisualAlert;
audibleAlert @5: AudibleAlert;
enum VisualAlert {
# these are the choices from the Honda
# map as good as you can for your car
none @0;
fcw @1;
steerRequired @2;
brakePressed @3;
wrongGear @4;
seatbeltUnbuckled @5;
speedTooHigh @6;
}
enum AudibleAlert {
# these are the choices from the Honda
# map as good as you can for your car
none @0;
beepSingle @1;
beepTriple @2;
beepRepeated @3;
chimeSingle @4;
chimeDouble @5;
chimeRepeated @6;
chimeContinuous @7;
}
}
}
# ****** car param ******
struct CarParams {
carName @0 :Text;
radarNameDEPRECATED @1 :Text;
carFingerprint @2 :Text;
enableSteer @3 :Bool;
enableGas @4 :Bool;
enableBrake @5 :Bool;
enableCruise @6 :Bool;
enableCamera @26 :Bool;
enableDsu @27 :Bool; # driving support unit
enableApgs @28 :Bool; # advanced parking guidance system
minEnableSpeed @17 :Float32;
safetyModel @18 :Int16;
safetyParam @41 :Int16;
steerMaxBP @19 :List(Float32);
steerMaxV @20 :List(Float32);
gasMaxBP @21 :List(Float32);
gasMaxV @22 :List(Float32);
brakeMaxBP @23 :List(Float32);
brakeMaxV @24 :List(Float32);
longPidDeadzoneBP @32 :List(Float32);
longPidDeadzoneV @33 :List(Float32);
enum SafetyModels {
# does NOT match board setting
noOutput @0;
honda @1;
toyota @2;
elm327 @3;
gm @4;
hondaBosch @5;
}
# 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
}
+28
View File
@@ -0,0 +1,28 @@
# Copyright (c) 2013-2015 Sandstorm Development Group, Inc. and contributors
# Licensed under the MIT License:
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
@0xc5f1af96651f70ea;
annotation package @0x9ee4c8f803b3b596 (file) : Text;
# Name of the package, such as "org.example.foo", in which the generated code will reside.
annotation outerClassname @0x9b066bb4881f7cd3 (file) : Text;
# Name of the outer class that will wrap the generated code.
+1576
View File
File diff suppressed because it is too large Load Diff
+18
View File
@@ -0,0 +1,18 @@
using Cxx = import "c++.capnp";
$Cxx.namespace("cereal");
using Java = import "java.capnp";
$Java.package("ai.comma.openpilot.cereal");
$Java.outerClassname("Map");
using Log = import "log.capnp";
@0xe1a6ab330ea7205f;
struct MapdRequest {
pos @0 :Log.ECEFPoint;
}
struct MapdResponse {
kfs @0 :List(Log.OrbKeyFrame);
}
-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")
-130
View File
@@ -1,130 +0,0 @@
import os
import binascii
import itertools
import re
import struct
import subprocess
import random
from cereal import log
NetworkType = log.ThermalData.NetworkType
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)
+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/"
-99
View File
@@ -1,99 +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", "ai.comma.plus.frame")
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_frame():
set_package_permissions()
system("am start -n ai.comma.plus.frame/.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")
appops_set("ai.comma.plus.offroad", "SU", "allow")
appops_set("ai.comma.plus.offroad", "WIFI_SCAN", "allow")
appops_set("ai.comma.plus.offroad", "READ_EXTERNAL_STORAGE", "allow")
appops_set("ai.comma.plus.offroad", "WRITE_EXTERNAL_STORAGE", "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)
-150
View File
@@ -1,150 +0,0 @@
import os
import numpy as np
import collections
from contextlib import closing
from common.file_helpers import mkdirs_exists_ok
class ColumnStoreReader():
def __init__(self, path, mmap=False, allow_pickle=False, direct_io=False):
if not (path and os.path.isdir(path)):
raise ValueError("Not a column store: {}".format(path))
self._path = os.path.realpath(path)
self._keys = os.listdir(self._path)
self._mmap = mmap
self._allow_pickle = allow_pickle
self._direct_io = direct_io
@property
def path(self):
return self._path
def close(self):
pass
def get(self, key):
try:
return self[key]
except KeyError:
return None
def keys(self):
return list(self._keys)
def iteritems(self):
for k in self:
yield (k, self[k])
def itervalues(self):
for k in self:
yield self[k]
def get_npy_path(self, key):
"""Gets a filesystem path for an npy file containing the specified array,
or none if the column store does not contain key.
"""
if key in self:
return os.path.join(self._path, key)
else:
return None
def __getitem__(self, key):
try:
path = os.path.join(self._path, key)
# TODO(mgraczyk): This implementation will need to change for zip.
if os.path.isdir(path):
return ColumnStoreReader(path)
else:
if self._mmap:
# note that direct i/o does nothing for mmap since file read/write interface is not used
ret = np.load(path, mmap_mode='r', allow_pickle=self._allow_pickle, fix_imports=False)
else:
if self._direct_io:
opener = lambda path, flags: os.open(path, os.O_RDONLY | os.O_DIRECT)
with open(path, 'rb', buffering=0, opener=opener) as f:
ret = np.load(f, allow_pickle=self._allow_pickle, fix_imports=False)
else:
ret = np.load(path, allow_pickle=self._allow_pickle, fix_imports=False)
if type(ret) == np.lib.npyio.NpzFile:
# if it's saved as compressed, it has arr_0 only in the file. deref this
return ret['arr_0']
else:
return ret
except IOError:
raise KeyError(key)
def __contains__(self, item):
try:
self[item]
return True
except KeyError:
return False
def __len__(self):
return len(self._keys)
def __bool__(self):
return bool(self._keys)
def __iter__(self):
return iter(self._keys)
def __str__(self):
return "ColumnStoreReader({})".format(str({k: "..." for k in self._keys}))
def __enter__(self): return self
def __exit__(self, type, value, traceback): self.close()
class ColumnStoreWriter():
def __init__(self, path, allow_pickle=False):
self._path = path
self._allow_pickle = allow_pickle
mkdirs_exists_ok(self._path)
def map_column(self, path, dtype, shape):
npy_path = os.path.join(self._path, path)
mkdirs_exists_ok(os.path.dirname(npy_path))
return np.lib.format.open_memmap(npy_path, mode='w+', dtype=dtype, shape=shape)
def add_column(self, path, data, dtype=None, compression=False, overwrite=False):
npy_path = os.path.join(self._path, path)
mkdirs_exists_ok(os.path.dirname(npy_path))
if overwrite:
f = open(npy_path, "wb")
else:
f = os.fdopen(os.open(npy_path, os.O_WRONLY | os.O_CREAT | os.O_EXCL), "wb")
with closing(f) as f:
data2 = np.array(data, copy=False, dtype=dtype)
if compression:
np.savez_compressed(f, data2)
else:
np.save(f, data2, allow_pickle=self._allow_pickle, fix_imports=False)
def add_group(self, group_name):
# TODO(mgraczyk): This implementation will need to change if we add zip or compression.
return ColumnStoreWriter(os.path.join(self._path, group_name))
def close(self):
pass
def __enter__(self): return self
def __exit__(self, type, value, traceback): self.close()
def _save_dict_as_column_store(values, writer):
for k, v in values.items():
if isinstance(v, collections.Mapping):
_save_dict_as_column_store(v, writer.add_group(k))
else:
writer.add_column(k, v)
def save_dict_as_column_store(values, output_path):
with ColumnStoreWriter(output_path) as writer:
_save_dict_as_column_store(values, writer)
-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,
)
-3
View File
@@ -1,3 +0,0 @@
# py2,3 compatiblity helpers
basestring = (str, bytes)
-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)
Executable
+220
View File
@@ -0,0 +1,220 @@
import re
import os
import struct
import bitstring
import sys
import numbers
from collections import namedtuple
def int_or_float(s):
# return number, trying to maintain int format
try:
return int(s)
except ValueError:
return float(s)
DBCSignal = namedtuple(
"DBCSignal", ["name", "start_bit", "size", "is_little_endian", "is_signed",
"factor", "offset", "tmin", "tmax", "units"])
class dbc(object):
def __init__(self, fn):
self.name, _ = os.path.splitext(os.path.basename(fn))
with open(fn) as f:
self.txt = f.read().split("\n")
self._warned_addresses = set()
# regexps from https://github.com/ebroecker/canmatrix/blob/master/canmatrix/importdbc.py
bo_regexp = re.compile(r"^BO\_ (\w+) (\w+) *: (\w+) (\w+)")
sg_regexp = re.compile(r"^SG\_ (\w+) : (\d+)\|(\d+)@(\d+)([\+|\-]) \(([0-9.+\-eE]+),([0-9.+\-eE]+)\) \[([0-9.+\-eE]+)\|([0-9.+\-eE]+)\] \"(.*)\" (.*)")
sgm_regexp = re.compile(r"^SG\_ (\w+) (\w+) *: (\d+)\|(\d+)@(\d+)([\+|\-]) \(([0-9.+\-eE]+),([0-9.+\-eE]+)\) \[([0-9.+\-eE]+)\|([0-9.+\-eE]+)\] \"(.*)\" (.*)")
# A dictionary which maps message ids to tuples ((name, size), signals).
# name is the ASCII name of the message.
# size is the size of the message in bytes.
# signals is a list signals contained in the message.
# signals is a list of DBCSignal in order of increasing start_bit.
self.msgs = {}
# lookup to bit reverse each byte
self.bits_index = [(i & ~0b111) + ((-i-1) & 0b111) for i in xrange(64)]
for l in self.txt:
l = l.strip()
if l.startswith("BO_ "):
# new group
dat = bo_regexp.match(l)
if dat is None:
print "bad BO", l
name = dat.group(2)
size = int(dat.group(3))
ids = int(dat.group(1), 0) # could be hex
if ids in self.msgs:
sys.exit("Duplicate address detected %d %s" % (ids, self.name))
self.msgs[ids] = ((name, size), [])
if l.startswith("SG_ "):
# new signal
dat = sg_regexp.match(l)
go = 0
if dat is None:
dat = sgm_regexp.match(l)
go = 1
if dat is None:
print "bad SG", l
sgname = dat.group(1)
start_bit = int(dat.group(go+2))
signal_size = int(dat.group(go+3))
is_little_endian = int(dat.group(go+4))==1
is_signed = dat.group(go+5)=='-'
factor = int_or_float(dat.group(go+6))
offset = int_or_float(dat.group(go+7))
tmin = int_or_float(dat.group(go+8))
tmax = int_or_float(dat.group(go+9))
units = dat.group(go+10)
self.msgs[ids][1].append(
DBCSignal(sgname, start_bit, signal_size, is_little_endian,
is_signed, factor, offset, tmin, tmax, units))
for msg in self.msgs.viewvalues():
msg[1].sort(key=lambda x: x.start_bit)
self.msg_name_to_address = {}
for address, m in self.msgs.items():
name = m[0][0]
self.msg_name_to_address[name] = address
def lookup_msg_id(self, msg_id):
if not isinstance(msg_id, numbers.Number):
msg_id = self.msg_name_to_address[msg_id]
return msg_id
def encode(self, msg_id, dd):
"""Encode a CAN message using the dbc.
Inputs:
msg_id: The message ID.
dd: A dictionary mapping signal name to signal data.
"""
msg_id = self.lookup_msg_id(msg_id)
# TODO: Stop using bitstring, which is super slow.
msg_def = self.msgs[msg_id]
size = msg_def[0][1]
bsf = bitstring.Bits(hex="00"*size)
for s in msg_def[1]:
ival = dd.get(s.name)
if ival is not None:
ival = (ival / s.factor) - s.offset
ival = int(round(ival))
# should pack this
if s.is_little_endian:
ss = s.start_bit
else:
ss = self.bits_index[s.start_bit]
if s.is_signed:
tbs = bitstring.Bits(int=ival, length=s.size)
else:
tbs = bitstring.Bits(uint=ival, length=s.size)
lpad = bitstring.Bits(bin="0b"+"0"*ss)
rpad = bitstring.Bits(bin="0b"+"0"*(8*size-(ss+s.size)))
tbs = lpad+tbs+rpad
bsf |= tbs
return bsf.tobytes()
def decode(self, x, arr=None, debug=False):
"""Decode a CAN message using the dbc.
Inputs:
x: A collection with elements (address, time, data), where address is
the CAN address, time is the bus time, and data is the CAN data as a
hex string.
arr: Optional list of signals which should be decoded and returned.
debug: True to print debugging statements.
Returns:
A tuple (name, data), where name is the name of the CAN message and data
is the decoded result. If arr is None, data is a dict of properties.
Otherwise data is a list of the same length as arr.
Returns (None, None) if the message could not be decoded.
"""
if arr is None:
out = {}
else:
out = [None]*len(arr)
msg = self.msgs.get(x[0])
if msg is None:
if x[0] not in self._warned_addresses:
#print("WARNING: Unknown message address {}".format(x[0]))
self._warned_addresses.add(x[0])
return None, None
name = msg[0][0]
if debug:
print name
blen = 8*len(x[2])
st = x[2].rjust(8, '\x00')
le, be = None, None
for s in msg[1]:
if arr is not None and s[0] not in arr:
continue
# big or little endian?
# see http://vi-firmware.openxcplatform.com/en/master/config/bit-numbering.html
if s[3] is False:
ss = self.bits_index[s[1]]
if be is None:
be = struct.unpack(">Q", st)[0]
x2_int = be
data_bit_pos = (blen - (ss + s[2]))
else:
if le is None:
le = struct.unpack("<Q", st)[0]
x2_int = le
ss = s[1]
data_bit_pos = ss
if data_bit_pos < 0:
continue
ival = (x2_int >> data_bit_pos) & ((1 << (s[2])) - 1)
if s[4] and (ival & (1<<(s[2]-1))): # signed
ival -= (1<<s[2])
# control the offset
ival = (ival * s[5]) + s[6]
#if debug:
# print "%40s %2d %2d %7.2f %s" % (s[0], s[1], s[2], ival, s[-1])
if arr is None:
out[s[0]] = ival
else:
out[arr.index(s[0])] = ival
return name, out
def get_signals(self, msg):
msg = self.lookup_msg_id(msg)
return [sgs.name for sgs in self.msgs[msg][1]]
if __name__ == "__main__":
from opendbc import DBC_PATH
dbc_test = dbc(os.path.join(DBC_PATH, sys.argv[1]))
print dbc_test.get_signals(0xe4)
-55
View File
@@ -1,55 +0,0 @@
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"
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()
try:
os.mkdir(tmpdir)
except OSError:
pass
fd = os.open(tmpdir, 0)
fcntl.flock(fd, fcntl.LOCK_EX)
try:
sys.path.append(tmpdir)
try:
mod = __import__(cache)
except Exception:
print("cache miss {0}".format(cache))
compile_code(cache, c_code, c_header, tmpdir, cflags, libraries)
mod = __import__(cache)
finally:
os.close(fd)
return mod.ffi, mod.lib
def compile_code(name, c_code, c_header, directory, cflags="", libraries=None):
if libraries is None:
libraries = []
ffibuilder = FFI()
ffibuilder.set_source(name, c_code, source_extension='.cpp', libraries=libraries)
ffibuilder.cdef(c_header)
os.environ['OPT'] = "-fwrapv -O2 -DNDEBUG -std=c++11"
os.environ['CFLAGS'] = cflags
ffibuilder.compile(verbose=True, debug=False, tmpdir=directory)
def wrap_compiled(name, directory):
sys.path.append(directory)
mod = __import__(name)
return mod.ffi, mod.lib
-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)
-10
View File
@@ -1,10 +0,0 @@
class FirstOrderFilter():
# first order filter
def __init__(self, x0, ts, dt):
self.k = (dt / ts) / (1. + dt / ts)
self.x = x0
def update(self, x):
self.x = (1. - self.k) * self.x + self.k * x
+126
View File
@@ -0,0 +1,126 @@
class HONDA:
CIVIC = "HONDA CIVIC 2016 TOURING"
ACURA_ILX = "ACURA ILX 2016 ACURAWATCH PLUS"
CRV = "HONDA CR-V 2016 TOURING"
ODYSSEY = "HONDA ODYSSEY 2018 EX-L"
ACURA_RDX = "ACURA RDX 2018 ACURAWATCH PLUS"
PILOT = "HONDA PILOT 2017 TOURING"
RIDGELINE = "HONDA RIDGELINE 2017 BLACK EDITION"
class TOYOTA:
PRIUS = "TOYOTA PRIUS 2017"
RAV4H = "TOYOTA RAV4 2017 HYBRID"
RAV4 = "TOYOTA RAV4 2017"
COROLLA = "TOYOTA COROLLA 2017"
LEXUS_RXH = "LEXUS RX HYBRID 2017"
class GM:
VOLT = "CHEVROLET VOLT PREMIER 2017"
_DEBUG_ADDRESS = {1880: 8} # reserved for debug purposes
_FINGERPRINTS = {
HONDA.ACURA_ILX: [{
1024L: 5, 513L: 6, 1027L: 5, 1029L: 8, 929L: 4, 1057L: 5, 777L: 8, 1034L: 5, 1036L: 8, 398L: 3, 399L: 7, 145L: 8, 660L: 8, 985L: 3, 923L: 2, 542L: 7, 773L: 7, 800L: 8, 432L: 7, 419L: 8, 420L: 8, 1030L: 5, 422L: 8, 808L: 8, 428L: 8, 304L: 8, 819L: 7, 821L: 5, 57L: 3, 316L: 8, 545L: 4, 464L: 8, 1108L: 8, 597L: 8, 342L: 6, 983L: 8, 344L: 8, 804L: 8, 1039L: 8, 476L: 4, 892L: 8, 490L: 8, 1064L: 7, 882L: 2, 884L: 7, 887L: 8, 888L: 8, 380L: 8, 1365L: 5,
# sent messages
0xe4: 5, 0x1fa: 8, 0x200: 6, 0x30c: 8, 0x33d: 5,
}],
HONDA.ACURA_RDX: [{
57L: 3, 145L: 8, 229L: 4, 308L: 5, 316L: 8, 342L: 6, 344L: 8, 380L: 8, 392L: 6, 398L: 3, 399L: 6, 404L: 4, 420L: 8, 422L: 8, 426L: 8, 432L: 7, 464L: 8, 474L: 5, 476L: 4, 487L: 4, 490L: 8, 506L: 8, 542L: 7, 545L: 4, 597L: 8, 660L: 8, 773L: 7, 777L: 8, 780L: 8, 800L: 8, 804L: 8, 808L: 8, 819L: 7, 821L: 5, 829L: 5, 882L: 2, 884L: 7, 887L: 8, 888L: 8, 892L: 8, 923L: 2, 929L: 4, 963L: 8, 965L: 8, 966L: 8, 967L: 8, 983L: 8, 985L: 3, 1024L: 5, 1027L: 5, 1029L: 8, 1033L: 5, 1034L: 5, 1036L: 8, 1039L: 8, 1057L: 5, 1064L: 7, 1108L: 8, 1365L: 5, 1424L: 5, 1729L: 1
}],
HONDA.CIVIC: [{
1024L: 5, 513L: 6, 1027L: 5, 1029L: 8, 777L: 8, 1036L: 8, 1039L: 8, 1424L: 5, 401L: 8, 148L: 8, 662L: 4, 985L: 3, 795L: 8, 773L: 7, 800L: 8, 545L: 6, 420L: 8, 806L: 8, 808L: 8, 1322L: 5, 427L: 3, 428L: 8, 304L: 8, 432L: 7, 57L: 3, 450L: 8, 929L: 8, 330L: 8, 1302L: 8, 464L: 8, 1361L: 5, 1108L: 8, 597L: 8, 470L: 2, 344L: 8, 804L: 8, 399L: 7, 476L: 7, 1633L: 8, 487L: 4, 892L: 8, 490L: 8, 493L: 5, 884L: 8, 891L: 8, 380L: 8, 1365L: 5,
# sent messages
0xe4: 5, 0x1fa: 8, 0x200: 6, 0x30c: 8, 0x33d: 5, 0x35e: 8, 0x39f: 8,
}],
HONDA.CRV: [{
57L: 3, 145L: 8, 316L: 8, 340L: 8, 342L: 6, 344L: 8, 380L: 8, 398L: 3, 399L: 6, 401L: 8, 420L: 8, 422L: 8, 426L: 8, 432L: 7, 464L: 8, 474L: 5, 476L: 4, 487L: 4, 490L: 8, 493L: 3, 507L: 1, 542L: 7, 545L: 4, 597L: 8, 660L: 8, 661L: 4, 773L: 7, 777L: 8, 800L: 8, 804L: 8, 808L: 8, 882L: 2, 884L: 7, 888L: 8, 891L: 8, 892L: 8, 923L: 2, 929L: 8, 983L: 8, 985L: 3, 1024L: 5, 1027L: 5, 1029L: 8, 1033L: 5, 1036L: 8, 1039L: 8, 1057L: 5, 1064L: 7, 1108L: 8, 1125L: 8, 1296L: 8, 1365L: 5, 1424L: 5, 1600L: 5, 1601L: 8,
# sent messages
0x194: 4, 0x1fa: 8, 0x30c: 8, 0x33d: 5,
}],
HONDA.ODYSSEY: [{
57L: 3, 148L: 8, 228L: 5, 229L: 4, 316L: 8, 342L: 6, 344L: 8, 380L: 8, 399L: 7, 411L: 5, 419L: 8, 420L: 8, 427L: 3, 432L: 7, 450L: 8, 463L: 8, 464L: 8, 476L: 4, 490L: 8, 506L: 8, 542L: 7, 545L: 6, 597L: 8, 662L: 4, 773L: 7, 777L: 8, 780L: 8, 795L: 8, 800L: 8, 804L: 8, 806L: 8, 808L: 8, 817L: 4, 819L: 7, 821L: 5, 825L: 4, 829L: 5, 837L: 5, 856L: 7, 862L: 8, 871L: 8, 881L: 8, 882L: 4, 884L: 8, 891L: 8, 892L: 8, 905L: 8, 923L: 2, 927L: 8, 929L: 8, 963L: 8, 965L: 8, 966L: 8, 967L: 8, 983L: 8, 985L: 3, 1029L: 8, 1036L: 8, 1052L: 8, 1064L: 7, 1088L: 8, 1089L: 8, 1092L: 1, 1108L: 8, 1110L: 8, 1125L: 8, 1296L: 8, 1302L: 8, 1600L: 5, 1601L: 8, 1612L: 5, 1613L: 5, 1614L: 5, 1615L: 8, 1616L: 5, 1619L: 5, 1623L: 5, 1668L: 5
},
# Odyssey Elite
{
57L: 3, 148L: 8, 228L: 5, 229L: 4, 304L: 8, 342L: 6, 344L: 8, 380L: 8, 399L: 7, 411L: 5, 419L: 8, 420L: 8, 427L: 3, 432L: 7, 440L: 8, 450L: 8, 463L: 8, 464L: 8, 476L: 4, 490L: 8, 506L: 8, 507L: 1, 542L: 7, 545L: 6, 597L: 8, 662L: 4, 773L: 7, 777L: 8, 780L: 8, 795L: 8, 800L: 8, 804L: 8, 806L: 8, 808L: 8, 817L: 4, 819L: 7, 821L: 5, 825L: 4, 829L: 5, 837L: 5, 856L: 7, 862L: 8, 871L: 8, 881L: 8, 882L: 4, 884L: 8, 891L: 8, 892L: 8, 905L: 8, 923L: 2, 927L: 8, 929L: 8, 963L: 8, 965L: 8, 966L: 8, 967L: 8, 983L: 8, 985L: 3, 1029L: 8, 1036L: 8, 1052L: 8, 1064L: 7, 1088L: 8, 1089L: 8, 1092L: 1, 1108L: 8, 1110L: 8, 1125L: 8, 1296L: 8, 1302L: 8, 1600L: 5, 1601L: 8, 1612L: 5, 1613L: 5, 1614L: 5, 1616L: 5, 1619L: 5, 1623L: 5, 1668L: 5
}],
HONDA.PILOT: [{
1600L: 5, 1027L: 5, 1668L: 5, 1029L: 8, 1601L: 8, 777L: 8, 891L: 8, 1036L: 8, 399L: 7, 1424L: 5, 145L: 8, 660L: 8, 985L: 3, 1616L: 5, 538L: 3, 795L: 8, 542L: 7, 773L: 7, 800L: 8, 545L: 5, 546L: 3, 419L: 8, 420L: 8, 422L: 8, 1064L: 7, 425L: 8, 426L: 8, 427L: 3, 432L: 7, 819L: 7, 308L: 5, 821L: 5, 57L: 3, 965L: 8, 316L: 8, 829L: 5, 1088L: 8, 1089L: 8, 963L: 8, 837L: 5, 966L: 8, 929L: 8, 780L: 8, 923L: 2, 1613L: 5, 334L: 8, 463L: 8, 464L: 8, 1618L: 5, 1108L: 8, 597L: 8, 342L: 6, 983L: 8, 856L: 7, 804L: 8, 1612L: 5, 476L: 4, 1125L: 8, 344L: 8, 1296L: 8, 379L: 8, 228L: 5, 229L: 4, 871L: 8, 892L: 8, 490L: 8, 808L: 8, 882L: 2, 884L: 7, 967L: 8, 506L: 8, 507L: 1, 380L: 8,
}],
HONDA.RIDGELINE: [{
57L: 3, 145L: 8, 228L: 5, 229L: 4, 308L: 5, 316L: 8, 339L: 7, 342L: 6, 344L: 8, 380L: 8, 392L: 6, 399L: 7, 419L: 8, 420L: 8, 422L: 8, 425L: 8, 426L: 8, 427L: 3, 432L: 7, 464L: 8, 471L: 3, 476L: 4, 490L: 8, 506L: 8, 545L: 5, 546L: 3, 597L: 8, 660L: 8, 773L: 7, 777L: 8, 780L: 8, 795L: 8, 800L: 8, 804L: 8, 808L: 8, 819L: 7, 821L: 5, 829L: 5, 871L: 8, 882L: 2, 884L: 7, 892L: 8, 923L: 2, 927L: 8, 929L: 8, 963L: 8, 965L: 8, 966L: 8, 967L: 8, 983L: 8, 985L: 3, 1027L: 5, 1029L: 8, 1036L: 8, 1039L: 8, 1064L: 7, 1088L: 8, 1089L: 8, 1108L: 8, 1125L: 8, 1296L: 8, 1365L: 5, 1424L: 5, 1600L: 5, 1601L: 8, 1613L: 5, 1616L: 5, 1618L: 5, 1668L: 5, 2015L: 3
}],
TOYOTA.RAV4: [{
36L: 8, 37L: 8, 170L: 8, 180L: 8, 186L: 4, 426L: 6, 452L: 8, 464L: 8, 466L: 8, 467L: 8, 547L: 8, 548L: 8, 552L: 4, 562L: 4, 608L: 8, 610L: 5, 643L: 7, 705L: 8, 725L: 2, 740L: 5, 800L: 8, 835L: 8, 836L: 8, 849L: 4, 869L: 7, 870L: 7, 871L: 2, 896L: 8, 897L: 8, 900L: 6, 902L: 6, 905L: 8, 911L: 8, 916L: 3, 918L: 7, 921L: 8, 933L: 8, 944L: 8, 945L: 8, 951L: 8, 955L: 4, 956L: 8, 979L: 2, 998L: 5, 999L: 7, 1000L: 8, 1001L: 8, 1005L: 2, 1008L: 2, 1014L: 8, 1017L: 8, 1041L: 8, 1042L: 8, 1043L: 8, 1044L: 8, 1056L: 8, 1059L: 1, 1114L: 8, 1161L: 8, 1162L: 8, 1163L: 8, 1176L: 8, 1177L: 8, 1178L: 8, 1179L: 8, 1180L: 8, 1181L: 8, 1190L: 8, 1191L: 8, 1192L: 8, 1196L: 8, 1227L: 8, 1228L: 8, 1235L: 8, 1237L: 8, 1263L: 8, 1264L: 8, 1279L: 8, 1408L: 8, 1409L: 8, 1410L: 8, 1552L: 8, 1553L: 8, 1554L: 8, 1555L: 8, 1556L: 8, 1557L: 8, 1561L: 8, 1562L: 8, 1568L: 8, 1569L: 8, 1570L: 8, 1571L: 8, 1572L: 8, 1584L: 8, 1589L: 8, 1592L: 8, 1593L: 8, 1595L: 8, 1596L: 8, 1597L: 8, 1600L: 8, 1656L: 8, 1664L: 8, 1728L: 8, 1745L: 8, 1779L: 8, 1904L: 8, 1912L: 8, 1990L: 8, 1998L: 8
}],
TOYOTA.RAV4H: [{
36L: 8, 37L: 8, 170L: 8, 180L: 8, 186L: 4, 296L: 8, 426L: 6, 452L: 8, 464L: 8, 466L: 8, 467L: 8, 547L: 8, 548L: 8, 550L: 8, 552L: 4, 560L: 7, 562L: 4, 581L: 5, 608L: 8, 610L: 5, 643L: 7, 705L: 8, 713L: 8, 725L: 2, 740L: 5, 800L: 8, 835L: 8, 836L: 8, 849L: 4, 869L: 7, 870L: 7, 871L: 2, 896L: 8, 897L: 8, 900L: 6, 902L: 6, 905L: 8, 911L: 8, 916L: 3, 918L: 7, 921L: 8, 933L: 8, 944L: 8, 945L: 8, 950L: 8, 951L: 8, 953L: 3, 955L: 8, 956L: 8, 979L: 2, 998L: 5, 999L: 7, 1000L: 8, 1001L: 8, 1005L: 2, 1008L: 2, 1014L: 8, 1017L: 8, 1041L: 8, 1042L: 8, 1043L: 8, 1044L: 8, 1056L: 8, 1059L: 1, 1114L: 8, 1161L: 8, 1162L: 8, 1163L: 8, 1176L: 8, 1177L: 8, 1178L: 8, 1179L: 8, 1180L: 8, 1181L: 8, 1184L: 8, 1185L: 8, 1186L: 8, 1190L: 8, 1191L: 8, 1192L: 8, 1196L: 8, 1197L: 8, 1198L: 8, 1199L: 8, 1212L: 8, 1227L: 8, 1228L: 8, 1232L: 8, 1235L: 8, 1237L: 8, 1263L: 8, 1264L: 8, 1279L: 8, 1408L: 8, 1409L: 8, 1410L: 8, 1552L: 8, 1553L: 8, 1554L: 8, 1555L: 8, 1556L: 8, 1557L: 8, 1561L: 8, 1562L: 8, 1568L: 8, 1569L: 8, 1570L: 8, 1571L: 8, 1572L: 8, 1584L: 8, 1589L: 8, 1592L: 8, 1593L: 8, 1595L: 8, 1596L: 8, 1597L: 8, 1600L: 8, 1656L: 8, 1664L: 8, 1728L: 8, 1745L: 8, 1779L: 8, 1904L: 8, 1912L: 8, 1990L: 8, 1998L: 8
}],
TOYOTA.PRIUS: [{
36L: 8, 37L: 8, 166L: 8, 170L: 8, 180L: 8, 295L: 8, 296L: 8, 426L: 6, 452L: 8, 466L: 8, 467L: 8, 550L: 8, 552L: 4, 560L: 7, 562L: 6, 581L: 5, 608L: 8, 610L: 8, 614L: 8, 643L: 7, 658L: 8, 713L: 8, 740L: 5, 742L: 8, 743L: 8, 800L: 8, 810L: 2, 814L: 8, 829L: 2, 830L: 7, 835L: 8, 836L: 8, 863L: 8, 869L: 7, 870L: 7, 871L: 2, 898L: 8, 900L: 6, 902L: 6, 905L: 8, 918L: 8, 921L: 8, 933L: 8, 944L: 8, 945L: 8, 950L: 8, 951L: 8, 953L: 8, 955L: 8, 956L: 8, 971L: 7, 975L: 5, 993L: 8, 998L: 5, 999L: 7, 1000L: 8, 1001L: 8, 1014L: 8, 1017L: 8, 1020L: 8, 1041L: 8, 1042L: 8, 1044L: 8, 1056L: 8, 1057L: 8, 1059L: 1, 1071L: 8, 1077L: 8, 1082L: 8, 1083L: 8, 1084L: 8, 1085L: 8, 1086L: 8, 1114L: 8, 1132L: 8, 1161L: 8, 1162L: 8, 1163L: 8, 1175L: 8, 1227L: 8, 1228L: 8, 1235L: 8, 1237L: 8, 1279L: 8, 1552L: 8, 1553L: 8, 1556L: 8, 1557L: 8, 1568L: 8, 1570L: 8, 1571L: 8, 1572L: 8, 1595L: 8, 1777L: 8, 1779L: 8, 1904L: 8, 1912L: 8, 1990L: 8, 1998L: 8
},
# Prius Prime
{
36L: 8, 37L: 8, 166L: 8, 170L: 8, 180L: 8, 295L: 8, 296L: 8, 426L: 6, 452L: 8, 466L: 8, 467L: 8, 550L: 8, 552L: 4, 560L: 7, 562L: 6, 581L: 5, 608L: 8, 610L: 8, 614L: 8, 643L: 7, 658L: 8, 713L: 8, 740L: 5, 742L: 8, 743L: 8, 800L: 8, 810L: 2, 814L: 8, 824L: 2, 829L: 2, 830L: 7, 835L: 8, 836L: 8, 863L: 8, 869L: 7, 870L: 7, 871L: 2,898L: 8, 900L: 6, 902L: 6, 905L: 8, 913L: 8, 918L: 8, 921L: 8, 933L: 8, 944L: 8, 945L: 8, 950L: 8, 951L: 8, 953L: 8, 955L: 8, 956L: 8, 971L: 7, 974L: 8, 975L: 5, 993L: 8, 998L: 5, 999L: 7, 1000L: 8, 1001L: 8, 1014L: 8, 1017L: 8, 1020L: 8, 1041L: 8, 1042L: 8, 1044L: 8, 1056L: 8, 1057L: 8, 1059L: 1, 1071L: 8, 1076L: 8, 1077L: 8, 1082L: 8, 1083L: 8, 1084L: 8, 1085L: 8, 1086L: 8, 1114L: 8, 1132L: 8, 1161L: 8, 1162L: 8, 1163L: 8, 1164L: 8, 1165L: 8, 1166L: 8, 1167L: 8, 1175L: 8, 1227L: 8, 1228L: 8, 1235L: 8, 1237L: 8, 1279L: 8, 1552L: 8, 1553L: 8, 1556L: 8, 1557L: 8, 1568L: 8, 1570L: 8, 1571L: 8, 1572L: 8, 1595L: 8, 1777L: 8, 1779L: 8, 1904L: 8, 1912L: 8, 1990L: 8, 1998L: 8
},
# Taiwanese Prius Prime
{
36L: 8, 37L: 8, 166L: 8, 170L: 8, 180L: 8, 295L: 8, 296L: 8, 426L: 6, 452L: 8, 466L: 8, 467L: 8, 550L: 8, 552L: 4, 560L: 7, 562L: 6, 581L: 5, 608L: 8, 610L: 8, 614L: 8, 643L: 7, 658L: 8, 713L: 8, 740L: 5, 742L: 8, 743L: 8, 800L: 8, 810L: 2, 814L: 8, 824L: 2, 829L: 2, 830L: 7, 835L: 8, 836L: 8, 845L: 5, 863L: 8, 869L: 7, 870L: 7, 871L: 2,898L: 8, 900L: 6, 902L: 6, 905L: 8, 913L: 8, 918L: 8, 921L: 8, 933L: 8, 944L: 8, 945L: 8, 950L: 8, 951L: 8, 953L: 8, 955L: 8, 956L: 8, 971L: 7, 974L: 8, 975L: 5, 993L: 8, 998L: 5, 999L: 7, 1000L: 8, 1001L: 8, 1005L: 2, 1014L: 8, 1017L: 8, 1020L: 8, 1041L: 8, 1042L: 8, 1044L: 8, 1056L: 8, 1057L: 8, 1059L: 1, 1071L: 8, 1076L: 8, 1077L: 8, 1082L: 8, 1083L: 8, 1084L: 8, 1085L: 8, 1086L: 8, 1114L: 8, 1132L: 8, 1161L: 8, 1162L: 8, 1163L: 8, 1164L: 8, 1165L: 8, 1166L: 8, 1167L: 8, 1175L: 8, 1227L: 8, 1228L: 8, 1235L: 8, 1237L: 8, 1264L: 8, 1279L: 8, 1552L: 8, 1553L: 8, 1556L: 8, 1557L: 8, 1568L: 8, 1570L: 8, 1571L: 8, 1572L: 8, 1595L: 8, 1777L: 8, 1779L: 8, 1904L: 8, 1912L: 8, 1990L: 8, 1998L: 8
}],
TOYOTA.COROLLA: [{
36: 8, 37: 8, 170: 8, 180: 8, 186: 4, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 547: 8, 548: 8, 552: 4, 608: 8, 610: 5, 643: 7, 705: 8, 740: 5, 800: 8, 835: 8, 836: 8, 849: 4, 869: 7, 870: 7, 871: 2, 896: 8, 897: 8, 900: 6, 902: 6, 905: 8, 911: 8, 916: 2, 921: 8, 933: 8, 944: 8, 945: 8, 951: 8, 955: 4, 956: 8, 979: 2, 992: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1017: 8, 1041: 8, 1042: 8, 1043: 8, 1044: 8, 1056: 8, 1059: 1, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1196: 8, 1227: 8, 1235: 8, 1279: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1561: 8, 1562: 8, 1568: 8, 1569: 8, 1570: 8, 1571: 8, 1572: 8, 1584: 8, 1589: 8, 1592: 8, 1596: 8, 1597: 8, 1600: 8, 1664: 8, 1728: 8, 1779: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8
},
# Corolla LE 2017
{
36: 8, 37: 8, 170: 8, 180: 8, 186: 4, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 547: 8, 548: 8, 552: 4, 608: 8, 610: 5, 643: 7, 705: 8, 740: 5, 800: 8, 835: 8, 836: 8, 849: 4, 869: 7, 870: 7, 871: 2, 896: 8, 897: 8, 900: 6, 902: 6, 905: 8, 911: 8, 916: 2, 921: 8, 933: 8, 944: 8, 945: 8, 951: 8, 955: 4, 956: 8, 979: 2, 998: 5, 999: 7, 1000: 8, 1001: 8, 1017: 8, 1041: 8, 1042: 8, 1043: 8, 1044: 8, 1056: 8, 1059: 1, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1196: 8, 1227: 8, 1235: 8, 1279: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1561: 8, 1562: 8, 1568: 8, 1569: 8, 1570: 8, 1571: 8, 1572: 8, 1592: 8, 1596: 8, 1597: 8, 1600: 8, 1664: 8, 1779: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8, 2016: 8, 2017: 8, 2018: 8, 2019: 8, 2020: 8, 2021: 8, 2022: 8, 2023: 8, 2024: 8
}],
TOYOTA.LEXUS_RXH: [{
36: 8, 37: 8, 166: 8, 170: 8, 180: 8, 295: 8, 296: 8, 426: 6, 452: 8, 466: 8, 467: 8, 550: 8, 552: 4, 560: 7, 562: 6, 581: 5, 608: 8, 610: 5, 643: 7, 658: 8, 713: 8, 740: 5, 742: 8, 743: 8, 800: 8, 810: 2, 812: 3, 814: 8, 830: 7, 835: 8, 836: 8, 845: 5, 863: 8, 869: 7, 870: 7, 871: 2, 898: 8, 900: 6, 902: 6, 905: 8, 913: 8, 918: 8, 921: 8, 933: 8, 944: 8, 945: 8, 950: 8, 951: 8, 953: 8, 955: 8, 956: 8, 971: 7, 975: 6, 993: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1005: 2, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1059: 1, 1063: 8, 1071: 8, 1077: 8, 1082: 8, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1227: 8, 1228: 8, 1235: 8, 1237: 8, 1264: 8, 1279: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1575: 8, 1595: 8, 1777: 8, 1779: 8, 1808: 8, 1810: 8, 1816: 8, 1818: 8, 1840: 8, 1848: 8, 1904: 8, 1912: 8, 1940: 8, 1941: 8, 1948: 8, 1949: 8, 1952: 8, 1956: 8, 1960: 8, 1964: 8, 1986: 8, 1990: 8, 1994: 8, 1998: 8, 2004: 8, 2012: 8
}],
GM.VOLT: [{
170: 8, 171: 8, 189: 7, 190: 6, 193: 8, 197: 8, 199: 4, 201: 8, 209: 7, 211: 2, 241: 6, 288: 5, 289: 8, 298: 8, 304: 1, 308: 4, 309: 8, 311: 8, 313: 8, 320: 3, 328: 1, 352: 5, 381: 6, 386: 8, 388: 8, 389: 2, 390: 7, 417: 7, 419: 1, 426: 7, 451: 8, 452: 8, 453: 6, 454: 8, 456: 8, 479: 3, 481: 7, 485: 8, 489: 8, 493: 8, 495: 4, 497: 8, 499: 3, 500: 6, 501: 8, 508: 8, 528: 4, 532: 6, 546: 7, 550: 8, 554: 3, 558: 8, 560: 8, 562: 8, 563: 5, 564: 5, 565: 5, 566: 5, 567: 3, 568: 1, 573: 1, 577: 8, 647: 3, 707: 8, 711: 6, 761: 7, 810: 8, 840: 5, 842: 5, 844: 8, 866: 4, 961: 8, 969: 8, 977: 8, 979: 7, 988: 6, 989: 8, 995: 7, 1001: 8, 1005: 6, 1009: 8, 1017: 8, 1019: 2, 1020: 8, 1105: 6, 1187: 4, 1217: 8, 1221: 5, 1223: 3, 1225: 7, 1227: 4, 1233: 8, 1249: 8, 1257: 6, 1265: 8, 1267: 1, 1273: 3, 1275: 3, 1280: 4, 1300: 8, 1322: 6, 1323: 4, 1328: 4, 1417: 8, 1601: 8, 1905: 7, 1906: 7, 1907: 7, 1910: 7, 1912: 7, 1922: 7, 1927: 7, 1928: 7, 2016: 8, 2020: 8, 2024: 8, 2028: 8
}],
}
# support additional internal only fingerprints
try:
from common.fingerprints_internal import add_additional_fingerprints
add_additional_fingerprints(_FINGERPRINTS)
except ImportError:
pass
def is_valid_for_fingerprint(msg, car_fingerprint):
adr = msg.address
return msg.src != 0 or (adr in car_fingerprint and car_fingerprint[adr] == len(msg.dat))
def eliminate_incompatible_cars(msg, candidate_cars):
"""Removes cars that could not have sent msg.
Inputs:
msg: A cereal/log CanData message from the car.
candidate_cars: A list of cars to consider.
Returns:
A list containing the subset of candidate_cars that could have sent msg.
"""
compatible_cars = []
for car_name in candidate_cars:
car_fingerprints = _FINGERPRINTS[car_name]
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()
-24
View File
@@ -1,24 +0,0 @@
import numpy as np
import os
import csv
path = os.path.dirname(os.path.abspath(__file__))
# locally cache cities from
# https://github.com/thampiman/reverse-geocoder
csv_file_name = path + '/rg_cities1000.csv'
# right hand drive is when the steering wheel is on the right of the car
# left hand traffic is when cars driver on the left side of the road
LHT_COUNTRIES = ['AU', 'IN', 'IE', 'JP', 'MU', 'MY', 'NZ', 'UK', 'ZA']
def get_city(lat, lon):
cities = np.array(list(csv.reader(open(csv_file_name))))[1:]
positions = cities[:,:2].astype(np.float32)
idx = np.argmin(np.linalg.norm((positions - np.array([lat, lon])), axis=1))
return cities[idx]
def is_lht(lat, lon):
city = get_city(lat, lon)
country = city[-1]
return country in LHT_COUNTRIES
File diff suppressed because it is too large Load Diff
-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")
+252
View File
@@ -0,0 +1,252 @@
# pylint: skip-file
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)
-12
View File
@@ -1,12 +0,0 @@
class lazy_property():
"""Defines a property whose value will be computed only once and as needed.
This can only be used on instance methods.
"""
def __init__(self, func):
self._func = func
def __get__(self, obj_self, cls):
value = self._func(obj_self)
setattr(obj_self, self._func.__name__, value)
return value
-284
View File
@@ -1,284 +0,0 @@
import os
import struct
import bisect
import numpy as np
import _io
import capnp
from cereal import log as capnp_log
class RawData():
def __init__(self, f):
self.f = _io.FileIO(f, 'rb')
self.lenn = struct.unpack("I", self.f.read(4))[0]
self.count = os.path.getsize(f) / (self.lenn+4)
def read(self, i):
self.f.seek((self.lenn+4)*i + 4)
return self.f.read(self.lenn)
def yuv420_to_rgb(raw, image_dim=None, swizzled=False):
def expand(x):
x = np.repeat(x, 2, axis=0)
return np.repeat(x, 2, axis=1)
if image_dim is None:
image_dim = (raw.shape[1]*2, raw.shape[2]*2)
swizzled = True
if not swizzled:
img_data = np.array(raw, copy=False, dtype=np.uint8)
uv_len = (image_dim[0]/2)*(image_dim[1]/2)
img_data_u = expand(img_data[image_dim[0]*image_dim[1]: \
image_dim[0]*image_dim[1]+uv_len]. \
reshape(image_dim[0]/2, image_dim[1]/2))
img_data_v = expand(img_data[image_dim[0]*image_dim[1]+uv_len: \
image_dim[0]*image_dim[1]+2*uv_len]. \
reshape(image_dim[0]/2, image_dim[1]/2))
img_data_y = img_data[0:image_dim[0]*image_dim[1]].reshape(image_dim)
else:
img_data_y = np.zeros(image_dim, dtype=np.uint8)
img_data_y[0::2, 0::2] = raw[0]
img_data_y[1::2, 0::2] = raw[1]
img_data_y[0::2, 1::2] = raw[2]
img_data_y[1::2, 1::2] = raw[3]
img_data_u = expand(raw[4])
img_data_v = expand(raw[5])
yuv = np.stack((img_data_y, img_data_u, img_data_v)).swapaxes(0,2).swapaxes(0,1)
yuv = yuv.astype(np.int16)
# http://maxsharabayko.blogspot.com/2016/01/fast-yuv-to-rgb-conversion-in-python-3.html
# according to ITU-R BT.709
yuv[:,:, 0] = yuv[:,:, 0].clip(16, 235).astype(yuv.dtype) - 16
yuv[:,:,1:] = yuv[:,:,1:].clip(16, 240).astype(yuv.dtype) - 128
A = np.array([[1.164, 0.000, 1.793],
[1.164, -0.213, -0.533],
[1.164, 2.112, 0.000]])
# our result
img = np.dot(yuv, A.T).clip(0, 255).astype('uint8')
return img
class YuvData():
def __init__(self, f, dim=(160,320)):
self.f = _io.FileIO(f, 'rb')
self.image_dim = dim
self.image_size = self.image_dim[0]/2 * self.image_dim[1]/2 * 6
self.count = os.path.getsize(f) / self.image_size
def read_frame(self, frame):
self.f.seek(self.image_size*frame)
raw = self.f.read(self.image_size)
return raw
def read_frames(self, range_start, range_len):
self.f.seek(self.image_size*range_start)
raw = self.f.read(self.image_size*range_len)
return raw
def read_frames_into(self, range_start, buf):
self.f.seek(self.image_size*range_start)
return self.f.readinto(buf)
def read(self, frame):
return yuv420_to_rgb(self.read_frame(frame), self.image_dim)
def close(self):
self.f.close()
def __enter__(self):
return self
def __exit__(self, type, value, traceback):
self.close()
class OneReader():
def __init__(self, base_path, goofy=False, segment_range=None):
self.base_path = base_path
route_name = os.path.basename(base_path)
self.rcamera_size = (304, 560)
if segment_range is None:
parent_path = os.path.dirname(base_path)
self.segment_nums = []
for p in os.listdir(parent_path):
if not p.startswith(route_name+"--"):
continue
self.segment_nums.append(int(p.rsplit("--", 1)[-1]))
if not self.segment_nums:
raise Exception("no route segments found")
self.segment_nums.sort()
self.segment_range = (self.segment_nums[0], self.segment_nums[-1])
else:
self.segment_range = segment_range
self.segment_nums = range(segment_range[0], segment_range[1]+1)
for i in self.segment_nums:
if not os.path.exists(base_path+"--"+str(i)):
raise Exception("missing segment in provided range")
# goofy data is broken with discontinuous logs
if goofy and (self.segment_range[0] != 0
or self.segment_nums != range(self.segment_range[0], self.segment_range[1]+1)):
raise Exception("goofy data needs all the segments for a route")
self.cur_seg = None
self.cur_seg_f = None
# index the frames
print("indexing frames {}...".format(self.segment_nums))
self.rcamera_encode_map = {} # frame_id -> (segment num, segment id, frame_time)
last_frame_id = -1
if goofy:
# goofy is goofy
frame_size = self.rcamera_size[0]*self.rcamera_size[1]*3/2
# find the encode id ranges for each segment by using the rcamera file size
segment_encode_ids = []
cur_encode_id = 0
for n in self.segment_nums:
camera_path = os.path.join(self.seg_path(n), "rcamera")
if not os.path.exists(camera_path):
# for goofy, missing camera files means a bad route
raise Exception("Missing camera file {}".format(camera_path))
camera_size = os.path.getsize(camera_path)
assert (camera_size % frame_size) == 0
num_frames = camera_size / frame_size
segment_encode_ids.append(cur_encode_id)
cur_encode_id += num_frames
last_encode_id = -1
# use the segment encode id map and frame events to build the frame index
for n in self.segment_nums:
log_path = os.path.join(self.seg_path(n), "rlog")
if os.path.exists(log_path):
with open(log_path, "rb") as f:
for evt in capnp_log.Event.read_multiple(f):
if evt.which() == 'frame':
if evt.frame.frameId < last_frame_id:
# a non-increasing frame id is bad route (eg visiond was restarted)
raise Exception("non-increasing frame id")
last_frame_id = evt.frame.frameId
seg_i = bisect.bisect_right(segment_encode_ids, evt.frame.encodeId)-1
assert seg_i >= 0
seg_num = self.segment_nums[seg_i]
seg_id = evt.frame.encodeId-segment_encode_ids[seg_i]
frame_time = evt.logMonoTime / 1.0e9
self.rcamera_encode_map[evt.frame.frameId] = (seg_num, seg_id,
frame_time)
last_encode_id = evt.frame.encodeId
if last_encode_id-cur_encode_id > 10:
# too many missing frames is a bad route (eg route from before encoder rotating worked)
raise Exception("goofy route is missing frames: {}, {}".format(
last_encode_id, cur_encode_id))
else:
# for harry data, build the index from encodeIdx events
for n in self.segment_nums:
log_path = os.path.join(self.seg_path(n), "rlog")
if os.path.exists(log_path):
with open(log_path, "rb") as f:
for evt in capnp_log.Event.read_multiple(f):
if evt.which() == 'encodeIdx' and evt.encodeIdx.type == 'bigBoxLossless':
frame_time = evt.logMonoTime / 1.0e9
self.rcamera_encode_map[evt.encodeIdx.frameId] = (
evt.encodeIdx.segmentNum, evt.encodeIdx.segmentId,
frame_time)
print("done")
# read the first event to find the start time
self.reset_to_seg(self.segment_range[0])
for evt in self.events():
if evt.which() != 'initData':
self.start_mono = evt.logMonoTime
break
self.reset_to_seg(self.segment_range[0])
def seg_path(self, num):
return self.base_path+"--"+str(num)
def reset_to_seg(self, seg):
self.cur_seg = seg
if self.cur_seg_f:
self.cur_seg_f.close()
self.cur_seg_f = None
def seek_ts(self, ts):
seek_seg = int(ts/60)
if seek_seg < self.segment_range[0] or seek_seg > self.segment_range[1]:
raise ValueError
self.reset_to_seg(seek_seg)
target_mono = self.start_mono + int(ts*1e9)
for evt in self.events():
if evt.logMonoTime >= target_mono:
break
def read_event(self):
while True:
if self.cur_seg > self.segment_range[1]:
return None
if self.cur_seg_f is None:
log_path = os.path.join(self.seg_path(self.cur_seg), "rlog")
if not os.path.exists(log_path):
print("missing log file!", log_path)
self.cur_seg += 1
continue
self.cur_seg_f = open(log_path, "rb")
try:
return capnp_log.Event.read(self.cur_seg_f)
except capnp.lib.capnp.KjException as e:
if 'EOF' in str(e): # dumb, but pycapnp does this too
self.cur_seg_f.close()
self.cur_seg_f = None
self.cur_seg += 1
else:
raise
def events(self):
while True:
r = self.read_event()
if r is None:
break
yield r
def read_frame(self, frame_id):
encode_idx = self.rcamera_encode_map.get(frame_id)
if encode_idx is None:
return None
seg_num, seg_id, _ = encode_idx
camera_path = os.path.join(self.seg_path(seg_num), "rcamera")
if not os.path.exists(camera_path):
return None
with YuvData(camera_path, self.rcamera_size) as data:
return data.read_frame(seg_id)
def close(self):
if self.cur_seg_f is not None:
self.cur_seg_f.close()
def __enter__(self):
return self
def __exit__(self, type, value, traceback):
self.close()
-92
View File
@@ -1,92 +0,0 @@
import sys
import json
# pip2 install msgpack-python
import msgpack
import zlib
import os
import logging
from Crypto.Cipher import AES
ext = ".gz"
SWAG = '\xde\xe2\x11\x15VVC\xf2\x8ep\xd7\xe4\x87\x8d,9'
def compress_json(in_file, out_file):
logging.debug("compressing %s -> %s", in_file, out_file)
errors = 0
good = []
last_can_time = 0
with open(in_file, 'r') as inf:
for ln in inf:
ln = ln.rstrip()
if not ln: continue
try:
ll = json.loads(ln)
except ValueError:
errors += 1
continue
if ll is None or ll[0] is None:
continue
if ll[0][1] == 1:
# no CAN in hex
ll[1][2] = ll[1][2].decode("hex")
# relativize the CAN timestamps
this_can_time = ll[1][1]
ll[1] = [ll[1][0], this_can_time - last_can_time, ll[1][2]]
last_can_time = this_can_time
good.append(ll)
logging.debug("compressing %s -> %s, read done", in_file, out_file)
data = msgpack.packb(good)
data_compressed = zlib.compress(data)
# zlib doesn't care about this
data_compressed += "\x00" * (16 - len(data_compressed)%16)
aes = AES.new(SWAG, AES.MODE_CBC, "\x00"*16)
data_encrypted = aes.encrypt(data_compressed)
with open(out_file, "wb") as outf:
outf.write(data_encrypted)
logging.debug("compressing %s -> %s, write done", in_file, out_file)
return errors
def decompress_json_internal(data_encrypted):
aes = AES.new(SWAG, AES.MODE_CBC, "\x00"*16)
data_compressed = aes.decrypt(data_encrypted)
data = zlib.decompress(data_compressed)
msgs = msgpack.unpackb(data)
good = []
last_can_time = 0
for ll in msgs:
if ll[0][1] == 1:
# back into hex
ll[1][2] = ll[1][2].encode("hex")
# derelativize CAN timestamps
last_can_time += ll[1][1]
ll[1] = [ll[1][0], last_can_time, ll[1][2]]
good.append(ll)
return good
def decompress_json(in_file, out_file):
logging.debug("decompressing %s -> %s", in_file, out_file)
f = open(in_file)
data_encrypted = f.read()
f.close()
good = decompress_json_internal(data_encrypted)
out = '\n'.join(map(lambda x: json.dumps(x), good)) + "\n"
logging.debug("decompressing %s -> %s, writing", in_file, out_file)
f = open(out_file, 'w')
f.write(out)
f.close()
logging.debug("decompressing %s -> %s, write finished", in_file, out_file)
if __name__ == "__main__":
for dat in sys.argv[1:]:
print(dat)
compress_json(dat, "/tmp/out"+ext)
decompress_json("/tmp/out"+ext, "/tmp/test")
os.system("diff "+dat+" /tmp/test")
+25 -73
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
@@ -20,7 +18,7 @@ def json_robust_dumps(obj):
class NiceOrderedDict(OrderedDict):
def __str__(self):
return json_robust_dumps(self)
return '{'+', '.join("%r: %r" % p for p in self.iteritems())+'}'
class SwagFormatter(logging.Formatter):
def __init__(self, swaglogger):
@@ -64,10 +62,6 @@ class SwagFormatter(logging.Formatter):
def format(self, record):
return json_robust_dumps(self.format_dict(record))
class SwagErrorFilter(logging.Filter):
def filter(self, record):
return record.levelno < logging.ERROR
_tmpfunc = lambda: 0
_srcfile = os.path.normcase(_tmpfunc.__code__.co_filename)
@@ -80,6 +74,28 @@ class SwagLogger(logging.Logger):
self.log_local = local()
self.log_local.ctx = {}
def findCaller(self):
"""
Find the stack frame of the caller so that we can note the source
file name, line number and function name.
"""
# f = currentframe()
f = sys._getframe(3)
#On some versions of IronPython, currentframe() returns None if
#IronPython isn't run with -X:Frames.
if f is not None:
f = f.f_back
rv = "(unknown file)", 0, "(unknown function)"
while hasattr(f, "f_code"):
co = f.f_code
filename = os.path.normcase(co.co_filename)
if filename in (logging._srcfile, _srcfile):
f = f.f_back
continue
rv = (co.co_filename, f.f_lineno, co.co_name)
break
return rv
def local_ctx(self):
try:
return self.log_local.ctx
@@ -112,79 +128,15 @@ class SwagLogger(logging.Logger):
if args:
evt['args'] = args
evt.update(kwargs)
ctx = self.get_ctx()
if ctx:
evt['ctx'] = self.get_ctx()
if 'error' in kwargs:
self.error(evt)
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
self.info(evt)
if __name__ == "__main__":
log = SwagLogger()
stdout_handler = logging.StreamHandler(sys.stdout)
stdout_handler.setLevel(logging.INFO)
stdout_handler.addFilter(SwagErrorFilter())
log.addHandler(stdout_handler)
stderr_handler = logging.StreamHandler(sys.stderr)
stderr_handler.setLevel(logging.ERROR)
log.addHandler(stderr_handler)
log.info("asdasd %s", "a")
log.info({'wut': 1})
log.warning("warning")
log.error("error")
log.critical("critical")
log.event("test", x="y")
with log.ctx():
stdout_handler.setFormatter(SwagFormatter(log))
stderr_handler.setFormatter(SwagFormatter(log))
log.bind(user="some user")
log.info("in req")
print("")
log.warning("warning")
print("")
log.error("error")
print("")
log.critical("critical")
print("")
log.event("do_req", a=1, b="c")
log.event("do_req")
+16 -8
View File
@@ -1,21 +1,29 @@
def int_rnd(x):
return int(round(x))
def clip(x, lo, hi):
return max(lo, min(hi, x))
def interp(x, xp, fp):
N = len(xp)
def get_interp(xv):
if not hasattr(x, '__iter__'):
hi = 0
while hi < N and xv > xp[hi]:
while hi < N and x > xp[hi]:
hi += 1
low = hi - 1
return fp[-1] if hi == N and xv > xp[low] else (
return fp[-1] if hi == N and x > xp[low] 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)
(x - xp[low]) * (fp[hi] - fp[low]) / (xp[hi] - xp[low]) + fp[low])
def mean(x):
return sum(x) / len(x)
result = []
for v in x:
hi = 0
while hi < N and v > xp[hi]:
hi += 1
low = hi - 1
result.append(fp[-1] if hi == N and v > xp[low] else (fp[
0] if hi == 0 else (v - xp[low]) * (fp[hi] - fp[low]) / (xp[hi] - xp[low]
) + fp[low]))
return result
-66
View File
@@ -1,66 +0,0 @@
import bisect
import numpy as np
from scipy.interpolate import interp1d
def deep_interp_0_fast(dx, x, y):
FIX = False
if len(y.shape) == 1:
y = y[:, None]
FIX = True
ret = np.zeros((dx.shape[0], y.shape[1]))
index = list(x)
for i in range(dx.shape[0]):
idx = bisect.bisect_left(index, dx[i])
if idx == x.shape[0]:
idx = x.shape[0] - 1
ret[i] = y[idx]
if FIX:
return ret[:, 0]
else:
return ret
def running_mean(x, N):
cumsum = np.cumsum(np.insert(x, [0]*(int(N/2)) + [-1]*(N-int(N/2)), [x[0]]*int(N/2) + [x[-1]]*(N-int(N/2))))
return (cumsum[N:] - cumsum[:-N]) / N
def deep_interp_np(x, xp, fp):
x = np.atleast_1d(x)
xp = np.array(xp)
if len(xp) < 2:
return np.repeat(fp, len(x), axis=0)
if min(np.diff(xp)) < 0:
raise RuntimeError('Bad x array for interpolation')
j = np.searchsorted(xp, x) - 1
j = np.clip(j, 0, len(xp)-2)
d = np.divide(x - xp[j], xp[j + 1] - xp[j], out=np.ones_like(x, dtype=np.float64), where=xp[j + 1] - xp[j] != 0)
vals_interp = (fp[j].T*(1 - d)).T + (fp[j + 1].T*d).T
if len(vals_interp) == 1:
return vals_interp[0]
else:
return vals_interp
def clipping_deep_interp(x, xp, fp):
if len(xp) < 2:
return deep_interp_np(x, xp, fp)
bad_idx = np.where(np.diff(xp) < 0)[0]
if len(bad_idx) > 0:
if bad_idx[0] ==1:
return np.zeros([] + list(fp.shape[1:]))
return deep_interp_np(x, xp[:bad_idx[0]], fp[:bad_idx[0]])
else:
return deep_interp_np(x, xp, fp)
def deep_interp(dx, x, y, kind="slinear"):
return interp1d(
x, y,
axis=0,
kind=kind,
bounds_error=False,
fill_value="extrapolate",
assume_sorted=True)(dx)
+60 -141
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.
@@ -27,9 +27,7 @@ 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:
@@ -38,71 +36,47 @@ def mkdirs_exists_ok(path):
if not os.path.isdir(path):
raise
class TxType(Enum):
PERSISTENT = 1
PERSISTANT = 1
CLEAR_ON_MANAGER_START = 2
CLEAR_ON_PANDA_DISCONNECT = 3
CLEAR_ON_CAR_START = 3
class UnknownKeyName(Exception):
pass
keys = {
"AccessToken": [TxType.PERSISTENT],
"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],
"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],
"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],
"LastUpdateTime": [TxType.PERSISTENT],
"LimitSetSpeed": [TxType.PERSISTENT],
"LimitSetSpeedNeural": [TxType.PERSISTENT],
"LiveParameters": [TxType.PERSISTENT],
"LongitudinalControl": [TxType.PERSISTENT],
"OpenpilotEnabledToggle": [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],
"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],
}
# written: manager
# read: loggerd, uploaderd, baseui
"DongleId": TxType.PERSISTANT,
"AccessToken": TxType.PERSISTANT,
"Version": TxType.PERSISTANT,
"GitCommit": TxType.PERSISTANT,
"GitBranch": TxType.PERSISTANT,
"GitRemote": TxType.PERSISTANT,
# written: baseui
# read: ui, controls
"IsMetric": TxType.PERSISTANT,
"IsRearViewMirror": TxType.PERSISTANT,
"IsFcwEnabled": TxType.PERSISTANT,
"HasAcceptedTerms": TxType.PERSISTANT,
"IsUploadVideoOverCellularEnabled": TxType.PERSISTANT,
# written: visiond
# read: visiond, controlsd
"CalibrationParams": TxType.PERSISTANT,
# written: visiond
# read: visiond, ui
"CloudCalibration": TxType.PERSISTANT,
# written: controlsd
# read: radard
"CarParams": TxType.CLEAR_ON_CAR_START,
"Passive": TxType.PERSISTANT,
"DoUninstall": TxType.CLEAR_ON_MANAGER_START,
"ShouldDoUpdate": TxType.CLEAR_ON_MANAGER_START,
"IsUpdateAvailable": TxType.PERSISTANT,
"RecordFront": TxType.PERSISTANT,
}
def fsync_dir(path):
fd = os.open(path, os.O_RDONLY)
@@ -112,7 +86,7 @@ def fsync_dir(path):
os.close(fd)
class FileLock():
class FileLock(object):
def __init__(self, path, create):
self._path = path
self._create = create
@@ -128,7 +102,7 @@ class FileLock():
self._fd = None
class DBAccessor():
class DBAccessor(object):
def __init__(self, path):
self._path = path
self._vals = None
@@ -289,112 +263,57 @@ class DBWriter(DBAccessor):
self._lock = None
def read_db(params_path, key):
path = "%s/d/%s" % (params_path, key)
try:
with open(path, "rb") as f:
return f.read()
except IOError:
return None
def write_db(params_path, key, value):
if isinstance(value, str):
value = value.encode('utf8')
class JSDB(object):
def __init__(self, fn):
self._fn = fn
prev_umask = os.umask(0)
lock = FileLock(params_path+"/.lock", True)
lock.acquire()
try:
tmp_path = tempfile.mktemp(prefix=".tmp", dir=params_path)
with open(tmp_path, "wb") as f:
f.write(value)
f.flush()
os.fsync(f.fileno())
path = "%s/d/%s" % (params_path, key)
os.rename(tmp_path, path)
fsync_dir(os.path.dirname(path))
finally:
os.umask(prev_umask)
lock.release()
class Params():
def __init__(self, db=PARAMS):
self.db = db
# create the database if it doesn't exist...
if not os.path.exists(self.db+"/d"):
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):
def begin(self, write=False):
if write:
return DBWriter(self.db)
return DBWriter(self._fn)
else:
return DBReader(self.db)
return DBReader(self._fn)
class Params(object):
def __init__(self, db='/data/params'):
self.env = JSDB(db)
def _clear_keys_with_type(self, tx_type):
with self.transaction(write=True) as txn:
with self.env.begin(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:
with self.env.begin(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)
while 1:
ret = read_db(self.db, key)
with self.env.begin() as txn:
ret = txn.get(key)
if not block or ret is not None:
break
# is polling really the best we can do?
time.sleep(0.05)
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
with self.env.begin(write=True) as txn:
txn.put(key, dat)
print "set", key
if __name__ == "__main__":
params = Params()
@@ -404,11 +323,11 @@ if __name__ == "__main__":
for k in keys:
pp = params.get(k)
if pp is None:
print("%s is None" % k)
print k, "is None"
elif all(ord(c) < 128 and ord(c) >= 32 for c in pp):
print("%s = %s" % (k, pp))
print k, pp
else:
print("%s = %s" % (k, pp.encode("hex")))
print k, pp.encode("hex")
# Test multiprocess:
# seq 0 100000 | xargs -P20 -I{} python common/params.py DongleId {} && sleep 0.05
-163
View File
@@ -1,163 +0,0 @@
#!/usr/bin/env python3
# Copyright (C) 2016 Sixten Bergman
# License WTFPL
#
# This program is free software. It comes without any warranty, to the extent
# permitted by applicable law.
# You can redistribute it and/or modify it under the terms of the Do What The
# Fuck You Want To Public License, Version 2, as published by Sam Hocevar. See
# http://www.wtfpl.net/ for more details.
#
# note that the function peakdetect is derived from code which was released to
# public domain see: http://billauer.co.il/peakdet.html
#
from math import log
import numpy as np
__all__ = ["peakdetect"]
def _datacheck_peakdetect(x_axis, y_axis):
if x_axis is None:
x_axis = range(len(y_axis))
if len(y_axis) != len(x_axis):
raise ValueError("Input vectors y_axis and x_axis must have same length")
#needs to be a numpy array
y_axis = np.array(y_axis)
x_axis = np.array(x_axis)
return x_axis, y_axis
def _pad(fft_data, pad_len):
"""
Pads fft data to interpolate in time domain
keyword arguments:
fft_data -- the fft
pad_len -- By how many times the time resolution should be increased by
return: padded list
"""
length = len(fft_data)
n = _n(length * pad_len)
fft_data = list(fft_data)
return fft_data[:length // 2] + [0] * (2**n-length) + fft_data[length // 2:]
def _n(x):
"""
Find the smallest value for n, which fulfils 2**n >= x
keyword arguments:
x -- the value, which 2**n must surpass
return: the integer n
"""
return int(log(x)/log(2)) + 1
def peakdetect(y_axis, x_axis=None, lookahead=200, delta=0):
"""
Converted from/based on a MATLAB script at:
http://billauer.co.il/peakdet.html
function for detecting local maxima and minima in a signal.
Discovers peaks by searching for values which are surrounded by lower
or larger values for maxima and minima respectively
keyword arguments:
y_axis -- A list containing the signal over which to find peaks
x_axis -- A x-axis whose values correspond to the y_axis list and is used
in the return to specify the position of the peaks. If omitted an
index of the y_axis is used.
(default: None)
lookahead -- distance to look ahead from a peak candidate to determine if
it is the actual peak
(default: 200)
'(samples / period) / f' where '4 >= f >= 1.25' might be a good value
delta -- this specifies a minimum difference between a peak and
the following points, before a peak may be considered a peak. Useful
to hinder the function from picking up false peaks towards to end of
the signal. To work well delta should be set to delta >= RMSnoise * 5.
(default: 0)
When omitted delta function causes a 20% decrease in speed.
When used Correctly it can double the speed of the function
return: two lists [max_peaks, min_peaks] containing the positive and
negative peaks respectively. Each cell of the lists contains a tuple
of: (position, peak_value)
to get the average peak value do: np.mean(max_peaks, 0)[1] on the
results to unpack one of the lists into x, y coordinates do:
x, y = zip(*max_peaks)
"""
max_peaks = []
min_peaks = []
dump = [] # Used to pop the first hit which almost always is false
# check input data
x_axis, y_axis = _datacheck_peakdetect(x_axis, y_axis)
# store data length for later use
length = len(y_axis)
#perform some checks
if lookahead < 1:
raise ValueError("Lookahead must be '1' or above in value")
if not (np.isscalar(delta) and delta >= 0):
raise ValueError("delta must be a positive number")
#maxima and minima candidates are temporarily stored in
#mx and mn respectively
mn, mx = np.Inf, -np.Inf
#Only detect peak if there is 'lookahead' amount of points after it
for index, (x, y) in enumerate(zip(x_axis[:-lookahead],
y_axis[:-lookahead])):
if y > mx:
mx = y
mxpos = x
if y < mn:
mn = y
mnpos = x
####look for max####
if y < mx-delta and mx != np.Inf:
#Maxima peak candidate found
#look ahead in signal to ensure that this is a peak and not jitter
if y_axis[index:index+lookahead].max() < mx:
max_peaks.append([mxpos, mx])
dump.append(True)
#set algorithm to only find minima now
mx = np.Inf
mn = np.Inf
if index+lookahead >= length:
#end is within lookahead no more peaks can be found
break
continue
#else: #slows shit down this does
# mx = ahead
# mxpos = x_axis[np.where(y_axis[index:index+lookahead]==mx)]
####look for min####
if y > mn+delta and mn != -np.Inf:
#Minima peak candidate found
#look ahead in signal to ensure that this is a peak and not jitter
if y_axis[index:index+lookahead].min() > mn:
min_peaks.append([mnpos, mn])
dump.append(False)
#set algorithm to only find maxima now
mn = -np.Inf
mx = -np.Inf
if index+lookahead >= length:
#end is within lookahead no more peaks can be found
break
#else: #slows shit down this does
# mn = ahead
# mnpos = x_axis[np.where(y_axis[index:index+lookahead]==mn)]
#Remove the false hit on the first value of the y_axis
try:
if dump[0]:
max_peaks.pop(0)
else:
min_peaks.pop(0)
del dump
except IndexError:
#no peaks were found, should the function return empty lists?
pass
return [max_peaks, min_peaks]
+5 -5
View File
@@ -1,6 +1,6 @@
import time
class Profiler():
class Profiler(object):
def __init__(self, enabled=False):
self.enabled = enabled
self.cp = {}
@@ -36,11 +36,11 @@ class Profiler():
if not self.enabled:
return
self.iter += 1
print("******* Profiling *******")
print "******* Profiling *******"
for n, ms in sorted(self.cp.items(), key=lambda x: -x[1]):
if n in self.cp_ignored:
print("%30s: %7.2f percent: %3.0f IGNORED" % (n, ms*1000.0, ms/self.tot*100))
print "%30s: %7.2f percent: %3.0f" % (n, ms*1000.0, ms/self.tot*100), " IGNORED"
else:
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))
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)
+50 -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,12 @@ 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
if __name__ == "__main__":
print sec_since_boot()
-78
View File
@@ -1,78 +0,0 @@
import os
import numpy as np
import random
class SamplingBuffer():
def __init__(self, fn, size, write=False):
self._fn = fn
self._write = write
if self._write:
self._f = open(self._fn, "ab")
else:
self._f = open(self._fn, "rb")
self._size = size
self._refresh()
def _refresh(self):
self.cnt = os.path.getsize(self._fn) / self._size
@property
def count(self):
self._refresh()
return self.cnt
def _fetch_one(self, x):
assert self._write == False
self._f.seek(x*self._size)
return self._f.read(self._size)
def sample(self, count, indices = None):
if indices == None:
cnt = self.count
assert cnt != 0
indices = map(lambda x: random.randint(0, cnt-1), range(count))
return map(self._fetch_one, indices)
def write(self, dat):
assert self._write == True
assert (len(dat) % self._size) == 0
self._f.write(dat)
self._f.flush()
class NumpySamplingBuffer():
def __init__(self, fn, size, dtype, write=False):
self._size = size
self._dtype = dtype
self._buf = SamplingBuffer(fn, len(np.zeros(size, dtype=dtype).tobytes()), write)
@property
def count(self):
return self._buf.count
def write(self, dat):
self._buf.write(dat.tobytes())
def sample(self, count, indices = None):
return np.fromstring(''.join(self._buf.sample(count, indices)), dtype=self._dtype).reshape([count]+list(self._size))
# TODO: n IOPS needed where n is the Multi
class MultiNumpySamplingBuffer():
def __init__(self, fn, npa, write=False):
self._bufs = []
for i,n in enumerate(npa):
self._bufs.append(NumpySamplingBuffer(fn + ("_%d" % i), n[0], n[1], write))
def write(self, dat):
for b,x in zip(self._bufs, dat):
b.write(x)
@property
def count(self):
return min(map(lambda x: x.count, self._bufs))
def sample(self, count):
cnt = self.count
assert cnt != 0
indices = map(lambda x: random.randint(0, cnt-1), range(count))
return map(lambda x: x.sample(count, indices), self._bufs)
-63
View File
@@ -1,63 +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 __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, max_trackable)
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():
-94
View File
@@ -1,94 +0,0 @@
import numpy as np
_DESC_FMT = """
{} (n={}):
MEAN={}
VAR={}
MIN={}
MAX={}
"""
class StatTracker():
def __init__(self, name):
self._name = name
self._mean = 0.
self._var = 0.
self._n = 0
self._min = -float("-inf")
self._max = -float("inf")
@property
def mean(self):
return self._mean
@property
def var(self):
return (self._n * self._var) / (self._n - 1.)
@property
def min(self):
return self._min
@property
def max(self):
return self._max
def update(self, samples):
# https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Parallel_algorithm
data = samples.reshape(-1)
n_a = data.size
mean_a = np.mean(data)
var_a = np.var(data, ddof=0)
n_b = self._n
mean_b = self._mean
delta = mean_b - mean_a
m_a = var_a * (n_a - 1)
m_b = self._var * (n_b - 1)
m2 = m_a + m_b + delta**2 * n_a * n_b / (n_a + n_b)
self._var = m2 / (n_a + n_b)
self._mean = (n_a * mean_a + n_b * mean_b) / (n_a + n_b)
self._n = n_a + n_b
self._min = min(self._min, np.min(data))
self._max = max(self._max, np.max(data))
def __str__(self):
return _DESC_FMT.format(self._name, self._n, self._mean, self.var, self._min,
self._max)
# FIXME(mgraczyk): The variance computation does not work with 1 sample batches.
class VectorStatTracker(StatTracker):
def __init__(self, name, dim):
self._name = name
self._mean = np.zeros((dim, ))
self._var = np.zeros((dim, dim))
self._n = 0
self._min = np.full((dim, ), -float("-inf"))
self._max = np.full((dim, ), -float("inf"))
@property
def cov(self):
return self.var
def update(self, samples):
n_a = samples.shape[0]
mean_a = np.mean(samples, axis=0)
var_a = np.cov(samples, ddof=0, rowvar=False)
n_b = self._n
mean_b = self._mean
delta = mean_b - mean_a
m_a = var_a * (n_a - 1)
m_b = self._var * (n_b - 1)
m2 = m_a + m_b + delta**2 * n_a * n_b / (n_a + n_b)
self._var = m2 / (n_a + n_b)
self._mean = (n_a * mean_a + n_b * mean_b) / (n_a + n_b)
self._n = n_a + n_b
self._min = np.minimum(self._min, np.min(samples, axis=0))
self._max = np.maximum(self._max, np.max(samples, axis=0))
-6
View File
@@ -1,6 +0,0 @@
def replace_right(s, old, new, occurrence):
# replace_right('1232425', '2', ' ', 1) -> '12324 5'
# replace_right('1232425', '2', ' ', 2) -> '123 4 5'
split = s.rsplit(old, occurrence)
return new.join(split)
-81
View File
@@ -1,81 +0,0 @@
#!/usr/bin/env python3
import sympy as sp
import numpy as np
def cross(x):
ret = sp.Matrix(np.zeros((3,3)))
ret[0,1], ret[0,2] = -x[2], x[1]
ret[1,0], ret[1,2] = x[2], -x[0]
ret[2,0], ret[2,1] = -x[1], x[0]
return ret
def euler_rotate(roll, pitch, yaw):
# make symbolic rotation matrix from eulers
matrix_roll = sp.Matrix([[1, 0, 0],
[0, sp.cos(roll), -sp.sin(roll)],
[0, sp.sin(roll), sp.cos(roll)]])
matrix_pitch = sp.Matrix([[sp.cos(pitch), 0, sp.sin(pitch)],
[0, 1, 0],
[-sp.sin(pitch), 0, sp.cos(pitch)]])
matrix_yaw = sp.Matrix([[sp.cos(yaw), -sp.sin(yaw), 0],
[sp.sin(yaw), sp.cos(yaw), 0],
[0, 0, 1]])
return matrix_yaw*matrix_pitch*matrix_roll
def quat_rotate(q0, q1, q2, q3):
# make symbolic rotation matrix from quat
return sp.Matrix([[q0**2 + q1**2 - q2**2 - q3**2, 2*(q1*q2 + q0*q3), 2*(q1*q3 - q0*q2)],
[2*(q1*q2 - q0*q3), q0**2 - q1**2 + q2**2 - q3**2, 2*(q2*q3 + q0*q1)],
[2*(q1*q3 + q0*q2), 2*(q2*q3 - q0*q1), q0**2 - q1**2 - q2**2 + q3**2]]).T
def quat_matrix_l(p):
return sp.Matrix([[p[0], -p[1], -p[2], -p[3]],
[p[1], p[0], -p[3], p[2]],
[p[2], p[3], p[0], -p[1]],
[p[3], -p[2], p[1], p[0]]])
def quat_matrix_r(p):
return sp.Matrix([[p[0], -p[1], -p[2], -p[3]],
[p[1], p[0], p[3], -p[2]],
[p[2], -p[3], p[0], p[1]],
[p[3], p[2], -p[1], p[0]]])
def sympy_into_c(sympy_functions):
from sympy.utilities import codegen
routines = []
for name, expr, args in sympy_functions:
r = codegen.make_routine(name, expr, language="C99")
# argument ordering input to sympy is broken with function with output arguments
nargs = []
# reorder the input arguments
for aa in args:
if aa is None:
nargs.append(codegen.InputArgument(sp.Symbol('unused'), dimensions=[1,1]))
continue
found = False
for a in r.arguments:
if str(aa.name) == str(a.name):
nargs.append(a)
found = True
break
if not found:
# [1,1] is a hack for Matrices
nargs.append(codegen.InputArgument(aa, dimensions=[1,1]))
# add the output arguments
for a in r.arguments:
if type(a) == codegen.OutputArgument:
nargs.append(a)
#assert len(r.arguments) == len(args)+1
r.arguments = nargs
# add routine to list
routines.append(r)
[(c_name, c_code), (h_name, c_header)] = codegen.get_code_generator('C', 'ekf', 'C99').write(routines, "ekf")
c_code = '\n'.join(x for x in c_code.split("\n") if len(x) > 0 and x[0] != '#')
c_header = '\n'.join(x for x in c_header.split("\n") if len(x) > 0 and x[0] != '#')
return c_header, c_code
-28
View File
@@ -1,28 +0,0 @@
import os
import unittest
from uuid import uuid4
from common.file_helpers import atomic_write_on_fs_tmp
from common.file_helpers import atomic_write_in_dir
class TestFileHelpers(unittest.TestCase):
def run_atomic_write_func(self, atomic_write_func):
path = "/tmp/tmp{}".format(uuid4())
with atomic_write_func(path) as f:
f.write("test")
with open(path) as f:
self.assertEqual(f.read(), "test")
self.assertEqual(os.stat(path).st_mode & 0o777, 0o644)
os.remove(path)
def test_atomic_write_on_fs_tmp(self):
self.run_atomic_write_func(atomic_write_on_fs_tmp)
def test_atomic_write_in_dir(self):
self.run_atomic_write_func(atomic_write_in_dir)
if __name__ == "__main__":
unittest.main()
-27
View File
@@ -1,27 +0,0 @@
import numpy as np
import unittest
import timeit
from common.numpy_fast import interp
class InterpTest(unittest.TestCase):
def test_correctness_controls(self):
_A_CRUISE_MIN_BP = np.asarray([0., 5., 10., 20., 40.])
_A_CRUISE_MIN_V = np.asarray([-1.0, -.8, -.67, -.5, -.30])
v_ego_arr = [-1, -1e-12, 0, 4, 5, 6, 7, 10, 11, 15.2, 20, 21, 39,
39.999999, 40, 41]
expected = np.interp(v_ego_arr, _A_CRUISE_MIN_BP, _A_CRUISE_MIN_V)
actual = interp(v_ego_arr, _A_CRUISE_MIN_BP, _A_CRUISE_MIN_V)
np.testing.assert_equal(actual, expected)
for v_ego in v_ego_arr:
expected = np.interp(v_ego, _A_CRUISE_MIN_BP, _A_CRUISE_MIN_V)
actual = interp(v_ego, _A_CRUISE_MIN_BP, _A_CRUISE_MIN_V)
np.testing.assert_equal(actual, expected)
if __name__ == "__main__":
unittest.main()
-63
View File
@@ -1,63 +0,0 @@
from common.params import Params, UnknownKeyName
import threading
import time
import tempfile
import shutil
import unittest
class TestParams(unittest.TestCase):
def setUp(self):
self.tmpdir = tempfile.mkdtemp()
print("using", self.tmpdir)
self.params = Params(self.tmpdir)
def tearDown(self):
shutil.rmtree(self.tmpdir)
def test_params_put_and_get(self):
self.params.put("DongleId", "cb38263377b873ee")
assert self.params.get("DongleId") == b"cb38263377b873ee"
def test_params_non_ascii(self):
st = b"\xe1\x90\xff"
self.params.put("CarParams", st)
assert self.params.get("CarParams") == st
def test_params_get_cleared_panda_disconnect(self):
self.params.put("CarParams", "test")
self.params.put("DongleId", "cb38263377b873ee")
assert self.params.get("CarParams") == b"test"
self.params.panda_disconnect()
assert self.params.get("CarParams") is None
assert self.params.get("DongleId") is not None
def test_params_get_cleared_manager_start(self):
self.params.put("CarParams", "test")
self.params.put("DongleId", "cb38263377b873ee")
assert self.params.get("CarParams") == b"test"
self.params.manager_start()
assert self.params.get("CarParams") is None
assert self.params.get("DongleId") is not None
def test_params_two_things(self):
self.params.put("DongleId", "bob")
self.params.put("AccessToken", "knope")
assert self.params.get("DongleId") == b"bob"
assert self.params.get("AccessToken") == b"knope"
def test_params_get_block(self):
def _delayed_writer():
time.sleep(0.1)
self.params.put("CarParams", "test")
threading.Thread(target=_delayed_writer).start()
assert self.params.get("CarParams") is None
assert self.params.get("CarParams", True) == b"test"
def test_params_unknown_key_fails(self):
with self.assertRaises(UnknownKeyName):
self.params.get("swag")
if __name__ == "__main__":
unittest.main()
-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)
-61
View File
@@ -1,61 +0,0 @@
Reference Frames
------
Many reference frames are used throughout. This
folder contains all helper functions needed to
transform between them. Generally this is done
by generating a rotation matrix and multiplying.
| Name | [x, y, z] | Units | Notes |
| :-------------: |:-------------:| :-----:| :----: |
| Geodetic | [Latitude, Longitude, Altitude] | geodetic coordinates | Sometimes used as [lon, lat, alt], avoid this frame. |
| ECEF | [x, y, z] | meters | We use **ITRF14 (IGS14)**, NOT NAD83. <br> This is the global Mesh3D frame. |
| NED | [North, East, Down] | meters | Relative to earth's surface, useful for vizualizing. |
| Device | [Forward, Right, Down] | meters | This is the Mesh3D local frame. <br> Relative to camera, **not imu.** <br> ![img](http://upload.wikimedia.org/wikipedia/commons/thumb/2/2f/RPY_angles_of_airplanes.png/440px-RPY_angles_of_airplanes.png)|
| Road | [Forward, Left, Up] | meters | On the road plane aligned to the vehicle. <br> ![img](https://upload.wikimedia.org/wikipedia/commons/f/f5/RPY_angles_of_cars.png) |
| View | [Right, Down, Forward] | meters | Like device frame, but according to camera conventions. |
| Camera | [u, v, focal] | pixels | Like view frame, but 2d on the camera image.|
| Normalized Camera | [u / focal, v / focal, 1] | / | |
| Model | [u, v, focal] | pixels | The sampled rectangle of the full camera frame the model uses. |
| Normalized Model | [u / focal, v / focal, 1] | / | |
Orientation Conventations
------
Quaternions, rotation matrices and euler angles are three
equivalent representations of orientation and all three are
used throughout the code base.
For euler angles the preferred convention is [roll, pitch, yaw]
which corresponds to rotations around the [x, y, z] axes. All
euler angles should always be in radians or radians/s unless
for plotting or display purposes. For quaternions the hamilton
notations is preferred which is [q<sub>w</sub>, q<sub>x</sub>, q<sub>y</sub>, q<sub>z</sub>]. All quaternions
should always be normalized with a strictly positive q<sub>w</sub>. **These
quaternions are a unique representation of orientation whereas euler angles
or rotation matrices are not.**
To rotate from one frame into another with euler angles the
convention is to rotate around roll, then pitch and then yaw,
while rotating around the rotated axes, not the original axes.
Calibration
------
EONs are not all mounted in the exact same way. To compensate for the effects of this the vision model takes in an image that is "calibrated". This means the image is aligned so the direction of travel of the car when it is going straight and the road is flat is always in the location on the image. This calibration is defined by a pitch and yaw angle that describe the direction of travel vector in device frame.
Example
------
To transform global Mesh3D positions and orientations (positions_ecef, quats_ecef) into the local frame described by the
first position and orientation from Mesh3D one would do:
```
ecef_from_local = rot_from_quat(quats_ecef[0])
local_from_ecef = ecef_from_local.T
positions_local = np.einsum('ij,kj->ki', local_from_ecef, postions_ecef - positions_ecef[0])
rotations_global = rot_from_quat(quats_ecef)
rotations_local = np.einsum('ij,kjl->kil', local_from_ecef, rotations_global)
eulers_local = euler_from_rot(rotations_local)
```
-227
View File
@@ -1,227 +0,0 @@
import numpy as np
import common.transformations.orientation as orient
import math
FULL_FRAME_SIZE = (1164, 874)
W, H = FULL_FRAME_SIZE[0], FULL_FRAME_SIZE[1]
eon_focal_length = FOCAL = 910.0
# aka 'K' aka camera_frame_from_view_frame
eon_intrinsics = np.array([
[FOCAL, 0., W/2.],
[ 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)
# device/mesh : x->forward, y-> right, z->down
# view : x->right, y->down, z->forward
device_frame_from_view_frame = np.array([
[ 0., 0., 1.],
[ 1., 0., 0.],
[ 0., 1., 0.]
])
view_frame_from_device_frame = device_frame_from_view_frame.T
def get_calib_from_vp(vp):
vp_norm = normalize(vp)
yaw_calib = np.arctan(vp_norm[0])
pitch_calib = -np.arctan(vp_norm[1]*np.cos(yaw_calib))
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):
device_from_road = orient.rot_from_euler([roll, pitch, yaw]).dot(np.diag([1, -1, -1]))
view_from_road = view_frame_from_device_frame.dot(device_from_road)
return np.hstack((view_from_road, [[0], [height], [0]]))
def vp_from_ke(m):
"""
Computes the vanishing point from the product of the intrinsic and extrinsic
matrices C = KE.
The vanishing point is defined as lim x->infinity C (x, 0, 0, 1).T
"""
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]),
-(m[0, 0] - m[0, 1] * m[2, 0] / m[2, 1]))
def normalize(img_pts, intrinsics=eon_intrinsics):
# normalizes image coordinates
# accepts single pt or array of pts
intrinsics_inv = np.linalg.inv(intrinsics)
img_pts = np.array(img_pts)
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[(img_pts < 0).any(axis=1)] = np.nan
return img_pts_normalized[:,:2].reshape(input_shape)
def denormalize(img_pts, intrinsics=eon_intrinsics):
# denormalizes image coordinates
# accepts single pt or array of pts
img_pts = np.array(img_pts)
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[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
img_pts_denormalized[img_pts_denormalized[:,1] < 0] = np.nan
return img_pts_denormalized[:,:2].reshape(input_shape)
def device_from_ecef(pos_ecef, orientation_ecef, pt_ecef):
# device from ecef frame
# device frame is x -> forward, y-> right, z -> down
# accepts single pt or array of pts
input_shape = pt_ecef.shape
pt_ecef = np.atleast_2d(pt_ecef)
ecef_from_device_rot = orient.rotations_from_quats(orientation_ecef)
device_from_ecef_rot = ecef_from_device_rot.T
pt_ecef_rel = pt_ecef - pos_ecef
pt_device = np.einsum('jk,ik->ij', device_from_ecef_rot, pt_ecef_rel)
return pt_device.reshape(input_shape)
def img_from_device(pt_device):
# img coordinates from pts in device frame
# first transforms to view frame, then to img coords
# accepts single pt or array of pts
input_shape = pt_device.shape
pt_device = np.atleast_2d(pt_device)
pt_view = np.einsum('jk,ik->ij', view_frame_from_device_frame, pt_device)
# This function should never return negative depths
pt_view[pt_view[:,2] < 0] = np.nan
pt_img = pt_view/pt_view[:,2:3]
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 transform_img(base_img,
augment_trans=np.array([0,0,0]),
augment_eulers=np.array([0,0,0]),
from_intr=eon_intrinsics,
to_intr=eon_intrinsics,
output_size=None,
pretransform=None,
top_hacks=False,
yuv=False,
alpha=1.0,
beta=0,
blur=0):
import cv2 # pylint: disable=import-error
cv2.setNumThreads(1)
if yuv:
base_img = cv2.cvtColor(base_img, cv2.COLOR_YUV2RGB_I420)
size = base_img.shape[:2]
if not output_size:
output_size = size[::-1]
cy = from_intr[1,2]
def get_M(h=1.22):
quadrangle = np.array([[0, cy + 20],
[size[1]-1, cy + 20],
[0, size[0]-1],
[size[1]-1, size[0]-1]], dtype=np.float32)
quadrangle_norm = np.hstack((normalize(quadrangle, intrinsics=from_intr), np.ones((4,1))))
quadrangle_world = np.column_stack((h*quadrangle_norm[:,0]/quadrangle_norm[:,1],
h*np.ones(4),
h/quadrangle_norm[:,1]))
rot = orient.rot_from_euler(augment_eulers)
to_extrinsics = np.hstack((rot.T, -augment_trans[:,None]))
to_KE = to_intr.dot(to_extrinsics)
warped_quadrangle_full = np.einsum('jk,ik->ij', to_KE, np.hstack((quadrangle_world, np.ones((4,1)))))
warped_quadrangle = np.column_stack((warped_quadrangle_full[:,0]/warped_quadrangle_full[:,2],
warped_quadrangle_full[:,1]/warped_quadrangle_full[:,2])).astype(np.float32)
M = cv2.getPerspectiveTransform(quadrangle, warped_quadrangle.astype(np.float32))
return M
M = get_M()
if pretransform is not None:
M = M.dot(pretransform)
augmented_rgb = cv2.warpPerspective(base_img, M, output_size, borderMode=cv2.BORDER_REPLICATE)
if top_hacks:
cyy = int(math.ceil(to_intr[1,2]))
M = get_M(1000)
if pretransform is not None:
M = M.dot(pretransform)
augmented_rgb[:cyy] = cv2.warpPerspective(base_img, M, (output_size[0], cyy), borderMode=cv2.BORDER_REPLICATE)
# brightness and contrast augment
augmented_rgb = np.clip((float(alpha)*augmented_rgb + beta), 0, 255).astype(np.uint8)
# gaussian blur
if blur > 0:
augmented_rgb = cv2.GaussianBlur(augmented_rgb,(blur*2+1,blur*2+1),cv2.BORDER_DEFAULT)
if yuv:
augmented_img = cv2.cvtColor(augmented_rgb, cv2.COLOR_RGB2YUV_I420)
else:
augmented_img = augmented_rgb
return augmented_img
def yuv_crop(frame, output_size, center=None):
# output_size in camera coordinates so u,v
# center in array coordinates so row, column
import cv2 # pylint: disable=import-error
rgb = cv2.cvtColor(frame, cv2.COLOR_YUV2RGB_I420)
if not center:
center = (rgb.shape[0]/2, rgb.shape[1]/2)
rgb_crop = rgb[center[0] - output_size[1]/2: center[0] + output_size[1]/2,
center[1] - output_size[0]/2: center[1] + output_size[0]/2]
return cv2.cvtColor(rgb_crop, cv2.COLOR_RGB2YUV_I420)
+33 -35
View File
@@ -12,14 +12,12 @@ esq = 6.69437999014 * 0.001
e1sq = 6.73949674228 * 0.001
def geodetic2ecef(geodetic, radians=False):
def geodetic2ecef(geodetic):
geodetic = np.array(geodetic)
input_shape = geodetic.shape
geodetic = np.atleast_2d(geodetic)
ratio = 1.0 if radians else (np.pi / 180.0)
lat = ratio*geodetic[:,0]
lon = ratio*geodetic[:,1]
lat = (np.pi/180)*geodetic[:,0]
lon = (np.pi/180)*geodetic[:,1]
alt = geodetic[:,2]
xi = np.sqrt(1 - esq * np.sin(lat)**2)
@@ -30,42 +28,42 @@ def geodetic2ecef(geodetic, radians=False):
return ecef.reshape(input_shape)
def ecef2geodetic(ecef, radians=False):
def ecef2geodetic(ecef):
"""
Convert ECEF coordinates to geodetic using ferrari's method
"""
# Save shape and export column
ecef = np.atleast_1d(ecef)
def ferrari(x, y, z):
# ferrari's method
r = np.sqrt(x * x + y * y)
Esq = a * a - b * b
F = 54 * b * b * z * z
G = r * r + (1 - esq) * z * z - esq * Esq
C = (esq * esq * F * r * r) / (pow(G, 3))
S = np.cbrt(1 + C + np.sqrt(C * C + 2 * C))
P = F / (3 * pow((S + 1 / S + 1), 2) * G * G)
Q = np.sqrt(1 + 2 * esq * esq * P)
r_0 = -(P * esq * r) / (1 + Q) + np.sqrt(0.5 * a * a*(1 + 1.0 / Q) - \
P * (1 - esq) * z * z / (Q * (1 + Q)) - 0.5 * P * r * r)
U = np.sqrt(pow((r - esq * r_0), 2) + z * z)
V = np.sqrt(pow((r - esq * r_0), 2) + (1 - esq) * z * z)
Z_0 = b * b * z / (a * V)
h = U * (1 - b * b / (a * V))
lat = (180/np.pi)*np.arctan((z + e1sq * Z_0) / r)
lon = (180/np.pi)*np.arctan2(y, x)
return lat, lon, h
geodetic = []
ecef = np.array(ecef)
input_shape = ecef.shape
ecef = np.atleast_2d(ecef)
x, y, z = ecef[:, 0], ecef[:, 1], ecef[:, 2]
ratio = 1.0 if radians else (180.0 / np.pi)
# Conver from ECEF to geodetic using Ferrari's methods
# https://en.wikipedia.org/wiki/Geographic_coordinate_conversion#Ferrari.27s_solution
r = np.sqrt(x * x + y * y)
Esq = a * a - b * b
F = 54 * b * b * z * z
G = r * r + (1 - esq) * z * z - esq * Esq
C = (esq * esq * F * r * r) / (pow(G, 3))
S = np.cbrt(1 + C + np.sqrt(C * C + 2 * C))
P = F / (3 * pow((S + 1 / S + 1), 2) * G * G)
Q = np.sqrt(1 + 2 * esq * esq * P)
r_0 = -(P * esq * r) / (1 + Q) + np.sqrt(0.5 * a * a*(1 + 1.0 / Q) - \
P * (1 - esq) * z * z / (Q * (1 + Q)) - 0.5 * P * r * r)
U = np.sqrt(pow((r - esq * r_0), 2) + z * z)
V = np.sqrt(pow((r - esq * r_0), 2) + (1 - esq) * z * z)
Z_0 = b * b * z / (a * V)
h = U * (1 - b * b / (a * V))
lat = ratio*np.arctan((z + e1sq * Z_0) / r)
lon = ratio*np.arctan2(y, x)
# stack the new columns and return to the original shape
geodetic = np.column_stack((lat, lon, h))
for p in ecef:
geodetic.append(ferrari(*p))
geodetic = np.array(geodetic)
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
@@ -73,7 +71,7 @@ class LocalCoord():
"""
def __init__(self, init_geodetic, init_ecef):
self.init_ecef = init_ecef
lat, lon, _ = (np.pi/180)*np.array(init_geodetic)
lat, lon, _ = (np.pi/180)*init_geodetic
self.ned2ecef_matrix = np.array([[-np.sin(lat)*np.cos(lon), -np.sin(lon), -np.cos(lat)*np.cos(lon)],
[-np.sin(lat)*np.sin(lon), np.cos(lon), -np.cos(lat)*np.sin(lon)],
[np.cos(lat), 0, -np.sin(lat)]])
-150
View File
@@ -1,150 +0,0 @@
import numpy as np
from common.transformations.camera import (FULL_FRAME_SIZE, eon_focal_length,
get_view_frame_from_road_frame,
vp_from_ke)
# segnet
SEGNET_SIZE = (512, 384)
segnet_frame_from_camera_frame = np.array([
[float(SEGNET_SIZE[0])/FULL_FRAME_SIZE[0], 0., ],
[ 0., float(SEGNET_SIZE[1])/FULL_FRAME_SIZE[1]]])
# model
MODEL_INPUT_SIZE = (320, 160)
MODEL_YUV_SIZE = (MODEL_INPUT_SIZE[0], MODEL_INPUT_SIZE[1] * 3 // 2)
MODEL_CX = MODEL_INPUT_SIZE[0]/2.
MODEL_CY = 21.
model_zoom = 1.25
model_height = 1.22
# canonical model transform
model_intrinsics = np.array(
[[ eon_focal_length / model_zoom, 0. , MODEL_CX],
[ 0. , eon_focal_length / model_zoom, MODEL_CY],
[ 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 = (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, 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))
# 'camera from model camera'
def get_model_height_transform(camera_frame_from_road_frame, height):
camera_frame_from_road_ground = np.dot(camera_frame_from_road_frame, np.array([
[1, 0, 0],
[0, 1, 0],
[0, 0, 0],
[0, 0, 1],
]))
camera_frame_from_road_high = np.dot(camera_frame_from_road_frame, np.array([
[1, 0, 0],
[0, 1, 0],
[0, 0, height - model_height],
[0, 0, 1],
]))
road_high_from_camera_frame = np.linalg.inv(camera_frame_from_road_high)
high_camera_from_low_camera = np.dot(camera_frame_from_road_ground, road_high_from_camera_frame)
return high_camera_from_low_camera
# camera_frame_from_model_frame aka 'warp matrix'
# was: calibration.h/CalibrationTransform
def get_camera_frame_from_model_frame(camera_frame_from_road_frame, height=model_height):
vp = vp_from_ke(camera_frame_from_road_frame)
model_camera_from_model_frame = np.array([
[model_zoom, 0., vp[0] - MODEL_CX * model_zoom],
[ 0., model_zoom, vp[1] - MODEL_CY * model_zoom],
[ 0., 0., 1.],
])
# This function is super slow, so skip it if height is very close to canonical
# TODO: speed it up!
if abs(height - model_height) > 0.001: #
camera_from_model_camera = get_model_height_transform(camera_frame_from_road_frame, height)
else:
camera_from_model_camera = np.eye(3)
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)]
ground_from_bigmodel_frame = np.linalg.inv(bigmodel_frame_from_ground)
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
-295
View File
@@ -1,295 +0,0 @@
import numpy as np
from numpy import dot, inner, array, linalg
from common.transformations.coordinates import LocalCoord
'''
Vectorized functions that transform between
rotation matrices, euler angles and quaternions.
All support lists, array or array of arrays as inputs.
Supports both x2y and y_from_x format (y_from_x preferred!).
'''
def euler2quat(eulers):
eulers = array(eulers)
if len(eulers.shape) > 1:
output_shape = (-1,4)
else:
output_shape = (4,)
eulers = np.atleast_2d(eulers)
gamma, theta, psi = eulers[:,0], eulers[:,1], eulers[:,2]
q0 = np.cos(gamma / 2) * np.cos(theta / 2) * np.cos(psi / 2) + \
np.sin(gamma / 2) * np.sin(theta / 2) * np.sin(psi / 2)
q1 = np.sin(gamma / 2) * np.cos(theta / 2) * np.cos(psi / 2) - \
np.cos(gamma / 2) * np.sin(theta / 2) * np.sin(psi / 2)
q2 = np.cos(gamma / 2) * np.sin(theta / 2) * np.cos(psi / 2) + \
np.sin(gamma / 2) * np.cos(theta / 2) * np.sin(psi / 2)
q3 = np.cos(gamma / 2) * np.cos(theta / 2) * np.sin(psi / 2) - \
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)):
if quats[i,0] < 0:
quats[i] = -quats[i]
return quats.reshape(output_shape)
def quat2euler(quats):
quats = array(quats)
if len(quats.shape) > 1:
output_shape = (-1,3)
else:
output_shape = (3,)
quats = np.atleast_2d(quats)
q0, q1, q2, q3 = quats[:,0], quats[:,1], quats[:,2], quats[:,3]
gamma = np.arctan2(2 * (q0 * q1 + q2 * q3), 1 - 2 * (q1**2 + q2**2))
theta = np.arcsin(2 * (q0 * q2 - q3 * q1))
psi = np.arctan2(2 * (q0 * q3 + q1 * q2), 1 - 2 * (q2**2 + q3**2))
eulers = array([gamma, theta, psi]).T
return eulers.reshape(output_shape)
def quat2rot(quats):
quats = array(quats)
input_shape = quats.shape
quats = np.atleast_2d(quats)
Rs = np.zeros((quats.shape[0], 3, 3))
q0 = quats[:, 0]
q1 = quats[:, 1]
q2 = quats[:, 2]
q3 = quats[:, 3]
Rs[:, 0, 0] = q0 * q0 + q1 * q1 - q2 * q2 - q3 * q3
Rs[:, 0, 1] = 2 * (q1 * q2 - q0 * q3)
Rs[:, 0, 2] = 2 * (q0 * q2 + q1 * q3)
Rs[:, 1, 0] = 2 * (q1 * q2 + q0 * q3)
Rs[:, 1, 1] = q0 * q0 - q1 * q1 + q2 * q2 - q3 * q3
Rs[:, 1, 2] = 2 * (q2 * q3 - q0 * q1)
Rs[:, 2, 0] = 2 * (q1 * q3 - q0 * q2)
Rs[:, 2, 1] = 2 * (q0 * q1 + q2 * q3)
Rs[:, 2, 2] = q0 * q0 - q1 * q1 - q2 * q2 + q3 * q3
if len(input_shape) < 2:
return Rs[0]
else:
return Rs
def rot2quat(rots):
input_shape = rots.shape
if len(input_shape) < 3:
rots = array([rots])
K3 = np.empty((len(rots), 4, 4))
K3[:, 0, 0] = (rots[:, 0, 0] - rots[:, 1, 1] - rots[:, 2, 2]) / 3.0
K3[:, 0, 1] = (rots[:, 1, 0] + rots[:, 0, 1]) / 3.0
K3[:, 0, 2] = (rots[:, 2, 0] + rots[:, 0, 2]) / 3.0
K3[:, 0, 3] = (rots[:, 1, 2] - rots[:, 2, 1]) / 3.0
K3[:, 1, 0] = K3[:, 0, 1]
K3[:, 1, 1] = (rots[:, 1, 1] - rots[:, 0, 0] - rots[:, 2, 2]) / 3.0
K3[:, 1, 2] = (rots[:, 2, 1] + rots[:, 1, 2]) / 3.0
K3[:, 1, 3] = (rots[:, 2, 0] - rots[:, 0, 2]) / 3.0
K3[:, 2, 0] = K3[:, 0, 2]
K3[:, 2, 1] = K3[:, 1, 2]
K3[:, 2, 2] = (rots[:, 2, 2] - rots[:, 0, 0] - rots[:, 1, 1]) / 3.0
K3[:, 2, 3] = (rots[:, 0, 1] - rots[:, 1, 0]) / 3.0
K3[:, 3, 0] = K3[:, 0, 3]
K3[:, 3, 1] = K3[:, 1, 3]
K3[:, 3, 2] = K3[:, 2, 3]
K3[:, 3, 3] = (rots[:, 0, 0] + rots[:, 1, 1] + rots[:, 2, 2]) / 3.0
q = np.empty((len(rots), 4))
for i in range(len(rots)):
_, eigvecs = linalg.eigh(K3[i].T)
eigvecs = eigvecs[:,3:]
q[i, 0] = eigvecs[-1]
q[i, 1:] = -eigvecs[:-1].flatten()
if q[i, 0] < 0:
q[i] = -q[i]
if len(input_shape) < 3:
return q[0]
else:
return q
def euler2rot(eulers):
return rotations_from_quats(euler2quat(eulers))
def rot2euler(rots):
return quat2euler(quats_from_rotations(rots))
quats_from_rotations = rot2quat
quat_from_rot = rot2quat
rotations_from_quats = quat2rot
rot_from_quat= quat2rot
rot_from_quat= quat2rot
euler_from_rot = rot2euler
euler_from_quat = quat2euler
rot_from_euler = euler2rot
quat_from_euler = euler2quat
'''
Random helpers below
'''
def quat_product(q, r):
t = np.zeros(4)
t[0] = r[0] * q[0] - r[1] * q[1] - r[2] * q[2] - r[3] * q[3]
t[1] = r[0] * q[1] + r[1] * q[0] - r[2] * q[3] + r[3] * q[2]
t[2] = r[0] * q[2] + r[1] * q[3] + r[2] * q[0] - r[3] * q[1]
t[3] = r[0] * q[3] - r[1] * q[2] + r[2] * q[1] + r[3] * q[0]
return t
def rot_matrix(roll, pitch, yaw):
cr, sr = np.cos(roll), np.sin(roll)
cp, sp = np.cos(pitch), np.sin(pitch)
cy, sy = np.cos(yaw), np.sin(yaw)
rr = array([[1,0,0],[0, cr,-sr],[0, sr, cr]])
rp = array([[cp,0,sp],[0, 1,0],[-sp, 0, cp]])
ry = array([[cy,-sy,0],[sy, cy,0],[0, 0, 1]])
return ry.dot(rp.dot(rr))
def rot(axis, angle):
# Rotates around an arbitrary axis
ret_1 = (1 - np.cos(angle)) * array([[axis[0]**2, axis[0] * axis[1], axis[0] * axis[2]], [
axis[1] * axis[0], axis[1]**2, axis[1] * axis[2]
], [axis[2] * axis[0], axis[2] * axis[1], axis[2]**2]])
ret_2 = np.cos(angle) * np.eye(3)
ret_3 = np.sin(angle) * array([[0, -axis[2], axis[1]], [axis[2], 0, -axis[0]],
[-axis[1], axis[0], 0]])
return ret_1 + ret_2 + ret_3
def ecef_euler_from_ned(ned_ecef_init, ned_pose):
'''
Got it from here:
Using Rotations to Build Aerospace Coordinate Systems
-Don Koks
'''
converter = LocalCoord.from_ecef(ned_ecef_init)
x0 = converter.ned2ecef([1, 0, 0]) - converter.ned2ecef([0, 0, 0])
y0 = converter.ned2ecef([0, 1, 0]) - converter.ned2ecef([0, 0, 0])
z0 = converter.ned2ecef([0, 0, 1]) - converter.ned2ecef([0, 0, 0])
x1 = rot(z0, ned_pose[2]).dot(x0)
y1 = rot(z0, ned_pose[2]).dot(y0)
z1 = rot(z0, ned_pose[2]).dot(z0)
x2 = rot(y1, ned_pose[1]).dot(x1)
y2 = rot(y1, ned_pose[1]).dot(y1)
z2 = rot(y1, ned_pose[1]).dot(z1)
x3 = rot(x2, ned_pose[0]).dot(x2)
y3 = rot(x2, ned_pose[0]).dot(y2)
#z3 = rot(x2, ned_pose[0]).dot(z2)
x0 = array([1, 0, 0])
y0 = array([0, 1, 0])
z0 = array([0, 0, 1])
psi = np.arctan2(inner(x3, y0), inner(x3, x0))
theta = np.arctan2(-inner(x3, z0), np.sqrt(inner(x3, x0)**2 + inner(x3, y0)**2))
y2 = rot(z0, psi).dot(y0)
z2 = rot(y2, theta).dot(z0)
phi = np.arctan2(inner(y3, z2), inner(y3, y2))
ret = array([phi, theta, psi])
return ret
def ned_euler_from_ecef(ned_ecef_init, ecef_poses):
'''
Got the math from here:
Using Rotations to Build Aerospace Coordinate Systems
-Don Koks
Also accepts array of ecef_poses and array of ned_ecef_inits.
Where each row is a pose and an ecef_init.
'''
ned_ecef_init = array(ned_ecef_init)
ecef_poses = array(ecef_poses)
output_shape = ecef_poses.shape
ned_ecef_init = np.atleast_2d(ned_ecef_init)
if ned_ecef_init.shape[0] == 1:
ned_ecef_init = np.tile(ned_ecef_init[0], (output_shape[0], 1))
ecef_poses = np.atleast_2d(ecef_poses)
ned_poses = np.zeros(ecef_poses.shape)
for i, ecef_pose in enumerate(ecef_poses):
converter = LocalCoord.from_ecef(ned_ecef_init[i])
x0 = array([1, 0, 0])
y0 = array([0, 1, 0])
z0 = array([0, 0, 1])
x1 = rot(z0, ecef_pose[2]).dot(x0)
y1 = rot(z0, ecef_pose[2]).dot(y0)
z1 = rot(z0, ecef_pose[2]).dot(z0)
x2 = rot(y1, ecef_pose[1]).dot(x1)
y2 = rot(y1, ecef_pose[1]).dot(y1)
z2 = rot(y1, ecef_pose[1]).dot(z1)
x3 = rot(x2, ecef_pose[0]).dot(x2)
y3 = rot(x2, ecef_pose[0]).dot(y2)
#z3 = rot(x2, ecef_pose[0]).dot(z2)
x0 = converter.ned2ecef([1, 0, 0]) - converter.ned2ecef([0, 0, 0])
y0 = converter.ned2ecef([0, 1, 0]) - converter.ned2ecef([0, 0, 0])
z0 = converter.ned2ecef([0, 0, 1]) - converter.ned2ecef([0, 0, 0])
psi = np.arctan2(inner(x3, y0), inner(x3, x0))
theta = np.arctan2(-inner(x3, z0), np.sqrt(inner(x3, x0)**2 + inner(x3, y0)**2))
y2 = rot(z0, psi).dot(y0)
z2 = rot(y2, theta).dot(z0)
phi = np.arctan2(inner(y3, z2), inner(y3, y2))
ned_poses[i] = array([phi, theta, psi])
return ned_poses.reshape(output_shape)
def ecef2car(car_ecef, psi, theta, points_ecef, ned_converter):
"""
TODO: add roll rotation
Converts an array of points in ecef coordinates into
x-forward, y-left, z-up coordinates
Parameters
----------
psi: yaw, radian
theta: pitch, radian
Returns
-------
[x, y, z] coordinates in car frame
"""
# input is an array of points in ecef cocrdinates
# output is an array of points in car's coordinate (x-front, y-left, z-up)
# convert points to NED
points_ned = []
for p in points_ecef:
points_ned.append(ned_converter.ecef2ned_matrix.dot(array(p) - car_ecef))
points_ned = np.vstack(points_ned).T
# n, e, d -> x, y, z
# Calculate relative postions and rotate wrt to heading and pitch of car
invert_R = array([[1., 0., 0.], [0., -1., 0.], [0., 0., -1.]])
c, s = np.cos(psi), np.sin(psi)
yaw_R = array([[c, s, 0.], [-s, c, 0.], [0., 0., 1.]])
c, s = np.cos(theta), np.sin(theta)
pitch_R = array([[c, 0., -s], [0., 1., 0.], [s, 0., c]])
return dot(pitch_R, dot(yaw_R, dot(invert_R, points_ned)))
@@ -1,122 +0,0 @@
#!/usr/bin/env python3
import numpy as np
import unittest
import common.transformations.coordinates as coord
geodetic_positions = np.array([[37.7610403, -122.4778699, 115],
[27.4840915, -68.5867592, 2380],
[32.4916858, -113.652821, -6],
[15.1392514, 103.6976037, 24],
[24.2302229, 44.2835412, 1650]])
geodetic_positions_radians = np.array([[0.65905448, -2.13764209, 115],
[0.47968789, -1.19706477, 2380],
[0.5670869, -1.98361593, -6],
[0.26422978, 1.80986461, 24],
[0.42289717, 0.7728936, 1650]])
ecef_positions = np.array([[-2711076.55270557, -4259167.14692758, 3884579.87669935],
[ 2068042.69652729, -5273435.40316622, 2927004.89190746],
[-2160412.60461669, -4932588.89873832, 3406542.29652851],
[-1458247.92550567, 5983060.87496612, 1654984.6099885 ],
[ 4167239.10867871, 4064301.90363223, 2602234.6065749 ]])
ecef_positions_offset = np.array([[-2711004.46961115, -4259099.33540613, 3884605.16002147],
[ 2068074.30639499, -5273413.78835412, 2927012.48741131],
[-2160344.53748176, -4932586.20092211, 3406636.2962545 ],
[-1458211.98517094, 5983151.11161276, 1655077.02698447],
[ 4167271.20055269, 4064398.22619263, 2602238.95265847]])
ned_offsets = np.array([[78.722153649976391, 24.396208657446344, 60.343017506838436],
[10.699003365155221, 37.319278617604269, 4.1084100025050407],
[95.282646251726959, 61.266689955574428, -25.376506058505054],
[68.535769283630003, -56.285970011848889, -100.54840137956515],
[-33.066609321880179, 46.549821994306861, -84.062540548335591]])
ecef_init_batch = np.array([2068042.69652729, -5273435.40316622, 2927004.89190746])
ecef_positions_offset_batch = np.array([[ 2068089.41454771, -5273434.46829148, 2927074.04783672],
[ 2068103.31628647, -5273393.92275431, 2927102.08725987],
[ 2068108.49939636, -5273359.27047121, 2927045.07091581],
[ 2068075.12395611, -5273381.69432566, 2927041.08207992],
[ 2068060.72033399, -5273430.6061505, 2927094.54928305]])
ned_offsets_batch = np.array([[ 53.88103168, 43.83445935, -46.27488057],
[ 93.83378995, 71.57943024, -30.23113187],
[ 57.26725796, 89.05602684, 23.02265814],
[ 49.71775195, 49.79767572, 17.15351015],
[ 78.56272609, 18.53100158, -43.25290759]])
class TestNED(unittest.TestCase):
def test_small_distances(self):
start_geodetic = np.array([33.8042184, -117.888593, 0.0])
local_coord = coord.LocalCoord.from_geodetic(start_geodetic)
start_ned = local_coord.geodetic2ned(start_geodetic)
np.testing.assert_array_equal(start_ned, np.zeros(3,))
west_geodetic = start_geodetic + [0, -0.0005, 0]
west_ned = local_coord.geodetic2ned(west_geodetic)
self.assertLess(np.abs(west_ned[0]), 1e-3)
self.assertLess(west_ned[1], 0)
southwest_geodetic = start_geodetic + [-0.0005, -0.002, 0]
southwest_ned = local_coord.geodetic2ned(southwest_geodetic)
self.assertLess(southwest_ned[0], 0)
self.assertLess(southwest_ned[1], 0)
def test_ecef_geodetic(self):
# testing single
np.testing.assert_allclose(ecef_positions[0], coord.geodetic2ecef(geodetic_positions[0]), rtol=1e-9)
np.testing.assert_allclose(geodetic_positions[0,:2], coord.ecef2geodetic(ecef_positions[0])[:2], rtol=1e-9)
np.testing.assert_allclose(geodetic_positions[0,2], coord.ecef2geodetic(ecef_positions[0])[2], rtol=1e-9, atol=1e-4)
np.testing.assert_allclose(geodetic_positions[:,:2], coord.ecef2geodetic(ecef_positions)[:,:2], rtol=1e-9)
np.testing.assert_allclose(geodetic_positions[:,2], coord.ecef2geodetic(ecef_positions)[:,2], rtol=1e-9, atol=1e-4)
np.testing.assert_allclose(ecef_positions, coord.geodetic2ecef(geodetic_positions), rtol=1e-9)
np.testing.assert_allclose(geodetic_positions_radians[0], coord.ecef2geodetic(ecef_positions[0], radians=True), rtol=1e-5)
np.testing.assert_allclose(geodetic_positions_radians[:,:2], coord.ecef2geodetic(ecef_positions, radians=True)[:,:2], rtol=1e-7)
np.testing.assert_allclose(geodetic_positions_radians[:,2], coord.ecef2geodetic(ecef_positions, radians=True)[:,2], rtol=1e-7, atol=1e-4)
def test_ned(self):
for ecef_pos in ecef_positions:
converter = coord.LocalCoord.from_ecef(ecef_pos)
ecef_pos_moved = ecef_pos + [25, -25, 25]
ecef_pos_moved_double_converted = converter.ned2ecef(converter.ecef2ned(ecef_pos_moved))
np.testing.assert_allclose(ecef_pos_moved, ecef_pos_moved_double_converted, rtol=1e-9)
for geo_pos in geodetic_positions:
converter = coord.LocalCoord.from_geodetic(geo_pos)
geo_pos_moved = geo_pos + np.array([0, 0, 10])
geo_pos_double_converted_moved = converter.ned2geodetic(converter.geodetic2ned(geo_pos) + np.array([0,0,-10]))
np.testing.assert_allclose(geo_pos_moved[:2], geo_pos_double_converted_moved[:2], rtol=1e-9, atol=1e-6)
np.testing.assert_allclose(geo_pos_moved[2], geo_pos_double_converted_moved[2], rtol=1e-9, atol=1e-4)
def test_ned_saved_results(self):
for i, ecef_pos in enumerate(ecef_positions):
converter = coord.LocalCoord.from_ecef(ecef_pos)
np.testing.assert_allclose(converter.ned2ecef(ned_offsets[i]),
ecef_positions_offset[i],
rtol=1e-9, atol=1e-4)
np.testing.assert_allclose(converter.ecef2ned(ecef_positions_offset[i]),
ned_offsets[i],
rtol=1e-9, atol=1e-4)
def test_ned_batch(self):
converter = coord.LocalCoord.from_ecef(ecef_init_batch)
np.testing.assert_allclose(converter.ecef2ned(ecef_positions_offset_batch),
ned_offsets_batch,
rtol=1e-9, atol=1e-7)
np.testing.assert_allclose(converter.ned2ecef(ned_offsets_batch),
ecef_positions_offset_batch,
rtol=1e-9, atol=1e-7)
if __name__ == "__main__":
unittest.main()

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