diff --git a/Pipfile b/Pipfile
index 614968710c9606..6b9f7e95bf0e44 100644
--- a/Pipfile
+++ b/Pipfile
@@ -96,6 +96,9 @@ fastcluster = "==1.1.25"
backports-abc = "*"
pygame = "*"
simplejson = "*"
+python-logstash-async = "*"
+pandas = "*"
+seaborn = "*"
[packages]
overpy = {git = "https://github.com/commaai/python-overpy.git",ref = "f86529af402d4642e1faeb146671c40284007323"}
diff --git a/Pipfile.lock b/Pipfile.lock
index e4623df10afb4c..30c43e28671cc0 100644
--- a/Pipfile.lock
+++ b/Pipfile.lock
@@ -1,7 +1,7 @@
{
"_meta": {
"hash": {
- "sha256": "72c6a6eac19abf85ca5f272d04761f8336150d5bec599423c4b16891c99cb0bf"
+ "sha256": "89070d7d9478ac9e6ad2c9848aaf724cb7362a1de4af9f8fb8c40be5f37c043d"
},
"pipfile-spec": 6,
"requires": {
@@ -43,15 +43,15 @@
"sha256:9d98697f088eb1b0fa451391f91afb5e3ebde16bbdb272819fd091151fda4f1a",
"sha256:f0b0e4eba956de51238e17573b7087e852dfe9854afd2e9c873f73fc0ca0a6dd"
],
- "markers": "python_version < '3.2'",
+ "markers": "python_version == '2.7'",
"version": "==1.5"
},
"certifi": {
"hashes": [
- "sha256:59b7658e26ca9c7339e00f8f4636cdfe59d34fa37b9b04f6f9e9926b3cece1a5",
- "sha256:b26104d6835d1f5e49452a26eb2ff87fe7090b89dfcaee5ea2212697e1e1d7ae"
+ "sha256:046832c04d4e752f37383b628bc601a7ea7211496b4638f6514d0e5b9acc4939",
+ "sha256:945e3ba63a0b9f577b1395204e13c3a231f9bc0223888be653286534e5873695"
],
- "version": "==2019.3.9"
+ "version": "==2019.6.16"
},
"cffi": {
"hashes": [
@@ -149,37 +149,37 @@
},
"cython": {
"hashes": [
- "sha256:0afa0b121b89de619e71587e25702e2b7068d7da2164c47e6eee80c17823a62f",
- "sha256:1c608ba76f7a20cc9f0c021b7fe5cb04bc1a70327ae93a9298b1bc3e0edddebe",
- "sha256:26229570d6787ff3caa932fe9d802960f51a89239b990d275ae845405ce43857",
- "sha256:2a9deafa437b6154cac2f25bb88e0bfd075a897c8dc847669d6f478d7e3ee6b1",
- "sha256:2f28396fbce6d9d68a40edbf49a6729cf9d92a4d39ff0f501947a89188e9099f",
- "sha256:3983dd7b67297db299b403b29b328d9e03e14c4c590ea90aa1ad1d7b35fb178b",
- "sha256:4100a3f8e8bbe47d499cdac00e56d5fe750f739701ea52dc049b6c56f5421d97",
- "sha256:51abfaa7b6c66f3f18028876713c8804e73d4c2b6ceddbcbcfa8ec62429377f0",
- "sha256:61c24f4554efdb8fb1ac6c8e75dab301bcdf2b7b739ed0c2b267493bb43163c5",
- "sha256:700ccf921b2fdc9b23910e95b5caae4b35767685e0812343fa7172409f1b5830",
- "sha256:7b41eb2e792822a790cb2a171df49d1a9e0baaa8e81f58077b7380a273b93d5f",
- "sha256:803987d3b16d55faa997bfc12e8b97f1091f145930dee229b020487aed8a1f44",
- "sha256:99af5cfcd208c81998dcf44b3ca466dee7e17453cfb50e98b87947c3a86f8753",
- "sha256:9faea1cca34501c7e139bc7ef8e504d532b77865c58592493e2c154a003b450f",
- "sha256:a7ba4c9a174db841cfee9a0b92563862a0301d7ca543334666c7266b541f141a",
- "sha256:b26071c2313d1880599c69fd831a07b32a8c961ba69d7ccbe5db1cd8d319a4ca",
- "sha256:b49dc8e1116abde13a3e6a9eb8da6ab292c5a3325155fb872e39011b110b37e6",
- "sha256:bd40def0fd013569887008baa6da9ca428e3d7247adeeaeada153006227bb2e7",
- "sha256:bfd0db770e8bd4e044e20298dcae6dfc42561f85d17ee546dcd978c8b23066ae",
- "sha256:c2fad1efae5889925c8fd7867fdd61f59480e4e0b510f9db096c912e884704f1",
- "sha256:c81aea93d526ccf6bc0b842c91216ee9867cd8792f6725a00f19c8b5837e1715",
- "sha256:da786e039b4ad2bce3d53d4799438cf1f5e01a0108f1b8d78ac08e6627281b1a",
- "sha256:deab85a069397540987082d251e9c89e0e5b2e3e044014344ff81f60e211fc4b",
- "sha256:e3f1e6224c3407beb1849bdc5ae3150929e593e4cffff6ca41c6ec2b10942c80",
- "sha256:e74eb224e53aae3943d66e2d29fe42322d5753fd4c0641329bccb7efb3a46552",
- "sha256:ee697c7ea65cb14915a64f36874da8ffc2123df43cf8bc952172e04a26656cd6",
- "sha256:f37792b16d11606c28e428460bd6a3d14b8917b109e77cdbe4ca78b0b9a52c87",
- "sha256:fd2906b54cbf879c09d875ad4e4687c58d87f5ed03496063fec1c9065569fd5d"
- ],
- "index": "pypi",
- "version": "==0.29.10"
+ "sha256:04ebf16df9406d3279a2489c3327803c782d9e17637d525bfb44ecf5ec65850f",
+ "sha256:1486ec88d1c73dea3846a5640054018b002608e04a791ccbd2082a47bce4440a",
+ "sha256:20da832a5e9a8e93d1e1eb64650258956723940968eb585506531719b55b804f",
+ "sha256:2464688b523d7a133b52cf1343c1c595b92fc6554af1015f74b9e49951e992d4",
+ "sha256:27827b68a8359e9ab6bf683c68d8ee79863a0c94a577acf56aa02cc302e16f51",
+ "sha256:27deeeeca0fd8933af07923e809c8fed0763d150a4fdd4082932a33b8c874ed6",
+ "sha256:31f4da785d5e09deb852ea59795a629c5befb6040929e7880c6f63e6668246ce",
+ "sha256:4828cf8fa638c35139e643f30201b240c0d156b1b9967a7321ae42d721d7224c",
+ "sha256:48b365e32cc5639ae2c239d7bd4f8a1d920a13a7ae92113c4c938903c9400147",
+ "sha256:4eb71856c1d1b33083df9318fd30143470ad6f0d1b9ad2ee61a120710842d28b",
+ "sha256:5b06ef8422d27d8128f8f80bdefa111eadcab246fba1d668720af4f0b97b7a0e",
+ "sha256:71c553640e1ddaaf143e38dbc6cd1863fa3c0738fb1830a9aaffba9a51838f30",
+ "sha256:73e2742ee1f923c5f213183bf493901f9630e395634fce5b739a53b7dc5d64be",
+ "sha256:82a632bc02063eff0b8e7ff3089aa3d912d1c7499709f51c8f04f57c8832cfe6",
+ "sha256:977ca1ac059e4d4a4bf5fe2224986baf42b69290453eda44822606f4deae6515",
+ "sha256:a7e6217d0dd864a7cc4f457172766864496efd64d24d4980df1521f75f992761",
+ "sha256:ad0ed7dd5dff76eb3aae8c18d95b1c9f885a91a92132728051a704fb8060d08c",
+ "sha256:b1b8eda9e931f0ca1aadb95a890811bdf530407e48c962643b85675329d99abf",
+ "sha256:cec99c79205131da3ee75becea1f3f55c57bf6a1c500431de9ae7a32ac8a5cc4",
+ "sha256:d4bbdaa6f61ce2ef26535a7d473d6ffa6e413013c5c580af999546bf1627ae11",
+ "sha256:d8bdb4208975b12048bdace46e9dd8e3dda3872432f95b53789700a1330e6060",
+ "sha256:dce0362ff9b61f8411d1efc9e16fc528dadbd3707a557561992457f5cb446297",
+ "sha256:defbbbf5653629ce5cc54091ce49c6830da8d3104de53ed2169c9efcb0720f27",
+ "sha256:e0c53a7e2b6d82ec3c26c009c937fc88eb8c7edf000c54334261beaf56bb08f2",
+ "sha256:e1065bacfe5303f107896e63263537dee90920d26050f2e23c4af12c37da2db6",
+ "sha256:e142837c4212c0b2c71e6773cb6740828922806b4c00ee4215be3ceb558671e6",
+ "sha256:f4cbbab28c93ffee6ec929cf0826f0b11d2488e53a708d51142a5e62f8cd9806",
+ "sha256:fa8f63b6551621eea9efea4db37ae401104352f0ebaee32f7d20be88cbe589c3"
+ ],
+ "index": "pypi",
+ "version": "==0.29.12"
},
"enum34": {
"hashes": [
@@ -193,19 +193,19 @@
},
"flask": {
"hashes": [
- "sha256:ad7c6d841e64296b962296c2c2dabc6543752985727af86a975072dea984b6f3",
- "sha256:e7d32475d1de5facaa55e3958bc4ec66d3762076b074296aa50ef8fdc5b9df61"
+ "sha256:13f9f196f330c7c2c5d7a5cf91af894110ca0215ac051b5844701f2bfd934d52",
+ "sha256:45eb5a6fd193d6cf7e0cf5d8a5b31f83d5faae0293695626f539a823e93b13f6"
],
"index": "pypi",
- "version": "==1.0.3"
+ "version": "==1.1.1"
},
"futures": {
"hashes": [
- "sha256:9ec02aa7d674acb8618afb127e27fde7fc68994c0437ad759fa094a574adb265",
- "sha256:ec0a6cb848cc212002b9828c3e34c675e0c9ff6741dc445cab6fdd4e1085d1f1"
+ "sha256:49b3f5b064b6e3afc3316421a3f25f66c137ae88f068abbf72830170033c5e16",
+ "sha256:7e033af76a5e35f58e56da7a91e687706faf4e7bdfb2cbc3f2cca6b9bcda9794"
],
"markers": "python_version < '3.2'",
- "version": "==3.2.0"
+ "version": "==3.3.0"
},
"gunicorn": {
"hashes": [
@@ -240,10 +240,10 @@
},
"isort": {
"hashes": [
- "sha256:c40744b6bc5162bbb39c1257fe298b7a393861d50978b565f3ccd9cb9de0182a",
- "sha256:f57abacd059dc3bd666258d1efb0377510a89777fda3e3274e3c01f7c03ae22d"
+ "sha256:54da7e92468955c4fceacd0c86bd0ec997b0e1ee80d97f67c35a78b719dccab1",
+ "sha256:6e811fcb295968434526407adb8796944f1988c5b65e8139058f2014cbe100fd"
],
- "version": "==4.3.20"
+ "version": "==4.3.21"
},
"itsdangerous": {
"hashes": [
@@ -470,11 +470,11 @@
},
"pylint": {
"hashes": [
- "sha256:02c2b6d268695a8b64ad61847f92e611e6afcff33fd26c3a2125370c4662905d",
- "sha256:ee1e85575587c5b58ddafa25e1c1b01691ef172e139fc25585e5d3f02451da93"
+ "sha256:367e3d49813d349a905390ac27989eff82ab84958731c5ef0bef867452cfdc42",
+ "sha256:97a42df23d436c70132971d1dcb9efad2fe5c0c6add55b90161e773caf729300"
],
"index": "pypi",
- "version": "==1.9.4"
+ "version": "==1.9.5"
},
"pyserial": {
"hashes": [
@@ -511,34 +511,34 @@
},
"pyzmq": {
"hashes": [
- "sha256:1651e52ed91f0736afd6d94ef9f3259b5534ce8beddb054f3d5ca989c4ef7c4f",
- "sha256:5ccb9b3d4cd20c000a9b75689d5add8cd3bce67fcbd0f8ae1b59345247d803af",
- "sha256:5e120c4cd3872e332fb35d255ad5998ebcee32ace4387b1b337416b6b90436c7",
- "sha256:5e2a3707c69a7281a9957f83718815fd74698cba31f6d69f9ed359921f662221",
- "sha256:63d51add9af8d0442dc90f916baf98fdc04e3b0a32afec4bfc83f8d85e72959f",
- "sha256:65c5a0bdc49e20f7d6b03a661f71e2fda7a99c51270cafe71598146d09810d0d",
- "sha256:66828fabe911aa545d919028441a585edb7c9c77969a5fea6722ef6e6ece38ab",
- "sha256:7d79427e82d9dad6e9b47c0b3e7ae5f9d489b1601e3a36ea629bb49501a4daf3",
- "sha256:824ee5d3078c4eae737ffc500fbf32f2b14e6ec89b26b435b7834febd70120cf",
- "sha256:89dc0a83cccec19ff3c62c091e43e66e0183d1e6b4658c16ee4e659518131494",
- "sha256:8b319805f6f7c907b101c864c3ca6cefc9db8ce0791356f180b1b644c7347e4c",
- "sha256:90facfb379ab47f94b19519c1ecc8ec8d10813b69d9c163117944948bdec5d15",
- "sha256:a0a178c7420021fc0730180a914a4b4b3092ce9696ceb8e72d0f60f8ce1655dd",
- "sha256:a7a89591ae315baccb8072f216614b3e59aed7385aef4393a6c741783d6ee9cf",
- "sha256:ba2578f0ae582452c02ed9fac2dc477b08e80ce05d2c0885becf5fff6651ccb0",
- "sha256:c69b0055c55702f5b0b6b354133e8325b9a56dbc80e1be2d240bead253fb9825",
- "sha256:ca434e1858fe222380221ddeb81e86f45522773344c9da63c311d17161df5e06",
- "sha256:d4b8ecfc3d92f114f04d5c40f60a65e5196198b827503341521dda12d8b14939",
- "sha256:d706025c47b09a54f005953ebe206f6d07a22516776faa4f509aaff681cc5468",
- "sha256:d8f27e958f8a2c0c8ffd4d8855c3ce8ac3fa1e105f0491ce31729aa2b3229740",
- "sha256:dbd264298f76b9060ce537008eb989317ca787c857e23cbd1b3ddf89f190a9b1",
- "sha256:e926d66f0df8fdbf03ba20583af0f215e475c667fb033d45fd031c66c63e34c9",
- "sha256:efc3bd48237f973a749f7312f68062f1b4ca5c2032a0673ca3ea8e46aa77187b",
- "sha256:f59bc782228777cbfe04555707a9c56d269c787ed25d6d28ed9d0fbb41cb1ad2",
- "sha256:f8da5322f4ff5f667a0d5a27e871b560c6637153c81e318b35cb012b2a98835c"
- ],
- "index": "pypi",
- "version": "==18.0.1"
+ "sha256:00dd015159eaeb1c0731ad49310e1f5d839c9a35a15e4f3267f5052233fad99b",
+ "sha256:03913b6beb8e7b417b9910b0ee1fd5d62e9626d218faefbe879d70714ceab1a2",
+ "sha256:13f17386df81d5e6efb9a4faea341d8de22cdc82e49a326dded26e33f42a3112",
+ "sha256:16c6281d96885db1e15f7047ddc1a8f48ff4ea35d31ca709f4d2eb39f246d356",
+ "sha256:17efab4a804e31f58361631256d660214204046f9e2b962738b171b9ad674ea7",
+ "sha256:2b79919ddeff3d3c96aa6087c21d294c8db1c01f6bfeee73324944683685f419",
+ "sha256:2f832e4711657bb8d16ea1feba860f676ec5f14fb9fe3b449b5953a60e89edae",
+ "sha256:31a11d37ac73107363b47e14c94547dbfc6a550029c3fe0530be443199026fc2",
+ "sha256:33a3e928e6c3138c675e1d6702dd11f6b7050177d7aab3fc322db6e1d2274490",
+ "sha256:34a38195a6d3a9646cbcdaf8eb245b4d935c7a57f7e1b3af467814bc1a92467e",
+ "sha256:42900054f1500acef6df7428edf806abbf641bf92eb9ceded24aa863397c3bae",
+ "sha256:4ccc7f3c63aa9d744dadb62c49eda2d0e7de55649b80c45d7c684d70161a69af",
+ "sha256:5b220c37c346e6575db8c88a940c1fc234f99ce8e0068c408919bb8896c4b6d2",
+ "sha256:6074848da5c8b44a1ca40adf75cf65aa92bc80f635e8249aa8f37a69b2b9b6f5",
+ "sha256:61a4155964bd4a14ef95bf46cb1651bcf8dcbbed8c0108e9c974c1fcbb57788f",
+ "sha256:62b5774688326600c52f587f7a033ca6b6284bef4c8b1b5fda32480897759eac",
+ "sha256:65a9ffa4f9f085d696f16fd7541f34b3c357d25fe99c90e3bce2ea59c3b5b4b6",
+ "sha256:76a077d2c30f8adc5e919a55985a784b96aeca69b53c1ea6fd5723d3ae2e6f53",
+ "sha256:8e5b4c51557071d6379d6dc1f54f35e9f6a137f5e84e102efb869c8d3c13c8ff",
+ "sha256:917f73e07cc04f0678a96d93e7bb8b1adcccdde9ccfe202e622814f4d1d1ecfd",
+ "sha256:91c75d3c4c357f9643e739db9e79ab9681b2f6ae8ec5678d6ef2ea0d01532596",
+ "sha256:923dd91618b100bb4c92ab9ed7b65825a595b8524a094ce03c7cb2aaae7d353b",
+ "sha256:9849054e0355e2bc7f4668766a25517ba76095031c9ff5e39ae8949cee5bb024",
+ "sha256:c9d453933f0e3f44b9759189f2a18aa765f7f1a4345c727c18ebe8ad0d748d26",
+ "sha256:cb7514936277abce64c2f4c56883e5704d85ed04d98d2d432d1c6764003bb003"
+ ],
+ "index": "pypi",
+ "version": "==18.0.2"
},
"raven": {
"hashes": [
@@ -597,11 +597,11 @@
},
"tqdm": {
"hashes": [
- "sha256:0a860bf2683fdbb4812fe539a6c22ea3f1777843ea985cb8c3807db448a0f7ab",
- "sha256:e288416eecd4df19d12407d0c913cbf77aa8009d7fddb18f632aded3bdbdda6b"
+ "sha256:14a285392c32b6f8222ecfbcd217838f88e11630affe9006cd0e94c7eff3cb61",
+ "sha256:25d4c0ea02a305a688e7e9c2cdc8f862f989ef2a4701ab28ee963295f5b109ab"
],
"index": "pypi",
- "version": "==4.32.1"
+ "version": "==4.32.2"
},
"urllib3": {
"hashes": [
@@ -613,10 +613,10 @@
},
"utm": {
"hashes": [
- "sha256:a6608a67df84418fd959a79b228b90ab55b2ae877827f9c210947104c5a75d0e"
+ "sha256:07e55707ed660eec1ae983bd54a406c437962618a6261b38d70592fe30f5f508"
],
"index": "pypi",
- "version": "==0.4.2"
+ "version": "==0.5.0"
},
"websocket-client": {
"hashes": [
@@ -628,16 +628,16 @@
},
"werkzeug": {
"hashes": [
- "sha256:865856ebb55c4dcd0630cdd8f3331a1847a819dda7e8c750d3db6f2aa6c0209c",
- "sha256:a0b915f0815982fb2a09161cb8f31708052d0951c3ba433ccc5e1aa276507ca6"
+ "sha256:87ae4e5b5366da2347eb3116c0e6c681a0e939a33b2805e2c0cbd282664932c4",
+ "sha256:a13b74dd3c45f758d4ebdb224be8f1ab8ef58b3c0ffc1783a8c7d9f4f50227e6"
],
- "version": "==0.15.4"
+ "version": "==0.15.5"
},
"wrapt": {
"hashes": [
- "sha256:4aea003270831cceb8a90ff27c4031da6ead7ec1886023b80ce0dfe0adf61533"
+ "sha256:565a021fd19419476b9362b05eeaa094178de64f8361e44468f9e9d7843901e1"
],
- "version": "==1.11.1"
+ "version": "==1.11.2"
}
},
"develop": {
@@ -649,19 +649,19 @@
},
"adal": {
"hashes": [
- "sha256:82e84fa0b442caf8131f1e87a7ebee2546f57ab16a8917a599a02b6e455cb1b0",
- "sha256:b6edd095be66561382bdaa59d40b04490e93149fb3b7fa44c1fa5504eed5b8b9"
+ "sha256:5a7f1e037c6290c6d7609cab33a9e5e988c2fbec5c51d1c4c649ee3faff37eaf",
+ "sha256:fd17e5661f60634ddf96a569b95d34ccb8a98de60593d729c28bdcfe360eaad1"
],
- "version": "==1.2.1"
+ "version": "==1.2.2"
},
"aenum": {
"hashes": [
- "sha256:3df9b84cce5dc9ed77c337079f97b66c44c0053eb87d6f4d46b888dc45801e38",
- "sha256:7a77c205c4bc9d7fe9bd73b3193002d724aebf5909fa0d297534208953891ec8",
- "sha256:a3208e4b28db3a7b232ff69b934aef2ea1bf27286d9978e1e597d46f490e4687"
+ "sha256:058f0cfaf911899dc21b334362047df74ce989335dd8dff8e4be1a6313b15232",
+ "sha256:6af970173d9b4ac0384ad7d1cfe9523eeb9a3578793e1664090c13cb59df6469",
+ "sha256:80f14366578d84f6bccb0670259744cb3a7f2ab504480c306238a23cdd569457"
],
"index": "pypi",
- "version": "==2.1.2"
+ "version": "==2.2.0"
},
"amqp": {
"hashes": [
@@ -760,7 +760,7 @@
"sha256:9d98697f088eb1b0fa451391f91afb5e3ebde16bbdb272819fd091151fda4f1a",
"sha256:f0b0e4eba956de51238e17573b7087e852dfe9854afd2e9c873f73fc0ca0a6dd"
],
- "markers": "python_version < '3.2'",
+ "markers": "python_version == '2.7'",
"version": "==1.5"
},
"backports.lzma": {
@@ -817,18 +817,18 @@
},
"boto3": {
"hashes": [
- "sha256:794a9a4b6a9e40c1ac57a377de609872d28d62afe4295c48cdc1b1c92f96ab8e",
- "sha256:962b078568cc520869ea2842f307864c9abc30ad5ed160e12b2a89debf220161"
+ "sha256:34a8ddb7247316be6ea94c7eeee41212312d250d99bf668fcd6748629b578622",
+ "sha256:71f3554cc69fa20be06cf20d6c9e0d8095d7c40695b48618676c3cd9a5ba0783"
],
"index": "pypi",
- "version": "==1.9.168"
+ "version": "==1.9.189"
},
"botocore": {
"hashes": [
- "sha256:675f2b66af486dd02f5825601bb0c8378773999f8705c6f75450849ca41fed80",
- "sha256:c3fc314c0e0aa13aa024d272d991e23d37550050abf96b3c7dea889ed1743723"
+ "sha256:4febbf206d1dc8b8299aa211d8e382d5bf3f22097855b9f98d5e8c401ef8192b",
+ "sha256:b62ab3e4e98e075fc9e8e8fd4e8f5b92ebf311a6dc9f7578650938c7bc94e592"
],
- "version": "==1.12.168"
+ "version": "==1.12.189"
},
"celery": {
"hashes": [
@@ -840,10 +840,10 @@
},
"certifi": {
"hashes": [
- "sha256:59b7658e26ca9c7339e00f8f4636cdfe59d34fa37b9b04f6f9e9926b3cece1a5",
- "sha256:b26104d6835d1f5e49452a26eb2ff87fe7090b89dfcaee5ea2212697e1e1d7ae"
+ "sha256:046832c04d4e752f37383b628bc601a7ea7211496b4638f6514d0e5b9acc4939",
+ "sha256:945e3ba63a0b9f577b1395204e13c3a231f9bc0223888be653286534e5873695"
],
- "version": "==2019.3.9"
+ "version": "==2019.6.16"
},
"cffi": {
"hashes": [
@@ -947,37 +947,37 @@
},
"cython": {
"hashes": [
- "sha256:0afa0b121b89de619e71587e25702e2b7068d7da2164c47e6eee80c17823a62f",
- "sha256:1c608ba76f7a20cc9f0c021b7fe5cb04bc1a70327ae93a9298b1bc3e0edddebe",
- "sha256:26229570d6787ff3caa932fe9d802960f51a89239b990d275ae845405ce43857",
- "sha256:2a9deafa437b6154cac2f25bb88e0bfd075a897c8dc847669d6f478d7e3ee6b1",
- "sha256:2f28396fbce6d9d68a40edbf49a6729cf9d92a4d39ff0f501947a89188e9099f",
- "sha256:3983dd7b67297db299b403b29b328d9e03e14c4c590ea90aa1ad1d7b35fb178b",
- "sha256:4100a3f8e8bbe47d499cdac00e56d5fe750f739701ea52dc049b6c56f5421d97",
- "sha256:51abfaa7b6c66f3f18028876713c8804e73d4c2b6ceddbcbcfa8ec62429377f0",
- "sha256:61c24f4554efdb8fb1ac6c8e75dab301bcdf2b7b739ed0c2b267493bb43163c5",
- "sha256:700ccf921b2fdc9b23910e95b5caae4b35767685e0812343fa7172409f1b5830",
- "sha256:7b41eb2e792822a790cb2a171df49d1a9e0baaa8e81f58077b7380a273b93d5f",
- "sha256:803987d3b16d55faa997bfc12e8b97f1091f145930dee229b020487aed8a1f44",
- "sha256:99af5cfcd208c81998dcf44b3ca466dee7e17453cfb50e98b87947c3a86f8753",
- "sha256:9faea1cca34501c7e139bc7ef8e504d532b77865c58592493e2c154a003b450f",
- "sha256:a7ba4c9a174db841cfee9a0b92563862a0301d7ca543334666c7266b541f141a",
- "sha256:b26071c2313d1880599c69fd831a07b32a8c961ba69d7ccbe5db1cd8d319a4ca",
- "sha256:b49dc8e1116abde13a3e6a9eb8da6ab292c5a3325155fb872e39011b110b37e6",
- "sha256:bd40def0fd013569887008baa6da9ca428e3d7247adeeaeada153006227bb2e7",
- "sha256:bfd0db770e8bd4e044e20298dcae6dfc42561f85d17ee546dcd978c8b23066ae",
- "sha256:c2fad1efae5889925c8fd7867fdd61f59480e4e0b510f9db096c912e884704f1",
- "sha256:c81aea93d526ccf6bc0b842c91216ee9867cd8792f6725a00f19c8b5837e1715",
- "sha256:da786e039b4ad2bce3d53d4799438cf1f5e01a0108f1b8d78ac08e6627281b1a",
- "sha256:deab85a069397540987082d251e9c89e0e5b2e3e044014344ff81f60e211fc4b",
- "sha256:e3f1e6224c3407beb1849bdc5ae3150929e593e4cffff6ca41c6ec2b10942c80",
- "sha256:e74eb224e53aae3943d66e2d29fe42322d5753fd4c0641329bccb7efb3a46552",
- "sha256:ee697c7ea65cb14915a64f36874da8ffc2123df43cf8bc952172e04a26656cd6",
- "sha256:f37792b16d11606c28e428460bd6a3d14b8917b109e77cdbe4ca78b0b9a52c87",
- "sha256:fd2906b54cbf879c09d875ad4e4687c58d87f5ed03496063fec1c9065569fd5d"
- ],
- "index": "pypi",
- "version": "==0.29.10"
+ "sha256:04ebf16df9406d3279a2489c3327803c782d9e17637d525bfb44ecf5ec65850f",
+ "sha256:1486ec88d1c73dea3846a5640054018b002608e04a791ccbd2082a47bce4440a",
+ "sha256:20da832a5e9a8e93d1e1eb64650258956723940968eb585506531719b55b804f",
+ "sha256:2464688b523d7a133b52cf1343c1c595b92fc6554af1015f74b9e49951e992d4",
+ "sha256:27827b68a8359e9ab6bf683c68d8ee79863a0c94a577acf56aa02cc302e16f51",
+ "sha256:27deeeeca0fd8933af07923e809c8fed0763d150a4fdd4082932a33b8c874ed6",
+ "sha256:31f4da785d5e09deb852ea59795a629c5befb6040929e7880c6f63e6668246ce",
+ "sha256:4828cf8fa638c35139e643f30201b240c0d156b1b9967a7321ae42d721d7224c",
+ "sha256:48b365e32cc5639ae2c239d7bd4f8a1d920a13a7ae92113c4c938903c9400147",
+ "sha256:4eb71856c1d1b33083df9318fd30143470ad6f0d1b9ad2ee61a120710842d28b",
+ "sha256:5b06ef8422d27d8128f8f80bdefa111eadcab246fba1d668720af4f0b97b7a0e",
+ "sha256:71c553640e1ddaaf143e38dbc6cd1863fa3c0738fb1830a9aaffba9a51838f30",
+ "sha256:73e2742ee1f923c5f213183bf493901f9630e395634fce5b739a53b7dc5d64be",
+ "sha256:82a632bc02063eff0b8e7ff3089aa3d912d1c7499709f51c8f04f57c8832cfe6",
+ "sha256:977ca1ac059e4d4a4bf5fe2224986baf42b69290453eda44822606f4deae6515",
+ "sha256:a7e6217d0dd864a7cc4f457172766864496efd64d24d4980df1521f75f992761",
+ "sha256:ad0ed7dd5dff76eb3aae8c18d95b1c9f885a91a92132728051a704fb8060d08c",
+ "sha256:b1b8eda9e931f0ca1aadb95a890811bdf530407e48c962643b85675329d99abf",
+ "sha256:cec99c79205131da3ee75becea1f3f55c57bf6a1c500431de9ae7a32ac8a5cc4",
+ "sha256:d4bbdaa6f61ce2ef26535a7d473d6ffa6e413013c5c580af999546bf1627ae11",
+ "sha256:d8bdb4208975b12048bdace46e9dd8e3dda3872432f95b53789700a1330e6060",
+ "sha256:dce0362ff9b61f8411d1efc9e16fc528dadbd3707a557561992457f5cb446297",
+ "sha256:defbbbf5653629ce5cc54091ce49c6830da8d3104de53ed2169c9efcb0720f27",
+ "sha256:e0c53a7e2b6d82ec3c26c009c937fc88eb8c7edf000c54334261beaf56bb08f2",
+ "sha256:e1065bacfe5303f107896e63263537dee90920d26050f2e23c4af12c37da2db6",
+ "sha256:e142837c4212c0b2c71e6773cb6740828922806b4c00ee4215be3ceb558671e6",
+ "sha256:f4cbbab28c93ffee6ec929cf0826f0b11d2488e53a708d51142a5e62f8cd9806",
+ "sha256:fa8f63b6551621eea9efea4db37ae401104352f0ebaee32f7d20be88cbe589c3"
+ ],
+ "index": "pypi",
+ "version": "==0.29.12"
},
"datadog": {
"hashes": [
@@ -1098,11 +1098,11 @@
},
"flask": {
"hashes": [
- "sha256:ad7c6d841e64296b962296c2c2dabc6543752985727af86a975072dea984b6f3",
- "sha256:e7d32475d1de5facaa55e3958bc4ec66d3762076b074296aa50ef8fdc5b9df61"
+ "sha256:13f9f196f330c7c2c5d7a5cf91af894110ca0215ac051b5844701f2bfd934d52",
+ "sha256:45eb5a6fd193d6cf7e0cf5d8a5b31f83d5faae0293695626f539a823e93b13f6"
],
"index": "pypi",
- "version": "==1.0.3"
+ "version": "==1.1.1"
},
"flask-cors": {
"hashes": [
@@ -1145,11 +1145,11 @@
},
"futures": {
"hashes": [
- "sha256:9ec02aa7d674acb8618afb127e27fde7fc68994c0437ad759fa094a574adb265",
- "sha256:ec0a6cb848cc212002b9828c3e34c675e0c9ff6741dc445cab6fdd4e1085d1f1"
+ "sha256:49b3f5b064b6e3afc3316421a3f25f66c137ae88f068abbf72830170033c5e16",
+ "sha256:7e033af76a5e35f58e56da7a91e687706faf4e7bdfb2cbc3f2cca6b9bcda9794"
],
"markers": "python_version < '3.2'",
- "version": "==3.2.0"
+ "version": "==3.3.0"
},
"gast": {
"hashes": [
@@ -1228,40 +1228,40 @@
},
"grpcio": {
"hashes": [
- "sha256:0232add03144dd3cf9b660e2718244cb8e175370dca4d3855cb4e489a7811b53",
- "sha256:0f20e6dcb1b8662cdca033bb97c0a8116a5343e3ebc7f71c5fe7f89039978350",
- "sha256:10b07a623d33d4966f45c85d410bc6a79c5ac6341f06c3beda6c22be12cbfe07",
- "sha256:10c0476d5a52d21f402fc073745dc43b87cc8e080a1f49bbff4e1059019310fb",
- "sha256:289dae0b35c59d191c524e976dd0a6f8c995d2062e72621eb866ad0f4472a635",
- "sha256:2be726f16142d358a0df1e81d583d6820ee561a7856a79cca2fbe49989308be7",
- "sha256:4338d2a81f5b4ca022e085040b3cfce19419a5ce44aa7e6810ac1df05365bed7",
- "sha256:4c535b46f20e66bee3097583231977e721acdfcb1671d1490c99b7be8902ce18",
- "sha256:557154aef70a0e979700cc9528bc8b606b668084a29a0d57dbc4b06b078a2f1c",
- "sha256:5bfdd7e6647498f979dc46583723c852d97b25afe995d55aa1c76a5f9816bc1f",
- "sha256:87d8943ae7aa6ca5bbad732867d7f17d2550e4966a0c15b52088e8b579422e47",
- "sha256:89d8719d8de4d137678f7caa979e1b0a6fd4026f8096ceef8c2d164bbabefaf2",
- "sha256:9c3f4af989ce860710ac1864dc2e867dd87e6cee51a2368df1b253596868e52f",
- "sha256:9da52c3c728883aee429bb7c315049f50b2139f680cd86bb1165418e4f93a982",
- "sha256:9e9736659987beab42d18525ed10d21f80a1ba8389eac03425fbfd5684e6bbf0",
- "sha256:9ebcbb1a054cab362d29d3be571d43d6b9b23302d9fc4b43e5327000da1680a9",
- "sha256:a93e08636623e24c939851e2e0c0140b14f524b2980c9cdc4ea52b70a871c7e0",
- "sha256:ac322d86d1a079e0a118d544443ee16f320af0062c191b4754c0c6ec2fc79310",
- "sha256:b1fb101459868f52df6b61e7bb13375e50badf17a160e39fe1d51ae19e53f461",
- "sha256:b39aac96cceac624a23d540473835086a3ffa77c91030189988c073488434493",
- "sha256:b65507bc273c6dbf539175a786a344cc0ac78d50e5584f72c6599733f8a3301f",
- "sha256:be5bb6e47417e537c884a2e2ff2e1a8b2c064a998fcfdfcc67528d4e63e7ebaf",
- "sha256:c92de6a28a909c4f460dc1bbbcb50d676cf0b1f40224b222761f73fdd851b522",
- "sha256:c9f5962eb7fa7607b20eb0e4f59ed35829bd600fc0eacb626a6db83229a3e445",
- "sha256:d00bdf9c546ed6e649f785c55b05288e8b2dbb6bf2eb74b6c579fa0d591d35bd",
- "sha256:da804b1dd8293bd9d61b1e6ea989c887ba042a808a4fbdd80001cfa059aafed2",
- "sha256:ead6c5aa3e807345913649c3be395aaca2bbb2d225f18b8f31f37eab225508f6",
- "sha256:eb4d81550ce6f826af4ec6e8d98be347fe96291d718bf115c3f254621ae8d98d",
- "sha256:ef6a18ec8fd32ec81748fe720544ea2fb2d2dc50fd6d06739d5e2eb8f0626a1c",
- "sha256:fad42835656e0b6d3b7ffc900598e776722e30f43b7234a48f2576ca30f31a47",
- "sha256:fb98dbfee0d963b49ae5754554028cf62e6bd695f22de16d242ba9d2f0b7339b",
- "sha256:fb9cd9bb8d26dc17c2dd715a46bca3a879ec8283879b164e85863110dc6e3b2a"
- ],
- "version": "==1.21.1"
+ "sha256:03b78b4e7dcdfe3e257bb528cc93923f9cbbab6d5babf15a60d21e9a4a70b1a2",
+ "sha256:1ce0ccfbdfe84387dbcbf44adb4ae16ec7ae70e166ffab478993eb1ea1cba3ce",
+ "sha256:22e167a9406d73dd19ffe8ed6a485f17e6eac82505be8c108897f15e68badcbb",
+ "sha256:31d0aeca8d8ee2301c62c5c340e0889d653b1280d68f9fa203982cb6337b050e",
+ "sha256:44c7f99ca17ebbcc96fc54ed00b454d8313f1eac28c563098d8b901025aff941",
+ "sha256:5471444f53f9db6a1f1f11f5dbc173228881df8446380b6b98f90afb8fd8348e",
+ "sha256:561bca3b1bde6d6564306eb05848fd155136e9c3a25d2961129b1e2edba22fce",
+ "sha256:5bf58e1d2c2f55365c06e8cb5abe067b88ca2e5550fb62009c41df4b54505acf",
+ "sha256:6b7163d1e85d76b0815df63fcc310daec02b44532bb433f743142d4febcb181f",
+ "sha256:766d79cddad95f5f6020037fe60ea8b98578afdf0c59d5a60c106c1bdd886303",
+ "sha256:770b7372d5ca68308ff66d7baee53369fa5ce985f84bcb6aa1948c1f2f7b02f2",
+ "sha256:7ab178da777fc0f55b6aef5a755f99726e8e4b75e3903954df07b27059b54fcf",
+ "sha256:8078305e77c2f6649d36b24d8778096413e474d9d7892c6f92cfb589c9d71b2e",
+ "sha256:85600b63a386d860eeaa955e9335e18dd0d7e5477e9214825abf2c2884488369",
+ "sha256:857d9b939ae128be1c0c792eb885c7ff6a386b9dea899ac4b06f4d90a31f9d87",
+ "sha256:87a41630c90c179fa5c593400f30a467c498972c702f348d41e19dafeb1d319e",
+ "sha256:8805d486c6128cc0fcc8ecf16c4095d99a8693a541ef851429ab334e028a4a97",
+ "sha256:8d71b7a89c306a41ccc7741fc9409b14f5b86727455c2a1c0c7cfcb0f784e1f2",
+ "sha256:9e1b80bd65f8f160880cb4dad7f55697f6d37b2d7f251fc0c2128e811928f369",
+ "sha256:9e290c84a145ae2411ee0ec9913c41cd7500e2e7485fe93632434d84ef4fda67",
+ "sha256:9ec9f88b5bc94bd99372f27cdd53af1c92ba06717380b127733b953cfb181174",
+ "sha256:a0a02a8b4ba6deadf706d5f849539b3685b72b186a3c9ef5d43e8972ed60fb6f",
+ "sha256:a4059c59519f5940e01a071f74ae2a60ea8f6185b03d22a09d40c7959a36b16b",
+ "sha256:a6e028c2a6da2ebfa2365a5b32531d311fbfec0e3600fc27e901b64f0ff7e54e",
+ "sha256:adcdebf9f8463df4120c427cf6c9aed39258bccd03ed37b6939e7a145d64d6e0",
+ "sha256:bdec982610259d07156a58f80b8c3e69be7751a9208bc577b059c5193d087fad",
+ "sha256:cefc4d4251ffb73feb303d4b7e9d6c367cb60f2db16d259ea28b114045f965aa",
+ "sha256:d4145c8aa6afbac10ad27e408f7ce15992fe89ba5d0b4abca31c0c2729864c03",
+ "sha256:da76dc5ad719ee99de5ea28a5629ff92172cbb4a70d8a6ae3a5b7a53c7382ce1",
+ "sha256:dde2452c08ef8b6426ccab6b5b6de9f06d836d9937d6870e68153cbf8cb49348",
+ "sha256:e3d88091d2539a4868750914a6fe7b9ec50e42b913851fc1b77423b5bd918530",
+ "sha256:f9c67cfe6278499d7f83559dc6322a8bbb108e307817a3d7acbfea807b3603cc"
+ ],
+ "version": "==1.22.0"
},
"gunicorn": {
"hashes": [
@@ -1384,10 +1384,10 @@
},
"ipywidgets": {
"hashes": [
- "sha256:0f2b5cde9f272cb49d52f3f0889fdd1a7ae1e74f37b48dac35a83152780d2b7b",
- "sha256:a3e224f430163f767047ab9a042fc55adbcab0c24bbe6cf9f306c4f89fdf0ba3"
+ "sha256:cb263c6974aca902d00a435711823bb4aaf6614a5f997f517e15fa84151e8fa2",
+ "sha256:eab6060f20f7f10d91f6efc8d33f9fd22133406980fcaee2738d836a910402f4"
],
- "version": "==7.4.2"
+ "version": "==7.5.0"
},
"isodate": {
"hashes": [
@@ -1398,10 +1398,10 @@
},
"isort": {
"hashes": [
- "sha256:c40744b6bc5162bbb39c1257fe298b7a393861d50978b565f3ccd9cb9de0182a",
- "sha256:f57abacd059dc3bd666258d1efb0377510a89777fda3e3274e3c01f7c03ae22d"
+ "sha256:54da7e92468955c4fceacd0c86bd0ec997b0e1ee80d97f67c35a78b719dccab1",
+ "sha256:6e811fcb295968434526407adb8796944f1988c5b65e8139058f2014cbe100fd"
],
- "version": "==4.3.20"
+ "version": "==4.3.21"
},
"itsdangerous": {
"hashes": [
@@ -1458,10 +1458,10 @@
},
"jupyter-client": {
"hashes": [
- "sha256:b5f9cb06105c1d2d30719db5ffb3ea67da60919fb68deaefa583deccd8813551",
- "sha256:c44411eb1463ed77548bc2d5ec0d744c9b81c4a542d9637c7a52824e2121b987"
+ "sha256:73a809a2964afa07adcc1521537fddb58c2ffbb7e84d53dc5901cf80480465b3",
+ "sha256:98e8af5edff5d24e4d31e73bc21043130ae9d955a91aa93fc0bc3b1d0f7b5880"
],
- "version": "==5.2.4"
+ "version": "==5.3.1"
},
"jupyter-console": {
"hashes": [
@@ -1472,10 +1472,10 @@
},
"jupyter-core": {
"hashes": [
- "sha256:927d713ffa616ea11972534411544589976b2493fc7e09ad946e010aa7eb9970",
- "sha256:ba70754aa680300306c699790128f6fbd8c306ee5927976cbe48adacf240c0b7"
+ "sha256:2c6e7c1e9f2ac45b5c2ceea5730bc9008d92fe59d0725eac57b04c0edfba24f7",
+ "sha256:f4fa22d6cf25f34807c995f22d2923693575c70f02557bcbfbe59bd5ec8d8b84"
],
- "version": "==4.4.0"
+ "version": "==4.5.0"
},
"keras": {
"hashes": [
@@ -1494,10 +1494,10 @@
},
"keras-maskrcnn": {
"hashes": [
- "sha256:7cbadcf5d8a41e64ebd19157253f0357f2c46f289584c6f58fd38a19f7cc3509"
+ "sha256:9e2258390d749986fe6dc05aabdd7198ae689e60696b6a5568929379457a2e98"
],
"index": "pypi",
- "version": "==0.2.1"
+ "version": "==0.2.2"
},
"keras-preprocessing": {
"hashes": [
@@ -1514,10 +1514,10 @@
},
"keras-retinanet": {
"hashes": [
- "sha256:257b77ca46c6846d8e9260e4eb1c77ab9b564c512bb5ebe23e72fc46b5c41899"
+ "sha256:6d4da9d83a9a82cb025298a88256546bc625e9c78cd4f1bbec576d11295910b6"
],
"index": "pypi",
- "version": "==0.5.0"
+ "version": "==0.5.1"
},
"kiwisolver": {
"hashes": [
@@ -1554,10 +1554,10 @@
},
"kombu": {
"hashes": [
- "sha256:056a31cc95b10ca4eb0d4ebcba714007b1db1c6c45c8e2d139fe91933481b00b",
- "sha256:af5b0f892b081f49d95c772a241fb7687f4cc3e42c94328f118dffb1f4e161e5"
+ "sha256:55b71d3785def3470a16217fe0780f9e6f95e61bf9ad39ef8dce0177224eab77",
+ "sha256:eb365ea795cd7e629ba2f1f398e0c3ba354b91ef4de225ffdf6ab45fdfc7d581"
],
- "version": "==4.6.1"
+ "version": "==4.6.3"
},
"lazy-object-proxy": {
"hashes": [
@@ -1584,10 +1584,17 @@
},
"libarchive": {
"hashes": [
- "sha256:37e8cca1eb85d30583cdcffc58116d83abc09be7549d5d6c9ead563c0a8d7b04"
+ "sha256:829dc298a08877f62335d528973bc034f7c1e8a03c16bfc1fa561e164e76a365"
],
"index": "pypi",
- "version": "==0.4.6"
+ "version": "==0.4.7"
+ },
+ "limits": {
+ "hashes": [
+ "sha256:9df578f4161017d79f5188609f1d65f6b639f8aad2914c3960c9252e56a0ff95",
+ "sha256:a017b8d9e9da6761f4574642149c337f8f540d4edfe573fb91ad2c4001a2bc76"
+ ],
+ "version": "==1.3"
},
"lru-dict": {
"hashes": [
@@ -1746,10 +1753,10 @@
},
"msrest": {
"hashes": [
- "sha256:05538c68251eb0c81bd2010524d8ff36d4266ec0669338fbdcecfd23c733231c",
- "sha256:8143093308975f815f968b0d2a1ac8e26ba217eb6d03f3f27aac616aa3a25bd0"
+ "sha256:2c0909570913785a4408a17286e151f3b28d39277113e5c63378572f7395c660",
+ "sha256:c9e9cbb0c47745f9f5c82cce60849d7c3ec9e33fc6fad9e2987b7657ad1ba479"
],
- "version": "==0.6.7"
+ "version": "==0.6.8"
},
"msrestazure": {
"hashes": [
@@ -1774,11 +1781,11 @@
},
"nbstripout": {
"hashes": [
- "sha256:814efbe00988445b2c3f3d1944c9f296a556e2b14a060f7b25372881c2e497d4",
- "sha256:8f085e26e60e9d9c0710748510d1c763c8f63905cb16df7658b35a2936e8ca2b"
+ "sha256:1960caf7d1c1e281126c6c5cb98053db89eca8aaa616b58eed381e3e1508c0f4",
+ "sha256:d35c553f724d3fb7ec9e9602c6e55a75101064a6bbec4f8c28e8c84d6e3dd060"
],
"index": "pypi",
- "version": "==0.3.5"
+ "version": "==0.3.6"
},
"networkx": {
"hashes": [
@@ -1841,10 +1848,10 @@
},
"oauthlib": {
"hashes": [
- "sha256:0ce32c5d989a1827e3f1148f98b9085ed2370fc939bf524c9c851d8714797298",
- "sha256:3e1e14f6cde7e5475128d30e97edc3bfb4dc857cb884d8714ec161fdbb3b358e"
+ "sha256:40a63637707e9163eda62d0f5345120c65e001a790480b8256448543c1f78f66",
+ "sha256:b4d99ae8ccfb7d33ba9591b59355c64eef5241534aa3da2e4c0435346b84bc8e"
],
- "version": "==3.0.1"
+ "version": "==3.0.2"
},
"opencv-python": {
"hashes": [
@@ -1905,6 +1912,32 @@
"index": "pypi",
"version": "==2.15.0"
},
+ "pandas": {
+ "hashes": [
+ "sha256:071e42b89b57baa17031af8c6b6bbd2e9a5c68c595bc6bf9adabd7a9ed125d3b",
+ "sha256:17450e25ae69e2e6b303817bdf26b2cd57f69595d8550a77c308be0cd0fd58fa",
+ "sha256:17916d818592c9ec891cbef2e90f98cc85e0f1e89ed0924c9b5220dc3209c846",
+ "sha256:2538f099ab0e9f9c9d09bbcd94b47fd889bad06dc7ae96b1ed583f1dc1a7a822",
+ "sha256:366f30710172cb45a6b4f43b66c220653b1ea50303fbbd94e50571637ffb9167",
+ "sha256:42e5ad741a0d09232efbc7fc648226ed93306551772fc8aecc6dce9f0e676794",
+ "sha256:4e718e7f395ba5bfe8b6f6aaf2ff1c65a09bb77a36af6394621434e7cc813204",
+ "sha256:4f919f409c433577a501e023943e582c57355d50a724c589e78bc1d551a535a2",
+ "sha256:4fe0d7e6438212e839fc5010c78b822664f1a824c0d263fd858f44131d9166e2",
+ "sha256:5149a6db3e74f23dc3f5a216c2c9ae2e12920aa2d4a5b77e44e5b804a5f93248",
+ "sha256:627594338d6dd995cfc0bacd8e654cd9e1252d2a7c959449228df6740d737eb8",
+ "sha256:83c702615052f2a0a7fb1dd289726e29ec87a27272d775cb77affe749cca28f8",
+ "sha256:8c872f7fdf3018b7891e1e3e86c55b190e6c5cee70cab771e8f246c855001296",
+ "sha256:90f116086063934afd51e61a802a943826d2aac572b2f7d55caaac51c13db5b5",
+ "sha256:a3352bacac12e1fc646213b998bce586f965c9d431773d9e91db27c7c48a1f7d",
+ "sha256:bcdd06007cca02d51350f96debe51331dec429ac8f93930a43eb8fb5639e3eb5",
+ "sha256:c1bd07ebc15285535f61ddd8c0c75d0d6293e80e1ee6d9a8d73f3f36954342d0",
+ "sha256:c9a4b7c55115eb278c19aa14b34fcf5920c8fe7797a09b7b053ddd6195ea89b3",
+ "sha256:cc8fc0c7a8d5951dc738f1c1447f71c43734244453616f32b8aa0ef6013a5dfb",
+ "sha256:d7b460bc316064540ce0c41c1438c416a40746fd8a4fb2999668bf18f3c4acf1"
+ ],
+ "index": "pypi",
+ "version": "==0.24.2"
+ },
"pandocfilters": {
"hashes": [
"sha256:b3dd70e169bb5449e6bc6ff96aea89c5eea8c5f6ab5e207fc2f521a2cf4a0da9"
@@ -1913,11 +1946,11 @@
},
"pathlib2": {
"hashes": [
- "sha256:25199318e8cc3c25dcb45cbe084cc061051336d5a9ea2a12448d3d8cb748f742",
- "sha256:5887121d7f7df3603bca2f710e7219f3eca0eb69e0b7cc6e0a022e155ac931a7"
+ "sha256:2156525d6576d21c4dcaddfa427fae887ef89a7a9de5cbfe0728b3aafa78427e",
+ "sha256:446014523bb9be5c28128c4d2a10ad6bb60769e78bd85658fe44a450674e0ef8"
],
"markers": "python_version in '2.6 2.7 3.2 3.3'",
- "version": "==2.3.3"
+ "version": "==2.3.4"
},
"pbr": {
"hashes": [
@@ -1951,34 +1984,34 @@
},
"pillow": {
"hashes": [
- "sha256:15c056bfa284c30a7f265a41ac4cbbc93bdbfc0dfe0613b9cb8a8581b51a9e55",
- "sha256:1a4e06ba4f74494ea0c58c24de2bb752818e9d504474ec95b0aa94f6b0a7e479",
- "sha256:1c3c707c76be43c9e99cb7e3d5f1bee1c8e5be8b8a2a5eeee665efbf8ddde91a",
- "sha256:1fd0b290203e3b0882d9605d807b03c0f47e3440f97824586c173eca0aadd99d",
- "sha256:24114e4a6e1870c5a24b1da8f60d0ba77a0b4027907860188ea82bd3508c80eb",
- "sha256:258d886a49b6b058cd7abb0ab4b2b85ce78669a857398e83e8b8e28b317b5abb",
- "sha256:33c79b6dd6bc7f65079ab9ca5bebffb5f5d1141c689c9c6a7855776d1b09b7e8",
- "sha256:367385fc797b2c31564c427430c7a8630db1a00bd040555dfc1d5c52e39fcd72",
- "sha256:3c1884ff078fb8bf5f63d7d86921838b82ed4a7d0c027add773c2f38b3168754",
- "sha256:44e5240e8f4f8861d748f2a58b3f04daadab5e22bfec896bf5434745f788f33f",
- "sha256:46aa988e15f3ea72dddd81afe3839437b755fffddb5e173886f11460be909dce",
- "sha256:74d90d499c9c736d52dd6d9b7221af5665b9c04f1767e35f5dd8694324bd4601",
- "sha256:809c0a2ce9032cbcd7b5313f71af4bdc5c8c771cb86eb7559afd954cab82ebb5",
- "sha256:85d1ef2cdafd5507c4221d201aaf62fc9276f8b0f71bd3933363e62a33abc734",
- "sha256:8c3889c7681af77ecfa4431cd42a2885d093ecb811e81fbe5e203abc07e0995b",
- "sha256:9218d81b9fca98d2c47d35d688a0cea0c42fd473159dfd5612dcb0483c63e40b",
- "sha256:9aa4f3827992288edd37c9df345783a69ef58bd20cc02e64b36e44bcd157bbf1",
- "sha256:9d80f44137a70b6f84c750d11019a3419f409c944526a95219bea0ac31f4dd91",
- "sha256:b7ebd36128a2fe93991293f997e44be9286503c7530ace6a55b938b20be288d8",
- "sha256:c4c78e2c71c257c136cdd43869fd3d5e34fc2162dc22e4a5406b0ebe86958239",
- "sha256:c6a842537f887be1fe115d8abb5daa9bc8cc124e455ff995830cc785624a97af",
- "sha256:cf0a2e040fdf5a6d95f4c286c6ef1df6b36c218b528c8a9158ec2452a804b9b8",
- "sha256:cfd28aad6fc61f7a5d4ee556a997dc6e5555d9381d1390c00ecaf984d57e4232",
- "sha256:dca5660e25932771460d4688ccbb515677caaf8595f3f3240ec16c117deff89a",
- "sha256:de7aedc85918c2f887886442e50f52c1b93545606317956d65f342bd81cb4fc3",
- "sha256:e6c0bbf8e277b74196e3140c35f9a1ae3eafd818f7f2d3a15819c49135d6c062"
- ],
- "version": "==6.0.0"
+ "sha256:0804f77cb1e9b6dbd37601cee11283bba39a8d44b9ddb053400c58e0c0d7d9de",
+ "sha256:0ab7c5b5d04691bcbd570658667dd1e21ca311c62dcfd315ad2255b1cd37f64f",
+ "sha256:0b3e6cf3ea1f8cecd625f1420b931c83ce74f00c29a0ff1ce4385f99900ac7c4",
+ "sha256:365c06a45712cd723ec16fa4ceb32ce46ad201eb7bbf6d3c16b063c72b61a3ed",
+ "sha256:38301fbc0af865baa4752ddae1bb3cbb24b3d8f221bf2850aad96b243306fa03",
+ "sha256:3aef1af1a91798536bbab35d70d35750bd2884f0832c88aeb2499aa2d1ed4992",
+ "sha256:3fe0ab49537d9330c9bba7f16a5f8b02da615b5c809cdf7124f356a0f182eccd",
+ "sha256:45a619d5c1915957449264c81c008934452e3fd3604e36809212300b2a4dab68",
+ "sha256:49f90f147883a0c3778fd29d3eb169d56416f25758d0f66775db9184debc8010",
+ "sha256:571b5a758baf1cb6a04233fb23d6cf1ca60b31f9f641b1700bfaab1194020555",
+ "sha256:5ac381e8b1259925287ccc5a87d9cf6322a2dc88ae28a97fe3e196385288413f",
+ "sha256:6153db744a743c0c8c91b8e3b9d40e0b13a5d31dbf8a12748c6d9bfd3ddc01ad",
+ "sha256:6fd63afd14a16f5d6b408f623cc2142917a1f92855f0df997e09a49f0341be8a",
+ "sha256:70acbcaba2a638923c2d337e0edea210505708d7859b87c2bd81e8f9902ae826",
+ "sha256:70b1594d56ed32d56ed21a7fbb2a5c6fd7446cdb7b21e749c9791eac3a64d9e4",
+ "sha256:76638865c83b1bb33bcac2a61ce4d13c17dba2204969dedb9ab60ef62bede686",
+ "sha256:7b2ec162c87fc496aa568258ac88631a2ce0acfe681a9af40842fc55deaedc99",
+ "sha256:7cee2cef07c8d76894ebefc54e4bb707dfc7f258ad155bd61d87f6cd487a70ff",
+ "sha256:7d16d4498f8b374fc625c4037742fbdd7f9ac383fd50b06f4df00c81ef60e829",
+ "sha256:b50bc1780681b127e28f0075dfb81d6135c3a293e0c1d0211133c75e2179b6c0",
+ "sha256:bd0582f831ad5bcad6ca001deba4568573a4675437db17c4031939156ff339fa",
+ "sha256:cfd40d8a4b59f7567620410f966bb1f32dc555b2b19f82a91b147fac296f645c",
+ "sha256:e3ae410089de680e8f84c68b755b42bc42c0ceb8c03dbea88a5099747091d38e",
+ "sha256:e9046e559c299b395b39ac7dbf16005308821c2f24a63cae2ab173bd6aa11616",
+ "sha256:ef6be704ae2bc8ad0ebc5cb850ee9139493b0fc4e81abcc240fb392a63ebc808",
+ "sha256:f8dc19d92896558f9c4317ee365729ead9d7bbcf2052a9a19a3ef17abbb8ac5b"
+ ],
+ "version": "==6.1.0"
},
"pprofile": {
"hashes": [
@@ -1996,9 +2029,9 @@
},
"prometheus-client": {
"hashes": [
- "sha256:ee0c90350595e4a9f36591f291e6f9933246ea67d7cd7d1d6139a9781b14eaae"
+ "sha256:71cd24a2b3eb335cb800c7159f423df1bd4dcd5171b234be15e3f31ec9f622da"
],
- "version": "==0.7.0"
+ "version": "==0.7.1"
},
"prompt-toolkit": {
"hashes": [
@@ -2010,26 +2043,26 @@
},
"protobuf": {
"hashes": [
- "sha256:03f43eac9d5b651f976e91cf46a25b75e5779d98f0f4114b0abfed83376d75f8",
- "sha256:0c94b21e6de01362f91a86b372555d22a60b59708599ca9d5032ae9fdf8e3538",
- "sha256:2d2a9f30f61f4063fadd7fb68a2510a6939b43c0d6ceeec5c4704f22225da28e",
- "sha256:34a0b05fca061e4abb77dd180209f68d8637115ff319f51e28a6a9382d69853a",
- "sha256:358710fd0db25372edcf1150fa691f48376a134a6c69ce29f38f185eea7699e6",
- "sha256:41e47198b94c27ba05a08b4a95160656105745c462af574e4bcb0807164065c0",
- "sha256:8c61cc8a76e9d381c665aecc5105fa0f1878cf7db8b5cd17202603bcb386d0fc",
- "sha256:a6eebc4db759e58fdac02efcd3028b811effac881d8a5bad1996e4e8ee6acb47",
- "sha256:a9c12f7c98093da0a46ba76ec40ace725daa1ac4038c41e4b1466afb5c45bb01",
- "sha256:cb95068492ba0859b8c9e61fa8ba206a83c64e5d0916fb4543700b2e2b214115",
- "sha256:cd98476ce7bb4dcd6a7b101f5eecdc073dafea19f311e36eb8fba1a349346277",
- "sha256:ce64cfbea18c535176bdaa10ba740c0fc4c6d998a3f511c17bedb0ae4b3b167c",
- "sha256:dcbb59eac73fd454e8f2c5fba9e3d3320fd4707ed6a9d3ea3717924a6f0903ea",
- "sha256:dd67f34458ae716029e2a71ede998e9092493b62a519236ca52e3c5202096c87",
- "sha256:e3c96056eb5b7284a20e256cb0bf783c8f36ad82a4ae5434a7b7cd02384144a7",
- "sha256:f612d584d7a27e2f39e7b17878430a959c1bc09a74ba09db096b468558e5e126",
- "sha256:f6de8a7d6122297b81566e5bd4df37fd5d62bec14f8f90ebff8ede1c9726cd0a",
- "sha256:fa529d9261682b24c2aaa683667253175c9acebe0a31105394b221090da75832"
- ],
- "version": "==3.8.0"
+ "sha256:05c36022fef3c7d3562ac22402965c0c2b9fe8421f459bb377323598996e407f",
+ "sha256:139b7eadcca0a861d60b523cb37d9475505e0dfb07972436b15407c2b968d87e",
+ "sha256:15f683006cb77fb849b1f561e509b03dd2b7dcc749086b8dd1831090d0ba4740",
+ "sha256:2ad566b7b7cdd8717c7af1825e19f09e8fef2787b77fcb979588944657679604",
+ "sha256:35cfcf97642ef62108e10a9431c77733ec7eaab8e32fe4653de20403429907cb",
+ "sha256:387822859ecdd012fdc25ec879f7f487da6e1d5b1ae6115e227e6be208836f71",
+ "sha256:4df14cbe1e7134afcfdbb9f058949e31c466de27d9b2f7fb4da9e0b67231b538",
+ "sha256:586c4ca37a7146d4822c700059f150ac3445ce0aef6f3ea258640838bb892dc2",
+ "sha256:58b11e530e954d29ab3180c48dc558a409f705bf16739fd4e0d3e07924ad7add",
+ "sha256:63c8c98ccb8c95f41c18fb829aeeab21c6249adee4ed75354125bdc44488f30e",
+ "sha256:72edcbacd0c73eef507d2ff1af99a6c27df18e66a3ff4351e401182e4de62b03",
+ "sha256:83dc8a561b3b954fd7002c690bb83278b8d1742a1e28abba9aaef28b0c8b437d",
+ "sha256:913171ecc84c2726b86574e40549a0ea619d569657c5a5ff782a3be7d81401a5",
+ "sha256:aabb7c741d3416671c3e6fe7c52970a226e6a8274417a97d7d795f953fadef36",
+ "sha256:b3452bbda12b1cbe2187d416779de07b2ab4c497d83a050e43c344778763721d",
+ "sha256:c5d5b8d4a9212338297fa1fa44589f69b470c0ba1d38168b432d577176b386a8",
+ "sha256:d86ee389c2c4fc3cebabb8ce83a8e97b6b3b5dc727b7419c1ccdc7b6e545a233",
+ "sha256:f2db8c754de788ab8be5e108e1e967c774c0942342b4f8aaaf14063889a6cfdc"
+ ],
+ "version": "==3.9.0"
},
"psutil": {
"hashes": [
@@ -2067,16 +2100,10 @@
},
"pycurl": {
"hashes": [
- "sha256:0f0cdfc7a92d4f2a5c44226162434e34f7d6967d3af416a6f1448649c09a25a4",
- "sha256:10510a0016c862af467c6e069e051409f15f5831552bed03f5104b395a5d7dd1",
- "sha256:208dd2c89e80d32a69397ba8a5cdb3bc0dc60f961a4f2a9662e5e1624dc799d1",
- "sha256:6dc6ee5e7628400083471cba8044010860fe8b22e4dee05e42150a68047d7d9d",
- "sha256:794bda39ea6fe434b6e1f58ab3bea9f0e6123fb43702fecd760eed6f1547b20a",
- "sha256:dae7277e7c06da00947f3cd32c095b1e65eae09f07478ada4ea9dfa57020b646",
- "sha256:eccea049aef47decc380746b3ff242d95636d578c907d0eab3b00918292d6c48"
+ "sha256:6f08330c5cf79fa8ef68b9912b9901db7ffd34b63e225dce74db56bb21deda8e"
],
"index": "pypi",
- "version": "==7.43.0.2"
+ "version": "==7.43.0.3"
},
"pygame": {
"hashes": [
@@ -2126,11 +2153,18 @@
},
"pylint": {
"hashes": [
- "sha256:02c2b6d268695a8b64ad61847f92e611e6afcff33fd26c3a2125370c4662905d",
- "sha256:ee1e85575587c5b58ddafa25e1c1b01691ef172e139fc25585e5d3f02451da93"
+ "sha256:367e3d49813d349a905390ac27989eff82ab84958731c5ef0bef867452cfdc42",
+ "sha256:97a42df23d436c70132971d1dcb9efad2fe5c0c6add55b90161e773caf729300"
],
"index": "pypi",
- "version": "==1.9.4"
+ "version": "==1.9.5"
+ },
+ "pylogbeat": {
+ "hashes": [
+ "sha256:11f3b1d04424151d406d8b844a8db6299442b4af1f10d5f622a6febf1ad5c41d",
+ "sha256:473494a0c798a560a8312ee662b333888181cf4db18cd8f87a8d7d1548beefd9"
+ ],
+ "version": "==1.0.2"
},
"pymongo": {
"hashes": [
@@ -2232,9 +2266,9 @@
},
"pyrsistent": {
"hashes": [
- "sha256:16692ee739d42cf5e39cef8d27649a8c1fdb7aa99887098f1460057c5eb75c3a"
+ "sha256:50cffebc87ca91b9d4be2dcc2e479272bcb466b5a0487b6c271f7ddea6917e14"
],
- "version": "==0.15.2"
+ "version": "==0.15.3"
},
"pysdl2": {
"hashes": [
@@ -2260,10 +2294,10 @@
},
"python-engineio": {
"hashes": [
- "sha256:9e4e7109d05d80ce5414f13b16f66725c2b5d574099fd43d37b024e7ea1c4354",
- "sha256:d3315d3f972bd9bd32e0738d45801a912f522177ff75094762f31a8c341d1f41"
+ "sha256:4850c3e04b2040e4fd262d1047797473d1815b37a073807e7b80304c1c5f4848",
+ "sha256:89b90ee3816ed440c68ac7b6143244ae7d56a46a49295fbac8e6696482e596d1"
],
- "version": "==3.8.1"
+ "version": "==3.8.2.post1"
},
"python-logstash": {
"hashes": [
@@ -2272,12 +2306,20 @@
"index": "pypi",
"version": "==0.4.6"
},
+ "python-logstash-async": {
+ "hashes": [
+ "sha256:994894e8b7e168e56f21e302334c08203af102c7bc760cacdb8d3d0f5aa74cea",
+ "sha256:ccd528a0a9c6b7aabd9944c01d628e9d6cc2149156011aafd3484c7c0abbce45"
+ ],
+ "index": "pypi",
+ "version": "==1.5.1"
+ },
"python-socketio": {
"hashes": [
- "sha256:89a48591a8850c1f30d735f8e5a0294846da245a9b8940c39e1106e460c7a14e",
- "sha256:c7ffeac3d81f2d8d63b3ec7ed1e2d4478cc84aa1da666c1934c19432f4b8c0f8"
+ "sha256:335bd0fab481d65edce4ab82c3bb5cac950afa843329ea7c38777cd56c8eba38",
+ "sha256:efec4844456791b7d702efefd543ed67a8e314ca45efb8f0bfca7ae18fdee60a"
],
- "version": "==4.1.0"
+ "version": "==4.2.0"
},
"python-utils": {
"hashes": [
@@ -2351,34 +2393,34 @@
},
"pyzmq": {
"hashes": [
- "sha256:1651e52ed91f0736afd6d94ef9f3259b5534ce8beddb054f3d5ca989c4ef7c4f",
- "sha256:5ccb9b3d4cd20c000a9b75689d5add8cd3bce67fcbd0f8ae1b59345247d803af",
- "sha256:5e120c4cd3872e332fb35d255ad5998ebcee32ace4387b1b337416b6b90436c7",
- "sha256:5e2a3707c69a7281a9957f83718815fd74698cba31f6d69f9ed359921f662221",
- "sha256:63d51add9af8d0442dc90f916baf98fdc04e3b0a32afec4bfc83f8d85e72959f",
- "sha256:65c5a0bdc49e20f7d6b03a661f71e2fda7a99c51270cafe71598146d09810d0d",
- "sha256:66828fabe911aa545d919028441a585edb7c9c77969a5fea6722ef6e6ece38ab",
- "sha256:7d79427e82d9dad6e9b47c0b3e7ae5f9d489b1601e3a36ea629bb49501a4daf3",
- "sha256:824ee5d3078c4eae737ffc500fbf32f2b14e6ec89b26b435b7834febd70120cf",
- "sha256:89dc0a83cccec19ff3c62c091e43e66e0183d1e6b4658c16ee4e659518131494",
- "sha256:8b319805f6f7c907b101c864c3ca6cefc9db8ce0791356f180b1b644c7347e4c",
- "sha256:90facfb379ab47f94b19519c1ecc8ec8d10813b69d9c163117944948bdec5d15",
- "sha256:a0a178c7420021fc0730180a914a4b4b3092ce9696ceb8e72d0f60f8ce1655dd",
- "sha256:a7a89591ae315baccb8072f216614b3e59aed7385aef4393a6c741783d6ee9cf",
- "sha256:ba2578f0ae582452c02ed9fac2dc477b08e80ce05d2c0885becf5fff6651ccb0",
- "sha256:c69b0055c55702f5b0b6b354133e8325b9a56dbc80e1be2d240bead253fb9825",
- "sha256:ca434e1858fe222380221ddeb81e86f45522773344c9da63c311d17161df5e06",
- "sha256:d4b8ecfc3d92f114f04d5c40f60a65e5196198b827503341521dda12d8b14939",
- "sha256:d706025c47b09a54f005953ebe206f6d07a22516776faa4f509aaff681cc5468",
- "sha256:d8f27e958f8a2c0c8ffd4d8855c3ce8ac3fa1e105f0491ce31729aa2b3229740",
- "sha256:dbd264298f76b9060ce537008eb989317ca787c857e23cbd1b3ddf89f190a9b1",
- "sha256:e926d66f0df8fdbf03ba20583af0f215e475c667fb033d45fd031c66c63e34c9",
- "sha256:efc3bd48237f973a749f7312f68062f1b4ca5c2032a0673ca3ea8e46aa77187b",
- "sha256:f59bc782228777cbfe04555707a9c56d269c787ed25d6d28ed9d0fbb41cb1ad2",
- "sha256:f8da5322f4ff5f667a0d5a27e871b560c6637153c81e318b35cb012b2a98835c"
- ],
- "index": "pypi",
- "version": "==18.0.1"
+ "sha256:00dd015159eaeb1c0731ad49310e1f5d839c9a35a15e4f3267f5052233fad99b",
+ "sha256:03913b6beb8e7b417b9910b0ee1fd5d62e9626d218faefbe879d70714ceab1a2",
+ "sha256:13f17386df81d5e6efb9a4faea341d8de22cdc82e49a326dded26e33f42a3112",
+ "sha256:16c6281d96885db1e15f7047ddc1a8f48ff4ea35d31ca709f4d2eb39f246d356",
+ "sha256:17efab4a804e31f58361631256d660214204046f9e2b962738b171b9ad674ea7",
+ "sha256:2b79919ddeff3d3c96aa6087c21d294c8db1c01f6bfeee73324944683685f419",
+ "sha256:2f832e4711657bb8d16ea1feba860f676ec5f14fb9fe3b449b5953a60e89edae",
+ "sha256:31a11d37ac73107363b47e14c94547dbfc6a550029c3fe0530be443199026fc2",
+ "sha256:33a3e928e6c3138c675e1d6702dd11f6b7050177d7aab3fc322db6e1d2274490",
+ "sha256:34a38195a6d3a9646cbcdaf8eb245b4d935c7a57f7e1b3af467814bc1a92467e",
+ "sha256:42900054f1500acef6df7428edf806abbf641bf92eb9ceded24aa863397c3bae",
+ "sha256:4ccc7f3c63aa9d744dadb62c49eda2d0e7de55649b80c45d7c684d70161a69af",
+ "sha256:5b220c37c346e6575db8c88a940c1fc234f99ce8e0068c408919bb8896c4b6d2",
+ "sha256:6074848da5c8b44a1ca40adf75cf65aa92bc80f635e8249aa8f37a69b2b9b6f5",
+ "sha256:61a4155964bd4a14ef95bf46cb1651bcf8dcbbed8c0108e9c974c1fcbb57788f",
+ "sha256:62b5774688326600c52f587f7a033ca6b6284bef4c8b1b5fda32480897759eac",
+ "sha256:65a9ffa4f9f085d696f16fd7541f34b3c357d25fe99c90e3bce2ea59c3b5b4b6",
+ "sha256:76a077d2c30f8adc5e919a55985a784b96aeca69b53c1ea6fd5723d3ae2e6f53",
+ "sha256:8e5b4c51557071d6379d6dc1f54f35e9f6a137f5e84e102efb869c8d3c13c8ff",
+ "sha256:917f73e07cc04f0678a96d93e7bb8b1adcccdde9ccfe202e622814f4d1d1ecfd",
+ "sha256:91c75d3c4c357f9643e739db9e79ab9681b2f6ae8ec5678d6ef2ea0d01532596",
+ "sha256:923dd91618b100bb4c92ab9ed7b65825a595b8524a094ce03c7cb2aaae7d353b",
+ "sha256:9849054e0355e2bc7f4668766a25517ba76095031c9ff5e39ae8949cee5bb024",
+ "sha256:c9d453933f0e3f44b9759189f2a18aa765f7f1a4345c727c18ebe8ad0d748d26",
+ "sha256:cb7514936277abce64c2f4c56883e5704d85ed04d98d2d432d1c6764003bb003"
+ ],
+ "index": "pypi",
+ "version": "==18.0.2"
},
"qtconsole": {
"hashes": [
@@ -2523,6 +2565,14 @@
"index": "pypi",
"version": "==1.2.2"
},
+ "seaborn": {
+ "hashes": [
+ "sha256:42e627b24e849c2d3bbfd059e00005f6afbc4a76e4895baf44ae23fe8a4b09a5",
+ "sha256:76c83f794ca320fb6b23a7c6192d5e185a5fcf4758966a0c0a54baee46d41e2f"
+ ],
+ "index": "pypi",
+ "version": "==0.9.0"
+ },
"send2trash": {
"hashes": [
"sha256:60001cc07d707fe247c94f74ca6ac0d3255aabcb930529690897ca2a39db28b2",
@@ -2612,11 +2662,11 @@
},
"supervisor": {
"hashes": [
- "sha256:a3289b9124e59aee1621d43b55cd1634468cb3212d09c5b0114a3183cc080cca",
- "sha256:f768abc073e8702892718938b8a0ab98ebcb91c2afcb39bf2cb570d3eb51149e"
+ "sha256:43e87c7b572a94acdb586aaebb06844dae1aa02856b984c5a738032abd753fb7",
+ "sha256:9644990d21a1ba03b1a7ac5e9a0c0c62e12822e258f9e98f4a0b128461b3f10a"
],
"index": "pypi",
- "version": "==4.0.3"
+ "version": "==4.0.4"
},
"tenacity": {
"hashes": [
@@ -2635,9 +2685,9 @@
},
"tensorflow-estimator": {
"hashes": [
- "sha256:7cfdaa3e83e3532f31713713feb98be7ea9f3065722be4267e49b6c301271419"
+ "sha256:ca073f66063407a091d610ec1b22e39ea30248710198cc6f13769320bdbe3992"
],
- "version": "==1.13.0"
+ "version": "==1.14.0"
},
"tensorflow-gpu": {
"hashes": [
@@ -2713,12 +2763,12 @@
},
"typing": {
"hashes": [
- "sha256:4027c5f6127a6267a435201981ba156de91ad0d1d98e9ddc2aa173453453492d",
- "sha256:57dcf675a99b74d64dacf6fba08fb17cf7e3d5fdff53d4a30ea2a5e7e52543d4",
- "sha256:a4c8473ce11a65999c8f59cb093e70686b6c84c98df58c1dae9b3b196089858a"
+ "sha256:38566c558a0a94d6531012c8e917b1b8518a41e418f7f15f00e129cc80162ad3",
+ "sha256:53765ec4f83a2b720214727e319607879fec4acde22c4fbb54fa2604e79e44ce",
+ "sha256:84698954b4e6719e912ef9a42a2431407fe3755590831699debda6fba92aac55"
],
"markers": "python_version < '3.5'",
- "version": "==3.6.6"
+ "version": "==3.7.4"
},
"urllib3": {
"hashes": [
@@ -2730,10 +2780,10 @@
},
"utm": {
"hashes": [
- "sha256:a6608a67df84418fd959a79b228b90ab55b2ae877827f9c210947104c5a75d0e"
+ "sha256:07e55707ed660eec1ae983bd54a406c437962618a6261b38d70592fe30f5f508"
],
"index": "pypi",
- "version": "==0.4.2"
+ "version": "==0.5.0"
},
"uwsgi": {
"hashes": [
@@ -2780,10 +2830,10 @@
},
"werkzeug": {
"hashes": [
- "sha256:865856ebb55c4dcd0630cdd8f3331a1847a819dda7e8c750d3db6f2aa6c0209c",
- "sha256:a0b915f0815982fb2a09161cb8f31708052d0951c3ba433ccc5e1aa276507ca6"
+ "sha256:87ae4e5b5366da2347eb3116c0e6c681a0e939a33b2805e2c0cbd282664932c4",
+ "sha256:a13b74dd3c45f758d4ebdb224be8f1ab8ef58b3c0ffc1783a8c7d9f4f50227e6"
],
- "version": "==0.15.4"
+ "version": "==0.15.5"
},
"wheel": {
"hashes": [
@@ -2795,16 +2845,16 @@
},
"widgetsnbextension": {
"hashes": [
- "sha256:14b2c65f9940c9a7d3b70adbe713dbd38b5ec69724eebaba034d1036cf3d4740",
- "sha256:fa618be8435447a017fd1bf2c7ae922d0428056cfc7449f7a8641edf76b48265"
+ "sha256:120f85acc3976450220b03b8933ce48678e518905cca69fc3c856ea5a0144196",
+ "sha256:8c9b4d73e388f2484296be18432d3cc0b8d59de243079a0db16a56c5571e1f86"
],
- "version": "==3.4.2"
+ "version": "==3.5.0"
},
"wrapt": {
"hashes": [
- "sha256:4aea003270831cceb8a90ff27c4031da6ead7ec1886023b80ce0dfe0adf61533"
+ "sha256:565a021fd19419476b9362b05eeaa094178de64f8361e44468f9e9d7843901e1"
],
- "version": "==1.11.1"
+ "version": "==1.11.2"
}
}
}
diff --git a/README.md b/README.md
index dfbb76803083a2..f6e3fbe7971ee8 100644
--- a/README.md
+++ b/README.md
@@ -60,13 +60,13 @@ Supported Cars
| Make | Model | Supported Package | Lateral | Longitudinal | No Accel Below | No Steer Below | Giraffe |
| ---------------------| -------------------------| ---------------------| --------| ---------------| -----------------| ---------------|-------------------|
-| Acura | ILX 2016-17 | AcuraWatch Plus | Yes | Yes | 25mph1| 25mph | Nidec |
-| Acura | RDX 2018 | AcuraWatch Plus | Yes | Yes | 25mph1| 12mph | Nidec |
+| Acura | ILX 2016-18 | AcuraWatch Plus | Yes | Yes | 25mph1| 25mph | Nidec |
+| Acura | RDX 2016-18 | AcuraWatch Plus | Yes | Yes | 25mph1| 12mph | Nidec |
| Buick3 | Regal 2018 | Adaptive Cruise | Yes | Yes | 0mph | 7mph | Custom7|
| Chevrolet3| Malibu 2017 | Adaptive Cruise | Yes | Yes | 0mph | 7mph | Custom7|
| Chevrolet3| Volt 2017-18 | Adaptive Cruise | Yes | Yes | 0mph | 7mph | Custom7|
| Cadillac3 | ATS 2018 | Adaptive Cruise | Yes | Yes | 0mph | 7mph | Custom7|
-| Chrysler | Pacifica 2018 | Adaptive Cruise | Yes | Stock | 0mph | 9mph | FCA |
+| Chrysler | Pacifica 2017-18 | Adaptive Cruise | Yes | Stock | 0mph | 9mph | FCA |
| Chrysler | Pacifica Hybrid 2017-18 | Adaptive Cruise | Yes | Stock | 0mph | 9mph | FCA |
| Chrysler | Pacifica Hybrid 2019 | Adaptive Cruise | Yes | Stock | 0mph | 39mph | FCA |
| GMC3 | Acadia Denali 2018 | Adaptive Cruise | Yes | Yes | 0mph | 7mph | Custom7|
@@ -84,9 +84,9 @@ Supported Cars
| Honda | Pilot 2019 | All | Yes | Yes | 25mph1| 12mph | Inverted Nidec |
| Honda | Ridgeline 2017-19 | Honda Sensing | Yes | Yes | 25mph1| 12mph | Nidec |
| Hyundai | Santa Fe 2019 | All | Yes | Stock | 0mph | 0mph | Custom6|
-| Hyundai | Elantra 2017 | SCC + LKAS | Yes | Stock | 19mph | 34mph | Custom6|
+| Hyundai | Elantra 2017-19 | SCC + LKAS | Yes | Stock | 19mph | 34mph | Custom6|
| Hyundai | Genesis 2018 | All | Yes | Stock | 19mph | 34mph | Custom6|
-| Jeep | Grand Cherokee 2017-18 | Adaptive Cruise | Yes | Stock | 0mph | 9mph | FCA |
+| Jeep | Grand Cherokee 2016-18 | Adaptive Cruise | Yes | Stock | 0mph | 9mph | FCA |
| Jeep | Grand Cherokee 2019 | Adaptive Cruise | Yes | Stock | 0mph | 39mph | FCA |
| Kia | Optima 2019 | SCC + LKAS | Yes | Stock | 0mph | 0mph | Custom6|
| Kia | Sorento 2018 | All | Yes | Stock | 0mph | 0mph | Custom6|
@@ -96,8 +96,9 @@ Supported Cars
| Subaru | Crosstrek 2018 | EyeSight | Yes | Stock | 0mph | 0mph | Custom4|
| Subaru | Impreza 2019 | EyeSight | Yes | Stock | 0mph | 0mph | Custom4|
| Toyota | Avalon 2016 | TSS-P | Yes | Yes2| 20mph1| 0mph | Toyota |
-| Toyota | Camry 2018 | All | Yes | Stock | 0mph5 | 0mph | Toyota |
-| Toyota | C-HR 2017-18 | All | Yes | Stock | 0mph | 0mph | Toyota |
+| Toyota | Avalon 2017-18 | All | Yes | Yes2| 20mph1| 0mph | Toyota |
+| Toyota | Camry 2018-19 | All | Yes | Stock | 0mph5 | 0mph | Toyota |
+| Toyota | C-HR 2017-19 | All | Yes | Stock | 0mph | 0mph | Toyota |
| Toyota | Corolla 2017-19 | All | Yes | Yes2| 20mph1| 0mph | Toyota |
| Toyota | Corolla 2020 | All | Yes | Yes | 0mph | 0mph | Toyota |
| Toyota | Corolla Hatchback 2019 | All | Yes | Yes | 0mph | 0mph | Toyota |
@@ -110,6 +111,7 @@ Supported Cars
| Toyota | Rav4 2017-18 | All | Yes | Yes2| 20mph1| 0mph | Toyota |
| Toyota | Rav4 2019 | All | Yes | Yes | 0mph | 0mph | Toyota |
| Toyota | Rav4 Hybrid 2017-18 | All | Yes | Yes2| 0mph | 0mph | Toyota |
+| Toyota | Sienna 2018 | All | Yes | Yes2| 0mph | 0mph | Toyota |
1[Comma Pedal](https://community.comma.ai/wiki/index.php/Comma_Pedal) is used to provide stop-and-go capability to some of the openpilot-supported cars that don't currently support stop-and-go. Here is how to [build a Comma Pedal](https://medium.com/@jfrux/comma-pedal-building-with-macrofab-6328bea791e8). ***NOTE: The Comma Pedal is not officially supported by [comma.ai](https://comma.ai).***
2When disconnecting the Driver Support Unit (DSU), otherwise longitudinal control is stock ACC. For DSU locations, see [Toyota Wiki page](https://community.comma.ai/wiki/index.php/Toyota).
diff --git a/RELEASES.md b/RELEASES.md
index f73b8daf83ebb8..07bbc6208d35e8 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -1,3 +1,10 @@
+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!
diff --git a/apk/ai.comma.plus.offroad.apk b/apk/ai.comma.plus.offroad.apk
index 41920230b4fa09..6161bfa528b44b 100644
Binary files a/apk/ai.comma.plus.offroad.apk and b/apk/ai.comma.plus.offroad.apk differ
diff --git a/common/file_helpers.py b/common/file_helpers.py
index bdfe9d0ecf84b5..3300ae595afe17 100644
--- a/common/file_helpers.py
+++ b/common/file_helpers.py
@@ -28,7 +28,7 @@ def get_tmpdir_on_same_filesystem(path):
normpath = os.path.normpath(path)
parts = normpath.split("/")
if len(parts) > 1:
- if parts[1].startswith("raid"):
+ if parts[1].startswith("raid") or parts[1].startswith("datasets"):
if len(parts) > 2 and parts[2] == "runner":
return "/{}/runner/tmp".format(parts[1])
elif len(parts) > 2 and parts[2] == "aws":
@@ -101,3 +101,18 @@ def atomic_write_in_dir(path, **kwargs):
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)
diff --git a/common/fingerprints.py b/common/fingerprints.py
index ddc3bceb66ae8d..0e29e6c1e71139 100644
--- a/common/fingerprints.py
+++ b/common/fingerprints.py
@@ -28,10 +28,8 @@ def get_fingerprint_list():
def is_valid_for_fingerprint(msg, car_fingerprint):
adr = msg.address
- bus = msg.src
# ignore addresses that are more than 11 bits
- return (adr in car_fingerprint and car_fingerprint[adr] == len(msg.dat)) or \
- bus != 0 or adr >= 0x800
+ return (adr in car_fingerprint and car_fingerprint[adr] == len(msg.dat)) or adr >= 0x800
def eliminate_incompatible_cars(msg, candidate_cars):
diff --git a/common/params.py b/common/params.py
index c374d5233e2b67..963debd091bf36 100755
--- a/common/params.py
+++ b/common/params.py
@@ -50,12 +50,14 @@ class UnknownKeyName(Exception):
keys = {
"AccessToken": [TxType.PERSISTENT],
+ "AthenadPid": [TxType.PERSISTENT],
"CalibrationParams": [TxType.PERSISTENT],
"CarParams": [TxType.CLEAR_ON_MANAGER_START, TxType.CLEAR_ON_PANDA_DISCONNECT],
"CompletedTrainingVersion": [TxType.PERSISTENT],
"ControlsParams": [TxType.PERSISTENT],
"DoUninstall": [TxType.CLEAR_ON_MANAGER_START],
"DongleId": [TxType.PERSISTENT],
+ "GithubSshKeys": [TxType.PERSISTENT],
"GitBranch": [TxType.PERSISTENT],
"GitCommit": [TxType.PERSISTENT],
"GitRemote": [TxType.PERSISTENT],
@@ -75,6 +77,7 @@ class UnknownKeyName(Exception):
"ShouldDoUpdate": [TxType.CLEAR_ON_MANAGER_START],
"SpeedLimitOffset": [TxType.PERSISTENT],
"SubscriberInfo": [TxType.PERSISTENT],
+ "TermsVersion": [TxType.PERSISTENT],
"TrainingVersion": [TxType.PERSISTENT],
"Version": [TxType.PERSISTENT],
}
diff --git a/selfdrive/athena/athenad.py b/selfdrive/athena/athenad.py
index 58918de81ae37c..d6d429d92b48b5 100755
--- a/selfdrive/athena/athenad.py
+++ b/selfdrive/athena/athenad.py
@@ -1,15 +1,22 @@
#!/usr/bin/env python2.7
import json
+import jwt
import os
import random
+import re
+import select
+import subprocess
+import socket
import time
import threading
import traceback
import zmq
import requests
import six.moves.queue
+from datetime import datetime, timedelta
+from functools import partial
from jsonrpc import JSONRPCResponseManager, dispatcher
-from websocket import create_connection, WebSocketTimeoutException
+from websocket import create_connection, WebSocketTimeoutException, ABNF
from selfdrive.loggerd.config import ROOT
import selfdrive.crash as crash
@@ -21,6 +28,7 @@
ATHENA_HOST = os.getenv('ATHENA_HOST', 'wss://athena.comma.ai')
HANDLER_THREADS = os.getenv('HANDLER_THREADS', 4)
+LOCAL_PORT_WHITELIST = set([8022])
dispatcher["echo"] = lambda s: s
payload_queue = six.moves.queue.Queue()
@@ -49,6 +57,7 @@ def handle_long_poll(ws):
thread.join()
def jsonrpc_handler(end_event):
+ dispatcher["startLocalProxy"] = partial(startLocalProxy, end_event)
while not end_event.is_set():
try:
data = payload_queue.get(timeout=1)
@@ -85,6 +94,109 @@ def uploadFileToUrl(fn, url, headers):
ret = requests.put(url, data=f, headers=headers, timeout=10)
return ret.status_code
+def startLocalProxy(global_end_event, remote_ws_uri, local_port):
+ try:
+ cloudlog.event("athena startLocalProxy", remote_ws_uri=remote_ws_uri, local_port=local_port)
+
+ if local_port not in LOCAL_PORT_WHITELIST:
+ raise Exception("Requested local port not whitelisted")
+
+ params = Params()
+ dongle_id = params.get("DongleId")
+ private_key = open("/persist/comma/id_rsa").read()
+ identity_token = jwt.encode({'identity':dongle_id, 'exp': datetime.utcnow() + timedelta(hours=1)}, private_key, algorithm='RS256')
+
+ ws = create_connection(remote_ws_uri,
+ cookie="jwt=" + identity_token,
+ enable_multithread=True)
+
+ ssock, csock = socket.socketpair()
+ local_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ local_sock.connect(('127.0.0.1', local_port))
+ local_sock.setblocking(0)
+
+ proxy_end_event = threading.Event()
+ threads = [
+ threading.Thread(target=ws_proxy_recv, args=(ws, local_sock, ssock, proxy_end_event, global_end_event)),
+ threading.Thread(target=ws_proxy_send, args=(ws, local_sock, csock, proxy_end_event))
+ ]
+
+ map(lambda thread: thread.start(), threads)
+
+ return {"success": 1}
+ except Exception as e:
+ traceback.print_exc()
+ raise e
+
+@dispatcher.add_method
+def getPublicKey():
+ if not os.path.isfile('/persist/comma/id_rsa.pub'):
+ return None
+
+ with open('/persist/comma/id_rsa.pub', 'r') as f:
+ return f.read()
+
+@dispatcher.add_method
+def getSshAuthorizedKeys():
+ with open('/system/comma/home/.ssh/authorized_keys', 'r') as f:
+ return f.read()
+
+@dispatcher.add_method
+def getSimInfo():
+ sim_state = subprocess.check_output(['getprop', 'gsm.sim.state']).strip().split(',')
+ network_type = subprocess.check_output(['getprop', 'gsm.network.type']).strip().split(',')
+ mcc_mnc = subprocess.check_output(['getprop', 'gsm.sim.operator.numeric']).strip() or None
+
+ sim_id_aidl_out = subprocess.check_output(['service', 'call', 'iphonesubinfo', '11'])
+ sim_id_aidl_lines = sim_id_aidl_out.split('\n')
+ if len(sim_id_aidl_lines) > 3:
+ sim_id_lines = sim_id_aidl_lines[1:4]
+ sim_id_fragments = [re.search(r"'([0-9\.]+)'", line).group(1) for line in sim_id_lines]
+ sim_id = reduce(lambda frag1, frag2: frag1.replace('.', '') + frag2.replace('.', ''), sim_id_fragments)
+ else:
+ sim_id = None
+
+ return {
+ 'sim_id': sim_id,
+ 'mcc_mnc': mcc_mnc,
+ 'network_type': network_type,
+ 'sim_state': sim_state
+ }
+
+def ws_proxy_recv(ws, local_sock, ssock, end_event, global_end_event):
+ while not (end_event.is_set() or global_end_event.is_set()):
+ try:
+ data = ws.recv()
+ local_sock.sendall(data)
+ except WebSocketTimeoutException:
+ pass
+ except Exception:
+ traceback.print_exc()
+ break
+
+ ssock.close()
+ end_event.set()
+
+def ws_proxy_send(ws, local_sock, signal_sock, end_event):
+ while not end_event.is_set():
+ try:
+ r, _, _ = select.select((local_sock, signal_sock), (), ())
+ if r:
+ if r[0].fileno() == signal_sock.fileno():
+ # got end signal from ws_proxy_recv
+ end_event.set()
+ break
+ data = local_sock.recv(4096)
+ if not data:
+ # local_sock is dead
+ end_event.set()
+ break
+
+ ws.send(data, ABNF.OPCODE_BINARY)
+ except Exception:
+ traceback.print_exc()
+ end_event.set()
+
def ws_recv(ws, end_event):
while not end_event.is_set():
try:
@@ -138,5 +250,7 @@ def main(gctx=None):
time.sleep(backoff(conn_retries))
+ params.delete("AthenadPid")
+
if __name__ == "__main__":
main()
diff --git a/selfdrive/boardd/boardd.cc b/selfdrive/boardd/boardd.cc
index 1a64416e9f4b4b..779ca7b279f16c 100644
--- a/selfdrive/boardd/boardd.cc
+++ b/selfdrive/boardd/boardd.cc
@@ -283,8 +283,9 @@ void can_health(void *s) {
uint8_t started;
uint8_t controls_allowed;
uint8_t gas_interceptor_detected;
- uint8_t started_signal_detected;
- uint8_t started_alt;
+ uint32_t can_send_errs;
+ uint32_t can_fwd_errs;
+ uint32_t gmlan_send_errs;
} health;
// recv from board
@@ -313,8 +314,10 @@ void can_health(void *s) {
}
healthData.setControlsAllowed(health.controls_allowed);
healthData.setGasInterceptorDetected(health.gas_interceptor_detected);
- healthData.setStartedSignalDetected(health.started_signal_detected);
healthData.setIsGreyPanda(is_grey_panda);
+ healthData.setCanSendErrs(health.can_send_errs);
+ healthData.setCanFwdErrs(health.can_fwd_errs);
+ healthData.setGmlanSendErrs(health.gmlan_send_errs);
// send to health
auto words = capnp::messageToFlatArray(msg);
diff --git a/selfdrive/can/parser.cc b/selfdrive/can/parser.cc
index e3225181ba7004..69b30fb511438d 100644
--- a/selfdrive/can/parser.cc
+++ b/selfdrive/can/parser.cc
@@ -194,32 +194,36 @@ class CANParser {
: bus(abus) {
// connect to can on 8006
context = zmq_ctx_new();
- subscriber = zmq_socket(context, ZMQ_SUB);
- zmq_setsockopt(subscriber, ZMQ_SUBSCRIBE, "", 0);
- zmq_setsockopt(subscriber, ZMQ_RCVTIMEO, &timeout, sizeof(int));
- std::string tcp_addr_str;
+ if (tcp_addr.length() > 0) {
+ subscriber = zmq_socket(context, ZMQ_SUB);
+ zmq_setsockopt(subscriber, ZMQ_SUBSCRIBE, "", 0);
+ zmq_setsockopt(subscriber, ZMQ_RCVTIMEO, &timeout, sizeof(int));
- if (sendcan) {
- tcp_addr_str = "tcp://" + tcp_addr + ":8017";
- } else {
- tcp_addr_str = "tcp://" + tcp_addr + ":8006";
- }
- const char *tcp_addr_char = tcp_addr_str.c_str();
+ std::string tcp_addr_str;
+
+ if (sendcan) {
+ tcp_addr_str = "tcp://" + tcp_addr + ":8017";
+ } else {
+ tcp_addr_str = "tcp://" + tcp_addr + ":8006";
+ }
+ const char *tcp_addr_char = tcp_addr_str.c_str();
- zmq_connect(subscriber, tcp_addr_char);
+ zmq_connect(subscriber, tcp_addr_char);
- // drain sendcan to delete any stale messages from previous runs
- zmq_msg_t msgDrain;
- zmq_msg_init(&msgDrain);
- int err = 0;
- while(err >= 0) {
- err = zmq_msg_recv(&msgDrain, subscriber, ZMQ_DONTWAIT);
+ // drain sendcan to delete any stale messages from previous runs
+ zmq_msg_t msgDrain;
+ zmq_msg_init(&msgDrain);
+ int err = 0;
+ while(err >= 0) {
+ err = zmq_msg_recv(&msgDrain, subscriber, ZMQ_DONTWAIT);
+ }
+ } else {
+ subscriber = NULL;
}
dbc = dbc_lookup(dbc_name);
- assert(dbc);
-
+ assert(dbc);
for (const auto& op : options) {
MessageState state = {
.address = op.address,
@@ -326,6 +330,21 @@ class CANParser {
}
}
+ void update_string(uint64_t sec, std::string data) {
+ // format for board, make copy due to alignment issues, will be freed on out of scope
+ auto amsg = kj::heapArray((data.length() / sizeof(capnp::word)) + 1);
+ memcpy(amsg.begin(), data.data(), data.length());
+
+ // extract the messages
+ capnp::FlatArrayMessageReader cmsg(amsg);
+ cereal::Event::Reader event = cmsg.getRoot();
+
+ auto cans = event.getCan();
+ UpdateCans(sec, cans);
+
+ UpdateValid(sec);
+ }
+
int update(uint64_t sec, bool wait) {
int err;
int result = 0;
@@ -336,7 +355,7 @@ class CANParser {
// multiple recv is fine
bool first = wait;
- while (1) {
+ while (subscriber != NULL) {
if (first) {
err = zmq_msg_recv(&msg, subscriber, 0);
first = false;
@@ -432,6 +451,11 @@ int can_update(void* can, uint64_t sec, bool wait) {
return cp->update(sec, wait);
}
+void can_update_string(void *can, uint64_t sec, const char* dat, int len) {
+ CANParser* cp = (CANParser*)can;
+ cp->update_string(sec, std::string(dat, len));
+}
+
size_t can_query(void* can, uint64_t sec, bool *out_can_valid, size_t out_values_size, SignalValue* out_values) {
CANParser* cp = (CANParser*)can;
diff --git a/selfdrive/can/parser_pyx.pxd b/selfdrive/can/parser_pyx.pxd
index 9d8efa318c8af3..ac619707acc77b 100644
--- a/selfdrive/can/parser_pyx.pxd
+++ b/selfdrive/can/parser_pyx.pxd
@@ -67,6 +67,7 @@ ctypedef void* (*can_init_with_vectors_func)(int bus, const char* dbc_name,
const char* tcp_addr,
int timeout)
ctypedef int (*can_update_func)(void* can, uint64_t sec, bool wait);
+ctypedef void (*can_update_string_func)(void* can, uint64_t sec, const char* dat, int len);
ctypedef size_t (*can_query_func)(void* can, uint64_t sec, bool *out_can_valid, size_t out_values_size, SignalValue* out_values);
ctypedef void (*can_query_vector_func)(void* can, uint64_t sec, bool *out_can_valid, vector[SignalValue] &values)
@@ -77,6 +78,7 @@ cdef class CANParser:
dbc_lookup_func dbc_lookup
can_init_with_vectors_func can_init_with_vectors
can_update_func can_update
+ can_update_string_func can_update_string
can_query_vector_func can_query_vector
map[string, uint32_t] msg_name_to_address
map[uint32_t, string] address_to_msg_name
diff --git a/selfdrive/can/parser_pyx.pyx b/selfdrive/can/parser_pyx.pyx
index 65c6f5ab21bb58..c6f1f58e030dc9 100644
--- a/selfdrive/can/parser_pyx.pyx
+++ b/selfdrive/can/parser_pyx.pyx
@@ -8,7 +8,7 @@ import numbers
cdef int CAN_INVALID_CNT = 5
cdef class CANParser:
- def __init__(self, dbc_name, signals, checks=None, bus=0, sendcan=False, tcp_addr="127.0.0.1", timeout=-1):
+ def __init__(self, dbc_name, signals, checks=None, bus=0, sendcan=False, tcp_addr="", timeout=-1):
self.test_mode_enabled = False
can_dir = os.path.dirname(os.path.abspath(__file__))
libdbc_fn = os.path.join(can_dir, "libdbc.so")
@@ -17,6 +17,7 @@ cdef class CANParser:
self.can_init_with_vectors = dlsym(libdbc, 'can_init_with_vectors')
self.dbc_lookup = dlsym(libdbc, 'dbc_lookup')
self.can_update = dlsym(libdbc, 'can_update')
+ self.can_update_string = dlsym(libdbc, 'can_update_string')
self.can_query_vector = dlsym(libdbc, 'can_query_vector')
if checks is None:
checks = []
@@ -99,6 +100,19 @@ cdef class CANParser:
return updated_val
+ def update_string(self, uint64_t sec, dat):
+ self.can_update_string(self.can, sec, dat, len(dat))
+ return self.update_vl(sec)
+
+ def update_strings(self, uint64_t sec, strings):
+ updated_vals = set()
+
+ for s in strings:
+ updated_val = self.update_string(sec, s)
+ updated_vals.update(updated_val)
+
+ return updated_vals
+
def update(self, uint64_t sec, bool wait):
r = (self.can_update(self.can, sec, wait) >= 0)
updated_val = self.update_vl(sec)
diff --git a/selfdrive/can/tests/test_parser.py b/selfdrive/can/tests/test_parser.py
index bb00d042fca80c..53c95ce912be15 100755
--- a/selfdrive/can/tests/test_parser.py
+++ b/selfdrive/can/tests/test_parser.py
@@ -47,8 +47,9 @@ def run_route(route):
CP = CarInterface.get_params(CAR.CIVIC, {})
signals, checks = get_can_signals(CP)
- parser_old = CANParserOld(DBC[CP.carFingerprint]['pt'], signals, checks, 0, timeout=-1)
- parser_new = CANParserNew(DBC[CP.carFingerprint]['pt'], signals, checks, 0, timeout=-1)
+ parser_old = CANParserOld(DBC[CP.carFingerprint]['pt'], signals, checks, 0, timeout=-1, tcp_addr="127.0.0.1")
+ parser_new = CANParserNew(DBC[CP.carFingerprint]['pt'], signals, checks, 0, timeout=-1, tcp_addr="127.0.0.1")
+ parser_string = CANParserNew(DBC[CP.carFingerprint]['pt'], signals, checks, 0, timeout=-1)
if dict_keys_differ(parser_old.vl, parser_new.vl):
return False
@@ -61,19 +62,29 @@ def run_route(route):
for msg in lr:
if msg.which() == 'can':
t += DT
- can.send(msg.as_builder().to_bytes())
+ msg_bytes = msg.as_builder().to_bytes()
+ can.send(msg_bytes)
_, updated_old = parser_old.update(t, True)
_, updated_new = parser_new.update(t, True)
+ updated_string = parser_string.update_string(t, msg_bytes)
if updated_old != updated_new:
route_ok = False
print(t, "Diff in seen")
+ if updated_new != updated_string:
+ route_ok = False
+ print(t, "Diff in seen string")
+
if dicts_vals_differ(parser_old.vl, parser_new.vl):
print(t, "Diff in dict")
route_ok = False
+ if dicts_vals_differ(parser_new.vl, parser_string.vl):
+ print(t, "Diff in dict string")
+ route_ok = False
+
return route_ok
class TestCanParser(unittest.TestCase):
diff --git a/selfdrive/car/car_helpers.py b/selfdrive/car/car_helpers.py
index f7e8c53757a8a0..155e443e1c7ce7 100644
--- a/selfdrive/car/car_helpers.py
+++ b/selfdrive/car/car_helpers.py
@@ -50,6 +50,8 @@ def _get_interface_names():
# imports from directory selfdrive/car//
interfaces = load_interfaces(_get_interface_names())
+def only_toyota_left(candidate_cars):
+ return all(("TOYOTA" in c or "LEXUS" in c) for c in candidate_cars)
# BOUNTY: every added fingerprint in selfdrive/car/*/values.py is a $100 coupon code on shop.comma.ai
# **** for use live only ****
@@ -59,7 +61,7 @@ def fingerprint(logcan, sendcan):
elif os.getenv("SIMULATOR") is not None:
return ("simulator", None, "")
- finger = {}
+ finger = {0: {}, 2:{}} # collect on bus 0 or 2
cloudlog.warning("waiting for fingerprint...")
candidate_cars = all_known_cars()
can_seen_frame = None
@@ -79,6 +81,7 @@ def fingerprint(logcan, sendcan):
vin = ""
frame = 0
+
while True:
a = messaging.recv_one(logcan)
@@ -98,9 +101,12 @@ def fingerprint(logcan, sendcan):
# ignore everything not on bus 0 and with more than 11 bits,
# which are ussually sporadic and hard to include in fingerprints.
- # also exclude VIN query response on 0x7e8
- if can.src == 0 and can.address < 0x800 and can.address != 0x7e8:
- finger[can.address] = len(can.dat)
+ # also exclude VIN query response on 0x7e8.
+ # Include bus 2 for toyotas to disambiguate cars using camera messages
+ # (ideally should be done for all cars but we can't for Honda Bosch)
+ if (can.src == 0 or (only_toyota_left(candidate_cars) and can.src == 2)) and \
+ can.address < 0x800 and can.address != 0x7e8:
+ finger[can.src][can.address] = len(can.dat)
candidate_cars = eliminate_incompatible_cars(can, candidate_cars)
if can_seen_frame is None and can_seen:
@@ -110,7 +116,7 @@ def fingerprint(logcan, sendcan):
# message has elapsed, exit. Toyota needs higher time_fingerprint, since DSU does not
# broadcast immediately
if len(candidate_cars) == 1 and can_seen_frame is not None:
- time_fingerprint = 1.0 if ("TOYOTA" in candidate_cars[0] or "LEXUS" in candidate_cars[0]) else 0.1
+ time_fingerprint = 1.0 if only_toyota_left(candidate_cars) else 0.1
if (frame - can_seen_frame) > (time_fingerprint * 100):
break
@@ -146,6 +152,6 @@ def get_car(logcan, sendcan):
candidate = "mock"
CarInterface, CarController = interfaces[candidate]
- params = CarInterface.get_params(candidate, fingerprints, vin)
+ params = CarInterface.get_params(candidate, fingerprints[0], vin)
return CarInterface(params, CarController), params
diff --git a/selfdrive/car/chrysler/carstate.py b/selfdrive/car/chrysler/carstate.py
index 1d38b8cdab7eab..24acc76a4b196a 100644
--- a/selfdrive/car/chrysler/carstate.py
+++ b/selfdrive/car/chrysler/carstate.py
@@ -60,7 +60,7 @@ def get_can_parser(CP):
("ACC_2", 50),
]
- return CANParser(DBC[CP.carFingerprint]['pt'], signals, checks, 0, timeout=100)
+ return CANParser(DBC[CP.carFingerprint]['pt'], signals, checks, 0)
def get_camera_parser(CP):
signals = [
@@ -72,7 +72,7 @@ def get_camera_parser(CP):
]
checks = []
- return CANParser(DBC[CP.carFingerprint]['pt'], signals, checks, 2, timeout=100)
+ return CANParser(DBC[CP.carFingerprint]['pt'], signals, checks, 2)
class CarState(object):
diff --git a/selfdrive/car/chrysler/interface.py b/selfdrive/car/chrysler/interface.py
index 793f7320844148..65a60904f51278 100755
--- a/selfdrive/car/chrysler/interface.py
+++ b/selfdrive/car/chrysler/interface.py
@@ -112,18 +112,17 @@ def get_params(candidate, fingerprint, vin=""):
return ret
# returns a car.CarState
- def update(self, c):
+ def update(self, c, can_strings):
# ******************* do can recv *******************
- canMonoTimes = []
- can_rcv_valid, _ = self.cp.update(int(sec_since_boot() * 1e9), True)
- cam_rcv_valid, _ = self.cp_cam.update(int(sec_since_boot() * 1e9), False)
+ self.cp.update_strings(int(sec_since_boot() * 1e9), can_strings)
+ self.cp_cam.update_strings(int(sec_since_boot() * 1e9), can_strings)
self.CS.update(self.cp, self.cp_cam)
# create message
ret = car.CarState.new_message()
- ret.canValid = can_rcv_valid and cam_rcv_valid and self.cp.can_valid and self.cp_cam.can_valid
+ ret.canValid = self.cp.can_valid and self.cp_cam.can_valid
# speeds
ret.vEgo = self.CS.v_ego
@@ -222,7 +221,6 @@ def update(self, c):
events.append(create_event('belowSteerSpeed', [ET.WARNING]))
ret.events = events
- ret.canMonoTimes = canMonoTimes
self.gas_pressed_prev = ret.gasPressed
self.brake_pressed_prev = ret.brakePressed
diff --git a/selfdrive/car/chrysler/radar_interface.py b/selfdrive/car/chrysler/radar_interface.py
index b4970b2223706a..43f5c6105eccf5 100755
--- a/selfdrive/car/chrysler/radar_interface.py
+++ b/selfdrive/car/chrysler/radar_interface.py
@@ -51,27 +51,24 @@ def __init__(self, CP):
self.pts = {}
self.delay = 0.0 # Delay of radar #TUNE
self.rcp = _create_radar_can_parser()
+ self.updated_messages = set()
+ self.trigger_msg = LAST_MSG
- def update(self):
- canMonoTimes = []
+ def update(self, can_strings):
+ tm = int(sec_since_boot() * 1e9)
+ vls = self.rcp.update_strings(tm, can_strings)
+ self.updated_messages.update(vls)
- updated_messages = set() # set of message IDs (sig_addresses) we've seen
-
- while 1:
- tm = int(sec_since_boot() * 1e9)
- _, vls = self.rcp.update(tm, True)
- updated_messages.update(vls)
- if LAST_MSG in updated_messages:
- break
+ if self.trigger_msg not in self.updated_messages:
+ return None
ret = car.RadarData.new_message()
errors = []
if not self.rcp.can_valid:
errors.append("canError")
ret.errors = errors
- ret.canMonoTimes = canMonoTimes
- for ii in updated_messages: # ii should be the message ID as a number
+ for ii in self.updated_messages: # ii should be the message ID as a number
cpt = self.rcp.vl[ii]
trackId = _address_to_track(ii)
@@ -92,11 +89,6 @@ def update(self):
# We want a list, not a dictionary. Filter out LONG_DIST==0 because that means it's not valid.
ret.points = [x for x in self.pts.values() if x.dRel != 0]
- return ret
-if __name__ == "__main__":
- RI = RadarInterface(None)
- while 1:
- ret = RI.update()
- print(chr(27) + "[2J") # clear screen
- print(ret)
+ self.updated_messages.clear()
+ return ret
diff --git a/selfdrive/car/ford/carstate.py b/selfdrive/car/ford/carstate.py
index dc6d824ff5a4b7..5e87a2c87812f1 100644
--- a/selfdrive/car/ford/carstate.py
+++ b/selfdrive/car/ford/carstate.py
@@ -29,7 +29,7 @@ def get_can_parser(CP):
checks = [
]
- return CANParser(DBC[CP.carFingerprint]['pt'], signals, checks, 0, timeout=100)
+ return CANParser(DBC[CP.carFingerprint]['pt'], signals, checks, 0)
class CarState(object):
diff --git a/selfdrive/car/ford/interface.py b/selfdrive/car/ford/interface.py
index 0f3bbc33cc2b84..ca0f9f830f63c9 100755
--- a/selfdrive/car/ford/interface.py
+++ b/selfdrive/car/ford/interface.py
@@ -105,18 +105,16 @@ def get_params(candidate, fingerprint, vin=""):
return ret
# returns a car.CarState
- def update(self, c):
+ def update(self, c, can_strings):
# ******************* do can recv *******************
- canMonoTimes = []
-
- can_rcv_valid, _ = self.cp.update(int(sec_since_boot() * 1e9), True)
+ self.cp.update_strings(int(sec_since_boot() * 1e9), can_strings)
self.CS.update(self.cp)
# create message
ret = car.CarState.new_message()
- ret.canValid = can_rcv_valid and self.cp.can_valid
+ ret.canValid = self.cp.can_valid
# speeds
ret.vEgo = self.CS.v_ego
@@ -167,7 +165,6 @@ def update(self, c):
events.append(create_event('steerTempUnavailableMute', [ET.WARNING]))
ret.events = events
- ret.canMonoTimes = canMonoTimes
self.gas_pressed_prev = ret.gasPressed
self.brake_pressed_prev = ret.brakePressed
diff --git a/selfdrive/car/ford/radar_interface.py b/selfdrive/car/ford/radar_interface.py
index 08b54723d6801f..04cab9c66d7e1b 100755
--- a/selfdrive/car/ford/radar_interface.py
+++ b/selfdrive/car/ford/radar_interface.py
@@ -28,28 +28,25 @@ def __init__(self, CP):
# Nidec
self.rcp = _create_radar_can_parser()
+ self.trigger_msg = 0x53f
+ self.updated_messages = set()
- def update(self):
- canMonoTimes = []
+ def update(self, can_strings):
+ tm = int(sec_since_boot() * 1e9)
+ vls = self.rcp.update_strings(tm, can_strings)
+ self.updated_messages.update(vls)
- updated_messages = set()
- while 1:
- tm = int(sec_since_boot() * 1e9)
- _, vls = self.rcp.update(tm, True)
- updated_messages.update(vls)
+ if self.trigger_msg not in self.updated_messages:
+ return None
- # TODO: do not hardcode last msg
- if 0x53f in updated_messages:
- break
ret = car.RadarData.new_message()
errors = []
if not self.rcp.can_valid:
errors.append("canError")
ret.errors = errors
- ret.canMonoTimes = canMonoTimes
- for ii in updated_messages:
+ for ii in self.updated_messages:
cpt = self.rcp.vl[ii]
if cpt['X_Rel'] > 0.00001:
@@ -78,11 +75,5 @@ def update(self):
del self.pts[ii]
ret.points = self.pts.values()
+ self.updated_messages.clear()
return ret
-
-if __name__ == "__main__":
- RI = RadarInterface(None)
- while 1:
- ret = RI.update()
- print(chr(27) + "[2J")
- print(ret)
diff --git a/selfdrive/car/gm/carstate.py b/selfdrive/car/gm/carstate.py
index 174d11b46b53c2..2501598dd6cf7d 100644
--- a/selfdrive/car/gm/carstate.py
+++ b/selfdrive/car/gm/carstate.py
@@ -47,7 +47,7 @@ def get_powertrain_can_parser(CP, canbus):
("CruiseState", "AcceleratorPedal2", 0),
]
- return CANParser(DBC[CP.carFingerprint]['pt'], signals, [], canbus.powertrain, timeout=100)
+ return CANParser(DBC[CP.carFingerprint]['pt'], signals, [], canbus.powertrain)
class CarState(object):
diff --git a/selfdrive/car/gm/interface.py b/selfdrive/car/gm/interface.py
index c066a6523f2213..71b0efad29d055 100755
--- a/selfdrive/car/gm/interface.py
+++ b/selfdrive/car/gm/interface.py
@@ -170,15 +170,15 @@ def get_params(candidate, fingerprint, vin=""):
return ret
# returns a car.CarState
- def update(self, c):
- can_rcv_valid, _ = self.pt_cp.update(int(sec_since_boot() * 1e9), True)
+ def update(self, c, can_strings):
+ self.pt_cp.update_strings(int(sec_since_boot() * 1e9), can_strings)
self.CS.update(self.pt_cp)
# create message
ret = car.CarState.new_message()
- ret.canValid = can_rcv_valid and self.pt_cp.can_valid
+ ret.canValid = self.pt_cp.can_valid
# speeds
ret.vEgo = self.CS.v_ego
diff --git a/selfdrive/car/gm/radar_interface.py b/selfdrive/car/gm/radar_interface.py
index 12fb7c23427380..6788e1ce74e414 100755
--- a/selfdrive/car/gm/radar_interface.py
+++ b/selfdrive/car/gm/radar_interface.py
@@ -52,21 +52,23 @@ def __init__(self, CP):
print "Using %d as obstacle CAN bus ID" % canbus.obstacle
self.rcp = create_radar_can_parser(canbus, CP.carFingerprint)
- def update(self):
- updated_messages = set()
- ret = car.RadarData.new_message()
- while 1:
+ self.trigger_msg = LAST_RADAR_MSG
+ self.updated_messages = set()
- if self.rcp is None:
- time.sleep(0.05) # nothing to do
- return ret
+ def update(self, can_strings):
+ if self.rcp is None:
+ time.sleep(0.05) # nothing to do
+ return car.RadarData.new_message()
- tm = int(sec_since_boot() * 1e9)
- _, vls = self.rcp.update(tm, True)
- updated_messages.update(vls)
- if LAST_RADAR_MSG in updated_messages:
- break
+ tm = int(sec_since_boot() * 1e9)
+ vls = self.rcp.update_strings(tm, can_strings)
+ self.updated_messages.update(vls)
+
+ if self.trigger_msg not in self.updated_messages:
+ return None
+
+ ret = car.RadarData.new_message()
header = self.rcp.vl[RADAR_HEADER_MSG]
fault = header['FLRRSnsrBlckd'] or header['FLRRSnstvFltPrsntInt'] or \
header['FLRRYawRtPlsblityFlt'] or header['FLRRHWFltPrsntInt'] or \
@@ -83,7 +85,7 @@ def update(self):
# Not all radar messages describe targets,
# no need to monitor all of the self.rcp.msgs_upd
- for ii in updated_messages:
+ for ii in self.updated_messages:
if ii == RADAR_HEADER_MSG:
continue
@@ -112,11 +114,5 @@ def update(self):
del self.pts[oldTarget]
ret.points = self.pts.values()
+ self.updated_messages.clear()
return ret
-
-if __name__ == "__main__":
- RI = RadarInterface(None)
- while 1:
- ret = RI.update()
- print(chr(27) + "[2J")
- print(ret)
diff --git a/selfdrive/car/honda/carstate.py b/selfdrive/car/honda/carstate.py
index 6c0aec52a03a5f..e2bb82c73c0351 100644
--- a/selfdrive/car/honda/carstate.py
+++ b/selfdrive/car/honda/carstate.py
@@ -146,6 +146,7 @@ def get_can_signals(CP):
# add gas interceptor reading if we are using it
if CP.enableGasInterceptor:
signals.append(("INTERCEPTOR_GAS", "GAS_SENSOR", 0))
+ signals.append(("INTERCEPTOR_GAS2", "GAS_SENSOR", 0))
checks.append(("GAS_SENSOR", 50))
return signals, checks
@@ -153,7 +154,7 @@ def get_can_signals(CP):
def get_can_parser(CP):
signals, checks = get_can_signals(CP)
- return CANParser(DBC[CP.carFingerprint]['pt'], signals, checks, 0, timeout=100)
+ return CANParser(DBC[CP.carFingerprint]['pt'], signals, checks, 0)
def get_cam_can_parser(CP):
@@ -166,7 +167,7 @@ def get_cam_can_parser(CP):
cam_bus = 1 if CP.carFingerprint in HONDA_BOSCH else 2
- return CANParser(DBC[CP.carFingerprint]['pt'], signals, checks, cam_bus, timeout=100)
+ return CANParser(DBC[CP.carFingerprint]['pt'], signals, checks, cam_bus)
class CarState(object):
def __init__(self, CP):
@@ -261,7 +262,7 @@ def update(self, cp, cp_cam):
# this is a hack for the interceptor. This is now only used in the simulation
# TODO: Replace tests by toyota so this can go away
if self.CP.enableGasInterceptor:
- self.user_gas = cp.vl["GAS_SENSOR"]['INTERCEPTOR_GAS']
+ self.user_gas = (cp.vl["GAS_SENSOR"]['INTERCEPTOR_GAS'] + cp.vl["GAS_SENSOR"]['INTERCEPTOR_GAS2']) / 2.
self.user_gas_pressed = self.user_gas > 0 # this works because interceptor read < 0 when pedal position is 0. Once calibrated, this will change
self.gear = 0 if self.CP.carFingerprint == CAR.CIVIC else cp.vl["GEARBOX"]['GEAR']
diff --git a/selfdrive/car/honda/interface.py b/selfdrive/car/honda/interface.py
index 93aaf0182b7db6..7ad72cdc48c1a5 100755
--- a/selfdrive/car/honda/interface.py
+++ b/selfdrive/car/honda/interface.py
@@ -358,18 +358,17 @@ def get_params(candidate, fingerprint, vin=""):
return ret
# returns a car.CarState
- def update(self, c):
+ def update(self, c, can_strings):
# ******************* do can recv *******************
- canMonoTimes = []
- can_rcv_valid, _ = self.cp.update(int(sec_since_boot() * 1e9), True)
- cam_rcv_valid, _ = self.cp_cam.update(int(sec_since_boot() * 1e9), False)
+ self.cp.update_strings(int(sec_since_boot() * 1e9), can_strings)
+ self.cp_cam.update_strings(int(sec_since_boot() * 1e9), can_strings)
self.CS.update(self.cp, self.cp_cam)
# create message
ret = car.CarState.new_message()
- ret.canValid = can_rcv_valid and cam_rcv_valid and self.cp.can_valid
+ ret.canValid = self.cp.can_valid
# speeds
ret.vEgo = self.CS.v_ego
@@ -547,7 +546,6 @@ def update(self, c):
events.append(create_event('buttonEnable', [ET.ENABLE]))
ret.events = events
- ret.canMonoTimes = canMonoTimes
# update previous brake/gas pressed
self.gas_pressed_prev = ret.gasPressed
diff --git a/selfdrive/car/honda/radar_interface.py b/selfdrive/car/honda/radar_interface.py
index 94e98cf2cb3351..f8cecd6de43d97 100755
--- a/selfdrive/car/honda/radar_interface.py
+++ b/selfdrive/car/honda/radar_interface.py
@@ -31,25 +31,30 @@ def __init__(self, CP):
# Nidec
self.rcp = _create_nidec_can_parser()
+ self.trigger_msg = 0x445
+ self.updated_messages = set()
- def update(self):
- canMonoTimes = []
-
- updated_messages = set()
- ret = car.RadarData.new_message()
-
+ def update(self, can_strings):
# in Bosch radar and we are only steering for now, so sleep 0.05s to keep
# radard at 20Hz and return no points
if self.radar_off_can:
time.sleep(0.05)
- return ret
+ return car.RadarData.new_message()
+
+ tm = int(sec_since_boot() * 1e9)
+ vls = self.rcp.update_strings(tm, can_strings)
+ self.updated_messages.update(vls)
+
+ if self.trigger_msg not in self.updated_messages:
+ return None
+
+ rr = self._update(self.updated_messages)
+ self.updated_messages.clear()
+ return rr
- while 1:
- tm = int(sec_since_boot() * 1e9)
- _, vls = self.rcp.update(tm, True)
- updated_messages.update(vls)
- if 0x445 in updated_messages:
- break
+
+ def _update(self, updated_messages):
+ ret = car.RadarData.new_message()
for ii in updated_messages:
cpt = self.rcp.vl[ii]
@@ -80,19 +85,7 @@ def update(self):
if self.radar_wrong_config:
errors.append("wrongConfig")
ret.errors = errors
- ret.canMonoTimes = canMonoTimes
ret.points = self.pts.values()
return ret
-
-
-if __name__ == "__main__":
- class CarParams:
- radarOffCan = False
-
- RI = RadarInterface(CarParams)
- while 1:
- ret = RI.update()
- print(chr(27) + "[2J")
- print(ret)
diff --git a/selfdrive/car/hyundai/carstate.py b/selfdrive/car/hyundai/carstate.py
index 8c900d73f8285d..f993bd2a0f6959 100644
--- a/selfdrive/car/hyundai/carstate.py
+++ b/selfdrive/car/hyundai/carstate.py
@@ -93,7 +93,7 @@ def get_can_parser(CP):
("SAS11", 100)
]
- return CANParser(DBC[CP.carFingerprint]['pt'], signals, checks, 0, timeout=100)
+ return CANParser(DBC[CP.carFingerprint]['pt'], signals, checks, 0)
def get_camera_parser(CP):
@@ -119,7 +119,7 @@ def get_camera_parser(CP):
checks = []
- return CANParser(DBC[CP.carFingerprint]['pt'], signals, checks, 2, timeout=100)
+ return CANParser(DBC[CP.carFingerprint]['pt'], signals, checks, 2)
class CarState(object):
diff --git a/selfdrive/car/hyundai/interface.py b/selfdrive/car/hyundai/interface.py
index 67ca2261ff7f17..4e1b2e6be2bcb0 100644
--- a/selfdrive/car/hyundai/interface.py
+++ b/selfdrive/car/hyundai/interface.py
@@ -151,17 +151,16 @@ def get_params(candidate, fingerprint, vin=""):
return ret
# returns a car.CarState
- def update(self, c):
+ def update(self, c, can_strings):
# ******************* do can recv *******************
- canMonoTimes = []
- can_rcv_valid, _ = self.cp.update(int(sec_since_boot() * 1e9), True)
- cam_rcv_valid, _ = self.cp_cam.update(int(sec_since_boot() * 1e9), False)
+ self.cp.update_strings(int(sec_since_boot() * 1e9), can_strings)
+ self.cp_cam.update_strings(int(sec_since_boot() * 1e9), can_strings)
self.CS.update(self.cp, self.cp_cam)
# create message
ret = car.CarState.new_message()
- ret.canValid = can_rcv_valid and cam_rcv_valid and self.cp.can_valid # TODO: check cp_cam validity
+ ret.canValid = self.cp.can_valid # TODO: check cp_cam validity
# speeds
ret.vEgo = self.CS.v_ego
@@ -269,7 +268,6 @@ def update(self, c):
events.append(create_event('belowSteerSpeed', [ET.WARNING]))
ret.events = events
- ret.canMonoTimes = canMonoTimes
self.gas_pressed_prev = ret.gasPressed
self.brake_pressed_prev = ret.brakePressed
diff --git a/selfdrive/car/hyundai/radar_interface.py b/selfdrive/car/hyundai/radar_interface.py
index 75256683de3187..1d7772fd3bb626 100644
--- a/selfdrive/car/hyundai/radar_interface.py
+++ b/selfdrive/car/hyundai/radar_interface.py
@@ -9,16 +9,8 @@ def __init__(self, CP):
self.pts = {}
self.delay = 0.1
- def update(self):
-
+ def update(self, can_strings):
ret = car.RadarData.new_message()
time.sleep(0.05) # radard runs on RI updates
return ret
-
-if __name__ == "__main__":
- RI = RadarInterface(None)
- while 1:
- ret = RI.update()
- print(chr(27) + "[2J")
- print(ret)
diff --git a/selfdrive/car/mock/interface.py b/selfdrive/car/mock/interface.py
index a18d2bf244bde0..3f47b9b00af7ea 100755
--- a/selfdrive/car/mock/interface.py
+++ b/selfdrive/car/mock/interface.py
@@ -80,7 +80,7 @@ def get_params(candidate, fingerprint, vin=""):
return ret
# returns a car.CarState
- def update(self, c):
+ def update(self, c, can_strings):
self.rk.keep_time()
# get basic data from phone and gps since CAN isn't connected
diff --git a/selfdrive/car/mock/radar_interface.py b/selfdrive/car/mock/radar_interface.py
index 437bb0538a8dd4..8e5f7b7fcaf150 100755
--- a/selfdrive/car/mock/radar_interface.py
+++ b/selfdrive/car/mock/radar_interface.py
@@ -9,15 +9,7 @@ def __init__(self, CP):
self.pts = {}
self.delay = 0.1
- def update(self):
-
+ def update(self, can_strings):
ret = car.RadarData.new_message()
time.sleep(0.05) # radard runs on RI updates
return ret
-
-if __name__ == "__main__":
- RI = RadarInterface(None)
- while 1:
- ret = RI.update()
- print(chr(27) + "[2J")
- print(ret)
diff --git a/selfdrive/car/subaru/carstate.py b/selfdrive/car/subaru/carstate.py
index 9a927775489335..6c5f6782662bc7 100644
--- a/selfdrive/car/subaru/carstate.py
+++ b/selfdrive/car/subaru/carstate.py
@@ -37,7 +37,7 @@ def get_powertrain_can_parser(CP):
("BodyInfo", 10),
]
- return CANParser(DBC[CP.carFingerprint]['pt'], signals, checks, 0, timeout=100)
+ return CANParser(DBC[CP.carFingerprint]['pt'], signals, checks, 0)
def get_camera_can_parser(CP):
@@ -79,7 +79,7 @@ def get_camera_can_parser(CP):
("ES_DashStatus", 10),
]
- return CANParser(DBC[CP.carFingerprint]['pt'], signals, checks, 2, timeout=100)
+ return CANParser(DBC[CP.carFingerprint]['pt'], signals, checks, 2)
class CarState(object):
diff --git a/selfdrive/car/subaru/interface.py b/selfdrive/car/subaru/interface.py
index e9d9c117fc714c..ad8d1d5a48e7ab 100644
--- a/selfdrive/car/subaru/interface.py
+++ b/selfdrive/car/subaru/interface.py
@@ -94,16 +94,16 @@ def get_params(candidate, fingerprint, vin=""):
return ret
# returns a car.CarState
- def update(self, c):
- can_rcv_valid, _ = self.pt_cp.update(int(sec_since_boot() * 1e9), True)
- cam_rcv_valid, _ = self.cam_cp.update(int(sec_since_boot() * 1e9), False)
+ def update(self, c, can_strings):
+ self.pt_cp.update_strings(int(sec_since_boot() * 1e9), can_strings)
+ self.cam_cp.update_strings(int(sec_since_boot() * 1e9), can_strings)
self.CS.update(self.pt_cp, self.cam_cp)
# create message
ret = car.CarState.new_message()
- ret.canValid = can_rcv_valid and cam_rcv_valid and self.pt_cp.can_valid and self.cam_cp.can_valid
+ ret.canValid = self.pt_cp.can_valid and self.cam_cp.can_valid
# speeds
ret.vEgo = self.CS.v_ego
diff --git a/selfdrive/car/subaru/radar_interface.py b/selfdrive/car/subaru/radar_interface.py
index 75256683de3187..0f8108771110ab 100644
--- a/selfdrive/car/subaru/radar_interface.py
+++ b/selfdrive/car/subaru/radar_interface.py
@@ -9,16 +9,9 @@ def __init__(self, CP):
self.pts = {}
self.delay = 0.1
- def update(self):
+ def update(self, can_strings):
ret = car.RadarData.new_message()
time.sleep(0.05) # radard runs on RI updates
return ret
-
-if __name__ == "__main__":
- RI = RadarInterface(None)
- while 1:
- ret = RI.update()
- print(chr(27) + "[2J")
- print(ret)
diff --git a/selfdrive/car/toyota/carstate.py b/selfdrive/car/toyota/carstate.py
index ee7c61d940617e..40be422db1bb13 100644
--- a/selfdrive/car/toyota/carstate.py
+++ b/selfdrive/car/toyota/carstate.py
@@ -1,7 +1,7 @@
import numpy as np
from common.kalman.simple_kalman import KF1D
-from selfdrive.can.parser import CANParser
from selfdrive.can.can_define import CANDefine
+from selfdrive.can.parser import CANParser
from selfdrive.config import Conversions as CV
from selfdrive.car.toyota.values import CAR, DBC, STEER_THRESHOLD, TSS2_CAR
@@ -70,9 +70,10 @@ def get_can_parser(CP):
# add gas interceptor reading if we are using it
if CP.enableGasInterceptor:
signals.append(("INTERCEPTOR_GAS", "GAS_SENSOR", 0))
+ signals.append(("INTERCEPTOR_GAS2", "GAS_SENSOR", 0))
checks.append(("GAS_SENSOR", 50))
- return CANParser(DBC[CP.carFingerprint]['pt'], signals, checks, 0, timeout=100)
+ return CANParser(DBC[CP.carFingerprint]['pt'], signals, checks, 0)
def get_cam_can_parser(CP):
@@ -82,7 +83,7 @@ def get_cam_can_parser(CP):
# use steering message to check if panda is connected to frc
checks = [("STEERING_LKA", 42)]
- return CANParser(DBC[CP.carFingerprint]['pt'], signals, checks, 2, timeout=100)
+ return CANParser(DBC[CP.carFingerprint]['pt'], signals, checks, 2)
class CarState(object):
@@ -118,7 +119,7 @@ def update(self, cp):
self.brake_pressed = cp.vl["BRAKE_MODULE"]['BRAKE_PRESSED']
if self.CP.enableGasInterceptor:
- self.pedal_gas = cp.vl["GAS_SENSOR"]['INTERCEPTOR_GAS']
+ self.pedal_gas = (cp.vl["GAS_SENSOR"]['INTERCEPTOR_GAS'] + cp.vl["GAS_SENSOR"]['INTERCEPTOR_GAS2']) / 2.
else:
self.pedal_gas = cp.vl["GAS_PEDAL"]['GAS_PEDAL']
self.car_gas = self.pedal_gas
diff --git a/selfdrive/car/toyota/interface.py b/selfdrive/car/toyota/interface.py
index 29abfeb8464db6..5e5cb2c8393d17 100755
--- a/selfdrive/car/toyota/interface.py
+++ b/selfdrive/car/toyota/interface.py
@@ -9,7 +9,6 @@
from selfdrive.car import STD_CARGO_KG, scale_rot_inertia, scale_tire_stiffness
from selfdrive.swaglog import cloudlog
-
class CarInterface(object):
def __init__(self, CP, CarController):
self.CP = CP
@@ -175,6 +174,16 @@ def get_params(candidate, fingerprint, vin=""):
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.6], [0.1]]
ret.lateralTuning.pid.kf = 0.00007818594
+ elif candidate == CAR.SIENNA:
+ stop_and_go = True
+ ret.safetyParam = 73
+ ret.wheelbase = 3.03
+ ret.steerRatio = 16.0
+ tire_stiffness_factor = 0.444
+ ret.mass = 4590. * CV.LB_TO_KG + STD_CARGO_KG
+ ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.3], [0.05]]
+ ret.lateralTuning.pid.kf = 0.00007818594
+
ret.steerRateCost = 1.
ret.centerToFront = ret.wheelbase * 0.44
@@ -201,8 +210,8 @@ def get_params(candidate, fingerprint, vin=""):
# steer, gas, brake limitations VS speed
ret.steerMaxBP = [16. * CV.KPH_TO_MS, 45. * CV.KPH_TO_MS] # breakpoints at 1 and 40 kph
ret.steerMaxV = [1., 1.] # 2/3rd torque allowed above 45 kph
- ret.brakeMaxBP = [5., 20.]
- ret.brakeMaxV = [1., 0.8]
+ ret.brakeMaxBP = [0.]
+ ret.brakeMaxV = [1.]
ret.enableCamera = not check_ecu_msgs(fingerprint, ECU.CAM)
ret.enableDsu = not check_ecu_msgs(fingerprint, ECU.DSU)
@@ -236,22 +245,20 @@ def get_params(candidate, fingerprint, vin=""):
return ret
# returns a car.CarState
- def update(self, c):
+ def update(self, c, can_strings):
# ******************* do can recv *******************
- canMonoTimes = []
-
- can_rcv_valid, _ = self.cp.update(int(sec_since_boot() * 1e9), True)
+ self.cp.update_strings(int(sec_since_boot() * 1e9), can_strings)
# run the cam can update for 10s as we just need to know if the camera is alive
if self.frame < 1000:
- self.cp_cam.update(int(sec_since_boot() * 1e9), False)
+ self.cp_cam.update_strings(int(sec_since_boot() * 1e9), can_strings)
self.CS.update(self.cp)
# create message
ret = car.CarState.new_message()
- ret.canValid = can_rcv_valid and self.cp.can_valid
+ ret.canValid = self.cp.can_valid
# speeds
ret.vEgo = self.CS.v_ego
@@ -368,7 +375,6 @@ def update(self, c):
events.append(create_event('pedalPressed', [ET.PRE_ENABLE]))
ret.events = events
- ret.canMonoTimes = canMonoTimes
self.gas_pressed_prev = ret.gasPressed
self.brake_pressed_prev = ret.brakePressed
diff --git a/selfdrive/car/toyota/radar_interface.py b/selfdrive/car/toyota/radar_interface.py
index c160e751aa06bc..4e0a0e809b777a 100755
--- a/selfdrive/car/toyota/radar_interface.py
+++ b/selfdrive/car/toyota/radar_interface.py
@@ -46,32 +46,36 @@ def __init__(self, CP):
self.valid_cnt = {key: 0 for key in self.RADAR_A_MSGS}
self.rcp = _create_radar_can_parser(CP.carFingerprint)
+ self.trigger_msg = self.RADAR_B_MSGS[-1]
+ self.updated_messages = set()
+
# No radar dbc for cars without DSU which are not TSS 2.0
# TODO: make a adas dbc file for dsu-less models
self.no_radar = CP.carFingerprint in NO_DSU_CAR and CP.carFingerprint not in TSS2_CAR
- def update(self):
-
- ret = car.RadarData.new_message()
-
+ def update(self, can_strings):
if self.no_radar:
time.sleep(0.05)
- return ret
+ return car.RadarData.new_message()
+
+ tm = int(sec_since_boot() * 1e9)
+ vls = self.rcp.update_strings(tm, can_strings)
+ self.updated_messages.update(vls)
- canMonoTimes = []
- updated_messages = set()
- while 1:
- tm = int(sec_since_boot() * 1e9)
- _, vls = self.rcp.update(tm, True)
- updated_messages.update(vls)
- if self.RADAR_B_MSGS[-1] in updated_messages:
- break
+ if self.trigger_msg not in self.updated_messages:
+ return None
+ rr = self._update(self.updated_messages)
+ self.updated_messages.clear()
+
+ return rr
+
+ def _update(self, updated_messages):
+ ret = car.RadarData.new_message()
errors = []
if not self.rcp.can_valid:
errors.append("canError")
ret.errors = errors
- ret.canMonoTimes = canMonoTimes
for ii in updated_messages:
if ii in self.RADAR_A_MSGS:
@@ -105,10 +109,3 @@ def update(self):
ret.points = self.pts.values()
return ret
-
-if __name__ == "__main__":
- RI = RadarInterface(None)
- while 1:
- ret = RI.update()
- print(chr(27) + "[2J")
- print(ret)
diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py
index da8b02dcd7212c..df535eab05a852 100644
--- a/selfdrive/car/toyota/values.py
+++ b/selfdrive/car/toyota/values.py
@@ -16,6 +16,7 @@ class CAR:
RAV4_TSS2 = "TOYOTA RAV4 2019"
COROLLA_TSS2 = "TOYOTA COROLLA TSS2 2019"
LEXUS_ESH_TSS2 = "LEXUS ES 300H 2019"
+ SIENNA = "TOYOTA SIENNA XLE 2018"
class ECU:
@@ -42,23 +43,23 @@ class ECU:
(0x4d3, ECU.CAM, (CAR.PRIUS, CAR.RAV4H, CAR.LEXUS_RXH, CAR.RAV4, CAR.COROLLA, CAR.AVALON), 0, 100, '\x1C\x00\x00\x01\x00\x00\x00\x00'),
(0x128, ECU.DSU, (CAR.PRIUS, CAR.RAV4H, CAR.LEXUS_RXH, CAR.RAV4, CAR.COROLLA, CAR.AVALON), 1, 3, '\xf4\x01\x90\x83\x00\x37'),
- (0x128, ECU.DSU, (CAR.HIGHLANDER, CAR.HIGHLANDERH), 1, 3, '\x03\x00\x20\x00\x00\x52'),
- (0x141, ECU.DSU, (CAR.PRIUS, CAR.RAV4H, CAR.LEXUS_RXH, CAR.RAV4, CAR.COROLLA, CAR.HIGHLANDER, CAR.HIGHLANDERH, CAR.AVALON), 1, 2, '\x00\x00\x00\x46'),
- (0x160, ECU.DSU, (CAR.PRIUS, CAR.RAV4H, CAR.LEXUS_RXH, CAR.RAV4, CAR.COROLLA, CAR.HIGHLANDER, CAR.HIGHLANDERH, CAR.AVALON), 1, 7, '\x00\x00\x08\x12\x01\x31\x9c\x51'),
+ (0x128, ECU.DSU, (CAR.HIGHLANDER, CAR.HIGHLANDERH, CAR.SIENNA), 1, 3, '\x03\x00\x20\x00\x00\x52'),
+ (0x141, ECU.DSU, (CAR.PRIUS, CAR.RAV4H, CAR.LEXUS_RXH, CAR.RAV4, CAR.COROLLA, CAR.HIGHLANDER, CAR.HIGHLANDERH, CAR.AVALON, CAR.SIENNA), 1, 2, '\x00\x00\x00\x46'),
+ (0x160, ECU.DSU, (CAR.PRIUS, CAR.RAV4H, CAR.LEXUS_RXH, CAR.RAV4, CAR.COROLLA, CAR.HIGHLANDER, CAR.HIGHLANDERH, CAR.AVALON, CAR.SIENNA), 1, 7, '\x00\x00\x08\x12\x01\x31\x9c\x51'),
(0x161, ECU.DSU, (CAR.PRIUS, CAR.RAV4H, CAR.LEXUS_RXH, CAR.RAV4, CAR.COROLLA, CAR.AVALON), 1, 7, '\x00\x1e\x00\x00\x00\x80\x07'),
- (0X161, ECU.DSU, (CAR.HIGHLANDERH, CAR.HIGHLANDER), 1, 7, '\x00\x1e\x00\xd4\x00\x00\x5b'),
- (0x283, ECU.DSU, (CAR.PRIUS, CAR.RAV4H, CAR.LEXUS_RXH, CAR.RAV4, CAR.COROLLA, CAR.HIGHLANDER, CAR.HIGHLANDERH, CAR.AVALON), 0, 3, '\x00\x00\x00\x00\x00\x00\x8c'),
+ (0X161, ECU.DSU, (CAR.HIGHLANDERH, CAR.HIGHLANDER, CAR.SIENNA), 1, 7, '\x00\x1e\x00\xd4\x00\x00\x5b'),
+ (0x283, ECU.DSU, (CAR.PRIUS, CAR.RAV4H, CAR.LEXUS_RXH, CAR.RAV4, CAR.COROLLA, CAR.HIGHLANDER, CAR.HIGHLANDERH, CAR.AVALON, CAR.SIENNA), 0, 3, '\x00\x00\x00\x00\x00\x00\x8c'),
(0x2E6, ECU.DSU, (CAR.PRIUS, CAR.RAV4H, CAR.LEXUS_RXH), 0, 3, '\xff\xf8\x00\x08\x7f\xe0\x00\x4e'),
(0x2E7, ECU.DSU, (CAR.PRIUS, CAR.RAV4H, CAR.LEXUS_RXH), 0, 3, '\xa8\x9c\x31\x9c\x00\x00\x00\x02'),
(0x33E, ECU.DSU, (CAR.PRIUS, CAR.RAV4H, CAR.LEXUS_RXH), 0, 20, '\x0f\xff\x26\x40\x00\x1f\x00'),
- (0x344, ECU.DSU, (CAR.PRIUS, CAR.RAV4H, CAR.LEXUS_RXH, CAR.RAV4, CAR.COROLLA, CAR.HIGHLANDER, CAR.HIGHLANDERH, CAR.AVALON), 0, 5, '\x00\x00\x01\x00\x00\x00\x00\x50'),
+ (0x344, ECU.DSU, (CAR.PRIUS, CAR.RAV4H, CAR.LEXUS_RXH, CAR.RAV4, CAR.COROLLA, CAR.HIGHLANDER, CAR.HIGHLANDERH, CAR.AVALON, CAR.SIENNA), 0, 5, '\x00\x00\x01\x00\x00\x00\x00\x50'),
(0x365, ECU.DSU, (CAR.PRIUS, CAR.LEXUS_RXH, CAR.HIGHLANDERH), 0, 20, '\x00\x00\x00\x80\x03\x00\x08'),
- (0x365, ECU.DSU, (CAR.RAV4, CAR.RAV4H, CAR.COROLLA, CAR.HIGHLANDER, CAR.AVALON), 0, 20, '\x00\x00\x00\x80\xfc\x00\x08'),
+ (0x365, ECU.DSU, (CAR.RAV4, CAR.RAV4H, CAR.COROLLA, CAR.HIGHLANDER, CAR.AVALON, CAR.SIENNA), 0, 20, '\x00\x00\x00\x80\xfc\x00\x08'),
(0x366, ECU.DSU, (CAR.PRIUS, CAR.RAV4H, CAR.LEXUS_RXH, CAR.HIGHLANDERH), 0, 20, '\x00\x00\x4d\x82\x40\x02\x00'),
- (0x366, ECU.DSU, (CAR.RAV4, CAR.COROLLA, CAR.HIGHLANDER, CAR.AVALON), 0, 20, '\x00\x72\x07\xff\x09\xfe\x00'),
+ (0x366, ECU.DSU, (CAR.RAV4, CAR.COROLLA, CAR.HIGHLANDER, CAR.AVALON, CAR.SIENNA), 0, 20, '\x00\x72\x07\xff\x09\xfe\x00'),
(0x470, ECU.DSU, (CAR.PRIUS, CAR.LEXUS_RXH), 1, 100, '\x00\x00\x02\x7a'),
- (0x470, ECU.DSU, (CAR.HIGHLANDER, CAR.HIGHLANDERH, CAR.RAV4H), 1, 100, '\x00\x00\x01\x79'),
- (0x4CB, ECU.DSU, (CAR.PRIUS, CAR.RAV4H, CAR.LEXUS_RXH, CAR.RAV4, CAR.COROLLA, CAR.HIGHLANDERH, CAR.HIGHLANDER, CAR.AVALON), 0, 100, '\x0c\x00\x00\x00\x00\x00\x00\x00'),
+ (0x470, ECU.DSU, (CAR.HIGHLANDER, CAR.HIGHLANDERH, CAR.RAV4H, CAR.SIENNA), 1, 100, '\x00\x00\x01\x79'),
+ (0x4CB, ECU.DSU, (CAR.PRIUS, CAR.RAV4H, CAR.LEXUS_RXH, CAR.RAV4, CAR.COROLLA, CAR.HIGHLANDERH, CAR.HIGHLANDER, CAR.AVALON, CAR.SIENNA), 0, 100, '\x0c\x00\x00\x00\x00\x00\x00\x00'),
(0x292, ECU.APGS, (CAR.PRIUS), 0, 3, '\x00\x00\x00\x00\x00\x00\x00\x9e'),
(0x32E, ECU.APGS, (CAR.PRIUS), 0, 20, '\x00\x00\x00\x00\x00\x00\x00\x00'),
@@ -178,6 +179,9 @@ def check_ecu_msgs(fingerprint, ecu):
{
36: 8, 37: 8, 166: 8, 170: 8, 180: 8, 295: 8, 296: 8, 401: 8, 426: 6, 452: 8, 466: 8, 467: 8, 550: 8, 552: 4, 560: 7, 562: 6, 581: 5, 608: 8, 610: 8, 643: 7, 658: 8, 713: 8, 728: 8, 740: 5, 742: 8, 743: 8, 744: 8, 761: 8, 764: 8, 765: 8, 800: 8, 810: 2, 812: 8, 814: 8, 818: 8, 824: 8, 829: 2, 830: 7, 835: 8, 836: 8, 863: 8, 865: 8, 869: 7, 870: 7, 871: 2, 877: 8, 881: 8, 882: 8, 885: 8, 889: 8, 896: 8, 898: 8, 900: 6, 902: 6, 905: 8, 913: 8, 918: 8, 921: 8, 933: 8, 934: 8, 935: 8, 944: 8, 945: 8, 950: 8, 951: 8, 953: 8, 955: 8, 956: 8, 971: 7, 975: 5, 987: 8, 993: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1002: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1056: 8, 1057: 8, 1059: 1, 1071: 8, 1076: 8, 1077: 8, 1082: 8, 1084: 8, 1085: 8, 1086: 8, 1114: 8, 1132: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1172: 8, 1228: 8, 1235: 8, 1264: 8, 1279: 8, 1541: 8, 1552: 8, 1553: 8, 1556: 8, 1557: 8, 1568: 8, 1570: 8, 1571: 8, 1572: 8, 1575: 8, 1592: 8, 1594: 8, 1595: 8, 1649: 8, 1696: 8, 1775: 8, 1777: 8, 1779: 8, 1786: 8, 1787: 8, 1788: 8, 1789: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8
}],
+ CAR.SIENNA: [{
+ 36: 8, 37: 8, 114: 5, 119: 6, 120: 4, 170: 8, 180: 8, 186: 4, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 544: 4, 545: 5, 548: 8, 550: 8, 552: 4, 562: 4, 608: 8, 610: 5, 643: 7, 705: 8, 725: 2, 740: 5, 764: 8, 800: 8, 824: 8, 835: 8, 836: 8, 849: 4, 869: 7, 870: 7, 871: 2, 888: 8, 896: 8, 900: 6, 902: 6, 905: 8, 911: 8, 916: 1, 918: 7, 921: 8, 933: 8, 944: 6, 945: 8, 951: 8, 955: 8, 956: 8, 979: 2, 992: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1002: 8, 1008: 2, 1014: 8, 1017: 8, 1041: 8, 1042: 8, 1043: 8, 1056: 8, 1059: 1, 1076: 8, 1077: 8, 1114: 8, 1160: 8, 1161: 8, 1162: 8, 1163: 8, 1164: 8, 1165: 8, 1166: 8, 1167: 8, 1176: 8, 1177: 8, 1178: 8, 1179: 8, 1180: 8, 1181: 8, 1182: 8, 1183: 8, 1191: 8, 1192: 8, 1196: 8, 1197: 8, 1198: 8, 1199: 8, 1200: 8, 1201: 8, 1202: 8, 1203: 8, 1212: 8, 1227: 8, 1228: 8, 1235: 8, 1237: 8, 1279: 8, 1552: 8, 1553: 8, 1555: 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, 1593: 8, 1595: 8, 1656: 8, 1664: 8, 1666: 8, 1667: 8, 1728: 8, 1745: 8, 1779: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8
+ }],
}
STEER_THRESHOLD = 100
@@ -198,8 +202,9 @@ def check_ecu_msgs(fingerprint, ecu):
CAR.RAV4_TSS2: dbc_dict('toyota_nodsu_pt_generated', 'toyota_tss2_adas'),
CAR.COROLLA_TSS2: dbc_dict('toyota_nodsu_pt_generated', 'toyota_tss2_adas'),
CAR.LEXUS_ESH_TSS2: dbc_dict('toyota_nodsu_pt_generated', 'toyota_tss2_adas'),
+ CAR.SIENNA: dbc_dict('toyota_sienna_xle_2018_pt_generated', 'toyota_adas'),
}
NO_DSU_CAR = [CAR.CHR, CAR.CHRH, CAR.CAMRY, CAR.CAMRYH, CAR.RAV4_TSS2, CAR.COROLLA_TSS2, CAR.LEXUS_ESH_TSS2]
TSS2_CAR = [CAR.RAV4_TSS2, CAR.COROLLA_TSS2, CAR.LEXUS_ESH_TSS2]
-NO_STOP_TIMER_CAR = [CAR.RAV4H, CAR.HIGHLANDERH, CAR.HIGHLANDER, CAR.RAV4_TSS2, CAR.COROLLA_TSS2, CAR.LEXUS_ESH_TSS2] # no resume button press required
+NO_STOP_TIMER_CAR = [CAR.RAV4H, CAR.HIGHLANDERH, CAR.HIGHLANDER, CAR.RAV4_TSS2, CAR.COROLLA_TSS2, CAR.LEXUS_ESH_TSS2, CAR.SIENNA] # no resume button press required
diff --git a/selfdrive/common/version.h b/selfdrive/common/version.h
index ad486deed50efd..5c21a9db872ca1 100644
--- a/selfdrive/common/version.h
+++ b/selfdrive/common/version.h
@@ -1 +1 @@
-#define COMMA_VERSION "0.6-release"
+#define COMMA_VERSION "0.6.1-release"
diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py
index f1c556ba12e2e0..5c5ba2f66183ba 100755
--- a/selfdrive/controls/controlsd.py
+++ b/selfdrive/controls/controlsd.py
@@ -22,7 +22,7 @@
from selfdrive.controls.lib.latcontrol_indi import LatControlINDI
from selfdrive.controls.lib.alertmanager import AlertManager
from selfdrive.controls.lib.vehicle_model import VehicleModel
-from selfdrive.controls.lib.driver_monitor import DriverStatus
+from selfdrive.controls.lib.driver_monitor import DriverStatus, MAX_TERMINAL_ALERTS
from selfdrive.controls.lib.planner import LON_MPC_STEP
from selfdrive.locationd.calibration_helpers import Calibration, Filter
@@ -49,16 +49,22 @@ def events_to_bytes(events):
return ret
-def data_sample(CI, CC, sm, cal_status, cal_perc, overtemp, free_space, low_battery,
+def data_sample(CI, CC, sm, can_sock, cal_status, cal_perc, overtemp, free_space, low_battery,
driver_status, state, mismatch_counter, params):
"""Receive data from sockets and create events for battery, temperature and disk space"""
# Update carstate from CAN and create events
- CS = CI.update(CC)
+ can_strs = messaging.drain_sock_raw(can_sock, wait_for_one=True)
+ CS = CI.update(CC, can_strs)
+
+ sm.update(0)
+
events = list(CS.events)
enabled = isEnabled(state)
- sm.update(0)
+ # Check for CAN timeout
+ if not can_strs:
+ events.append(create_event('canError', [ET.NO_ENTRY, ET.IMMEDIATE_DISABLE]))
if sm.updated['thermal']:
overtemp = sm['thermal'].thermalStatus >= ThermalStatus.red
@@ -73,6 +79,7 @@ def data_sample(CI, CC, sm, cal_status, cal_perc, overtemp, free_space, low_batt
if free_space:
events.append(create_event('outOfSpace', [ET.NO_ENTRY]))
+
# Handle calibration
if sm.updated['liveCalibration']:
cal_status = sm['liveCalibration'].calStatus
@@ -102,6 +109,9 @@ def data_sample(CI, CC, sm, cal_status, cal_perc, overtemp, free_space, low_batt
if sm.updated['driverMonitoring']:
driver_status.get_pose(sm['driverMonitoring'], params)
+ if driver_status.terminal_alert_cnt >= MAX_TERMINAL_ALERTS:
+ events.append(create_event("tooDistracted", [ET.NO_ENTRY]))
+
return CS, events, cal_status, cal_perc, overtemp, free_space, low_battery, mismatch_counter
@@ -402,6 +412,7 @@ def controlsd_thread(gctx=None):
params = Params()
+
# Pub Sockets
sendcan = messaging.pub_sock(service_list['sendcan'].port)
controlsstate = messaging.pub_sock(service_list['controlsState'].port)
@@ -414,10 +425,15 @@ def controlsd_thread(gctx=None):
passive = params.get("Passive") != "0"
sm = messaging.SubMaster(['thermal', 'health', 'liveCalibration', 'driverMonitoring', 'plan', 'pathPlan'])
+
logcan = messaging.sub_sock(service_list['can'].port)
+ CI, CP = get_car(logcan, sendcan)
+ logcan.close()
+
+ # TODO: Use the logcan socket from above, but that will currenly break the tests
+ can_sock = messaging.sub_sock(service_list['can'].port, timeout=100)
CC = car.CarControl.new_message()
- CI, CP = get_car(logcan, sendcan)
AM = AlertManager()
car_recognized = CP.carName != 'mock'
@@ -469,7 +485,7 @@ def controlsd_thread(gctx=None):
# Sample data and compute car events
CS, events, cal_status, cal_perc, overtemp, free_space, low_battery, mismatch_counter =\
- data_sample(CI, CC, sm, cal_status, cal_perc, overtemp, free_space, low_battery,
+ data_sample(CI, CC, sm, can_sock, cal_status, cal_perc, overtemp, free_space, low_battery,
driver_status, state, mismatch_counter, params)
prof.checkpoint("Sample")
diff --git a/selfdrive/controls/lib/alerts.py b/selfdrive/controls/lib/alerts.py
index da7e88acbd46dd..0b0d5b1d5475b7 100644
--- a/selfdrive/controls/lib/alerts.py
+++ b/selfdrive/controls/lib/alerts.py
@@ -298,6 +298,13 @@ def __gt__(self, alert2):
AlertStatus.normal, AlertSize.mid,
Priority.LOW, VisualAlert.none, AudibleAlert.chimeError, .4, 2., 3.),
+ Alert(
+ "tooDistractedNoEntry",
+ "openpilot Unavailable",
+ "Distraction Level Too High",
+ AlertStatus.normal, AlertSize.mid,
+ Priority.LOW, VisualAlert.none, AudibleAlert.chimeError, .4, 2., 3.),
+
# Cancellation alerts causing soft disabling
Alert(
"overheat",
diff --git a/selfdrive/controls/lib/driver_monitor.py b/selfdrive/controls/lib/driver_monitor.py
index e813d0b176c81e..d38a115f974190 100644
--- a/selfdrive/controls/lib/driver_monitor.py
+++ b/selfdrive/controls/lib/driver_monitor.py
@@ -14,11 +14,12 @@
_METRIC_THRESHOLD = 0.4
_PITCH_POS_ALLOWANCE = 0.08 # rad, to not be too sensitive on positive pitch
_PITCH_NATURAL_OFFSET = 0.1 # people don't seem to look straight when they drive relaxed, rather a bit up
-_YAW_NATURAL_OFFSET = 0.08 # people don't seem to look straight when they drive relaxed, rather a bit to the right (center of car)
+_YAW_NATURAL_OFFSET = 0.08 # people don't seem to look straight when they drive relaxed, rather a bit to the right (center of car)
_STD_THRESHOLD = 0.1 # above this standard deviation consider the measurement invalid
_DISTRACTED_FILTER_TS = 0.25 # 0.6Hz
_VARIANCE_FILTER_TS = 20. # 0.008Hz
+MAX_TERMINAL_ALERTS = 3 # not allowed to engage after 3 terminal alerts
RESIZED_FOCAL = 320.0
H, W, FULL_W = 320, 160, 426
@@ -68,6 +69,7 @@ def __init__(self, monitor_on=False):
self.variance_filter = FirstOrderFilter(0., _VARIANCE_FILTER_TS, DT_DMON)
self.ts_last_check = 0.
self.face_detected = False
+ self.terminal_alert_cnt = 0
self._set_timers()
def _reset_filters(self):
@@ -133,6 +135,7 @@ def get_pose(self, driver_monitoring, params):
def update(self, events, driver_engaged, ctrl_active, standstill):
driver_engaged |= (self.driver_distraction_filter.x < 0.37 and self.monitor_on)
+ awareness_prev = self.awareness
if (driver_engaged and self.awareness > 0.) or not ctrl_active:
# always reset if driver is in control (unless we are in red alert state) or op isn't active
@@ -144,15 +147,18 @@ def update(self, events, driver_engaged, ctrl_active, standstill):
self.awareness = max(self.awareness - self.step_change, -0.1)
alert = None
- if self.awareness <= 0.:
+ if self.awareness < 0.:
# terminal red alert: disengagement required
alert = 'driverDistracted' if self.monitor_on else 'driverUnresponsive'
+ if awareness_prev >= 0.:
+ self.terminal_alert_cnt += 1
elif self.awareness <= self.threshold_prompt:
# prompt orange alert
alert = 'promptDriverDistracted' if self.monitor_on else 'promptDriverUnresponsive'
elif self.awareness <= self.threshold_pre:
# pre green alert
alert = 'preDriverDistracted' if self.monitor_on else 'preDriverUnresponsive'
+
if alert is not None:
events.append(create_event(alert, [ET.WARNING]))
diff --git a/selfdrive/controls/lib/fcw.py b/selfdrive/controls/lib/fcw.py
index f93a72cfcce321..8180fadebae42d 100644
--- a/selfdrive/controls/lib/fcw.py
+++ b/selfdrive/controls/lib/fcw.py
@@ -43,8 +43,10 @@ def calc_ttc(v_ego, a_ego, x_lead, v_lead, a_lead):
ttc = np.minimum(2 * x_lead / (np.sqrt(delta) + v_rel), max_ttc)
return ttc
- def update(self, mpc_solution, cur_time, v_ego, a_ego, x_lead, v_lead, a_lead, y_lead, vlat_lead, fcw_lead, blinkers):
+ def update(self, mpc_solution, cur_time, active, v_ego, a_ego, x_lead, v_lead, a_lead, y_lead, vlat_lead, fcw_lead, blinkers):
mpc_solution_a = list(mpc_solution[0].a_ego)
+ a_target = mpc_solution_a[1]
+
self.last_min_a = min(mpc_solution_a)
self.v_lead_max = max(self.v_lead_max, v_lead)
@@ -62,8 +64,11 @@ def update(self, mpc_solution, cur_time, v_ego, a_ego, x_lead, v_lead, a_lead, y
a_thr = interp(v_lead, _FCW_A_ACT_BP, _FCW_A_ACT_V)
a_delta = min(mpc_solution_a[:15]) - min(0.0, a_ego)
- fcw_allowed = all(c >= 10 for c in self.counters.values())
- if (self.last_min_a < -3.0 or a_delta < a_thr) and fcw_allowed and self.last_fcw_time + 5.0 < cur_time:
+ future_fcw_allowed = all(c >= 10 for c in self.counters.values())
+ future_fcw = (self.last_min_a < -3.0 or a_delta < a_thr) and future_fcw_allowed
+ current_fcw = a_target < -3.0 and active
+
+ if (future_fcw or current_fcw) and (self.last_fcw_time + 5.0 < cur_time):
self.last_fcw_time = cur_time
self.last_fcw_a = self.last_min_a
return True
diff --git a/selfdrive/controls/lib/planner.py b/selfdrive/controls/lib/planner.py
index 9aaec513bee969..94cc2fc1358cad 100755
--- a/selfdrive/controls/lib/planner.py
+++ b/selfdrive/controls/lib/planner.py
@@ -201,7 +201,9 @@ def update(self, sm, CP, VM, PP, live_map_data):
self.fcw_checker.reset_lead(cur_time)
blinkers = sm['carState'].leftBlinker or sm['carState'].rightBlinker
- fcw = self.fcw_checker.update(self.mpc1.mpc_solution, cur_time, v_ego, sm['carState'].aEgo,
+ fcw = self.fcw_checker.update(self.mpc1.mpc_solution, cur_time,
+ sm['controlsState'].active,
+ v_ego, sm['carState'].aEgo,
lead_1.dRel, lead_1.vLead, lead_1.aLeadK,
lead_1.yRel, lead_1.vLat,
lead_1.fcw, blinkers) and not sm['carState'].brakePressed
diff --git a/selfdrive/controls/radard.py b/selfdrive/controls/radard.py
index b37ed8f75519b5..afb4ffd2bc6f13 100755
--- a/selfdrive/controls/radard.py
+++ b/selfdrive/controls/radard.py
@@ -26,6 +26,11 @@
XV, SPEEDV = 0, 1
VISION_POINT = -1
+path_x = np.arange(0.0, 140.0, 0.1) # 140 meters is max
+
+# Time-alignment
+rate = 1. / DT_MDL # model and radar are both at 20Hz
+v_len = 20 # how many speed data points to remember for t alignment with rdr data
class EKFV1D(EKF):
def __init__(self):
@@ -43,171 +48,133 @@ def calc_transfer_fun(self, dt):
tfj = tf
return tf, tfj
+class RadarD(object):
+ def __init__(self, VM, mocked):
+ self.VM = VM
+ self.mocked = mocked
-## fuses camera and radar data for best lead detection
-def radard_thread(gctx=None):
- set_realtime_priority(2)
+ self.MP = ModelParser()
+ self.tracks = defaultdict(dict)
- # wait for stats about the car to come in from controls
- cloudlog.info("radard is waiting for CarParams")
- CP = car.CarParams.from_bytes(Params().get("CarParams", block=True))
- mocked = CP.carName == "mock"
- VM = VehicleModel(CP)
- cloudlog.info("radard got CarParams")
-
- # import the radar from the fingerprint
- cloudlog.info("radard is importing %s", CP.carName)
- RadarInterface = importlib.import_module('selfdrive.car.%s.radar_interface' % CP.carName).RadarInterface
-
- sm = messaging.SubMaster(['model', 'controlsState', 'liveParameters'])
+ self.last_md_ts = 0
+ self.last_controls_state_ts = 0
- # Default parameters
- live_parameters = messaging.new_message()
- live_parameters.init('liveParameters')
- live_parameters.liveParameters.valid = True
- live_parameters.liveParameters.steerRatio = CP.steerRatio
- live_parameters.liveParameters.stiffnessFactor = 1.0
+ self.active = 0
+ self.steer_angle = 0.
+ self.steer_override = False
- MP = ModelParser()
- RI = RadarInterface(CP)
+ # Kalman filter stuff:
+ self.ekfv = EKFV1D()
+ self.speedSensorV = SimpleSensor(XV, 1, 2)
- last_md_ts = 0
- last_controls_state_ts = 0
-
- # *** publish radarState and liveTracks
- radarState = messaging.pub_sock(service_list['radarState'].port)
- liveTracks = messaging.pub_sock(service_list['liveTracks'].port)
-
- path_x = np.arange(0.0, 140.0, 0.1) # 140 meters is max
-
- # Time-alignment
- rate = 1. / DT_MDL # model and radar are both at 20Hz
- v_len = 20 # how many speed data points to remember for t alignment with rdr data
-
- active = 0
- steer_angle = 0.
- steer_override = False
-
- tracks = defaultdict(dict)
-
- # Kalman filter stuff:
- ekfv = EKFV1D()
- speedSensorV = SimpleSensor(XV, 1, 2)
-
- # v_ego
- v_ego = 0.
- v_ego_hist_t = deque([0], maxlen=v_len)
- v_ego_hist_v = deque([0], maxlen=v_len)
- v_ego_t_aligned = 0.
-
- rk = Ratekeeper(rate, print_delay_threshold=None)
- while 1:
- rr = RI.update()
+ # v_ego
+ self.v_ego = 0.
+ self.v_ego_hist_t = deque([0], maxlen=v_len)
+ self.v_ego_hist_v = deque([0], maxlen=v_len)
+ self.v_ego_t_aligned = 0.
+ def update(self, frame, delay, sm, rr):
ar_pts = {}
for pt in rr.points:
ar_pts[pt.trackId] = [pt.dRel + RDR_TO_LDR, pt.yRel, pt.vRel, pt.measured]
- sm.update(0)
-
if sm.updated['liveParameters']:
- VM.update_params(sm['liveParameters'].stiffnessFactor, sm['liveParameters'].steerRatio)
+ self.VM.update_params(sm['liveParameters'].stiffnessFactor, sm['liveParameters'].steerRatio)
if sm.updated['controlsState']:
- active = sm['controlsState'].active
- v_ego = sm['controlsState'].vEgo
- steer_angle = sm['controlsState'].angleSteers
- steer_override = sm['controlsState'].steerOverride
+ self.active = sm['controlsState'].active
+ self.v_ego = sm['controlsState'].vEgo
+ self.steer_angle = sm['controlsState'].angleSteers
+ self.steer_override = sm['controlsState'].steerOverride
- v_ego_hist_v.append(v_ego)
- v_ego_hist_t.append(float(rk.frame)/rate)
+ self.v_ego_hist_v.append(self.v_ego)
+ self.v_ego_hist_t.append(float(frame)/rate)
- last_controls_state_ts = sm.logMonoTime['controlsState']
+ self.last_controls_state_ts = sm.logMonoTime['controlsState']
if sm.updated['model']:
- last_md_ts = sm.logMonoTime['model']
- MP.update(v_ego, sm['model'])
-
+ self.last_md_ts = sm.logMonoTime['model']
+ self.MP.update(self.v_ego, sm['model'])
# run kalman filter only if prob is high enough
- if MP.lead_prob > 0.7:
- reading = speedSensorV.read(MP.lead_dist, covar=np.matrix(MP.lead_var))
- ekfv.update_scalar(reading)
- ekfv.predict(DT_MDL)
+ if self.MP.lead_prob > 0.7:
+ reading = self.speedSensorV.read(self.MP.lead_dist, covar=np.matrix(self.MP.lead_var))
+ self.ekfv.update_scalar(reading)
+ self.ekfv.predict(DT_MDL)
# When changing lanes the distance to the lead car can suddenly change,
# which makes the Kalman filter output large relative acceleration
- if mocked and abs(MP.lead_dist - ekfv.state[XV]) > 2.0:
- ekfv.state[XV] = MP.lead_dist
- ekfv.covar = (np.diag([MP.lead_var, ekfv.var_init]))
- ekfv.state[SPEEDV] = 0.
+ if self.mocked and abs(self.MP.lead_dist - self.ekfv.state[XV]) > 2.0:
+ self.ekfv.state[XV] = self.MP.lead_dist
+ self.ekfv.covar = (np.diag([self.MP.lead_var, self.ekfv.var_init]))
+ self.ekfv.state[SPEEDV] = 0.
- ar_pts[VISION_POINT] = (float(ekfv.state[XV]), np.polyval(MP.d_poly, float(ekfv.state[XV])),
- float(ekfv.state[SPEEDV]), False)
+ ar_pts[VISION_POINT] = (float(self.ekfv.state[XV]), np.polyval(self.MP.d_poly, float(self.ekfv.state[XV])),
+ float(self.ekfv.state[SPEEDV]), False)
else:
- ekfv.state[XV] = MP.lead_dist
- ekfv.covar = (np.diag([MP.lead_var, ekfv.var_init]))
- ekfv.state[SPEEDV] = 0.
+ self.ekfv.state[XV] = self.MP.lead_dist
+ self.ekfv.covar = (np.diag([self.MP.lead_var, self.ekfv.var_init]))
+ self.ekfv.state[SPEEDV] = 0.
if VISION_POINT in ar_pts:
del ar_pts[VISION_POINT]
# *** compute the likely path_y ***
- if (active and not steer_override) or mocked:
+ if (self.active and not self.steer_override) or self.mocked:
# use path from model (always when mocking as steering is too noisy)
- path_y = np.polyval(MP.d_poly, path_x)
+ path_y = np.polyval(self.MP.d_poly, path_x)
else:
# use path from steer, set angle_offset to 0 it does not only report the physical offset
- path_y = calc_lookahead_offset(v_ego, steer_angle, path_x, VM, angle_offset=live_parameters.liveParameters.angleOffsetAverage)[0]
+ path_y = calc_lookahead_offset(self.v_ego, self.steer_angle, path_x, self.VM, angle_offset=sm['liveParameters'].angleOffsetAverage)[0]
# *** remove missing points from meta data ***
- for ids in tracks.keys():
+ for ids in self.tracks.keys():
if ids not in ar_pts:
- tracks.pop(ids, None)
+ self.tracks.pop(ids, None)
# *** compute the tracks ***
for ids in ar_pts:
# ignore standalone vision point, unless we are mocking the radar
- if ids == VISION_POINT and not mocked:
+ if ids == VISION_POINT and not self.mocked:
continue
rpt = ar_pts[ids]
# align v_ego by a fixed time to align it with the radar measurement
- cur_time = float(rk.frame)/rate
- v_ego_t_aligned = np.interp(cur_time - RI.delay, v_ego_hist_t, v_ego_hist_v)
+ cur_time = float(frame)/rate
+ self.v_ego_t_aligned = np.interp(cur_time - delay, self.v_ego_hist_t, self.v_ego_hist_v)
d_path = np.sqrt(np.amin((path_x - rpt[0]) ** 2 + (path_y - rpt[1]) ** 2))
# add sign
d_path *= np.sign(rpt[1] - np.interp(rpt[0], path_x, path_y))
# create the track if it doesn't exist or it's a new track
- if ids not in tracks:
- tracks[ids] = Track()
- tracks[ids].update(rpt[0], rpt[1], rpt[2], d_path, v_ego_t_aligned, rpt[3], steer_override)
+ if ids not in self.tracks:
+ self.tracks[ids] = Track()
+ self.tracks[ids].update(rpt[0], rpt[1], rpt[2], d_path, self.v_ego_t_aligned, rpt[3], self.steer_override)
# allow the vision model to remove the stationary flag if distance and rel speed roughly match
if VISION_POINT in ar_pts:
fused_id = None
best_score = NO_FUSION_SCORE
- for ids in tracks:
- dist_to_vision = np.sqrt((0.5*(ar_pts[VISION_POINT][0] - tracks[ids].dRel)) ** 2 + (2*(ar_pts[VISION_POINT][1] - tracks[ids].yRel)) ** 2)
- rel_speed_diff = abs(ar_pts[VISION_POINT][2] - tracks[ids].vRel)
- tracks[ids].update_vision_score(dist_to_vision, rel_speed_diff)
- if best_score > tracks[ids].vision_score:
+ for ids in self.tracks:
+ dist_to_vision = np.sqrt((0.5*(ar_pts[VISION_POINT][0] - self.tracks[ids].dRel)) ** 2 + (2*(ar_pts[VISION_POINT][1] - self.tracks[ids].yRel)) ** 2)
+ rel_speed_diff = abs(ar_pts[VISION_POINT][2] - self.tracks[ids].vRel)
+ self.tracks[ids].update_vision_score(dist_to_vision, rel_speed_diff)
+ if best_score > self.tracks[ids].vision_score:
fused_id = ids
- best_score = tracks[ids].vision_score
+ best_score = self.tracks[ids].vision_score
if fused_id is not None:
- tracks[fused_id].vision_cnt += 1
- tracks[fused_id].update_vision_fusion()
+ self.tracks[fused_id].vision_cnt += 1
+ self.tracks[fused_id].update_vision_fusion()
if DEBUG:
print("NEW CYCLE")
if VISION_POINT in ar_pts:
print("vision", ar_pts[VISION_POINT])
- idens = list(tracks.keys())
- track_pts = np.array([tracks[iden].get_key_for_cluster() for iden in idens])
+ idens = list(self.tracks.keys())
+ track_pts = np.array([self.tracks[iden].get_key_for_cluster() for iden in idens])
# If we have multiple points, cluster them
if len(track_pts) > 1:
@@ -218,12 +185,12 @@ def radard_thread(gctx=None):
cluster_i = cluster_idxs[idx]
if clusters[cluster_i] is None:
clusters[cluster_i] = Cluster()
- clusters[cluster_i].add(tracks[idens[idx]])
+ clusters[cluster_i].add(self.tracks[idens[idx]])
elif len(track_pts) == 1:
# TODO: why do we need this?
clusters = [Cluster()]
- clusters[0].add(tracks[idens[0]])
+ clusters[0].add(self.tracks[idens[0]])
else:
clusters = []
@@ -232,7 +199,7 @@ def radard_thread(gctx=None):
print(i)
# *** extract the lead car ***
lead_clusters = [c for c in clusters
- if c.is_potential_lead(v_ego)]
+ if c.is_potential_lead(self.v_ego)]
lead_clusters.sort(key=lambda x: x.dRel)
lead_len = len(lead_clusters)
@@ -246,10 +213,10 @@ def radard_thread(gctx=None):
dat = messaging.new_message()
dat.init('radarState')
dat.valid = sm.all_alive_and_valid(service_list=['controlsState'])
- dat.radarState.mdMonoTime = last_md_ts
+ dat.radarState.mdMonoTime = self.last_md_ts
dat.radarState.canMonoTimes = list(rr.canMonoTimes)
dat.radarState.radarErrors = list(rr.errors)
- dat.radarState.controlsStateMonoTime = last_controls_state_ts
+ dat.radarState.controlsStateMonoTime = self.last_controls_state_ts
if lead_len > 0:
dat.radarState.leadOne = lead_clusters[0].toRadarState()
if lead2_len > 0:
@@ -259,10 +226,51 @@ def radard_thread(gctx=None):
else:
dat.radarState.leadOne.status = False
+ return dat
+
+## fuses camera and radar data for best lead detection
+def radard_thread(gctx=None):
+ set_realtime_priority(2)
+
+ # wait for stats about the car to come in from controls
+ cloudlog.info("radard is waiting for CarParams")
+ CP = car.CarParams.from_bytes(Params().get("CarParams", block=True))
+ mocked = CP.carName == "mock"
+ VM = VehicleModel(CP)
+ cloudlog.info("radard got CarParams")
+
+ # import the radar from the fingerprint
+ cloudlog.info("radard is importing %s", CP.carName)
+ RadarInterface = importlib.import_module('selfdrive.car.%s.radar_interface' % CP.carName).RadarInterface
+
+ can_sock = messaging.sub_sock(service_list['can'].port)
+ sm = messaging.SubMaster(['model', 'controlsState', 'liveParameters'])
+
+ RI = RadarInterface(CP)
+
+ # *** publish radarState and liveTracks
+ radarState = messaging.pub_sock(service_list['radarState'].port)
+ liveTracks = messaging.pub_sock(service_list['liveTracks'].port)
+
+ rk = Ratekeeper(rate, print_delay_threshold=None)
+ RD = RadarD(VM, mocked)
+
+ while 1:
+ can_strings = messaging.drain_sock_raw(can_sock, wait_for_one=True)
+ rr = RI.update(can_strings)
+
+ if rr is None:
+ continue
+
+ sm.update(0)
+
+ dat = RD.update(rk.frame, RI.delay, sm, rr)
dat.radarState.cumLagMs = -rk.remaining*1000.
+
radarState.send(dat.to_bytes())
# *** publish tracks for UI debugging (keep last) ***
+ tracks = RD.tracks
dat = messaging.new_message()
dat.init('liveTracks', len(tracks))
diff --git a/selfdrive/locationd/.gitignore b/selfdrive/locationd/.gitignore
index 8cdb0d23050783..6ea757462e62f8 100644
--- a/selfdrive/locationd/.gitignore
+++ b/selfdrive/locationd/.gitignore
@@ -1,3 +1,4 @@
ubloxd
ubloxd_test
-params_learner
\ No newline at end of file
+params_learner
+paramsd
\ No newline at end of file
diff --git a/selfdrive/locationd/Makefile b/selfdrive/locationd/Makefile
index f7652648e1bbe1..ff46847689c805 100644
--- a/selfdrive/locationd/Makefile
+++ b/selfdrive/locationd/Makefile
@@ -40,11 +40,11 @@ EXTRA_LIBS += -llog -luuid
endif
.PHONY: all
-all: ubloxd params_learner
+all: ubloxd paramsd
include ../common/cereal.mk
-LOC_OBJS = locationd_yawrate.o params_learner.o \
+LOC_OBJS = locationd_yawrate.o params_learner.o paramsd.o \
../common/swaglog.o \
../common/params.o \
../common/util.o \
@@ -71,7 +71,7 @@ liblocationd.so: $(LOC_OBJS)
$(ZMQ_SHARED_LIBS) \
$(EXTRA_LIBS)
-params_learner: $(LOC_OBJS)
+paramsd: $(LOC_OBJS)
@echo "[ LINK ] $@"
$(CXX) -fPIC -o '$@' $^ \
$(CEREAL_LIBS) \
@@ -115,7 +115,7 @@ ubloxd_test: ubloxd_test.o $(OBJS)
.PHONY: clean
clean:
- rm -f ubloxd params_learner liblocationd.so ubloxd.d ubloxd.o ubloxd_test ubloxd_test.o ubloxd_test.d $(OBJS) $(LOC_OBJS) $(DEPS)
+ rm -f ubloxd paramsd liblocationd.so ubloxd.d ubloxd.o ubloxd_test ubloxd_test.o ubloxd_test.d $(OBJS) $(LOC_OBJS) $(DEPS)
-include $(DEPS)
-include $(LOC_DEPS)
diff --git a/selfdrive/locationd/locationd_yawrate.cc b/selfdrive/locationd/locationd_yawrate.cc
index f03f808ffdb99d..ae4b05a71a1c67 100644
--- a/selfdrive/locationd/locationd_yawrate.cc
+++ b/selfdrive/locationd/locationd_yawrate.cc
@@ -1,287 +1,96 @@
#include
-#include
#include
-#include
#include
#include
#include
-#include "json11.hpp"
-#include "cereal/gen/cpp/log.capnp.h"
-#include "common/swaglog.h"
-#include "common/messaging.h"
-#include "common/params.h"
-#include "common/timing.h"
-#include "params_learner.h"
+#include "locationd_yawrate.h"
-const int num_polls = 3;
-
-class Localizer
-{
- Eigen::Matrix2d A;
- Eigen::Matrix2d I;
- Eigen::Matrix2d Q;
- Eigen::Matrix2d P;
- Eigen::Matrix C_posenet;
- Eigen::Matrix C_gyro;
-
- double R_gyro;
-
- void update_state(const Eigen::Matrix &C, const double R, double current_time, double meas) {
- double dt = current_time - prev_update_time;
- prev_update_time = current_time;
- if (dt < 1.0e-9) {
- return;
- }
-
- // x = A * x;
- // P = A * P * A.transpose() + dt * Q;
- // Simplify because A is unity
- P = P + dt * Q;
-
- double y = meas - C * x;
- double S = R + C * P * C.transpose();
- Eigen::Vector2d K = P * C.transpose() * (1.0 / S);
- x = x + K * y;
- P = (I - K * C) * P;
- }
-
- void handle_sensor_events(capnp::List::Reader sensor_events, double current_time) {
- for (cereal::SensorEventData::Reader sensor_event : sensor_events){
- if (sensor_event.getType() == 4) {
- sensor_data_time = current_time;
-
- double meas = -sensor_event.getGyro().getV()[0];
- update_state(C_gyro, R_gyro, current_time, meas);
- }
- }
+void Localizer::update_state(const Eigen::Matrix &C, const double R, double current_time, double meas) {
+ double dt = current_time - prev_update_time;
+ prev_update_time = current_time;
+ if (dt < 1.0e-9) {
+ return;
}
- void handle_camera_odometry(cereal::CameraOdometry::Reader camera_odometry, double current_time) {
- double R = 250.0 * pow(camera_odometry.getRotStd()[2], 2);
- double meas = camera_odometry.getRot()[2];
- update_state(C_posenet, R, current_time, meas);
- }
-
- void handle_controls_state(cereal::ControlsState::Reader controls_state, double current_time) {
- steering_angle = controls_state.getAngleSteers() * DEGREES_TO_RADIANS;
- car_speed = controls_state.getVEgo();
- controls_state_time = current_time;
- }
+ // x = A * x;
+ // P = A * P * A.transpose() + dt * Q;
+ // Simplify because A is unity
+ P = P + dt * Q;
+ double y = meas - C * x;
+ double S = R + C * P * C.transpose();
+ Eigen::Vector2d K = P * C.transpose() * (1.0 / S);
+ x = x + K * y;
+ P = (I - K * C) * P;
+}
-public:
- Eigen::Vector2d x;
- double steering_angle = 0;
- double car_speed = 0;
- double prev_update_time = -1;
- double controls_state_time = -1;
- double sensor_data_time = -1;
-
- Localizer() {
- A << 1, 0, 0, 1;
- I << 1, 0, 0, 1;
-
- Q << pow(0.1, 2.0), 0, 0, pow(0.005 / 100.0, 2.0);
- P << pow(1.0, 2.0), 0, 0, pow(0.05, 2.0);
-
- C_posenet << 1, 0;
- C_gyro << 1, 1;
- x << 0, 0;
-
- R_gyro = pow(0.05, 2.0);
- }
-
- cereal::Event::Which handle_log(const unsigned char* msg_dat, size_t msg_size) {
- const kj::ArrayPtr view((const capnp::word*)msg_dat, msg_size);
- capnp::FlatArrayMessageReader msg(view);
- cereal::Event::Reader event = msg.getRoot();
- double current_time = event.getLogMonoTime() / 1.0e9;
-
- if (prev_update_time < 0) {
- prev_update_time = current_time;
- }
+void Localizer::handle_sensor_events(capnp::List::Reader sensor_events, double current_time) {
+ for (cereal::SensorEventData::Reader sensor_event : sensor_events){
+ if (sensor_event.getType() == 4) {
+ sensor_data_time = current_time;
- auto type = event.which();
- switch(type) {
- case cereal::Event::CONTROLS_STATE:
- handle_controls_state(event.getControlsState(), current_time);
- break;
- case cereal::Event::CAMERA_ODOMETRY:
- handle_camera_odometry(event.getCameraOdometry(), current_time);
- break;
- case cereal::Event::SENSOR_EVENTS:
- handle_sensor_events(event.getSensorEvents(), current_time);
- break;
- default:
- break;
+ double meas = -sensor_event.getGyro().getV()[0];
+ update_state(C_gyro, R_gyro, current_time, meas);
}
-
- return type;
}
-};
-
-
-
-int main(int argc, char *argv[]) {
- auto ctx = zmq_ctx_new();
- auto controls_state_sock = sub_sock(ctx, "tcp://127.0.0.1:8007");
- auto sensor_events_sock = sub_sock(ctx, "tcp://127.0.0.1:8003");
- auto camera_odometry_sock = sub_sock(ctx, "tcp://127.0.0.1:8066");
-
- auto live_parameters_sock = zsock_new_pub("@tcp://*:8064");
- assert(live_parameters_sock);
- auto live_parameters_sock_raw = zsock_resolve(live_parameters_sock);
-
- int err;
- Localizer localizer;
-
- zmq_pollitem_t polls[num_polls] = {{0}};
- polls[0].socket = controls_state_sock;
- polls[0].events = ZMQ_POLLIN;
- polls[1].socket = sensor_events_sock;
- polls[1].events = ZMQ_POLLIN;
- polls[2].socket = camera_odometry_sock;
- polls[2].events = ZMQ_POLLIN;
-
- // Read car params
- char *value;
- size_t value_sz = 0;
+}
- LOGW("waiting for params to set vehicle model");
- while (true) {
- read_db_value(NULL, "CarParams", &value, &value_sz);
- if (value_sz > 0) break;
- usleep(100*1000);
- }
- LOGW("got %d bytes CarParams", value_sz);
+void Localizer::handle_camera_odometry(cereal::CameraOdometry::Reader camera_odometry, double current_time) {
+ double R = 250.0 * pow(camera_odometry.getRotStd()[2], 2);
+ double meas = camera_odometry.getRot()[2];
+ update_state(C_posenet, R, current_time, meas);
+}
- // make copy due to alignment issues
- auto amsg = kj::heapArray((value_sz / sizeof(capnp::word)) + 1);
- memcpy(amsg.begin(), value, value_sz);
- free(value);
+void Localizer::handle_controls_state(cereal::ControlsState::Reader controls_state, double current_time) {
+ steering_angle = controls_state.getAngleSteers() * DEGREES_TO_RADIANS;
+ car_speed = controls_state.getVEgo();
+ controls_state_time = current_time;
+}
- capnp::FlatArrayMessageReader cmsg(amsg);
- cereal::CarParams::Reader car_params = cmsg.getRoot();
- // Read params from previous run
- const int result = read_db_value(NULL, "LiveParameters", &value, &value_sz);
+Localizer::Localizer() {
+ A << 1, 0, 0, 1;
+ I << 1, 0, 0, 1;
- std::string fingerprint = car_params.getCarFingerprint();
- std::string vin = car_params.getCarVin();
- double sR = car_params.getSteerRatio();
- double x = 1.0;
- double ao = 0.0;
+ Q << pow(0.1, 2.0), 0, 0, pow(0.005 / 100.0, 2.0);
+ P << pow(1.0, 2.0), 0, 0, pow(0.05, 2.0);
- if (result == 0){
- auto str = std::string(value, value_sz);
- free(value);
+ C_posenet << 1, 0;
+ C_gyro << 1, 1;
+ x << 0, 0;
- std::string err;
- auto json = json11::Json::parse(str, err);
- if (json.is_null() || !err.empty()) {
- std::string log = "Error parsing json: " + err;
- LOGW(log.c_str());
- } else {
- std::string new_fingerprint = json["carFingerprint"].string_value();
- std::string new_vin = json["carVin"].string_value();
+ R_gyro = pow(0.05, 2.0);
+}
- if (fingerprint == new_fingerprint && vin == new_vin) {
- std::string log = "Parameter starting with: " + str;
- LOGW(log.c_str());
+cereal::Event::Which Localizer::handle_log(const unsigned char* msg_dat, size_t msg_size) {
+ const kj::ArrayPtr view((const capnp::word*)msg_dat, msg_size);
+ capnp::FlatArrayMessageReader msg(view);
+ cereal::Event::Reader event = msg.getRoot();
+ double current_time = event.getLogMonoTime() / 1.0e9;
- sR = json["steerRatio"].number_value();
- x = json["stiffnessFactor"].number_value();
- ao = json["angleOffsetAverage"].number_value();
- }
- }
+ if (prev_update_time < 0) {
+ prev_update_time = current_time;
}
- ParamsLearner learner(car_params, ao, x, sR, 1.0);
-
- // Main loop
- int save_counter = 0;
- while (true){
- int ret = zmq_poll(polls, num_polls, 100);
-
- if (ret == 0){
- continue;
- } else if (ret < 0){
- break;
- }
-
- for (int i=0; i < num_polls; i++) {
- if (polls[i].revents) {
- zmq_msg_t msg;
- err = zmq_msg_init(&msg);
- assert(err == 0);
- err = zmq_msg_recv(&msg, polls[i].socket, 0);
- assert(err >= 0);
- // make copy due to alignment issues, will be freed on out of scope
- auto amsg = kj::heapArray((zmq_msg_size(&msg) / sizeof(capnp::word)) + 1);
- memcpy(amsg.begin(), zmq_msg_data(&msg), zmq_msg_size(&msg));
-
- auto which = localizer.handle_log((const unsigned char*)amsg.begin(), amsg.size());
- zmq_msg_close(&msg);
-
- if (which == cereal::Event::CONTROLS_STATE){
- save_counter++;
-
- double yaw_rate = -localizer.x[0];
- bool valid = learner.update(yaw_rate, localizer.car_speed, localizer.steering_angle);
-
- // TODO: Fix in replay
- double sensor_data_age = localizer.controls_state_time - localizer.sensor_data_time;
-
- double angle_offset_degrees = RADIANS_TO_DEGREES * learner.ao;
- double angle_offset_average_degrees = RADIANS_TO_DEGREES * learner.slow_ao;
-
- // Send parameters at 10 Hz
- if (save_counter % 10 == 0){
- capnp::MallocMessageBuilder msg;
- cereal::Event::Builder event = msg.initRoot();
- event.setLogMonoTime(nanos_since_boot());
- auto live_params = event.initLiveParameters();
- live_params.setValid(valid);
- live_params.setYawRate(localizer.x[0]);
- live_params.setGyroBias(localizer.x[1]);
- live_params.setSensorValid(sensor_data_age < 5.0);
- live_params.setAngleOffset(angle_offset_degrees);
- live_params.setAngleOffsetAverage(angle_offset_average_degrees);
- live_params.setStiffnessFactor(learner.x);
- live_params.setSteerRatio(learner.sR);
-
- auto words = capnp::messageToFlatArray(msg);
- auto bytes = words.asBytes();
- zmq_send(live_parameters_sock_raw, bytes.begin(), bytes.size(), ZMQ_DONTWAIT);
- }
-
-
- // Save parameters every minute
- if (save_counter % 6000 == 0) {
- json11::Json json = json11::Json::object {
- {"carVin", vin},
- {"carFingerprint", fingerprint},
- {"steerRatio", learner.sR},
- {"stiffnessFactor", learner.x},
- {"angleOffsetAverage", angle_offset_average_degrees},
- };
-
- std::string out = json.dump();
- write_db_value(NULL, "LiveParameters", out.c_str(), out.length());
- }
- }
- }
- }
+ auto type = event.which();
+ switch(type) {
+ case cereal::Event::CONTROLS_STATE:
+ handle_controls_state(event.getControlsState(), current_time);
+ break;
+ case cereal::Event::CAMERA_ODOMETRY:
+ handle_camera_odometry(event.getCameraOdometry(), current_time);
+ break;
+ case cereal::Event::SENSOR_EVENTS:
+ handle_sensor_events(event.getSensorEvents(), current_time);
+ break;
+ default:
+ break;
}
- zmq_close(controls_state_sock);
- zmq_close(sensor_events_sock);
- zmq_close(camera_odometry_sock);
- zmq_close(live_parameters_sock_raw);
- return 0;
+ return type;
}
diff --git a/selfdrive/locationd/locationd_yawrate.h b/selfdrive/locationd/locationd_yawrate.h
new file mode 100644
index 00000000000000..323e87de4eab10
--- /dev/null
+++ b/selfdrive/locationd/locationd_yawrate.h
@@ -0,0 +1,34 @@
+#pragma once
+
+#include
+#include "cereal/gen/cpp/log.capnp.h"
+
+#define DEGREES_TO_RADIANS 0.017453292519943295
+
+class Localizer
+{
+ Eigen::Matrix2d A;
+ Eigen::Matrix2d I;
+ Eigen::Matrix2d Q;
+ Eigen::Matrix2d P;
+ Eigen::Matrix C_posenet;
+ Eigen::Matrix C_gyro;
+
+ double R_gyro;
+
+ void update_state(const Eigen::Matrix &C, const double R, double current_time, double meas);
+ void handle_sensor_events(capnp::List::Reader sensor_events, double current_time);
+ void handle_camera_odometry(cereal::CameraOdometry::Reader camera_odometry, double current_time);
+ void handle_controls_state(cereal::ControlsState::Reader controls_state, double current_time);
+
+public:
+ Eigen::Vector2d x;
+ double steering_angle = 0;
+ double car_speed = 0;
+ double prev_update_time = -1;
+ double controls_state_time = -1;
+ double sensor_data_time = -1;
+
+ Localizer();
+ cereal::Event::Which handle_log(const unsigned char* msg_dat, size_t msg_size);
+};
diff --git a/selfdrive/locationd/params_learner.cc b/selfdrive/locationd/params_learner.cc
index a150805d863f03..912abde35704b0 100644
--- a/selfdrive/locationd/params_learner.cc
+++ b/selfdrive/locationd/params_learner.cc
@@ -2,6 +2,8 @@
#include
#include
+#include
+#include
#include "cereal/gen/cpp/log.capnp.h"
#include "cereal/gen/cpp/car.capnp.h"
#include "params_learner.h"
@@ -14,14 +16,15 @@ T clip(const T& n, const T& lower, const T& upper) {
}
ParamsLearner::ParamsLearner(cereal::CarParams::Reader car_params,
- double angle_offset,
- double stiffness_factor,
- double steer_ratio,
- double learning_rate) :
- ao(angle_offset * DEGREES_TO_RADIANS),
- slow_ao(angle_offset * DEGREES_TO_RADIANS),
- x(stiffness_factor),
- sR(steer_ratio) {
+ double angle_offset,
+ double stiffness_factor,
+ double steer_ratio,
+ double learning_rate) :
+ ao(angle_offset * DEGREES_TO_RADIANS),
+ slow_ao(angle_offset * DEGREES_TO_RADIANS),
+ x(stiffness_factor),
+ sR(steer_ratio) {
+
cF0 = car_params.getTireStiffnessFront();
cR0 = car_params.getTireStiffnessRear();
@@ -73,3 +76,43 @@ bool ParamsLearner::update(double psi, double u, double sa) {
valid = valid && sR < max_sr_th;
return valid;
}
+
+
+extern "C" {
+ void *params_learner_init(size_t len, char * params, double angle_offset, double stiffness_factor, double steer_ratio, double learning_rate) {
+
+ auto amsg = kj::heapArray((len / sizeof(capnp::word)) + 1);
+ memcpy(amsg.begin(), params, len);
+
+ capnp::FlatArrayMessageReader cmsg(amsg);
+ cereal::CarParams::Reader car_params = cmsg.getRoot();
+
+ ParamsLearner * p = new ParamsLearner(car_params, angle_offset, stiffness_factor, steer_ratio, learning_rate);
+ return (void*)p;
+ }
+
+ bool params_learner_update(void * params_learner, double psi, double u, double sa) {
+ ParamsLearner * p = (ParamsLearner*) params_learner;
+ return p->update(psi, u, sa);
+ }
+
+ double params_learner_get_ao(void * params_learner){
+ ParamsLearner * p = (ParamsLearner*) params_learner;
+ return p->ao;
+ }
+
+ double params_learner_get_x(void * params_learner){
+ ParamsLearner * p = (ParamsLearner*) params_learner;
+ return p->x;
+ }
+
+ double params_learner_get_slow_ao(void * params_learner){
+ ParamsLearner * p = (ParamsLearner*) params_learner;
+ return p->slow_ao;
+ }
+
+ double params_learner_get_sR(void * params_learner){
+ ParamsLearner * p = (ParamsLearner*) params_learner;
+ return p->sR;
+ }
+}
diff --git a/selfdrive/locationd/paramsd.cc b/selfdrive/locationd/paramsd.cc
new file mode 100644
index 00000000000000..9fc3ad625d920f
--- /dev/null
+++ b/selfdrive/locationd/paramsd.cc
@@ -0,0 +1,174 @@
+#include
+#include
+#include
+
+#include "locationd_yawrate.h"
+#include "cereal/gen/cpp/log.capnp.h"
+
+#include "common/swaglog.h"
+#include "common/messaging.h"
+#include "common/params.h"
+#include "common/timing.h"
+#include "params_learner.h"
+#include "json11.hpp"
+
+const int num_polls = 3;
+
+int main(int argc, char *argv[]) {
+ auto ctx = zmq_ctx_new();
+ auto controls_state_sock = sub_sock(ctx, "tcp://127.0.0.1:8007");
+ auto sensor_events_sock = sub_sock(ctx, "tcp://127.0.0.1:8003");
+ auto camera_odometry_sock = sub_sock(ctx, "tcp://127.0.0.1:8066");
+
+ auto live_parameters_sock = zsock_new_pub("@tcp://*:8064");
+ assert(live_parameters_sock);
+ auto live_parameters_sock_raw = zsock_resolve(live_parameters_sock);
+
+ int err;
+ Localizer localizer;
+
+ zmq_pollitem_t polls[num_polls] = {{0}};
+ polls[0].socket = controls_state_sock;
+ polls[0].events = ZMQ_POLLIN;
+ polls[1].socket = sensor_events_sock;
+ polls[1].events = ZMQ_POLLIN;
+ polls[2].socket = camera_odometry_sock;
+ polls[2].events = ZMQ_POLLIN;
+
+ // Read car params
+ char *value;
+ size_t value_sz = 0;
+
+ LOGW("waiting for params to set vehicle model");
+ while (true) {
+ read_db_value(NULL, "CarParams", &value, &value_sz);
+ if (value_sz > 0) break;
+ usleep(100*1000);
+ }
+ LOGW("got %d bytes CarParams", value_sz);
+
+ // make copy due to alignment issues
+ auto amsg = kj::heapArray((value_sz / sizeof(capnp::word)) + 1);
+ memcpy(amsg.begin(), value, value_sz);
+ free(value);
+
+ capnp::FlatArrayMessageReader cmsg(amsg);
+ cereal::CarParams::Reader car_params = cmsg.getRoot();
+
+ // Read params from previous run
+ const int result = read_db_value(NULL, "LiveParameters", &value, &value_sz);
+
+ std::string fingerprint = car_params.getCarFingerprint();
+ std::string vin = car_params.getCarVin();
+ double sR = car_params.getSteerRatio();
+ double x = 1.0;
+ double ao = 0.0;
+
+ if (result == 0){
+ auto str = std::string(value, value_sz);
+ free(value);
+
+ std::string err;
+ auto json = json11::Json::parse(str, err);
+ if (json.is_null() || !err.empty()) {
+ std::string log = "Error parsing json: " + err;
+ LOGW(log.c_str());
+ } else {
+ std::string new_fingerprint = json["carFingerprint"].string_value();
+ std::string new_vin = json["carVin"].string_value();
+
+ if (fingerprint == new_fingerprint && vin == new_vin) {
+ std::string log = "Parameter starting with: " + str;
+ LOGW(log.c_str());
+
+ sR = json["steerRatio"].number_value();
+ x = json["stiffnessFactor"].number_value();
+ ao = json["angleOffsetAverage"].number_value();
+ }
+ }
+ }
+
+ ParamsLearner learner(car_params, ao, x, sR, 1.0);
+
+ // Main loop
+ int save_counter = 0;
+ while (true){
+ int ret = zmq_poll(polls, num_polls, 100);
+
+ if (ret == 0){
+ continue;
+ } else if (ret < 0){
+ break;
+ }
+
+ for (int i=0; i < num_polls; i++) {
+ if (polls[i].revents) {
+ zmq_msg_t msg;
+ err = zmq_msg_init(&msg);
+ assert(err == 0);
+ err = zmq_msg_recv(&msg, polls[i].socket, 0);
+ assert(err >= 0);
+ // make copy due to alignment issues, will be freed on out of scope
+ auto amsg = kj::heapArray((zmq_msg_size(&msg) / sizeof(capnp::word)) + 1);
+ memcpy(amsg.begin(), zmq_msg_data(&msg), zmq_msg_size(&msg));
+
+ auto which = localizer.handle_log((const unsigned char*)amsg.begin(), amsg.size());
+ zmq_msg_close(&msg);
+
+ if (which == cereal::Event::CONTROLS_STATE){
+ save_counter++;
+
+ double yaw_rate = -localizer.x[0];
+ bool valid = learner.update(yaw_rate, localizer.car_speed, localizer.steering_angle);
+
+ // TODO: Fix in replay
+ double sensor_data_age = localizer.controls_state_time - localizer.sensor_data_time;
+
+ double angle_offset_degrees = RADIANS_TO_DEGREES * learner.ao;
+ double angle_offset_average_degrees = RADIANS_TO_DEGREES * learner.slow_ao;
+
+ // Send parameters at 10 Hz
+ if (save_counter % 10 == 0){
+ capnp::MallocMessageBuilder msg;
+ cereal::Event::Builder event = msg.initRoot();
+ event.setLogMonoTime(nanos_since_boot());
+ auto live_params = event.initLiveParameters();
+ live_params.setValid(valid);
+ live_params.setYawRate(localizer.x[0]);
+ live_params.setGyroBias(localizer.x[1]);
+ live_params.setSensorValid(sensor_data_age < 5.0);
+ live_params.setAngleOffset(angle_offset_degrees);
+ live_params.setAngleOffsetAverage(angle_offset_average_degrees);
+ live_params.setStiffnessFactor(learner.x);
+ live_params.setSteerRatio(learner.sR);
+
+ auto words = capnp::messageToFlatArray(msg);
+ auto bytes = words.asBytes();
+ zmq_send(live_parameters_sock_raw, bytes.begin(), bytes.size(), ZMQ_DONTWAIT);
+ }
+
+
+ // Save parameters every minute
+ if (save_counter % 6000 == 0) {
+ json11::Json json = json11::Json::object {
+ {"carVin", vin},
+ {"carFingerprint", fingerprint},
+ {"steerRatio", learner.sR},
+ {"stiffnessFactor", learner.x},
+ {"angleOffsetAverage", angle_offset_average_degrees},
+ };
+
+ std::string out = json.dump();
+ write_db_value(NULL, "LiveParameters", out.c_str(), out.length());
+ }
+ }
+ }
+ }
+ }
+
+ zmq_close(controls_state_sock);
+ zmq_close(sensor_events_sock);
+ zmq_close(camera_odometry_sock);
+ zmq_close(live_parameters_sock_raw);
+ return 0;
+}
diff --git a/selfdrive/locationd/test/test_params_learner.py b/selfdrive/locationd/test/test_params_learner.py
new file mode 100755
index 00000000000000..e2a6913c0cd31c
--- /dev/null
+++ b/selfdrive/locationd/test/test_params_learner.py
@@ -0,0 +1,53 @@
+#!/usr/bin/env python
+
+import numpy as np
+import unittest
+
+from selfdrive.car.honda.interface import CarInterface
+from selfdrive.car.honda.values import CAR
+from selfdrive.controls.lib.vehicle_model import VehicleModel
+from selfdrive.locationd.liblocationd_py import liblocationd # pylint: disable=no-name-in-module, import-error
+
+
+class TestParamsLearner(unittest.TestCase):
+ def setUp(self):
+
+ self.CP = CarInterface.get_params(CAR.CIVIC, {})
+ bts = self.CP.to_bytes()
+
+ self.params_learner = liblocationd.params_learner_init(len(bts), bts, 0.0, 1.0, self.CP.steerRatio, 1.0)
+
+ def test_convergence(self):
+ # Setup vehicle model with wrong parameters
+ VM_sim = VehicleModel(self.CP)
+ x_target = 0.75
+ sr_target = 14
+ ao_target = -1.0
+ VM_sim.update_params(x_target, sr_target)
+
+ # Run simulation
+ times = np.arange(0, 10*3600, 0.01)
+ angle_offset = np.radians(ao_target)
+ steering_angles = np.radians(10 * np.sin(2 * np.pi * times / 100.)) + angle_offset
+ speeds = 10 * np.sin(2 * np.pi * times / 1000.) + 25
+
+ for i, t in enumerate(times):
+ u = speeds[i]
+ sa = steering_angles[i]
+ psi = VM_sim.yaw_rate(sa - angle_offset, u)
+ liblocationd.params_learner_update(self.params_learner, psi, u, sa)
+
+ # Verify learned parameters
+ sr = liblocationd.params_learner_get_sR(self.params_learner)
+ ao_slow = np.degrees(liblocationd.params_learner_get_slow_ao(self.params_learner))
+ x = liblocationd.params_learner_get_x(self.params_learner)
+ self.assertAlmostEqual(x_target, x, places=1)
+ self.assertAlmostEqual(ao_target, ao_slow, places=1)
+ self.assertAlmostEqual(sr_target, sr, places=1)
+
+
+
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/selfdrive/loggerd/uploader.py b/selfdrive/loggerd/uploader.py
index 7cad71bf7da010..0bd2ff18f1d54c 100644
--- a/selfdrive/loggerd/uploader.py
+++ b/selfdrive/loggerd/uploader.py
@@ -168,7 +168,7 @@ def next_file_to_upload(self, with_raw):
def do_upload(self, key, fn):
try:
- url_resp = api_get("v1.2/"+self.dongle_id+"/upload_url/", timeout=2, path=key, access_token=self.access_token)
+ url_resp = api_get("v1.2/"+self.dongle_id+"/upload_url/", timeout=10, path=key, access_token=self.access_token)
url_resp_json = json.loads(url_resp.text)
url = url_resp_json['url']
headers = url_resp_json['headers']
@@ -223,7 +223,7 @@ def upload(self, key, fn):
try:
os.unlink(fn)
except OSError:
- cloudlog.exception("delete_failed", stat=stat, exc=self.last_exc, key=key, fn=fn, sz=sz)
+ cloudlog.event("delete_failed", stat=stat, exc=self.last_exc, key=key, fn=fn, sz=sz)
success = True
else:
diff --git a/selfdrive/manager.py b/selfdrive/manager.py
index c3be2c094d09ed..4e52f2beb4bd4c 100755
--- a/selfdrive/manager.py
+++ b/selfdrive/manager.py
@@ -72,12 +72,15 @@ def unblock_stdout():
import shutil
import hashlib
import importlib
+import re
+import stat
import subprocess
import traceback
from multiprocessing import Process
from setproctitle import setproctitle #pylint: disable=no-name-in-module
+from common.file_helpers import atomic_write_in_dir_neos
from common.params import Params
import cereal
ThermalStatus = cereal.log.ThermalData.ThermalStatus
@@ -109,12 +112,14 @@ def unblock_stdout():
"pandad": "selfdrive.pandad",
"ui": ("selfdrive/ui", ["./start.py"]),
"calibrationd": "selfdrive.locationd.calibrationd",
- "params_learner": ("selfdrive/locationd", ["./params_learner"]),
+ "paramsd": ("selfdrive/locationd", ["./paramsd"]),
"visiond": ("selfdrive/visiond", ["./visiond"]),
"sensord": ("selfdrive/sensord", ["./start_sensord.py"]),
"gpsd": ("selfdrive/sensord", ["./start_gpsd.py"]),
"updated": "selfdrive.updated",
- "athena": "selfdrive.athena.athenad",
+}
+daemon_processes = {
+ "athenad": "selfdrive.athena.athenad",
}
android_packages = ("ai.comma.plus.offroad", "ai.comma.plus.frame")
@@ -136,7 +141,6 @@ def get_running():
'uploader',
'ui',
'updated',
- 'athena',
]
car_started_processes = [
@@ -146,7 +150,7 @@ def get_running():
'sensord',
'radard',
'calibrationd',
- 'params_learner',
+ 'paramsd',
'visiond',
'proclogd',
'ubloxd',
@@ -209,6 +213,29 @@ def start_managed_process(name):
running[name] = Process(name=name, target=nativelauncher, args=(pargs, cwd))
running[name].start()
+def start_daemon_process(name, params):
+ proc = daemon_processes[name]
+ pid_param = name.capitalize() + 'Pid'
+ pid = params.get(pid_param)
+
+ if pid is not None:
+ try:
+ os.kill(int(pid), 0)
+ # process is running (kill is a poorly-named system call)
+ return
+ except OSError:
+ # process is dead
+ pass
+
+ cloudlog.info("starting daemon %s" % name)
+ proc = subprocess.Popen(['python', '-m', proc],
+ cwd='/',
+ stdout=open('/dev/null', 'w'),
+ stderr=open('/dev/null', 'w'),
+ preexec_fn=os.setpgrp)
+
+ params.put(pid_param, str(proc.pid))
+
def prepare_managed_process(p):
proc = managed_processes[p]
if isinstance(proc, str):
@@ -321,6 +348,12 @@ def manager_thread():
# save boot log
subprocess.call(["./loggerd", "--bootlog"], cwd=os.path.join(BASEDIR, "selfdrive/loggerd"))
+ params = Params()
+
+ # start daemon processes
+ for p in daemon_processes:
+ start_daemon_process(p, params)
+
# start persistent processes
for p in persistent_processes:
start_managed_process(p)
@@ -332,7 +365,6 @@ def manager_thread():
if os.getenv("NOBOARD") is None:
start_managed_process("pandad")
- params = Params()
logger_dead = False
while 1:
@@ -420,10 +452,46 @@ def update_apks():
assert success
+def update_ssh():
+ ssh_home_dirpath = "/system/comma/home/.ssh/"
+ auth_keys_path = os.path.join(ssh_home_dirpath, "authorized_keys")
+ auth_keys_persist_path = os.path.join(ssh_home_dirpath, "authorized_keys.persist")
+ auth_keys_mode = stat.S_IREAD | stat.S_IWRITE
+
+ params = Params()
+ github_keys = params.get("GithubSshKeys") or ''
+
+ old_keys = open(auth_keys_path).read()
+ has_persisted_keys = os.path.exists(auth_keys_persist_path)
+ if has_persisted_keys:
+ persisted_keys = open(auth_keys_persist_path).read()
+ else:
+ # add host filter
+ persisted_keys = re.sub(r'^(?!.+?from.+? )(ssh|ecdsa)', 'from="10.0.0.0/8,172.16.0.0/12,192.168.0.0/16" \\1', old_keys, flags=re.MULTILINE)
+
+ new_keys = persisted_keys + '\n' + github_keys
+
+ if has_persisted_keys and new_keys == old_keys and os.stat(auth_keys_path)[stat.ST_MODE] == auth_keys_mode:
+ # nothing to do - let's avoid remount
+ return
+
+ try:
+ subprocess.check_call(["mount", "-o", "rw,remount", "/system"])
+ if not has_persisted_keys:
+ atomic_write_in_dir_neos(auth_keys_persist_path, persisted_keys, mode=auth_keys_mode)
+
+ atomic_write_in_dir_neos(auth_keys_path, new_keys, mode=auth_keys_mode)
+ finally:
+ try:
+ subprocess.check_call(["mount", "-o", "ro,remount", "/system"])
+ except:
+ cloudlog.exception("Failed to remount as read-only")
+ # this can fail due to "Device busy" - reboot if so
+ os.system("reboot")
+ raise RuntimeError
+
def manager_update():
- if os.path.exists(os.path.join(BASEDIR, "vpn")):
- cloudlog.info("installing vpn")
- os.system(os.path.join(BASEDIR, "vpn", "install.sh"))
+ update_ssh()
update_apks()
def manager_prepare():
diff --git a/selfdrive/messaging.py b/selfdrive/messaging.py
index 4e78f66c817bad..cad7e2e8bf79db 100644
--- a/selfdrive/messaging.py
+++ b/selfdrive/messaging.py
@@ -16,17 +16,34 @@ def pub_sock(port, addr="*"):
sock.bind("tcp://%s:%d" % (addr, port))
return sock
-def sub_sock(port, poller=None, addr="127.0.0.1", conflate=False):
+def sub_sock(port, poller=None, addr="127.0.0.1", conflate=False, timeout=None):
context = zmq.Context.instance()
sock = context.socket(zmq.SUB)
if conflate:
sock.setsockopt(zmq.CONFLATE, 1)
sock.connect("tcp://%s:%d" % (addr, port))
sock.setsockopt(zmq.SUBSCRIBE, b"")
+
+ if timeout is not None:
+ sock.RCVTIMEO = timeout
+
if poller is not None:
poller.register(sock, zmq.POLLIN)
return sock
+def drain_sock_raw(sock, wait_for_one=False):
+ ret = []
+ while 1:
+ try:
+ if wait_for_one and len(ret) == 0:
+ dat = sock.recv()
+ else:
+ dat = sock.recv(zmq.NOBLOCK)
+ ret.append(dat)
+ except zmq.error.Again:
+ break
+ return ret
+
def drain_sock(sock, wait_for_one=False):
ret = []
while 1:
@@ -82,24 +99,29 @@ def __init__(self, services, addr="127.0.0.1"):
self.valid = {}
for s in services:
# TODO: get address automatically from service_list
- self.sock[s] = sub_sock(service_list[s].port, poller=self.poller, addr=addr, conflate=True)
+ if addr is not None:
+ self.sock[s] = sub_sock(service_list[s].port, poller=self.poller, addr=addr, conflate=True)
self.freq[s] = service_list[s].frequency
data = new_message()
data.init(s)
self.data[s] = getattr(data, s)
- self.logMonoTime[s] = data.logMonoTime
+ self.logMonoTime[s] = 0
self.valid[s] = data.valid
def __getitem__(self, s):
return self.data[s]
def update(self, timeout=-1):
+ msgs = []
+ for sock, _ in self.poller.poll(timeout):
+ msgs.append(recv_one(sock))
+ self.update_msgs(sec_since_boot(), msgs)
+
+ def update_msgs(self, cur_time, msgs):
# TODO: add optional input that specify the service to wait for
self.frame += 1
self.updated = dict.fromkeys(self.updated, False)
- cur_time = sec_since_boot()
- for sock, _ in self.poller.poll(timeout):
- msg = recv_one(sock)
+ for msg in msgs:
s = msg.which()
self.updated[s] = True
self.rcv_time[s] = cur_time
diff --git a/selfdrive/registration.py b/selfdrive/registration.py
index 9f689984999c06..f8a084bd3605e7 100644
--- a/selfdrive/registration.py
+++ b/selfdrive/registration.py
@@ -5,7 +5,7 @@
from datetime import datetime, timedelta
from selfdrive.swaglog import cloudlog
-from selfdrive.version import version, training_version, get_git_commit, get_git_branch, get_git_remote
+from selfdrive.version import version, terms_version, training_version, get_git_commit, get_git_branch, get_git_remote
from common.api import api_get
from common.params import Params
from common.file_helpers import mkdirs_exists_ok
@@ -53,6 +53,7 @@ def get_subscriber_info():
def register():
params = Params()
params.put("Version", version)
+ params.put("TermsVersion", terms_version)
params.put("TrainingVersion", training_version)
params.put("GitCommit", get_git_commit())
params.put("GitBranch", get_git_branch())
diff --git a/selfdrive/test/plant/plant.py b/selfdrive/test/plant/plant.py
index e39bafd7921961..930f83be8720d9 100755
--- a/selfdrive/test/plant/plant.py
+++ b/selfdrive/test/plant/plant.py
@@ -244,6 +244,7 @@ def step(self, v_lead=0.0, cruise_buttons=None, grade=0.0, publish_model = True)
'EPB_STATE',
'BRAKE_HOLD_ACTIVE',
'INTERCEPTOR_GAS',
+ 'INTERCEPTOR_GAS2',
'IMPERIAL_UNIT',
])
vls = vls_tuple(
@@ -276,6 +277,7 @@ def step(self, v_lead=0.0, cruise_buttons=None, grade=0.0, publish_model = True)
0, # EPB State
0, # Brake hold
0, # Interceptor feedback
+ 0, # Interceptor 2 feedback
False
)
diff --git a/selfdrive/thermald.py b/selfdrive/thermald.py
index ef75cfffd982f1..9a29b96fec2800 100755
--- a/selfdrive/thermald.py
+++ b/selfdrive/thermald.py
@@ -2,7 +2,7 @@
import os
from smbus2 import SMBus
from cereal import log
-from selfdrive.version import training_version
+from selfdrive.version import terms_version, training_version
from selfdrive.swaglog import cloudlog
import selfdrive.messaging as messaging
from selfdrive.services import service_list
@@ -216,7 +216,7 @@ def thermald_thread():
ignition = True
do_uninstall = params.get("DoUninstall") == "1"
- accepted_terms = params.get("HasAcceptedTerms") == "1"
+ accepted_terms = params.get("HasAcceptedTerms") == terms_version
completed_training = params.get("CompletedTrainingVersion") == training_version
should_start = ignition
diff --git a/selfdrive/version.py b/selfdrive/version.py
index 4acc183502f9f4..2eb39dc9769826 100644
--- a/selfdrive/version.py
+++ b/selfdrive/version.py
@@ -59,6 +59,7 @@ def get_git_remote():
dirty = True
training_version = "0.1.0"
+terms_version = "2"
if __name__ == "__main__":
print("Dirty: %s" % dirty)
diff --git a/selfdrive/visiond/models/driving.cc b/selfdrive/visiond/models/driving.cc
index bf5933f4288ae7..28876c81b1acbe 100644
--- a/selfdrive/visiond/models/driving.cc
+++ b/selfdrive/visiond/models/driving.cc
@@ -135,7 +135,14 @@ void poly_fit(float *in_pts, float *in_stds, float *out) {
Eigen::Matrix lhs = vander.array().colwise() / std.array();
Eigen::Matrix rhs = pts.array() / std.array();
+ // Improve numerical stability
+ Eigen::Matrix scale = 1. / (lhs.array()*lhs.array()).sqrt().colwise().sum();
+ lhs = lhs * scale.asDiagonal();
+
// Solve inplace
Eigen::ColPivHouseholderQR > qr(lhs);
p = qr.solve(rhs);
+
+ // Apply scale to output
+ p = p.transpose() * scale.asDiagonal();
}