diff --git a/.github/PULL_REQUEST_TEMPLATE/car_port.md b/.github/PULL_REQUEST_TEMPLATE/car_port.md
index d275468395..4264363ba2 100644
--- a/.github/PULL_REQUEST_TEMPLATE/car_port.md
+++ b/.github/PULL_REQUEST_TEMPLATE/car_port.md
@@ -9,7 +9,7 @@ assignees: ''
**Checklist**
- [ ] added to README
-- [ ] test route added to [test_routes.py](https://github.com/commaai/openpilot/blob/master/selfdrive/test/test_models.py)
+- [ ] test route added to [routes.py](https://github.com/commaai/openpilot/blob/master/selfdrive/car/tests/routes.py)
- [ ] route with openpilot:
- [ ] route with stock system:
- [ ] car harness used (if comma doesn't sell it, put N/A):
diff --git a/.github/workflows/selfdrive_tests.yaml b/.github/workflows/selfdrive_tests.yaml
index 9870637003..0083d39c3a 100644
--- a/.github/workflows/selfdrive_tests.yaml
+++ b/.github/workflows/selfdrive_tests.yaml
@@ -245,7 +245,6 @@ jobs:
- name: Run unit tests
run: |
${{ env.RUN }} "scons -j$(nproc) --test && \
- coverage run selfdrive/test/test_fingerprints.py && \
$UNIT_TEST common && \
$UNIT_TEST opendbc/can && \
$UNIT_TEST selfdrive/boardd && \
@@ -384,7 +383,7 @@ jobs:
uses: actions/cache@v2
with:
path: /tmp/comma_download_cache
- key: car_models-${{ hashFiles('selfdrive/test/test_models.py', 'selfdrive/test/test_routes.py') }}-${{ matrix.job }}
+ key: car_models-${{ hashFiles('selfdrive/car/tests/test_models.py', 'selfdrive/test/test_routes.py') }}-${{ matrix.job }}
- name: Cache scons
id: scons-cache
# TODO: Change the version to the released version when https://github.com/actions/cache/pull/489 (or 571) is merged.
@@ -402,7 +401,7 @@ jobs:
- name: Test car models
run: |
${{ env.RUN }} "scons -j$(nproc) --test && \
- FILEREADER_CACHE=1 coverage run -m pytest selfdrive/test/test_models.py && \
+ FILEREADER_CACHE=1 coverage run -m pytest selfdrive/car/tests/test_models.py && \
coverage xml && \
chmod -R 777 /tmp/comma_download_cache"
env:
diff --git a/Pipfile.lock b/Pipfile.lock
index 25cc81cbb2..fdad4cb64d 100644
--- a/Pipfile.lock
+++ b/Pipfile.lock
@@ -16,20 +16,13 @@
]
},
"default": {
- "appdirs": {
- "hashes": [
- "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41",
- "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"
- ],
- "version": "==1.4.4"
- },
"astroid": {
"hashes": [
- "sha256:72ace9c3333e274e9248168fc4f3e300da8545af1c303bd69197027f49e2bfff",
- "sha256:aa296702f1a5c3102c860de49473aaa90a7f6d221555d5cf2678940a9be32a4e"
+ "sha256:1efdf4e867d4d8ba4a9f6cf9ce07cd182c4c41de77f23814feb27ca93ca9d877",
+ "sha256:506daabe5edffb7e696ad82483ad0228245a9742ed7d2d8c9cdb31537decf9f6"
],
"markers": "python_full_version >= '3.6.2'",
- "version": "==2.9.2"
+ "version": "==2.9.3"
},
"atomicwrites": {
"hashes": [
@@ -149,19 +142,19 @@
},
"charset-normalizer": {
"hashes": [
- "sha256:876d180e9d7432c5d1dfd4c5d26b72f099d503e8fcc0feb7532c9289be60fcbd",
- "sha256:cb957888737fc0bbcd78e3df769addb41fd1ff8cf950dc9e7ad7793f1bf44455"
+ "sha256:2857e29ff0d34db842cd7ca3230549d1a697f96ee6d3fb071cfa6c7393832597",
+ "sha256:6881edbebdb17b39b4eaaa821b438bf6eddffb4468cf344f09f89def34a8b1df"
],
"markers": "python_version >= '3'",
- "version": "==2.0.10"
+ "version": "==2.0.12"
},
"click": {
"hashes": [
- "sha256:353f466495adaeb40b6b5f592f9f91cb22372351c84caeb068132442a4518ef3",
- "sha256:410e932b050f5eed773c4cda94de75971c89cdb3155a72a0831139a79e5ecb5b"
+ "sha256:6a7a62563bbfabfda3a38f3023a1db4a35978c0abd76f6c9605ecd6554d6d9b1",
+ "sha256:8458d7b1287c5fb128c90e23381cf99dcde74beaf6c7ff6384ce84d6fe090adb"
],
"markers": "python_version >= '3.6'",
- "version": "==8.0.3"
+ "version": "==8.0.4"
},
"crcmod": {
"hashes": [
@@ -201,55 +194,45 @@
},
"cython": {
"hashes": [
- "sha256:0205b685802eb4c039b14f67b7ac3f00c55ff04b9e3871df2249576d3e59ba42",
- "sha256:0c3093bc99facfc97e5019f6c5bc39987663792265c1334d9fc9e37c3a3dcd6f",
- "sha256:0ffce25bf50fa926ec6bf8d6f29650e7cb33fae445938c9880e1ce9b776353ef",
- "sha256:10402f0f1564ffc6ecb9c45e07f995771d05bb0b0e1d151e40574638292ee3a5",
- "sha256:1519eb639de308f5763eb0666b4cc7bd3958268f3f6228cc610b7b4d6c94b68b",
- "sha256:233a87db76941626f1db08f4b25a4a5b425b13b64ed0e673c3641f7b650a48d8",
- "sha256:2b834ff6e4d10ba6d7a0d676dd71c1b427a181ddbbbbf79e91d1861557aab59f",
- "sha256:362fbb9cb4627c7786231429768b54aaba5459a2a0e46c25e59f202ca6155437",
- "sha256:3aed8c642e8fb27024bca46830b7f62335a44a92354acf708d6b8d050f945a3a",
- "sha256:41ee918480371ae5e5851ba9b1ead5a183e24aedb27bf807c7405d124e943f40",
- "sha256:4b7d04b393d9a4b5fec0cbc4b0f29fe083a9d862d95231a6e7608978bd661d7e",
- "sha256:4d868e1a41f5123f51a20c1b8e82f7cb6fa3370c104e98e707f7c910e8cadad1",
- "sha256:5041adfef502d67ecd5e291a7cf645a37fed7a9dac557f40d491053f35204d00",
- "sha256:51923120f57a42c59f5ee6bba9e89a31a394ae8cd419c753f64d8a3aea1ee8b7",
- "sha256:531303085503959338e6cdac630626280ef111aecbb22d48321673a8c3897c0a",
- "sha256:5ecf5cf5b57086cc6c1cfc76d6353bbd7023e95da32e0883f1302ca50e481c33",
- "sha256:5fd5db458c9d3d2c2abd047f3190624d9cce8a80a8e0ca0baa69cfd133a523bc",
- "sha256:6773cce9d4b3b6168d8feb2b6f06b658ef1e11cbfec075041745666d8e2a5e45",
- "sha256:6b385f68789c3e8a75b4827e8a4970ff04605ad3cb1c0b41005cc69368dad65d",
- "sha256:706ea55f58c2722206e51cd9a8754ed0995c4c4231d24b095875d2641d745222",
- "sha256:75eaa22911d2ec37a3841f77b710b178c805cd378b5e1c4fb82dbc35620d2062",
- "sha256:77913fe27c5e22c995bac090d01e200ff91e5f58aa944e2d2e94cbf67ea2ae34",
- "sha256:7df94e56872df8f396ca669466fee60256f69f678654239f706b1e643c2ac4a5",
- "sha256:82881565d04027728d7762edd8c085927a840873af7ee049d703e0ca226bc08d",
- "sha256:868f309095e557f06dc58723ae865e8c65cfedb2646a562bd8080c92d69e4e4b",
- "sha256:8e07121b34221458a2151d37e137b8f5b011a9c51dd38db2499a6198590aa319",
- "sha256:93840f2071c1f15e613509eadee1fbcd335e8666772437fe5038e24059edd48c",
- "sha256:a1cc55db32cd39474081d478263b96e036552cdbbab8831c90ea43fb385a9b66",
- "sha256:af377d543a762867da11fcf6e558f7a4a535ff8693f30cce123fab10c00fa312",
- "sha256:af91dd63ac5f1f7fc70dc91ea063f727db42b5eb934d1f3832611be18e25171e",
- "sha256:b3041e45aefaa4449fd671902132c0ac1f72eedaedac745c0e1a70a13bf990bb",
- "sha256:b5ca05c2bfba0c2480b5fd390ecffe46b8da574d887d600388d6e3caf3f99a88",
- "sha256:bbf0149680c1fca07200a3ed372b22e6bad7851d191b717a61f9a68af370e180",
- "sha256:be13be1e2b9b7395588f2a23bfa692f2f3e6f7936ccf7825c83431b8c8c3452b",
- "sha256:be550b566345bf53b95616334793ce42a128cf1d9dcde1e28cbf7ce52ea61d6d",
- "sha256:c4b003b6b7aa9e74552ef8d4e6009b3e3c3e8fa585710b3a6d062e088e460c1b",
- "sha256:c813799d533194b7d85203d881d8b4f567a8c644a67f50d47f1ffbf316df412f",
- "sha256:c91b1ba0d43f7f7ccde8121c672207c7891735ddcc83496af1e0ab617ddc4aba",
- "sha256:ca10e9fde0eaba1407ab353ff07a26daaa3e4dbe356108a149e482d441f070dd",
- "sha256:ce804a021c92fea66c8c100781a111706f21bade7a546895c5a9c57fe2df8b24",
- "sha256:d83dad8dc6c63706cb3178dc79010b3865b1345090727189d2cd61758a825ee8",
- "sha256:e118525defec3f67471d8ee5ce04340d43195410a87e5d7ec8a1a9e953c0066a",
- "sha256:ebe32e002a9e6553de399033e259ece72aa17c77f740b265e66f122572a8a278",
- "sha256:ed76fb98979f02b5e89079906071983a36f3634d3028b86f935cf0196f24fcaa",
- "sha256:f5e15ff892c8afad64931ee3dd723c4755c2c516606f9aae7613bebfac62b0f6",
- "sha256:fec66cd0a48697fab903854566235aecf1084f62e3163d6589ae7335a1b4d448"
- ],
- "index": "pypi",
- "version": "==0.29.26"
+ "sha256:004387d8b94c64681ee05660d6a234e125396097726cf2f419c0fa2ac38034d6",
+ "sha256:0378a14d2580dcea234d7a2dc8d75f60c091105885096e6dd5b032be97542c16",
+ "sha256:03b749e4f0bbf631cee472add2806d338a7d496f8383f6fb28cc5fdc34b7fdb8",
+ "sha256:05edfa51c0ff31a8df3cb291b90ca93ab499686d023b9b81c216cd3509f73def",
+ "sha256:076aa8da83383e2bed0ca5f92c13a7e76e684bc41fe8e438bbed735f5b1c2731",
+ "sha256:09448aadb818387160ca4d1e1b82dbb7001526b6d0bed7529c4e8ac12e3b6f4c",
+ "sha256:1612d7439590ba3b8de5f907bf0e54bd8e024eafb8c59261531a7988030c182d",
+ "sha256:16f2e74fcac223c53e298ecead62c353d3cffa107bea5d8232e4b2ba40781634",
+ "sha256:26d8d0ededca42be50e0ac377c08408e18802b1391caa3aea045a72c1bff47ac",
+ "sha256:31465dce7fd3f058d02afb98b13af962848cc607052388814428dc801cc26f57",
+ "sha256:33b69ac9bbf2b93d8cae336cfe48889397a857e6ceeb5cef0b2f0b31b6c54f2b",
+ "sha256:341917bdb2c95bcf8322aacfe50bbe6b4794880b16fa8b2300330520e123a5e5",
+ "sha256:43eca77169f855dd04be11921a585c8854a174f30bc925257e92bc7b9197fbd2",
+ "sha256:49076747b731ed78acf203666c3b3c5d664754ea01ca4527f62f6d8675703688",
+ "sha256:4b3089255b6b1cc69e4b854626a41193e6acae5332263d24707976b3cb8ca644",
+ "sha256:5658fa477e80d96c49d5ff011938dd4b62da9aa428f771b91f1a7c49af45aad8",
+ "sha256:59f4e86b415620a097cf0ec602adf5a7ee3cc33e8220567ded96566f753483f8",
+ "sha256:5e82f6b3dc2133b2e0e2c5c63d352d40a695e40cc7ed99f4cbe83334bcf9ab39",
+ "sha256:6626f9691ce2093ccbcc9932f449efe3b6e1c893b556910881d177c61612e8ff",
+ "sha256:75686c586e37b1fed0fe4a2c053474f96fc07da0063bbfc98023454540515d31",
+ "sha256:7962a78ceb80cdec21345fb5088e675060fa65982030d446069f2d675d30e3cd",
+ "sha256:9d39ee7ddef6856413f950b8959e852d83376d9db1c509505e3f4873df32aa70",
+ "sha256:9f2b7c86a73db0d8dbbd885fe67f04c7b787df37a3848b9867270d3484101fbd",
+ "sha256:a0ed39c63ba52edd03a39ea9d6da6f5326aaee5d333c317feba543270a1b3af5",
+ "sha256:a3b27812ac9e9737026bfbb1dd47434f3e84013f430bafe1c6cbaf1cd51b5518",
+ "sha256:b6c77cc24861a33714e74212abfab4e54bf42e1ad602623f193b8e369389af2f",
+ "sha256:c9848a423a14e8f51bd4bbf8e2ff37031764ce66bdc7c6bc06c70d4084eb23c7",
+ "sha256:d6036f6a5a0c7fb1af88889872268b15bf20dd9cefe33a6602d79ba18b8db20f",
+ "sha256:d6fac2342802c30e51426828fe084ff4deb1b3387367cf98976bb2e64b6f8e45",
+ "sha256:d7c98727397c2547a56aa0c3c98140f1873c69a0642edc9446c6c870d0d8a5b5",
+ "sha256:d7d7beb600d5dd551e9322e1393b74286f4a3d4aa387f7bfbaccc1495a98603b",
+ "sha256:ded4fd3da4dee2f4414c35214244e29befa7f6fede3e9be317e765169df2cbc7",
+ "sha256:e24bd94946ffa37f30fcb865f2340fb6d429a3c7bf87b47b22f7d22e0e68a15c",
+ "sha256:e9cc6af0c9c477c5e175e807dce439509934efefc24ea2da9fced7fbc8170591",
+ "sha256:ed32c206e1d68056a34b21d2ec0cf0f23d338d6531476a68c73e21e20bd7bb63",
+ "sha256:fdcef7abb09fd827691e3abe6fd42c6c34beaccfa0bc2df6074f0a49949df6a8"
+ ],
+ "index": "pypi",
+ "version": "==0.29.28"
},
"flake8": {
"hashes": [
@@ -261,11 +244,11 @@
},
"flask": {
"hashes": [
- "sha256:7b2fb8e934ddd50731893bdcdb00fc8c0315916f9fcd50d22c7cc1a95ab634e2",
- "sha256:cb90f62f1d8e4dc4621f52106613488b5ba826b2e1e10a33eac92f723093ab6a"
+ "sha256:59da8a3170004800a2837844bfa84d49b022550616070f7cb1a659682b2e7c9f",
+ "sha256:e1120c228ca2f553b470df4a5fa927ab66258467526069981b3eb0a91902687d"
],
"index": "pypi",
- "version": "==2.0.2"
+ "version": "==2.0.3"
},
"flatbuffers": {
"hashes": [
@@ -315,11 +298,11 @@
},
"itsdangerous": {
"hashes": [
- "sha256:5174094b9637652bdb841a3029700391451bd092ba3db90600dea710ba28e97c",
- "sha256:9e724d68fc22902a1435351f84c3fb8623f303fffcc566a4cb952df8c572cff0"
+ "sha256:29285842166554469a56d427addc0843914172343784cb909695fdbe90a3e129",
+ "sha256:d848fcb8bc7d507c4546b448574e8a44fc4ea2ba84ebf8d783290d53e81992f5"
],
- "markers": "python_version >= '3.6'",
- "version": "==2.0.1"
+ "markers": "python_version >= '3.7'",
+ "version": "==2.1.0"
},
"jinja2": {
"hashes": [
@@ -382,88 +365,59 @@
},
"libusb1": {
"hashes": [
- "sha256:81381ce1d8852a4d4345b2ee8218971d35865b5f025fef96b43ee082757099cd",
- "sha256:9fda3055c98ab043cfb3beac93ef1de2900ad11d949c694f58bdf414ce2bd03c",
- "sha256:a97bcb90f589d863c5e971b013c8cf7e1915680a951e66c4222a2c5bb64b7153",
- "sha256:d3ba82ecf7ab6a48d21dac6697e26504670cc3522b8e5941bd28fb56cf3f6c46"
+ "sha256:083f75e5d15cb5e2159e64c308c5317284eae926a820d6dce53a9505d18be3b2",
+ "sha256:0e652b04cbe85ec8e74f9ee82b49f861fb14b5320ae51399387ad2601ccc0500",
+ "sha256:5792a9defee40f15d330a40d9b1800545c32e47ba7fc66b6f28f133c9fcc8538",
+ "sha256:6f6bb010632ada35c661d17a65e135077beef0fbb2434d5ffdb3a4a911fd9490"
],
"index": "pypi",
- "version": "==2.0.1"
+ "version": "==3.0.0"
},
"markupsafe": {
"hashes": [
- "sha256:01a9b8ea66f1658938f65b93a85ebe8bc016e6769611be228d797c9d998dd298",
- "sha256:023cb26ec21ece8dc3907c0e8320058b2e0cb3c55cf9564da612bc325bed5e64",
- "sha256:0446679737af14f45767963a1a9ef7620189912317d095f2d9ffa183a4d25d2b",
- "sha256:04635854b943835a6ea959e948d19dcd311762c5c0c6e1f0e16ee57022669194",
- "sha256:0717a7390a68be14b8c793ba258e075c6f4ca819f15edfc2a3a027c823718567",
- "sha256:0955295dd5eec6cb6cc2fe1698f4c6d84af2e92de33fbcac4111913cd100a6ff",
- "sha256:0d4b31cc67ab36e3392bbf3862cfbadac3db12bdd8b02a2731f509ed5b829724",
- "sha256:10f82115e21dc0dfec9ab5c0223652f7197feb168c940f3ef61563fc2d6beb74",
- "sha256:168cd0a3642de83558a5153c8bd34f175a9a6e7f6dc6384b9655d2697312a646",
- "sha256:1d609f577dc6e1aa17d746f8bd3c31aa4d258f4070d61b2aa5c4166c1539de35",
- "sha256:1f2ade76b9903f39aa442b4aadd2177decb66525062db244b35d71d0ee8599b6",
- "sha256:20dca64a3ef2d6e4d5d615a3fd418ad3bde77a47ec8a23d984a12b5b4c74491a",
- "sha256:2a7d351cbd8cfeb19ca00de495e224dea7e7d919659c2841bbb7f420ad03e2d6",
- "sha256:2d7d807855b419fc2ed3e631034685db6079889a1f01d5d9dac950f764da3dad",
- "sha256:2ef54abee730b502252bcdf31b10dacb0a416229b72c18b19e24a4509f273d26",
- "sha256:36bc903cbb393720fad60fc28c10de6acf10dc6cc883f3e24ee4012371399a38",
- "sha256:37205cac2a79194e3750b0af2a5720d95f786a55ce7df90c3af697bfa100eaac",
- "sha256:3c112550557578c26af18a1ccc9e090bfe03832ae994343cfdacd287db6a6ae7",
- "sha256:3dd007d54ee88b46be476e293f48c85048603f5f516008bee124ddd891398ed6",
- "sha256:4296f2b1ce8c86a6aea78613c34bb1a672ea0e3de9c6ba08a960efe0b0a09047",
- "sha256:47ab1e7b91c098ab893b828deafa1203de86d0bc6ab587b160f78fe6c4011f75",
- "sha256:49e3ceeabbfb9d66c3aef5af3a60cc43b85c33df25ce03d0031a608b0a8b2e3f",
- "sha256:4dc8f9fb58f7364b63fd9f85013b780ef83c11857ae79f2feda41e270468dd9b",
- "sha256:4efca8f86c54b22348a5467704e3fec767b2db12fc39c6d963168ab1d3fc9135",
- "sha256:53edb4da6925ad13c07b6d26c2a852bd81e364f95301c66e930ab2aef5b5ddd8",
- "sha256:5855f8438a7d1d458206a2466bf82b0f104a3724bf96a1c781ab731e4201731a",
- "sha256:594c67807fb16238b30c44bdf74f36c02cdf22d1c8cda91ef8a0ed8dabf5620a",
- "sha256:5b6d930f030f8ed98e3e6c98ffa0652bdb82601e7a016ec2ab5d7ff23baa78d1",
- "sha256:5bb28c636d87e840583ee3adeb78172efc47c8b26127267f54a9c0ec251d41a9",
- "sha256:60bf42e36abfaf9aff1f50f52644b336d4f0a3fd6d8a60ca0d054ac9f713a864",
- "sha256:611d1ad9a4288cf3e3c16014564df047fe08410e628f89805e475368bd304914",
- "sha256:6300b8454aa6930a24b9618fbb54b5a68135092bc666f7b06901f897fa5c2fee",
- "sha256:63f3268ba69ace99cab4e3e3b5840b03340efed0948ab8f78d2fd87ee5442a4f",
- "sha256:6557b31b5e2c9ddf0de32a691f2312a32f77cd7681d8af66c2692efdbef84c18",
- "sha256:693ce3f9e70a6cf7d2fb9e6c9d8b204b6b39897a2c4a1aa65728d5ac97dcc1d8",
- "sha256:6a7fae0dd14cf60ad5ff42baa2e95727c3d81ded453457771d02b7d2b3f9c0c2",
- "sha256:6c4ca60fa24e85fe25b912b01e62cb969d69a23a5d5867682dd3e80b5b02581d",
- "sha256:6fcf051089389abe060c9cd7caa212c707e58153afa2c649f00346ce6d260f1b",
- "sha256:7d91275b0245b1da4d4cfa07e0faedd5b0812efc15b702576d103293e252af1b",
- "sha256:89c687013cb1cd489a0f0ac24febe8c7a666e6e221b783e53ac50ebf68e45d86",
- "sha256:8d206346619592c6200148b01a2142798c989edcb9c896f9ac9722a99d4e77e6",
- "sha256:905fec760bd2fa1388bb5b489ee8ee5f7291d692638ea5f67982d968366bef9f",
- "sha256:97383d78eb34da7e1fa37dd273c20ad4320929af65d156e35a5e2d89566d9dfb",
- "sha256:984d76483eb32f1bcb536dc27e4ad56bba4baa70be32fa87152832cdd9db0833",
- "sha256:99df47edb6bda1249d3e80fdabb1dab8c08ef3975f69aed437cb69d0a5de1e28",
- "sha256:9f02365d4e99430a12647f09b6cc8bab61a6564363f313126f775eb4f6ef798e",
- "sha256:a30e67a65b53ea0a5e62fe23682cfe22712e01f453b95233b25502f7c61cb415",
- "sha256:ab3ef638ace319fa26553db0624c4699e31a28bb2a835c5faca8f8acf6a5a902",
- "sha256:aca6377c0cb8a8253e493c6b451565ac77e98c2951c45f913e0b52facdcff83f",
- "sha256:add36cb2dbb8b736611303cd3bfcee00afd96471b09cda130da3581cbdc56a6d",
- "sha256:b2f4bf27480f5e5e8ce285a8c8fd176c0b03e93dcc6646477d4630e83440c6a9",
- "sha256:b7f2d075102dc8c794cbde1947378051c4e5180d52d276987b8d28a3bd58c17d",
- "sha256:baa1a4e8f868845af802979fcdbf0bb11f94f1cb7ced4c4b8a351bb60d108145",
- "sha256:be98f628055368795d818ebf93da628541e10b75b41c559fdf36d104c5787066",
- "sha256:bf5d821ffabf0ef3533c39c518f3357b171a1651c1ff6827325e4489b0e46c3c",
- "sha256:c47adbc92fc1bb2b3274c4b3a43ae0e4573d9fbff4f54cd484555edbf030baf1",
- "sha256:cdfba22ea2f0029c9261a4bd07e830a8da012291fbe44dc794e488b6c9bb353a",
- "sha256:d6c7ebd4e944c85e2c3421e612a7057a2f48d478d79e61800d81468a8d842207",
- "sha256:d7f9850398e85aba693bb640262d3611788b1f29a79f0c93c565694658f4071f",
- "sha256:d8446c54dc28c01e5a2dbac5a25f071f6653e6e40f3a8818e8b45d790fe6ef53",
- "sha256:deb993cacb280823246a026e3b2d81c493c53de6acfd5e6bfe31ab3402bb37dd",
- "sha256:e0f138900af21926a02425cf736db95be9f4af72ba1bb21453432a07f6082134",
- "sha256:e9936f0b261d4df76ad22f8fee3ae83b60d7c3e871292cd42f40b81b70afae85",
- "sha256:f0567c4dc99f264f49fe27da5f735f414c4e7e7dd850cfd8e69f0862d7c74ea9",
- "sha256:f5653a225f31e113b152e56f154ccbe59eeb1c7487b39b9d9f9cdb58e6c79dc5",
- "sha256:f826e31d18b516f653fe296d967d700fddad5901ae07c622bb3705955e1faa94",
- "sha256:f8ba0e8349a38d3001fae7eadded3f6606f0da5d748ee53cc1dab1d6527b9509",
- "sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51",
- "sha256:fa130dd50c57d53368c9d59395cb5526eda596d3ffe36666cd81a44d56e48872"
+ "sha256:023af8c54fe63530545f70dd2a2a7eed18d07a9a77b94e8bf1e2ff7f252db9a3",
+ "sha256:09c86c9643cceb1d87ca08cdc30160d1b7ab49a8a21564868921959bd16441b8",
+ "sha256:142119fb14a1ef6d758912b25c4e803c3ff66920635c44078666fe7cc3f8f759",
+ "sha256:1d1fb9b2eec3c9714dd936860850300b51dbaa37404209c8d4cb66547884b7ed",
+ "sha256:204730fd5fe2fe3b1e9ccadb2bd18ba8712b111dcabce185af0b3b5285a7c989",
+ "sha256:24c3be29abb6b34052fd26fc7a8e0a49b1ee9d282e3665e8ad09a0a68faee5b3",
+ "sha256:290b02bab3c9e216da57c1d11d2ba73a9f73a614bbdcc027d299a60cdfabb11a",
+ "sha256:3028252424c72b2602a323f70fbf50aa80a5d3aa616ea6add4ba21ae9cc9da4c",
+ "sha256:30c653fde75a6e5eb814d2a0a89378f83d1d3f502ab710904ee585c38888816c",
+ "sha256:3cace1837bc84e63b3fd2dfce37f08f8c18aeb81ef5cf6bb9b51f625cb4e6cd8",
+ "sha256:4056f752015dfa9828dce3140dbadd543b555afb3252507348c493def166d454",
+ "sha256:454ffc1cbb75227d15667c09f164a0099159da0c1f3d2636aa648f12675491ad",
+ "sha256:598b65d74615c021423bd45c2bc5e9b59539c875a9bdb7e5f2a6b92dfcfc268d",
+ "sha256:599941da468f2cf22bf90a84f6e2a65524e87be2fce844f96f2dd9a6c9d1e635",
+ "sha256:5ddea4c352a488b5e1069069f2f501006b1a4362cb906bee9a193ef1245a7a61",
+ "sha256:62c0285e91414f5c8f621a17b69fc0088394ccdaa961ef469e833dbff64bd5ea",
+ "sha256:679cbb78914ab212c49c67ba2c7396dc599a8479de51b9a87b174700abd9ea49",
+ "sha256:6e104c0c2b4cd765b4e83909cde7ec61a1e313f8a75775897db321450e928cce",
+ "sha256:736895a020e31b428b3382a7887bfea96102c529530299f426bf2e636aacec9e",
+ "sha256:75bb36f134883fdbe13d8e63b8675f5f12b80bb6627f7714c7d6c5becf22719f",
+ "sha256:7d2f5d97fcbd004c03df8d8fe2b973fe2b14e7bfeb2cfa012eaa8759ce9a762f",
+ "sha256:80beaf63ddfbc64a0452b841d8036ca0611e049650e20afcb882f5d3c266d65f",
+ "sha256:84ad5e29bf8bab3ad70fd707d3c05524862bddc54dc040982b0dbcff36481de7",
+ "sha256:8da5924cb1f9064589767b0f3fc39d03e3d0fb5aa29e0cb21d43106519bd624a",
+ "sha256:961eb86e5be7d0973789f30ebcf6caab60b844203f4396ece27310295a6082c7",
+ "sha256:96de1932237abe0a13ba68b63e94113678c379dca45afa040a17b6e1ad7ed076",
+ "sha256:a0a0abef2ca47b33fb615b491ce31b055ef2430de52c5b3fb19a4042dbc5cadb",
+ "sha256:b2a5a856019d2833c56a3dcac1b80fe795c95f401818ea963594b345929dffa7",
+ "sha256:b8811d48078d1cf2a6863dafb896e68406c5f513048451cd2ded0473133473c7",
+ "sha256:c532d5ab79be0199fa2658e24a02fce8542df196e60665dd322409a03db6a52c",
+ "sha256:d3b64c65328cb4cd252c94f83e66e3d7acf8891e60ebf588d7b493a55a1dbf26",
+ "sha256:d4e702eea4a2903441f2735799d217f4ac1b55f7d8ad96ab7d4e25417cb0827c",
+ "sha256:d5653619b3eb5cbd35bfba3c12d575db2a74d15e0e1c08bf1db788069d410ce8",
+ "sha256:d66624f04de4af8bbf1c7f21cc06649c1c69a7f84109179add573ce35e46d448",
+ "sha256:e67ec74fada3841b8c5f4c4f197bea916025cb9aa3fe5abf7d52b655d042f956",
+ "sha256:e6f7f3f41faffaea6596da86ecc2389672fa949bd035251eab26dc6697451d05",
+ "sha256:f02cf7221d5cd915d7fa58ab64f7ee6dd0f6cddbb48683debf5d04ae9b1c2cc1",
+ "sha256:f0eddfcabd6936558ec020130f932d479930581171368fd728efcfb6ef0dd357",
+ "sha256:fabbe18087c3d33c5824cb145ffca52eccd053061df1d79d4b66dafa5ad2a5ea",
+ "sha256:fc3150f85e2dbcf99e65238c842d1cfe69d3e7649b19864c1cc043213d9cd730"
],
- "markers": "python_version >= '3.6'",
- "version": "==2.0.1"
+ "markers": "python_version >= '3.7'",
+ "version": "==2.1.0"
},
"mccabe": {
"hashes": [
@@ -490,62 +444,59 @@
},
"numpy": {
"hashes": [
- "sha256:0cfe07133fd00b27edee5e6385e333e9eeb010607e8a46e1cd673f05f8596595",
- "sha256:11a1f3816ea82eed4178102c56281782690ab5993251fdfd75039aad4d20385f",
- "sha256:2762331de395739c91f1abb88041f94a080cb1143aeec791b3b223976228af3f",
- "sha256:283d9de87c0133ef98f93dfc09fad3fb382f2a15580de75c02b5bb36a5a159a5",
- "sha256:3d22662b4b10112c545c91a0741f2436f8ca979ab3d69d03d19322aa970f9695",
- "sha256:41388e32e40b41dd56eb37fcaa7488b2b47b0adf77c66154d6b89622c110dfe9",
- "sha256:42c16cec1c8cf2728f1d539bd55aaa9d6bb48a7de2f41eb944697293ef65a559",
- "sha256:47ee7a839f5885bc0c63a74aabb91f6f40d7d7b639253768c4199b37aede7982",
- "sha256:5a311ee4d983c487a0ab546708edbdd759393a3dc9cd30305170149fedd23c88",
- "sha256:5dc65644f75a4c2970f21394ad8bea1a844104f0fe01f278631be1c7eae27226",
- "sha256:6ed0d073a9c54ac40c41a9c2d53fcc3d4d4ed607670b9e7b0de1ba13b4cbfe6f",
- "sha256:76ba7c40e80f9dc815c5e896330700fd6e20814e69da9c1267d65a4d051080f1",
- "sha256:818b9be7900e8dc23e013a92779135623476f44a0de58b40c32a15368c01d471",
- "sha256:a024181d7aef0004d76fb3bce2a4c9f2e67a609a9e2a6ff2571d30e9976aa383",
- "sha256:a955e4128ac36797aaffd49ab44ec74a71c11d6938df83b1285492d277db5397",
- "sha256:a97a954a8c2f046d3817c2bce16e3c7e9a9c2afffaf0400f5c16df5172a67c9c",
- "sha256:a97e82c39d9856fe7d4f9b86d8a1e66eff99cf3a8b7ba48202f659703d27c46f",
- "sha256:b55b953a1bdb465f4dc181758570d321db4ac23005f90ffd2b434cc6609a63dd",
- "sha256:bb02929b0d6bfab4c48a79bd805bd7419114606947ec8284476167415171f55b",
- "sha256:bece0a4a49e60e472a6d1f70ac6cdea00f9ab80ff01132f96bd970cdd8a9e5a9",
- "sha256:e41e8951749c4b5c9a2dc5fdbc1a4eec6ab2a140fdae9b460b0f557eed870f4d",
- "sha256:f71d57cc8645f14816ae249407d309be250ad8de93ef61d9709b45a0ddf4050c"
- ],
- "index": "pypi",
- "version": "==1.22.0"
+ "sha256:03ae5850619abb34a879d5f2d4bb4dcd025d6d8fb72f5e461dae84edccfe129f",
+ "sha256:076aee5a3763d41da6bef9565fdf3cb987606f567cd8b104aded2b38b7b47abf",
+ "sha256:0b536b6840e84c1c6a410f3a5aa727821e6108f3454d81a5cd5900999ef04f89",
+ "sha256:15efb7b93806d438e3bc590ca8ef2f953b0ce4f86f337ef4559d31ec6cf9d7dd",
+ "sha256:168259b1b184aa83a514f307352c25c56af111c269ffc109d9704e81f72e764b",
+ "sha256:2638389562bda1635b564490d76713695ff497242a83d9b684d27bb4a6cc9d7a",
+ "sha256:3556c5550de40027d3121ebbb170f61bbe19eb639c7ad0c7b482cd9b560cd23b",
+ "sha256:4a176959b6e7e00b5a0d6f549a479f869829bfd8150282c590deee6d099bbb6e",
+ "sha256:515a8b6edbb904594685da6e176ac9fbea8f73a5ebae947281de6613e27f1956",
+ "sha256:55535c7c2f61e2b2fc817c5cbe1af7cb907c7f011e46ae0a52caa4be1f19afe2",
+ "sha256:59153979d60f5bfe9e4c00e401e24dfe0469ef8da6d68247439d3278f30a180f",
+ "sha256:60cb8e5933193a3cc2912ee29ca331e9c15b2da034f76159b7abc520b3d1233a",
+ "sha256:6767ad399e9327bfdbaa40871be4254d1995f4a3ca3806127f10cec778bd9896",
+ "sha256:76a4f9bce0278becc2da7da3b8ef854bed41a991f4226911a24a9711baad672c",
+ "sha256:8cf33634b60c9cef346663a222d9841d3bbbc0a2f00221d6bcfd0d993d5543f6",
+ "sha256:94dd11d9f13ea1be17bac39c1942f527cbf7065f94953cf62dfe805653da2f8f",
+ "sha256:aafa46b5a39a27aca566198d3312fb3bde95ce9677085efd02c86f7ef6be4ec7",
+ "sha256:badca914580eb46385e7f7e4e426fea6de0a37b9e06bec252e481ae7ec287082",
+ "sha256:d76a26c5118c4d96e264acc9e3242d72e1a2b92e739807b3b69d8d47684b6677"
+ ],
+ "index": "pypi",
+ "version": "==1.22.2"
},
"onnx": {
"hashes": [
- "sha256:0c176ef6e0c3b6bdfb69a43a66dcb8e6ba687437e302c79b4efb75027e1007dc",
- "sha256:186abf5e9189b4b011da290c6d83d5499adefac8f6a07f5d596a192b4c911098",
- "sha256:1e2f92a77d84ae84d25ac84ec84a77b53e427cc7b2eb72ed7d56f2204f885715",
- "sha256:24d73ca7dfd7e6c7339944f89554b4010719899337924fca1447d8f1b5db50d6",
- "sha256:24e654cca4c7285ea339fae15998dd33a5b9e57831d8ecb0bdb1f439c61c5736",
- "sha256:253fd36cbcfcbbbe00e55dde7a09995b22fc2cc825f6de28e5ef9c47f581f264",
- "sha256:358fc6f71841e30ca793a0c1bcd3d0b9c62e436e215773e77a301acb6106cbda",
- "sha256:38e7d106fa98921faf909c2908bfd022eb2c594ecfbd275b60f80e0161cb8476",
- "sha256:3b73128c269ef84694099dad2b06568f2672ce95761a51e0225401695dc2c136",
- "sha256:4138093cbf11e4300b7a7679aedfe1972f81abeb284a731e90dffdf3ef6c5ca3",
- "sha256:48a747b247bc626e049341b8e8c4aeac20aa2306d6b8dff9c9e53a6b14931f1e",
- "sha256:4a53055b8f13747b607dbf835914c2bd60fa7214ee719893b003ceb5fc903220",
- "sha256:526de93b57dd65b136bec85d5b4c6fa4455d6d817bb319b54797d29111b9c407",
- "sha256:57f93db536766b1dcfeee583c02bd86c9f1c9a652253bd4f9bf189a39446de1c",
- "sha256:6205849c935837a934a9ec1fd994f1e858ad7d253e02d0bacbe4add211e4255d",
- "sha256:63aee84aed68c8e14583af48c79d99405844034043dee1efbd1937a78dfa7f6b",
- "sha256:796fa0b80f108f2824cccf5c7298895a925aaea7831330a0bd720ceffc7be3c6",
- "sha256:7e59a6da6e437488059080babc9d96cde7c929cc758ffe4b0171aceaea559ada",
- "sha256:86baab35fc1a317369f2a0cd3816c0eeb9036c29f9a27ed5e8f6935e67cbf0a8",
- "sha256:898915bcba9c1d54abef00f4ea7d60e59fdb2d21d49e7493acac40c121eca4df",
- "sha256:a86e3f956e2a1d39772ae36d28c5b7f20fb6a883ae35971ada261b25548a8b32",
- "sha256:bd31e61ba95c62548543d8de2007fcb18fd2f017a9a36f712bbc08ddad1f25f4",
- "sha256:cc830b15fe11846911fdf068460fd5f20b0f711c8b4c575c68478a6bf2884304",
- "sha256:ce14dbe32a250b7691751e809c232b9a206da138ac055e24b9e60a1500b4d5b8",
- "sha256:d0a3951276ac83fde93632303ad0b3b69e10894b69b7fe5eab0361e4f4212627"
- ],
- "index": "pypi",
- "version": "==1.10.2"
+ "sha256:0cf47c205b376b3763beef92a6de4152f3b1552d6f640d93044938500baf5958",
+ "sha256:3403884c482859f8cf2e0c276da84bd9ac2235d266726f4ddc9625d3fd263218",
+ "sha256:43b32a2f20c94aa98866deae9e4218faf0495144ad05402e918fa279674b6df9",
+ "sha256:4454906de80a351de6929b0896ad605d106c324c3112c92249240e531f68fbba",
+ "sha256:4aa899f74acd4c5543f0efed8bfe98a3b701df75c5ffa179212e3088c51971bb",
+ "sha256:58d4873ec587ac14c44227d8027787edc88cd61596e646e3417f2a826a920898",
+ "sha256:593ca9e11f15afa26b3aaf2d170bb803d4bd86dbd560aa7be4e5f535d03f83d5",
+ "sha256:67c6d2654c1c203e5c839a47900b51f588fd0de71bbd497fb193d30a0b3ec1e9",
+ "sha256:7924d9baa13dbbf335737229f6d068f380d153679f357e495da60007b61cf56d",
+ "sha256:7a2f5d6998fe79aed80fad9d4522140d02c4d29513047e335d5c5355c1ebda5e",
+ "sha256:82221a07707b1ccf71fb18c6abb77f2566517a55d5185809775b5ff008bfb35c",
+ "sha256:89420e5b824d7e182846fe2aa09190ddb41162b261465c6ca928174bc2ac10b7",
+ "sha256:997d91ffd7b7ae7aee09c6d652a896d906be430d425865c759b51a8de5df9fe0",
+ "sha256:9b9f58ea01c1b20b057f55f628df4fc0403bbc160b7282a56e3bb4df5c7fb96f",
+ "sha256:a6e9135f1d02539ca7573f699fb0d31d3c43d10fac1d2d2239a9a1c553506c29",
+ "sha256:ae74bf8fa343b64e2b7fe205091b7f3728887c018ae061d161dd86ec95eb66a8",
+ "sha256:b2de0b117ad77689d308824a0c9eb89539ec28a799b4e2e05b3bb977b0da0b45",
+ "sha256:c3d3503110f2cab2c818f4a7b2bc8abc3bc79649daa39e70d5fb504b208ddb1e",
+ "sha256:d6581dd2122525549d1d8b431b8bf375298993c77bddb8fd0bf0d92611df76a1",
+ "sha256:d6ddbe89e32f885db736d36fcb132784e368331a18c3b6168ac9f561eb462057",
+ "sha256:df85666ab2b88fd9cf9b2504bcb551da39422eab65a143926a8db58f81b09164",
+ "sha256:ea06dbf57a287657b6dc4e189918e4cb451450308589d482117216194d6f83d6",
+ "sha256:eb46f31f12bb0bfdcfb68497d10b20447cf8fa6c4f693120c013e052645357b8",
+ "sha256:eca224c7c2c8ee4072a0743e4898a84a9bdf8297b5e5910a2632e4c4182ffb2a",
+ "sha256:f335d982b8ed201cf767459b993630acfd20c32b100529f70af9f28a26e72167"
+ ],
+ "index": "pypi",
+ "version": "==1.11.0"
},
"onnxruntime-gpu": {
"hashes": [
@@ -564,79 +515,84 @@
},
"pillow": {
"hashes": [
- "sha256:03b27b197deb4ee400ed57d8d4e572d2d8d80f825b6634daf6e2c18c3c6ccfa6",
- "sha256:0b281fcadbb688607ea6ece7649c5d59d4bbd574e90db6cd030e9e85bde9fecc",
- "sha256:0ebd8b9137630a7bbbff8c4b31e774ff05bbb90f7911d93ea2c9371e41039b52",
- "sha256:113723312215b25c22df1fdf0e2da7a3b9c357a7d24a93ebbe80bfda4f37a8d4",
- "sha256:2d16b6196fb7a54aff6b5e3ecd00f7c0bab1b56eee39214b2b223a9d938c50af",
- "sha256:2fd8053e1f8ff1844419842fd474fc359676b2e2a2b66b11cc59f4fa0a301315",
- "sha256:31b265496e603985fad54d52d11970383e317d11e18e856971bdbb86af7242a4",
- "sha256:3586e12d874ce2f1bc875a3ffba98732ebb12e18fb6d97be482bd62b56803281",
- "sha256:47f5cf60bcb9fbc46011f75c9b45a8b5ad077ca352a78185bd3e7f1d294b98bb",
- "sha256:490e52e99224858f154975db61c060686df8a6b3f0212a678e5d2e2ce24675c9",
- "sha256:500d397ddf4bbf2ca42e198399ac13e7841956c72645513e8ddf243b31ad2128",
- "sha256:52abae4c96b5da630a8b4247de5428f593465291e5b239f3f843a911a3cf0105",
- "sha256:6579f9ba84a3d4f1807c4aab4be06f373017fc65fff43498885ac50a9b47a553",
- "sha256:68e06f8b2248f6dc8b899c3e7ecf02c9f413aab622f4d6190df53a78b93d97a5",
- "sha256:6c5439bfb35a89cac50e81c751317faea647b9a3ec11c039900cd6915831064d",
- "sha256:72c3110228944019e5f27232296c5923398496b28be42535e3b2dc7297b6e8b6",
- "sha256:72f649d93d4cc4d8cf79c91ebc25137c358718ad75f99e99e043325ea7d56100",
- "sha256:7aaf07085c756f6cb1c692ee0d5a86c531703b6e8c9cae581b31b562c16b98ce",
- "sha256:80fe92813d208ce8aa7d76da878bdc84b90809f79ccbad2a288e9bcbeac1d9bd",
- "sha256:95545137fc56ce8c10de646074d242001a112a92de169986abd8c88c27566a05",
- "sha256:97b6d21771da41497b81652d44191489296555b761684f82b7b544c49989110f",
- "sha256:98cb63ca63cb61f594511c06218ab4394bf80388b3d66cd61d0b1f63ee0ea69f",
- "sha256:9f3b4522148586d35e78313db4db0df4b759ddd7649ef70002b6c3767d0fdeb7",
- "sha256:a09a9d4ec2b7887f7a088bbaacfd5c07160e746e3d47ec5e8050ae3b2a229e9f",
- "sha256:b5050d681bcf5c9f2570b93bee5d3ec8ae4cf23158812f91ed57f7126df91762",
- "sha256:bb47a548cea95b86494a26c89d153fd31122ed65255db5dcbc421a2d28eb3379",
- "sha256:bc462d24500ba707e9cbdef436c16e5c8cbf29908278af053008d9f689f56dee",
- "sha256:c2067b3bb0781f14059b112c9da5a91c80a600a97915b4f48b37f197895dd925",
- "sha256:d154ed971a4cc04b93a6d5b47f37948d1f621f25de3e8fa0c26b2d44f24e3e8f",
- "sha256:d5dcea1387331c905405b09cdbfb34611050cc52c865d71f2362f354faee1e9f",
- "sha256:ee6e2963e92762923956fe5d3479b1fdc3b76c83f290aad131a2f98c3df0593e",
- "sha256:fd0e5062f11cb3e730450a7d9f323f4051b532781026395c4323b8ad055523c4"
- ],
- "index": "pypi",
- "version": "==9.0.0"
+ "sha256:011233e0c42a4a7836498e98c1acf5e744c96a67dd5032a6f666cc1fb97eab97",
+ "sha256:0f29d831e2151e0b7b39981756d201f7108d3d215896212ffe2e992d06bfe049",
+ "sha256:12875d118f21cf35604176872447cdb57b07126750a33748bac15e77f90f1f9c",
+ "sha256:14d4b1341ac07ae07eb2cc682f459bec932a380c3b122f5540432d8977e64eae",
+ "sha256:1c3c33ac69cf059bbb9d1a71eeaba76781b450bc307e2291f8a4764d779a6b28",
+ "sha256:1d19397351f73a88904ad1aee421e800fe4bbcd1aeee6435fb62d0a05ccd1030",
+ "sha256:253e8a302a96df6927310a9d44e6103055e8fb96a6822f8b7f514bb7ef77de56",
+ "sha256:2632d0f846b7c7600edf53c48f8f9f1e13e62f66a6dbc15191029d950bfed976",
+ "sha256:335ace1a22325395c4ea88e00ba3dc89ca029bd66bd5a3c382d53e44f0ccd77e",
+ "sha256:413ce0bbf9fc6278b2d63309dfeefe452835e1c78398efb431bab0672fe9274e",
+ "sha256:5100b45a4638e3c00e4d2320d3193bdabb2d75e79793af7c3eb139e4f569f16f",
+ "sha256:514ceac913076feefbeaf89771fd6febde78b0c4c1b23aaeab082c41c694e81b",
+ "sha256:528a2a692c65dd5cafc130de286030af251d2ee0483a5bf50c9348aefe834e8a",
+ "sha256:6295f6763749b89c994fcb6d8a7f7ce03c3992e695f89f00b741b4580b199b7e",
+ "sha256:6c8bc8238a7dfdaf7a75f5ec5a663f4173f8c367e5a39f87e720495e1eed75fa",
+ "sha256:718856856ba31f14f13ba885ff13874be7fefc53984d2832458f12c38205f7f7",
+ "sha256:7f7609a718b177bf171ac93cea9fd2ddc0e03e84d8fa4e887bdfc39671d46b00",
+ "sha256:80ca33961ced9c63358056bd08403ff866512038883e74f3a4bf88ad3eb66838",
+ "sha256:80fe64a6deb6fcfdf7b8386f2cf216d329be6f2781f7d90304351811fb591360",
+ "sha256:81c4b81611e3a3cb30e59b0cf05b888c675f97e3adb2c8672c3154047980726b",
+ "sha256:855c583f268edde09474b081e3ddcd5cf3b20c12f26e0d434e1386cc5d318e7a",
+ "sha256:9bfdb82cdfeccec50aad441afc332faf8606dfa5e8efd18a6692b5d6e79f00fd",
+ "sha256:a5d24e1d674dd9d72c66ad3ea9131322819ff86250b30dc5821cbafcfa0b96b4",
+ "sha256:a9f44cd7e162ac6191491d7249cceb02b8116b0f7e847ee33f739d7cb1ea1f70",
+ "sha256:b5b3f092fe345c03bca1e0b687dfbb39364b21ebb8ba90e3fa707374b7915204",
+ "sha256:b9618823bd237c0d2575283f2939655f54d51b4527ec3972907a927acbcc5bfc",
+ "sha256:cef9c85ccbe9bee00909758936ea841ef12035296c748aaceee535969e27d31b",
+ "sha256:d21237d0cd37acded35154e29aec853e945950321dd2ffd1a7d86fe686814669",
+ "sha256:d3c5c79ab7dfce6d88f1ba639b77e77a17ea33a01b07b99840d6ed08031cb2a7",
+ "sha256:d9d7942b624b04b895cb95af03a23407f17646815495ce4547f0e60e0b06f58e",
+ "sha256:db6d9fac65bd08cea7f3540b899977c6dee9edad959fa4eaf305940d9cbd861c",
+ "sha256:ede5af4a2702444a832a800b8eb7f0a7a1c0eed55b644642e049c98d589e5092",
+ "sha256:effb7749713d5317478bb3acb3f81d9d7c7f86726d41c1facca068a04cf5bb4c",
+ "sha256:f154d173286a5d1863637a7dcd8c3437bb557520b01bddb0be0258dcb72696b5",
+ "sha256:f25ed6e28ddf50de7e7ea99d7a976d6a9c415f03adcaac9c41ff6ff41b6d86ac"
+ ],
+ "index": "pypi",
+ "version": "==9.0.1"
},
"platformdirs": {
"hashes": [
- "sha256:1d7385c7db91728b83efd0ca99a5afb296cab9d0ed8313a45ed8ba17967ecfca",
- "sha256:440633ddfebcc36264232365d7840a970e75e1018d15b4327d11f91909045fda"
+ "sha256:7535e70dfa32e84d4b34996ea99c5e432fa29a708d0f4e394bbcb2a8faa4f16d",
+ "sha256:bcae7cab893c2d310a711b70b24efb93334febe65f8de776ee320b517471e227"
],
"markers": "python_version >= '3.7'",
- "version": "==2.4.1"
+ "version": "==2.5.1"
},
"protobuf": {
"hashes": [
- "sha256:038daf4fa38a7e818dd61f51f22588d61755160a98db087a046f80d66b855942",
- "sha256:28ccea56d4dc38d35cd70c43c2da2f40ac0be0a355ef882242e8586c6d66666f",
- "sha256:36d90676d6f426718463fe382ec6274909337ca6319d375eebd2044e6c6ac560",
- "sha256:3cd0458870ea7d1c58e948ac8078f6ba8a7ecc44a57e03032ed066c5bb318089",
- "sha256:5935c8ce02e3d89c7900140a8a42b35bc037ec07a6aeb61cc108be8d3c9438a6",
- "sha256:615b426a177780ce381ecd212edc1e0f70db8557ed72560b82096bd36b01bc04",
- "sha256:62a8e4baa9cb9e064eb62d1002eca820857ab2138440cb4b3ea4243830f94ca7",
- "sha256:655264ed0d0efe47a523e2255fc1106a22f6faab7cc46cfe99b5bae085c2a13e",
- "sha256:6e8ea9173403219239cdfd8d946ed101f2ab6ecc025b0fda0c6c713c35c9981d",
- "sha256:71b0250b0cfb738442d60cab68abc166de43411f2a4f791d31378590bfb71bd7",
- "sha256:74f33edeb4f3b7ed13d567881da8e5a92a72b36495d57d696c2ea1ae0cfee80c",
- "sha256:77d2fadcf369b3f22859ab25bd12bb8e98fb11e05d9ff9b7cd45b711c719c002",
- "sha256:8b30a7de128c46b5ecb343917d9fa737612a6e8280f440874e5cc2ba0d79b8f6",
- "sha256:8e51561d72efd5bd5c91490af1f13e32bcba8dab4643761eb7de3ce18e64a853",
- "sha256:a529e7df52204565bcd33738a7a5f288f3d2d37d86caa5d78c458fa5fabbd54d",
- "sha256:b691d996c6d0984947c4cf8b7ae2fe372d99b32821d0584f0b90277aa36982d3",
- "sha256:d80f80eb175bf5f1169139c2e0c5ada98b1c098e2b3c3736667f28cbbea39fc8",
- "sha256:d83e1ef8cb74009bebee3e61cc84b1c9cd04935b72bca0cbc83217d140424995",
- "sha256:d8919368410110633717c406ab5c97e8df5ce93020cfcf3012834f28b1fab1ea",
- "sha256:db3532d9f7a6ebbe2392041350437953b6d7a792de10e629c1e4f5a6b1fe1ac6",
- "sha256:e7b24c11df36ee8e0c085e5b0dc560289e4b58804746fb487287dda51410f1e2",
- "sha256:e7e8d2c20921f8da0dea277dfefc6abac05903ceac8e72839b2da519db69206b",
- "sha256:e813b1c9006b6399308e917ac5d298f345d95bb31f46f02b60cd92970a9afa17",
- "sha256:fd390367fc211cc0ffcf3a9e149dfeca78fecc62adb911371db0cec5c8b7472d"
+ "sha256:072fbc78d705d3edc7ccac58a62c4c8e0cec856987da7df8aca86e647be4e35c",
+ "sha256:09297b7972da685ce269ec52af761743714996b4381c085205914c41fcab59fb",
+ "sha256:16f519de1313f1b7139ad70772e7db515b1420d208cb16c6d7858ea989fc64a9",
+ "sha256:1c91ef4110fdd2c590effb5dca8fdbdcb3bf563eece99287019c4204f53d81a4",
+ "sha256:3112b58aac3bac9c8be2b60a9daf6b558ca3f7681c130dcdd788ade7c9ffbdca",
+ "sha256:36cecbabbda242915529b8ff364f2263cd4de7c46bbe361418b5ed859677ba58",
+ "sha256:4276cdec4447bd5015453e41bdc0c0c1234eda08420b7c9a18b8d647add51e4b",
+ "sha256:435bb78b37fc386f9275a7035fe4fb1364484e38980d0dd91bc834a02c5ec909",
+ "sha256:48ed3877fa43e22bcacc852ca76d4775741f9709dd9575881a373bd3e85e54b2",
+ "sha256:54a1473077f3b616779ce31f477351a45b4fef8c9fd7892d6d87e287a38df368",
+ "sha256:69da7d39e39942bd52848438462674c463e23963a1fdaa84d88df7fbd7e749b2",
+ "sha256:6cbc312be5e71869d9d5ea25147cdf652a6781cf4d906497ca7690b7b9b5df13",
+ "sha256:7bb03bc2873a2842e5ebb4801f5c7ff1bfbdf426f85d0172f7644fcda0671ae0",
+ "sha256:7ca7da9c339ca8890d66958f5462beabd611eca6c958691a8fe6eccbd1eb0c6e",
+ "sha256:835a9c949dc193953c319603b2961c5c8f4327957fe23d914ca80d982665e8ee",
+ "sha256:84123274d982b9e248a143dadd1b9815049f4477dc783bf84efe6250eb4b836a",
+ "sha256:8961c3a78ebfcd000920c9060a262f082f29838682b1f7201889300c1fbe0616",
+ "sha256:96bd766831596d6014ca88d86dc8fe0fb2e428c0b02432fd9db3943202bf8c5e",
+ "sha256:9df0c10adf3e83015ced42a9a7bd64e13d06c4cf45c340d2c63020ea04499d0a",
+ "sha256:b38057450a0c566cbd04890a40edf916db890f2818e8682221611d78dc32ae26",
+ "sha256:bd95d1dfb9c4f4563e6093a9aa19d9c186bf98fa54da5252531cc0d3a07977e7",
+ "sha256:c1068287025f8ea025103e37d62ffd63fec8e9e636246b89c341aeda8a67c934",
+ "sha256:c438268eebb8cf039552897d78f402d734a404f1360592fef55297285f7f953f",
+ "sha256:cdc076c03381f5c1d9bb1abdcc5503d9ca8b53cf0a9d31a9f6754ec9e6c8af0f",
+ "sha256:f358aa33e03b7a84e0d91270a4d4d8f5df6921abe99a377828839e8ed0c04e07",
+ "sha256:f51d5a9f137f7a2cec2d326a74b6e3fc79d635d69ffe1b036d39fc7d75430d37"
],
"markers": "python_version >= '3.5'",
- "version": "==3.19.1"
+ "version": "==3.19.4"
},
"psutil": {
"hashes": [
@@ -644,6 +600,7 @@
"sha256:1070a9b287846a21a5d572d6dddd369517510b68710fca56b0e9e02fd24bed9a",
"sha256:1d7b433519b9a38192dfda962dd8f44446668c009833e1429a52424624f408b4",
"sha256:3151a58f0fbd8942ba94f7c31c7e6b310d2989f4da74fcbf28b934374e9bf841",
+ "sha256:32acf55cb9a8cbfb29167cd005951df81b567099295291bcfd1027365b36591d",
"sha256:3611e87eea393f779a35b192b46a164b1d01167c9d323dda9b1e527ea69d697d",
"sha256:3d00a664e31921009a84367266b35ba0aac04a2a6cad09c550a89041034d19a0",
"sha256:4e2fb92e3aeae3ec3b7b66c528981fd327fb93fd906a77215200404444ec1845",
@@ -662,8 +619,12 @@
"sha256:9b51917c1af3fa35a3f2dabd7ba96a2a4f19df3dec911da73875e1edaf22a40b",
"sha256:b2237f35c4bbae932ee98902a08050a27821f8f6dfa880a47195e5993af4702d",
"sha256:c3400cae15bdb449d518545cbd5b649117de54e3596ded84aacabfbb3297ead2",
+ "sha256:c51f1af02334e4b516ec221ee26b8fdf105032418ca5a5ab9737e8c87dafe203",
"sha256:cb8d10461c1ceee0c25a64f2dd54872b70b89c26419e147a05a10b753ad36ec2",
+ "sha256:d62a2796e08dd024b8179bd441cb714e0f81226c352c802fca0fd3f89eeacd94",
"sha256:df2c8bd48fb83a8408c8390b143c6a6fa10cb1a674ca664954de193fdcab36a9",
+ "sha256:e5c783d0b1ad6ca8a5d3e7b680468c9c926b804be83a3a8e95141b05c39c9f64",
+ "sha256:e9805fed4f2a81de98ae5fe38b75a74c6e6ad2df8a5c479594c7629a1fe35f56",
"sha256:ea42d747c5f71b5ccaa6897b216a7dadb9f52c72a0fe2b872ef7d3e1eacf3ba3",
"sha256:ef216cc9feb60634bda2f341a9559ac594e2eeaadd0ba187a4c2eb5b5d40b91c",
"sha256:ff0d41f8b3e9ebb6b6110057e40019a432e96aae2008951121ba4e56040b84f3"
@@ -707,39 +668,39 @@
},
"pycryptodome": {
"hashes": [
- "sha256:1181c90d1a6aee68a84826825548d0db1b58d8541101f908d779d601d1690586",
- "sha256:12c7343aec5a3b3df5c47265281b12b611f26ec9367b6129199d67da54b768c1",
- "sha256:212c7f7fe11cad9275fbcff50ca977f1c6643f13560d081e7b0f70596df447b8",
- "sha256:32d15da81959faea6cbed95df2bb44f7f796211c110cf90b5ad3b2aeeb97fc8e",
- "sha256:341c6bbf932c406b4f3ee2372e8589b67ac0cf4e99e7dc081440f43a3cde9f0f",
- "sha256:3558616f45d8584aee3eba27559bc6fd0ba9be6c076610ed3cc62bd5229ffdc3",
- "sha256:39da5807aa1ff820799c928f745f89432908bf6624b9e981d2d7f9e55d91b860",
- "sha256:3f2f3dd596c6128d91314e60a6bcf4344610ef0e97f4ae4dd1770f86dd0748d8",
- "sha256:4cded12e13785bbdf4ba1ff5fb9d261cd98162145f869e4fbc4a4b9083392f0b",
- "sha256:5a8c24d39d4a237dbfe181ea6593792bf9b5582c7fcfa7b8e0e12fda5eec07af",
- "sha256:5d4264039a2087977f50072aaff2346d1c1c101cb359f9444cf92e3d1f42b4cd",
- "sha256:6bb0d340c93bcb674ea8899e2f6408ec64c6c21731a59481332b4b2a8143cc60",
- "sha256:6f8f5b7b53516da7511951910ab458e799173722c91fea54e2ba2f56d102e4aa",
- "sha256:90ad3381ccdc6a24cc2841e295706a168f32abefe64c679695712acac71fd5da",
- "sha256:93acad54a72d81253242eb0a15064be559ec9d989e5173286dc21cad19f01765",
- "sha256:9ea2f6674c803602a7c0437fccdc2ea036707e60456974fe26ca263bd501ec45",
- "sha256:a6e1bcd9d5855f1a3c0f8d585f44c81b08f39a02754007f374fb8db9605ba29c",
- "sha256:a78e4324e566b5fbc2b51e9240950d82fa9e1c7eb77acdf27f58712f65622c1d",
- "sha256:aceb1d217c3a025fb963849071446cf3aca1353282fe1c3cb7bd7339a4d47947",
- "sha256:aed7eb4b64c600fbc5e6d4238991ad1b4179a558401f203d1fcbd24883748982",
- "sha256:b07a4238465eb8c65dd5df2ab8ba6df127e412293c0ed7656c003336f557a100",
- "sha256:b91404611767a7485837a6f1fd20cf9a5ae0ad362040a022cd65827ecb1b0d00",
- "sha256:d8083de50f6dec56c3c6f270fb193590999583a1b27c9c75bc0b5cac22d438cc",
- "sha256:d845c587ceb82ac7cbac7d0bf8c62a1a0fe7190b028b322da5ca65f6e5a18b9e",
- "sha256:db66ccda65d5d20c17b00768e462a86f6f540f9aea8419a7f76cc7d9effd82cd",
- "sha256:dc88355c4b261ed259268e65705b28b44d99570337694d593f06e3b1698eaaf3",
- "sha256:de0b711d673904dd6c65307ead36cb76622365a393569bf880895cba21195b7a",
- "sha256:e05f994f30f1cda3cbe57441f41220d16731cf99d868bb02a8f6484c454c206b",
- "sha256:e80f7469b0b3ea0f694230477d8501dc5a30a717e94fddd4821e6721f3053eae",
- "sha256:f699360ae285fcae9c8f53ca6acf33796025a82bb0ccd7c1c551b04c1726def3"
- ],
- "index": "pypi",
- "version": "==3.12.0"
+ "sha256:028dcbf62d128b4335b61c9fbb7dd8c376594db607ef36d5721ee659719935d5",
+ "sha256:12ef157eb1e01a157ca43eda275fa68f8db0dd2792bc4fe00479ab8f0e6ae075",
+ "sha256:2562de213960693b6d657098505fd4493c45f3429304da67efcbeb61f0edfe89",
+ "sha256:27e92c1293afcb8d2639baf7eb43f4baada86e4de0f1fb22312bfc989b95dae2",
+ "sha256:36e3242c4792e54ed906c53f5d840712793dc68b726ec6baefd8d978c5282d30",
+ "sha256:50a5346af703330944bea503106cd50c9c2212174cfcb9939db4deb5305a8367",
+ "sha256:53dedbd2a6a0b02924718b520a723e88bcf22e37076191eb9b91b79934fb2192",
+ "sha256:69f05aaa90c99ac2f2af72d8d7f185f729721ad7c4be89e9e3d0ab101b0ee875",
+ "sha256:75a3a364fee153e77ed889c957f6f94ec6d234b82e7195b117180dcc9fc16f96",
+ "sha256:766a8e9832128c70012e0c2b263049506cbf334fb21ff7224e2704102b6ef59e",
+ "sha256:7fb90a5000cc9c9ff34b4d99f7f039e9c3477700e309ff234eafca7b7471afc0",
+ "sha256:893f32210de74b9f8ac869ed66c97d04e7d351182d6d39ebd3b36d3db8bda65d",
+ "sha256:8b5c28058102e2974b9868d72ae5144128485d466ba8739abd674b77971454cc",
+ "sha256:924b6aad5386fb54f2645f22658cb0398b1f25bc1e714a6d1522c75d527deaa5",
+ "sha256:9924248d6920b59c260adcae3ee231cd5af404ac706ad30aa4cd87051bf09c50",
+ "sha256:9ec761a35dbac4a99dcbc5cd557e6e57432ddf3e17af8c3c86b44af9da0189c0",
+ "sha256:a36ab51674b014ba03da7f98b675fcb8eabd709a2d8e18219f784aba2db73b72",
+ "sha256:aae395f79fa549fb1f6e3dc85cf277f0351e15a22e6547250056c7f0c990d6a5",
+ "sha256:c880a98376939165b7dc504559f60abe234b99e294523a273847f9e7756f4132",
+ "sha256:ce7a875694cd6ccd8682017a7c06c6483600f151d8916f2b25cf7a439e600263",
+ "sha256:d1b7739b68a032ad14c5e51f7e4e1a5f92f3628bba024a2bda1f30c481fc85d8",
+ "sha256:dcd65355acba9a1d0fc9b923875da35ed50506e339b35436277703d7ace3e222",
+ "sha256:e04e40a7f8c1669195536a37979dd87da2c32dbdc73d6fe35f0077b0c17c803b",
+ "sha256:e0c04c41e9ade19fbc0eff6aacea40b831bfcb2c91c266137bcdfd0d7b2f33ba",
+ "sha256:e24d4ec4b029611359566c52f31af45c5aecde7ef90bf8f31620fd44c438efe7",
+ "sha256:e64738207a02a83590df35f59d708bf1e7ea0d6adce712a777be2967e5f7043c",
+ "sha256:ea56a35fd0d13121417d39a83f291017551fa2c62d6daa6b04af6ece7ed30d84",
+ "sha256:f2772af1c3ef8025c85335f8b828d0193fa1e43256621f613280e2c81bfad423",
+ "sha256:f403a3e297a59d94121cb3ee4b1cf41f844332940a62d71f9e4a009cc3533493",
+ "sha256:f572a3ff7b6029dd9b904d6be4e0ce9e309dcb847b03e3ac8698d9d23bb36525"
+ ],
+ "index": "pypi",
+ "version": "==3.14.1"
},
"pyflakes": {
"hashes": [
@@ -767,16 +728,16 @@
},
"pyopencl": {
"hashes": [
- "sha256:0a7cc1a461a4e57aa142b558b678fe23114aa6314d4a0c969bd2e2b5a02b65ad",
- "sha256:2042811175bc8c915f5b56d8aa43561a5c62d6a145d67309e1e3f93d3b964744",
- "sha256:334a6cdde7ef18e4370604b9a1d6551b055e8828a4da004893f26091669b561b",
- "sha256:3678c8b02494e6d9627647c037aabed8244088d51cc6de8605f3854747985ac1",
- "sha256:8bc2495cc4d78e8ca2358d3d14c5ba4b078cdbdb1a38e765a10c70e13df4871c",
- "sha256:93f0c93e0fb6607ba0ee9bd11165edaf6406bf303b4ec795c3d2caa2e44f394e",
- "sha256:e007e4e932170f0343cf1ab7733a2568aa8fda89f9a62e02aa359066084ee5c9"
+ "sha256:1ab792ff11a7ff271b1ba39686bd7aae271168e813a7e771bff6aa611ada383b",
+ "sha256:24c6d9a0a1ff7609f3d7365ebd8778616a5433c426566c2c8e35ffab00ef22c4",
+ "sha256:3b3f0d8b69923064f6d64b520c594aa2506e96ab398a0f1ed4895c4fceb20ff4",
+ "sha256:4bea0e965252f477204a87cc73eca492de5c30252198bc6679ef4968880a2443",
+ "sha256:7d9ec6c8daf283666dd577d6bcc49ab3d5b44c9532c2f642daf7e9c85b73606f",
+ "sha256:d8af9c4ea375f51237059124f7bab1fd32e32a8893997ffa05dff88efc4d9274",
+ "sha256:dee72b29c4e47a99f5ecc7fc7ba70bfc3d85e3cc9734765d6992380f5296787b"
],
"index": "pypi",
- "version": "==2021.2.11"
+ "version": "==2022.1"
},
"pyserial": {
"hashes": [
@@ -796,10 +757,10 @@
},
"pytools": {
"hashes": [
- "sha256:db6cf83c9ba0a165d545029e2301621486d1e9ef295684072e5cd75316a13755"
+ "sha256:197aacf6e1f5d60c715b92438792acb7702aed59ebbfb147fa84eda780e54fee"
],
"markers": "python_version ~= '3.6'",
- "version": "==2021.2.9"
+ "version": "==2022.1"
},
"pyyaml": {
"hashes": [
@@ -911,11 +872,11 @@
},
"sentry-sdk": {
"hashes": [
- "sha256:2a1757d6611e4bec7d672c2b7ef45afef79fed201d064f53994753303944f5a8",
- "sha256:e4cb107e305b2c1b919414775fa73a9997f996447417d22b98e7610ded1e9eb5"
+ "sha256:1ab34e3851a34aeb3d1af1a0f77cec73978c4e9698e5210d050e4932953cb241",
+ "sha256:ac2a50128409d57655279817aedcb7800cace1f76b266f3dd62055d5afd6e098"
],
"index": "pypi",
- "version": "==1.5.1"
+ "version": "==1.5.6"
},
"setproctitle": {
"hashes": [
@@ -946,11 +907,11 @@
},
"setuptools": {
"hashes": [
- "sha256:5c89b1a14a67ac5f0956f1cb0aeb7d1d3f4c8ba4e4e1ab7bf1af4933f9a2f0fe",
- "sha256:675fcebecb43c32eb930481abf907619137547f4336206e4d673180242e1a278"
+ "sha256:2347b2b432c891a863acadca2da9ac101eae6169b1d3dfee2ec605ecd50dbfe5",
+ "sha256:e4f30b9f84e5ab3decf945113119649fec09c1fc3507c6ebffec75646c56e62b"
],
"markers": "python_version >= '3.7'",
- "version": "==60.2.0"
+ "version": "==60.9.3"
},
"six": {
"hashes": [
@@ -1002,19 +963,19 @@
},
"typing-extensions": {
"hashes": [
- "sha256:4ca091dea149f945ec56afb48dae714f21e8692ef22a395223bcd328961b6a0e",
- "sha256:7f001e5ac290a0c0401508864c7ec868be4e701886d5b573a9528ed3973d9d3b"
+ "sha256:1a9462dcc3347a79b1f1c0271fbe79e844580bb598bafa1ed208b94da3cdcd42",
+ "sha256:21c85e0fe4b9a155d0799430b0ad741cdce7e359660ccbd8b530613e8df88ce2"
],
- "markers": "python_version < '3.10'",
- "version": "==4.0.1"
+ "markers": "python_version >= '3.6'",
+ "version": "==4.1.1"
},
"urllib3": {
"hashes": [
- "sha256:4987c65554f7a2dbf30c18fd48778ef124af6fab771a377103da0585e2336ece",
- "sha256:c4fdf4019605b6e5423637e01bc9fe4daef873709a7973e195ceba0a62bbc844"
+ "sha256:000ca7f471a233c2251c6c7023ee85305721bfdf18621ebff4fd17a8653427ed",
+ "sha256:0e7c33d9a63e7ddfcb86780aac87befc2fbddf46c58dbb487e0855f7ceec283c"
],
"index": "pypi",
- "version": "==1.26.7"
+ "version": "==1.26.8"
},
"utm": {
"hashes": [
@@ -1025,19 +986,19 @@
},
"websocket-client": {
"hashes": [
- "sha256:1315816c0acc508997eb3ae03b9d3ff619c9d12d544c9a9b553704b1cc4f6af5",
- "sha256:2eed4cc58e4d65613ed6114af2f380f7910ff416fc8c46947f6e76b6815f56c0"
+ "sha256:074e2ed575e7c822fc0940d31c3ac9bb2b1142c303eafcf3e304e6ce035522e8",
+ "sha256:6278a75065395418283f887de7c3beafb3aa68dada5cacbe4b214e8d26da499b"
],
"index": "pypi",
- "version": "==1.2.3"
+ "version": "==1.3.1"
},
"werkzeug": {
"hashes": [
- "sha256:63d3dc1cf60e7b7e35e97fa9861f7397283b75d765afcaefd993d6046899de8f",
- "sha256:aa2bb6fc8dee8d6c504c0ac1e7f5f7dc5810a9903e793b6f715a9f015bdadb9a"
+ "sha256:1421ebfc7648a39a5c58c601b154165d05cf47a3cd0ccb70857cbdacf6c8f2b8",
+ "sha256:b863f8ff057c522164b6067c9e28b041161b4be5ba4d0daceeaa50a163822d3c"
],
"markers": "python_version >= '3.6'",
- "version": "==2.0.2"
+ "version": "==2.0.3"
},
"wrapt": {
"hashes": [
@@ -1139,11 +1100,11 @@
},
"breathe": {
"hashes": [
- "sha256:19faef9d63c39acb3026eeaf6e6fdc5edb95334ed36fe0c627b358d6a2d5e0da",
- "sha256:925eeff96c6640cd857e4ddeae6f75464a1d5e2e08ee56dccce4043583ae2050"
+ "sha256:553aeffb00efc2cf96c4c9ed388d6ee8036ecd6d1bd9bd0c656fc25ca271bd3c",
+ "sha256:c4b9ff4d5298fd91518d336ede28b6a2d8cacc685d0eae17eb20e760e06bb904"
],
"index": "pypi",
- "version": "==4.31.0"
+ "version": "==4.33.1"
},
"certifi": {
"hashes": [
@@ -1218,11 +1179,11 @@
},
"charset-normalizer": {
"hashes": [
- "sha256:876d180e9d7432c5d1dfd4c5d26b72f099d503e8fcc0feb7532c9289be60fcbd",
- "sha256:cb957888737fc0bbcd78e3df769addb41fd1ff8cf950dc9e7ad7793f1bf44455"
+ "sha256:2857e29ff0d34db842cd7ca3230549d1a697f96ee6d3fb071cfa6c7393832597",
+ "sha256:6881edbebdb17b39b4eaaa821b438bf6eddffb4468cf344f09f89def34a8b1df"
],
"markers": "python_version >= '3'",
- "version": "==2.0.10"
+ "version": "==2.0.12"
},
"control": {
"hashes": [
@@ -1233,56 +1194,50 @@
},
"coverage": {
"hashes": [
- "sha256:01774a2c2c729619760320270e42cd9e797427ecfddd32c2a7b639cdc481f3c0",
- "sha256:03b20e52b7d31be571c9c06b74746746d4eb82fc260e594dc662ed48145e9efd",
- "sha256:0a7726f74ff63f41e95ed3a89fef002916c828bb5fcae83b505b49d81a066884",
- "sha256:1219d760ccfafc03c0822ae2e06e3b1248a8e6d1a70928966bafc6838d3c9e48",
- "sha256:13362889b2d46e8d9f97c421539c97c963e34031ab0cb89e8ca83a10cc71ac76",
- "sha256:174cf9b4bef0db2e8244f82059a5a72bd47e1d40e71c68ab055425172b16b7d0",
- "sha256:17e6c11038d4ed6e8af1407d9e89a2904d573be29d51515f14262d7f10ef0a64",
- "sha256:215f8afcc02a24c2d9a10d3790b21054b58d71f4b3c6f055d4bb1b15cecce685",
- "sha256:22e60a3ca5acba37d1d4a2ee66e051f5b0e1b9ac950b5b0cf4aa5366eda41d47",
- "sha256:2641f803ee9f95b1f387f3e8f3bf28d83d9b69a39e9911e5bfee832bea75240d",
- "sha256:276651978c94a8c5672ea60a2656e95a3cce2a3f31e9fb2d5ebd4c215d095840",
- "sha256:3f7c17209eef285c86f819ff04a6d4cbee9b33ef05cbcaae4c0b4e8e06b3ec8f",
- "sha256:3feac4084291642165c3a0d9eaebedf19ffa505016c4d3db15bfe235718d4971",
- "sha256:49dbff64961bc9bdd2289a2bda6a3a5a331964ba5497f694e2cbd540d656dc1c",
- "sha256:4e547122ca2d244f7c090fe3f4b5a5861255ff66b7ab6d98f44a0222aaf8671a",
- "sha256:5829192582c0ec8ca4a2532407bc14c2f338d9878a10442f5d03804a95fac9de",
- "sha256:5d6b09c972ce9200264c35a1d53d43ca55ef61836d9ec60f0d44273a31aa9f17",
- "sha256:600617008aa82032ddeace2535626d1bc212dfff32b43989539deda63b3f36e4",
- "sha256:619346d57c7126ae49ac95b11b0dc8e36c1dd49d148477461bb66c8cf13bb521",
- "sha256:63c424e6f5b4ab1cf1e23a43b12f542b0ec2e54f99ec9f11b75382152981df57",
- "sha256:6dbc1536e105adda7a6312c778f15aaabe583b0e9a0b0a324990334fd458c94b",
- "sha256:6e1394d24d5938e561fbeaa0cd3d356207579c28bd1792f25a068743f2d5b282",
- "sha256:86f2e78b1eff847609b1ca8050c9e1fa3bd44ce755b2ec30e70f2d3ba3844644",
- "sha256:8bdfe9ff3a4ea37d17f172ac0dff1e1c383aec17a636b9b35906babc9f0f5475",
- "sha256:8e2c35a4c1f269704e90888e56f794e2d9c0262fb0c1b1c8c4ee44d9b9e77b5d",
- "sha256:92b8c845527eae547a2a6617d336adc56394050c3ed8a6918683646328fbb6da",
- "sha256:9365ed5cce5d0cf2c10afc6add145c5037d3148585b8ae0e77cc1efdd6aa2953",
- "sha256:9a29311bd6429be317c1f3fe4bc06c4c5ee45e2fa61b2a19d4d1d6111cb94af2",
- "sha256:9a2b5b52be0a8626fcbffd7e689781bf8c2ac01613e77feda93d96184949a98e",
- "sha256:a4bdeb0a52d1d04123b41d90a4390b096f3ef38eee35e11f0b22c2d031222c6c",
- "sha256:a9c8c4283e17690ff1a7427123ffb428ad6a52ed720d550e299e8291e33184dc",
- "sha256:b637c57fdb8be84e91fac60d9325a66a5981f8086c954ea2772efe28425eaf64",
- "sha256:bf154ba7ee2fd613eb541c2bc03d3d9ac667080a737449d1a3fb342740eb1a74",
- "sha256:c254b03032d5a06de049ce8bca8338a5185f07fb76600afff3c161e053d88617",
- "sha256:c332d8f8d448ded473b97fefe4a0983265af21917d8b0cdcb8bb06b2afe632c3",
- "sha256:c7912d1526299cb04c88288e148c6c87c0df600eca76efd99d84396cfe00ef1d",
- "sha256:cfd9386c1d6f13b37e05a91a8583e802f8059bebfccde61a418c5808dea6bbfa",
- "sha256:d5d2033d5db1d58ae2d62f095e1aefb6988af65b4b12cb8987af409587cc0739",
- "sha256:dca38a21e4423f3edb821292e97cec7ad38086f84313462098568baedf4331f8",
- "sha256:e2cad8093172b7d1595b4ad66f24270808658e11acf43a8f95b41276162eb5b8",
- "sha256:e3db840a4dee542e37e09f30859f1612da90e1c5239a6a2498c473183a50e781",
- "sha256:edcada2e24ed68f019175c2b2af2a8b481d3d084798b8c20d15d34f5c733fa58",
- "sha256:f467bbb837691ab5a8ca359199d3429a11a01e6dfb3d9dcc676dc035ca93c0a9",
- "sha256:f506af4f27def639ba45789fa6fde45f9a217da0be05f8910458e4557eed020c",
- "sha256:f614fc9956d76d8a88a88bb41ddc12709caa755666f580af3a688899721efecd",
- "sha256:f9afb5b746781fc2abce26193d1c817b7eb0e11459510fba65d2bd77fe161d9e",
- "sha256:fb8b8ee99b3fffe4fd86f4c81b35a6bf7e4462cba019997af2fe679365db0c49"
- ],
- "index": "pypi",
- "version": "==6.2"
+ "sha256:03e2a7826086b91ef345ff18742ee9fc47a6839ccd517061ef8fa1976e652ce9",
+ "sha256:07e6db90cd9686c767dcc593dff16c8c09f9814f5e9c51034066cad3373b914d",
+ "sha256:18d520c6860515a771708937d2f78f63cc47ab3b80cb78e86573b0a760161faf",
+ "sha256:1ebf730d2381158ecf3dfd4453fbca0613e16eaa547b4170e2450c9707665ce7",
+ "sha256:21b7745788866028adeb1e0eca3bf1101109e2dc58456cb49d2d9b99a8c516e6",
+ "sha256:26e2deacd414fc2f97dd9f7676ee3eaecd299ca751412d89f40bc01557a6b1b4",
+ "sha256:2c6dbb42f3ad25760010c45191e9757e7dce981cbfb90e42feef301d71540059",
+ "sha256:2fea046bfb455510e05be95e879f0e768d45c10c11509e20e06d8fcaa31d9e39",
+ "sha256:34626a7eee2a3da12af0507780bb51eb52dca0e1751fd1471d0810539cefb536",
+ "sha256:37d1141ad6b2466a7b53a22e08fe76994c2d35a5b6b469590424a9953155afac",
+ "sha256:46191097ebc381fbf89bdce207a6c107ac4ec0890d8d20f3360345ff5976155c",
+ "sha256:4dd8bafa458b5c7d061540f1ee9f18025a68e2d8471b3e858a9dad47c8d41903",
+ "sha256:4e21876082ed887baed0146fe222f861b5815455ada3b33b890f4105d806128d",
+ "sha256:58303469e9a272b4abdb9e302a780072c0633cdcc0165db7eec0f9e32f901e05",
+ "sha256:5ca5aeb4344b30d0bec47481536b8ba1181d50dbe783b0e4ad03c95dc1296684",
+ "sha256:68353fe7cdf91f109fc7d474461b46e7f1f14e533e911a2a2cbb8b0fc8613cf1",
+ "sha256:6f89d05e028d274ce4fa1a86887b071ae1755082ef94a6740238cd7a8178804f",
+ "sha256:7a15dc0a14008f1da3d1ebd44bdda3e357dbabdf5a0b5034d38fcde0b5c234b7",
+ "sha256:8bdde1177f2311ee552f47ae6e5aa7750c0e3291ca6b75f71f7ffe1f1dab3dca",
+ "sha256:8ce257cac556cb03be4a248d92ed36904a59a4a5ff55a994e92214cde15c5bad",
+ "sha256:8cf5cfcb1521dc3255d845d9dca3ff204b3229401994ef8d1984b32746bb45ca",
+ "sha256:8fbbdc8d55990eac1b0919ca69eb5a988a802b854488c34b8f37f3e2025fa90d",
+ "sha256:9548f10d8be799551eb3a9c74bbf2b4934ddb330e08a73320123c07f95cc2d92",
+ "sha256:96f8a1cb43ca1422f36492bebe63312d396491a9165ed3b9231e778d43a7fca4",
+ "sha256:9b27d894748475fa858f9597c0ee1d4829f44683f3813633aaf94b19cb5453cf",
+ "sha256:9baff2a45ae1f17c8078452e9e5962e518eab705e50a0aa8083733ea7d45f3a6",
+ "sha256:a2a8b8bcc399edb4347a5ca8b9b87e7524c0967b335fbb08a83c8421489ddee1",
+ "sha256:acf53bc2cf7282ab9b8ba346746afe703474004d9e566ad164c91a7a59f188a4",
+ "sha256:b0be84e5a6209858a1d3e8d1806c46214e867ce1b0fd32e4ea03f4bd8b2e3359",
+ "sha256:b31651d018b23ec463e95cf10070d0b2c548aa950a03d0b559eaa11c7e5a6fa3",
+ "sha256:b78e5afb39941572209f71866aa0b206c12f0109835aa0d601e41552f9b3e620",
+ "sha256:c76aeef1b95aff3905fb2ae2d96e319caca5b76fa41d3470b19d4e4a3a313512",
+ "sha256:dd035edafefee4d573140a76fdc785dc38829fe5a455c4bb12bac8c20cfc3d69",
+ "sha256:dd6fe30bd519694b356cbfcaca9bd5c1737cddd20778c6a581ae20dc8c04def2",
+ "sha256:e5f4e1edcf57ce94e5475fe09e5afa3e3145081318e5fd1a43a6b4539a97e518",
+ "sha256:ec6bc7fe73a938933d4178c9b23c4e0568e43e220aef9472c4f6044bfc6dd0f0",
+ "sha256:f1555ea6d6da108e1999b2463ea1003fe03f29213e459145e70edbaf3e004aaa",
+ "sha256:f5fa5803f47e095d7ad8443d28b01d48c0359484fec1b9d8606d0e3282084bc4",
+ "sha256:f7331dbf301b7289013175087636bbaf5b2405e57259dd2c42fdcc9fcc47325e",
+ "sha256:f9987b0354b06d4df0f4d3e0ec1ae76d7ce7cbca9a2f98c25041eb79eec766f1",
+ "sha256:fd9e830e9d8d89b20ab1e5af09b32d33e1a08ef4c4e14411e559556fd788e6b2"
+ ],
+ "index": "pypi",
+ "version": "==6.3.2"
},
"cryptography": {
"hashes": [
@@ -1374,19 +1329,19 @@
},
"filelock": {
"hashes": [
- "sha256:38b4f4c989f9d06d44524df1b24bd19e167d851f19b50bf3e3559952dddc5b80",
- "sha256:cf0fc6a2f8d26bd900f19bf33915ca70ba4dd8c56903eeb14e1e7a2fd7590146"
+ "sha256:9cd540a9352e432c7246a48fe4e8712b10acb1df2ad1f30e8c070b82ae1fed85",
+ "sha256:f8314284bfffbdcfa0ff3d7992b023d4c628ced6feb957351d4c48d059f56bc0"
],
"markers": "python_version >= '3.7'",
- "version": "==3.4.2"
+ "version": "==3.6.0"
},
"fonttools": {
"hashes": [
- "sha256:545c05d0f7903a863c2020e07b8f0a57517f2c40d940bded77076397872d14ca",
- "sha256:edf251d5d2cc0580d5f72de4621c338d8c66c5f61abb50cf486640f73c8194d5"
+ "sha256:1933415e0fbdf068815cb1baaa1f159e17830215f7e8624e5731122761627557",
+ "sha256:2b18a172120e32128a80efee04cff487d5d140fe7d817deb648b2eee023a40e4"
],
"markers": "python_version >= '3.7'",
- "version": "==4.28.5"
+ "version": "==4.29.1"
},
"hexdump": {
"hashes": [
@@ -1397,19 +1352,19 @@
},
"hypothesis": {
"hashes": [
- "sha256:317f8d2f670fa69e258ab43e21c2befd413c559e386581f7e9641a80460b1063",
- "sha256:803792d416ff71307d775fe760e2b2f07ca302a2c941b576629668092b9f3e3d"
+ "sha256:1c1777ccd3074fcca768d7594a284a41501c99843089d37e3235d38319e3f217",
+ "sha256:79321035b9174ffa506d724ca5e8af375d7bf532c80e4f602bd433792c527e6c"
],
"index": "pypi",
- "version": "==6.34.2"
+ "version": "==6.37.2"
},
"identify": {
"hashes": [
- "sha256:0192893ff68b03d37fed553e261d4a22f94ea974093aefb33b29df2ff35fed3c",
- "sha256:64d4885e539f505dd8ffb5e93c142a1db45480452b1594cacd3e91dca9a984e9"
+ "sha256:2986942d3974c8f2e5019a190523b0b0e2a07cb8e89bf236727fb4b26f27f8fd",
+ "sha256:fd906823ed1db23c7a48f9b176a1d71cb8abede1e21ebe614bac7bdd688d9213"
],
- "markers": "python_full_version >= '3.6.1'",
- "version": "==2.4.1"
+ "markers": "python_version >= '3.7'",
+ "version": "==2.4.11"
},
"idna": {
"hashes": [
@@ -1427,6 +1382,14 @@
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==1.3.0"
},
+ "importlib-metadata": {
+ "hashes": [
+ "sha256:175f4ee440a0317f6e8d81b7f8d4869f93316170a65ad2b007d2929186c8052c",
+ "sha256:e0bc84ff355328a4adfc5240c4f211e0ab386f80aa640d1b11f0618a1d282094"
+ ],
+ "markers": "python_version < '3.10'",
+ "version": "==4.11.1"
+ },
"iniconfig": {
"hashes": [
"sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3",
@@ -1509,86 +1472,57 @@
},
"markdown-it-py": {
"hashes": [
- "sha256:15cc69c5b7c493ba8603722b710e39ce3fab2961994179fb4fa1c99b070d2059",
- "sha256:c138a596f6c9988e0b5fa3299bc38ffa76c75076bc178e8dfac40a84343c7022"
+ "sha256:31974138ca8cafbcb62213f4974b29571b940e78364584729233f59b8dfdb8bd",
+ "sha256:7b5c153ae1ab2cde00a33938bce68f3ad5d68fbe363f946de7d28555bed4e08a"
],
"index": "pypi",
- "version": "==2.0.0"
+ "version": "==2.0.1"
},
"markupsafe": {
"hashes": [
- "sha256:01a9b8ea66f1658938f65b93a85ebe8bc016e6769611be228d797c9d998dd298",
- "sha256:023cb26ec21ece8dc3907c0e8320058b2e0cb3c55cf9564da612bc325bed5e64",
- "sha256:0446679737af14f45767963a1a9ef7620189912317d095f2d9ffa183a4d25d2b",
- "sha256:04635854b943835a6ea959e948d19dcd311762c5c0c6e1f0e16ee57022669194",
- "sha256:0717a7390a68be14b8c793ba258e075c6f4ca819f15edfc2a3a027c823718567",
- "sha256:0955295dd5eec6cb6cc2fe1698f4c6d84af2e92de33fbcac4111913cd100a6ff",
- "sha256:0d4b31cc67ab36e3392bbf3862cfbadac3db12bdd8b02a2731f509ed5b829724",
- "sha256:10f82115e21dc0dfec9ab5c0223652f7197feb168c940f3ef61563fc2d6beb74",
- "sha256:168cd0a3642de83558a5153c8bd34f175a9a6e7f6dc6384b9655d2697312a646",
- "sha256:1d609f577dc6e1aa17d746f8bd3c31aa4d258f4070d61b2aa5c4166c1539de35",
- "sha256:1f2ade76b9903f39aa442b4aadd2177decb66525062db244b35d71d0ee8599b6",
- "sha256:20dca64a3ef2d6e4d5d615a3fd418ad3bde77a47ec8a23d984a12b5b4c74491a",
- "sha256:2a7d351cbd8cfeb19ca00de495e224dea7e7d919659c2841bbb7f420ad03e2d6",
- "sha256:2d7d807855b419fc2ed3e631034685db6079889a1f01d5d9dac950f764da3dad",
- "sha256:2ef54abee730b502252bcdf31b10dacb0a416229b72c18b19e24a4509f273d26",
- "sha256:36bc903cbb393720fad60fc28c10de6acf10dc6cc883f3e24ee4012371399a38",
- "sha256:37205cac2a79194e3750b0af2a5720d95f786a55ce7df90c3af697bfa100eaac",
- "sha256:3c112550557578c26af18a1ccc9e090bfe03832ae994343cfdacd287db6a6ae7",
- "sha256:3dd007d54ee88b46be476e293f48c85048603f5f516008bee124ddd891398ed6",
- "sha256:4296f2b1ce8c86a6aea78613c34bb1a672ea0e3de9c6ba08a960efe0b0a09047",
- "sha256:47ab1e7b91c098ab893b828deafa1203de86d0bc6ab587b160f78fe6c4011f75",
- "sha256:49e3ceeabbfb9d66c3aef5af3a60cc43b85c33df25ce03d0031a608b0a8b2e3f",
- "sha256:4dc8f9fb58f7364b63fd9f85013b780ef83c11857ae79f2feda41e270468dd9b",
- "sha256:4efca8f86c54b22348a5467704e3fec767b2db12fc39c6d963168ab1d3fc9135",
- "sha256:53edb4da6925ad13c07b6d26c2a852bd81e364f95301c66e930ab2aef5b5ddd8",
- "sha256:5855f8438a7d1d458206a2466bf82b0f104a3724bf96a1c781ab731e4201731a",
- "sha256:594c67807fb16238b30c44bdf74f36c02cdf22d1c8cda91ef8a0ed8dabf5620a",
- "sha256:5b6d930f030f8ed98e3e6c98ffa0652bdb82601e7a016ec2ab5d7ff23baa78d1",
- "sha256:5bb28c636d87e840583ee3adeb78172efc47c8b26127267f54a9c0ec251d41a9",
- "sha256:60bf42e36abfaf9aff1f50f52644b336d4f0a3fd6d8a60ca0d054ac9f713a864",
- "sha256:611d1ad9a4288cf3e3c16014564df047fe08410e628f89805e475368bd304914",
- "sha256:6300b8454aa6930a24b9618fbb54b5a68135092bc666f7b06901f897fa5c2fee",
- "sha256:63f3268ba69ace99cab4e3e3b5840b03340efed0948ab8f78d2fd87ee5442a4f",
- "sha256:6557b31b5e2c9ddf0de32a691f2312a32f77cd7681d8af66c2692efdbef84c18",
- "sha256:693ce3f9e70a6cf7d2fb9e6c9d8b204b6b39897a2c4a1aa65728d5ac97dcc1d8",
- "sha256:6a7fae0dd14cf60ad5ff42baa2e95727c3d81ded453457771d02b7d2b3f9c0c2",
- "sha256:6c4ca60fa24e85fe25b912b01e62cb969d69a23a5d5867682dd3e80b5b02581d",
- "sha256:6fcf051089389abe060c9cd7caa212c707e58153afa2c649f00346ce6d260f1b",
- "sha256:7d91275b0245b1da4d4cfa07e0faedd5b0812efc15b702576d103293e252af1b",
- "sha256:89c687013cb1cd489a0f0ac24febe8c7a666e6e221b783e53ac50ebf68e45d86",
- "sha256:8d206346619592c6200148b01a2142798c989edcb9c896f9ac9722a99d4e77e6",
- "sha256:905fec760bd2fa1388bb5b489ee8ee5f7291d692638ea5f67982d968366bef9f",
- "sha256:97383d78eb34da7e1fa37dd273c20ad4320929af65d156e35a5e2d89566d9dfb",
- "sha256:984d76483eb32f1bcb536dc27e4ad56bba4baa70be32fa87152832cdd9db0833",
- "sha256:99df47edb6bda1249d3e80fdabb1dab8c08ef3975f69aed437cb69d0a5de1e28",
- "sha256:9f02365d4e99430a12647f09b6cc8bab61a6564363f313126f775eb4f6ef798e",
- "sha256:a30e67a65b53ea0a5e62fe23682cfe22712e01f453b95233b25502f7c61cb415",
- "sha256:ab3ef638ace319fa26553db0624c4699e31a28bb2a835c5faca8f8acf6a5a902",
- "sha256:aca6377c0cb8a8253e493c6b451565ac77e98c2951c45f913e0b52facdcff83f",
- "sha256:add36cb2dbb8b736611303cd3bfcee00afd96471b09cda130da3581cbdc56a6d",
- "sha256:b2f4bf27480f5e5e8ce285a8c8fd176c0b03e93dcc6646477d4630e83440c6a9",
- "sha256:b7f2d075102dc8c794cbde1947378051c4e5180d52d276987b8d28a3bd58c17d",
- "sha256:baa1a4e8f868845af802979fcdbf0bb11f94f1cb7ced4c4b8a351bb60d108145",
- "sha256:be98f628055368795d818ebf93da628541e10b75b41c559fdf36d104c5787066",
- "sha256:bf5d821ffabf0ef3533c39c518f3357b171a1651c1ff6827325e4489b0e46c3c",
- "sha256:c47adbc92fc1bb2b3274c4b3a43ae0e4573d9fbff4f54cd484555edbf030baf1",
- "sha256:cdfba22ea2f0029c9261a4bd07e830a8da012291fbe44dc794e488b6c9bb353a",
- "sha256:d6c7ebd4e944c85e2c3421e612a7057a2f48d478d79e61800d81468a8d842207",
- "sha256:d7f9850398e85aba693bb640262d3611788b1f29a79f0c93c565694658f4071f",
- "sha256:d8446c54dc28c01e5a2dbac5a25f071f6653e6e40f3a8818e8b45d790fe6ef53",
- "sha256:deb993cacb280823246a026e3b2d81c493c53de6acfd5e6bfe31ab3402bb37dd",
- "sha256:e0f138900af21926a02425cf736db95be9f4af72ba1bb21453432a07f6082134",
- "sha256:e9936f0b261d4df76ad22f8fee3ae83b60d7c3e871292cd42f40b81b70afae85",
- "sha256:f0567c4dc99f264f49fe27da5f735f414c4e7e7dd850cfd8e69f0862d7c74ea9",
- "sha256:f5653a225f31e113b152e56f154ccbe59eeb1c7487b39b9d9f9cdb58e6c79dc5",
- "sha256:f826e31d18b516f653fe296d967d700fddad5901ae07c622bb3705955e1faa94",
- "sha256:f8ba0e8349a38d3001fae7eadded3f6606f0da5d748ee53cc1dab1d6527b9509",
- "sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51",
- "sha256:fa130dd50c57d53368c9d59395cb5526eda596d3ffe36666cd81a44d56e48872"
+ "sha256:023af8c54fe63530545f70dd2a2a7eed18d07a9a77b94e8bf1e2ff7f252db9a3",
+ "sha256:09c86c9643cceb1d87ca08cdc30160d1b7ab49a8a21564868921959bd16441b8",
+ "sha256:142119fb14a1ef6d758912b25c4e803c3ff66920635c44078666fe7cc3f8f759",
+ "sha256:1d1fb9b2eec3c9714dd936860850300b51dbaa37404209c8d4cb66547884b7ed",
+ "sha256:204730fd5fe2fe3b1e9ccadb2bd18ba8712b111dcabce185af0b3b5285a7c989",
+ "sha256:24c3be29abb6b34052fd26fc7a8e0a49b1ee9d282e3665e8ad09a0a68faee5b3",
+ "sha256:290b02bab3c9e216da57c1d11d2ba73a9f73a614bbdcc027d299a60cdfabb11a",
+ "sha256:3028252424c72b2602a323f70fbf50aa80a5d3aa616ea6add4ba21ae9cc9da4c",
+ "sha256:30c653fde75a6e5eb814d2a0a89378f83d1d3f502ab710904ee585c38888816c",
+ "sha256:3cace1837bc84e63b3fd2dfce37f08f8c18aeb81ef5cf6bb9b51f625cb4e6cd8",
+ "sha256:4056f752015dfa9828dce3140dbadd543b555afb3252507348c493def166d454",
+ "sha256:454ffc1cbb75227d15667c09f164a0099159da0c1f3d2636aa648f12675491ad",
+ "sha256:598b65d74615c021423bd45c2bc5e9b59539c875a9bdb7e5f2a6b92dfcfc268d",
+ "sha256:599941da468f2cf22bf90a84f6e2a65524e87be2fce844f96f2dd9a6c9d1e635",
+ "sha256:5ddea4c352a488b5e1069069f2f501006b1a4362cb906bee9a193ef1245a7a61",
+ "sha256:62c0285e91414f5c8f621a17b69fc0088394ccdaa961ef469e833dbff64bd5ea",
+ "sha256:679cbb78914ab212c49c67ba2c7396dc599a8479de51b9a87b174700abd9ea49",
+ "sha256:6e104c0c2b4cd765b4e83909cde7ec61a1e313f8a75775897db321450e928cce",
+ "sha256:736895a020e31b428b3382a7887bfea96102c529530299f426bf2e636aacec9e",
+ "sha256:75bb36f134883fdbe13d8e63b8675f5f12b80bb6627f7714c7d6c5becf22719f",
+ "sha256:7d2f5d97fcbd004c03df8d8fe2b973fe2b14e7bfeb2cfa012eaa8759ce9a762f",
+ "sha256:80beaf63ddfbc64a0452b841d8036ca0611e049650e20afcb882f5d3c266d65f",
+ "sha256:84ad5e29bf8bab3ad70fd707d3c05524862bddc54dc040982b0dbcff36481de7",
+ "sha256:8da5924cb1f9064589767b0f3fc39d03e3d0fb5aa29e0cb21d43106519bd624a",
+ "sha256:961eb86e5be7d0973789f30ebcf6caab60b844203f4396ece27310295a6082c7",
+ "sha256:96de1932237abe0a13ba68b63e94113678c379dca45afa040a17b6e1ad7ed076",
+ "sha256:a0a0abef2ca47b33fb615b491ce31b055ef2430de52c5b3fb19a4042dbc5cadb",
+ "sha256:b2a5a856019d2833c56a3dcac1b80fe795c95f401818ea963594b345929dffa7",
+ "sha256:b8811d48078d1cf2a6863dafb896e68406c5f513048451cd2ded0473133473c7",
+ "sha256:c532d5ab79be0199fa2658e24a02fce8542df196e60665dd322409a03db6a52c",
+ "sha256:d3b64c65328cb4cd252c94f83e66e3d7acf8891e60ebf588d7b493a55a1dbf26",
+ "sha256:d4e702eea4a2903441f2735799d217f4ac1b55f7d8ad96ab7d4e25417cb0827c",
+ "sha256:d5653619b3eb5cbd35bfba3c12d575db2a74d15e0e1c08bf1db788069d410ce8",
+ "sha256:d66624f04de4af8bbf1c7f21cc06649c1c69a7f84109179add573ce35e46d448",
+ "sha256:e67ec74fada3841b8c5f4c4f197bea916025cb9aa3fe5abf7d52b655d042f956",
+ "sha256:e6f7f3f41faffaea6596da86ecc2389672fa949bd035251eab26dc6697451d05",
+ "sha256:f02cf7221d5cd915d7fa58ab64f7ee6dd0f6cddbb48683debf5d04ae9b1c2cc1",
+ "sha256:f0eddfcabd6936558ec020130f932d479930581171368fd728efcfb6ef0dd357",
+ "sha256:fabbe18087c3d33c5824cb145ffca52eccd053061df1d79d4b66dafa5ad2a5ea",
+ "sha256:fc3150f85e2dbcf99e65238c842d1cfe69d3e7649b19864c1cc043213d9cd730"
],
- "markers": "python_version >= '3.6'",
- "version": "==2.0.1"
+ "markers": "python_version >= '3.7'",
+ "version": "==2.1.0"
},
"matplotlib": {
"hashes": [
@@ -1649,29 +1583,29 @@
},
"mypy": {
"hashes": [
- "sha256:0feb82e9fa849affca7edd24713dbe809dce780ced9f3feca5ed3d80e40b777f",
- "sha256:1d2296f35aae9802eeb1327058b550371ee382d71374b3e7d2804035ef0b830b",
- "sha256:1e689e92cdebd87607a041585f1dc7339aa2e8a9f9bad9ba7e6ece619431b20c",
- "sha256:1ea7199780c1d7940b82dbc0a4e37722b4e3851264dbba81e01abecc9052d8a7",
- "sha256:221cc94dc6a801ccc2be7c0c9fd791c5e08d1fa2c5e1c12dec4eab15b2469871",
- "sha256:2e9c5409e9cb81049bb03fa1009b573dea87976713e3898561567a86c4eaee01",
- "sha256:45a4dc21c789cfd09b8ccafe114d6de66f0b341ad761338de717192f19397a8c",
- "sha256:51426262ae4714cc7dd5439814676e0992b55bcc0f6514eccb4cf8e0678962c2",
- "sha256:554873e45c1ca20f31ddf873deb67fa5d2e87b76b97db50669f0468ccded8fae",
- "sha256:5feb56f8bb280468fe5fc8e6f56f48f99aa0df9eed3c507a11505ee4657b5380",
- "sha256:601f46593f627f8a9b944f74fd387c9b5f4266b39abad77471947069c2fc7651",
- "sha256:70b197dd8c78fc5d2daf84bd093e8466a2b2e007eedaa85e792e513a820adbf7",
- "sha256:959319b9a3cafc33a8185f440a433ba520239c72e733bf91f9efd67b0a8e9b30",
- "sha256:a9d8dffefba634b27d650e0de2564379a1a367e2e08d6617d8f89261a3bf63b2",
- "sha256:b419e9721260161e70d054a15abbd50603c16f159860cfd0daeab647d828fc29",
- "sha256:bc1a0607ea03c30225347334af66b0af12eefba018a89a88c209e02b7065ea95",
- "sha256:bf4a44e03040206f7c058d1f5ba02ef2d1820720c88bc4285c7d9a4269f54173",
- "sha256:db3a87376a1380f396d465bed462e76ea89f838f4c5e967d68ff6ee34b785c31",
- "sha256:ed4e0ea066bb12f56b2812a15ff223c57c0a44eca817ceb96b214bb055c7051f",
- "sha256:f9f665d69034b1fcfdbcd4197480d26298bbfb5d2dfe206245b6498addb34999"
- ],
- "index": "pypi",
- "version": "==0.930"
+ "sha256:0038b21890867793581e4cb0d810829f5fd4441aa75796b53033af3aa30430ce",
+ "sha256:1171f2e0859cfff2d366da2c7092b06130f232c636a3f7301e3feb8b41f6377d",
+ "sha256:1b06268df7eb53a8feea99cbfff77a6e2b205e70bf31743e786678ef87ee8069",
+ "sha256:1b65714dc296a7991000b6ee59a35b3f550e0073411ac9d3202f6516621ba66c",
+ "sha256:1bf752559797c897cdd2c65f7b60c2b6969ffe458417b8d947b8340cc9cec08d",
+ "sha256:300717a07ad09525401a508ef5d105e6b56646f7942eb92715a1c8d610149714",
+ "sha256:3c5b42d0815e15518b1f0990cff7a705805961613e701db60387e6fb663fe78a",
+ "sha256:4365c60266b95a3f216a3047f1d8e3f895da6c7402e9e1ddfab96393122cc58d",
+ "sha256:50c7346a46dc76a4ed88f3277d4959de8a2bd0a0fa47fa87a4cde36fe247ac05",
+ "sha256:5b56154f8c09427bae082b32275a21f500b24d93c88d69a5e82f3978018a0266",
+ "sha256:74f7eccbfd436abe9c352ad9fb65872cc0f1f0a868e9d9c44db0893440f0c697",
+ "sha256:7b3f6f557ba4afc7f2ce6d3215d5db279bcf120b3cfd0add20a5d4f4abdae5bc",
+ "sha256:8c11003aaeaf7cc2d0f1bc101c1cc9454ec4cc9cb825aef3cafff8a5fdf4c799",
+ "sha256:8ca7f8c4b1584d63c9a0f827c37ba7a47226c19a23a753d52e5b5eddb201afcd",
+ "sha256:c89702cac5b302f0c5d33b172d2b55b5df2bede3344a2fbed99ff96bddb2cf00",
+ "sha256:d8f1ff62f7a879c9fe5917b3f9eb93a79b78aad47b533911b853a757223f72e7",
+ "sha256:d9d2b84b2007cea426e327d2483238f040c49405a6bf4074f605f0156c91a47a",
+ "sha256:e839191b8da5b4e5d805f940537efcaa13ea5dd98418f06dc585d2891d228cf0",
+ "sha256:f9fe20d0872b26c4bba1c1be02c5340de1019530302cf2dcc85c7f9fc3252ae0",
+ "sha256:ff3bf387c14c805ab1388185dd22d6b210824e164d4bb324b195ff34e322d166"
+ ],
+ "index": "pypi",
+ "version": "==0.931"
},
"mypy-extensions": {
"hashes": [
@@ -1682,11 +1616,11 @@
},
"myst-parser": {
"hashes": [
- "sha256:617a90ceda2162ebf81cd13ad17d879bd4f49e7fb5c4f177bb905272555a2268",
- "sha256:a6473b9735c8c74959b49b36550725464f4aecc4481340c9a5f9153829191f83"
+ "sha256:555ec2950aba5ae5dac5c162c7e9a43ad4a7291cfac644d8f5f84da8efa6f356",
+ "sha256:d412347a5cacb77ebc03d7f7ffef050cd61957d46f234313d350e84e24972260"
],
"index": "pypi",
- "version": "==0.16.1"
+ "version": "==0.17.0"
},
"nodeenv": {
"hashes": [
@@ -1697,31 +1631,28 @@
},
"numpy": {
"hashes": [
- "sha256:0cfe07133fd00b27edee5e6385e333e9eeb010607e8a46e1cd673f05f8596595",
- "sha256:11a1f3816ea82eed4178102c56281782690ab5993251fdfd75039aad4d20385f",
- "sha256:2762331de395739c91f1abb88041f94a080cb1143aeec791b3b223976228af3f",
- "sha256:283d9de87c0133ef98f93dfc09fad3fb382f2a15580de75c02b5bb36a5a159a5",
- "sha256:3d22662b4b10112c545c91a0741f2436f8ca979ab3d69d03d19322aa970f9695",
- "sha256:41388e32e40b41dd56eb37fcaa7488b2b47b0adf77c66154d6b89622c110dfe9",
- "sha256:42c16cec1c8cf2728f1d539bd55aaa9d6bb48a7de2f41eb944697293ef65a559",
- "sha256:47ee7a839f5885bc0c63a74aabb91f6f40d7d7b639253768c4199b37aede7982",
- "sha256:5a311ee4d983c487a0ab546708edbdd759393a3dc9cd30305170149fedd23c88",
- "sha256:5dc65644f75a4c2970f21394ad8bea1a844104f0fe01f278631be1c7eae27226",
- "sha256:6ed0d073a9c54ac40c41a9c2d53fcc3d4d4ed607670b9e7b0de1ba13b4cbfe6f",
- "sha256:76ba7c40e80f9dc815c5e896330700fd6e20814e69da9c1267d65a4d051080f1",
- "sha256:818b9be7900e8dc23e013a92779135623476f44a0de58b40c32a15368c01d471",
- "sha256:a024181d7aef0004d76fb3bce2a4c9f2e67a609a9e2a6ff2571d30e9976aa383",
- "sha256:a955e4128ac36797aaffd49ab44ec74a71c11d6938df83b1285492d277db5397",
- "sha256:a97a954a8c2f046d3817c2bce16e3c7e9a9c2afffaf0400f5c16df5172a67c9c",
- "sha256:a97e82c39d9856fe7d4f9b86d8a1e66eff99cf3a8b7ba48202f659703d27c46f",
- "sha256:b55b953a1bdb465f4dc181758570d321db4ac23005f90ffd2b434cc6609a63dd",
- "sha256:bb02929b0d6bfab4c48a79bd805bd7419114606947ec8284476167415171f55b",
- "sha256:bece0a4a49e60e472a6d1f70ac6cdea00f9ab80ff01132f96bd970cdd8a9e5a9",
- "sha256:e41e8951749c4b5c9a2dc5fdbc1a4eec6ab2a140fdae9b460b0f557eed870f4d",
- "sha256:f71d57cc8645f14816ae249407d309be250ad8de93ef61d9709b45a0ddf4050c"
- ],
- "index": "pypi",
- "version": "==1.22.0"
+ "sha256:03ae5850619abb34a879d5f2d4bb4dcd025d6d8fb72f5e461dae84edccfe129f",
+ "sha256:076aee5a3763d41da6bef9565fdf3cb987606f567cd8b104aded2b38b7b47abf",
+ "sha256:0b536b6840e84c1c6a410f3a5aa727821e6108f3454d81a5cd5900999ef04f89",
+ "sha256:15efb7b93806d438e3bc590ca8ef2f953b0ce4f86f337ef4559d31ec6cf9d7dd",
+ "sha256:168259b1b184aa83a514f307352c25c56af111c269ffc109d9704e81f72e764b",
+ "sha256:2638389562bda1635b564490d76713695ff497242a83d9b684d27bb4a6cc9d7a",
+ "sha256:3556c5550de40027d3121ebbb170f61bbe19eb639c7ad0c7b482cd9b560cd23b",
+ "sha256:4a176959b6e7e00b5a0d6f549a479f869829bfd8150282c590deee6d099bbb6e",
+ "sha256:515a8b6edbb904594685da6e176ac9fbea8f73a5ebae947281de6613e27f1956",
+ "sha256:55535c7c2f61e2b2fc817c5cbe1af7cb907c7f011e46ae0a52caa4be1f19afe2",
+ "sha256:59153979d60f5bfe9e4c00e401e24dfe0469ef8da6d68247439d3278f30a180f",
+ "sha256:60cb8e5933193a3cc2912ee29ca331e9c15b2da034f76159b7abc520b3d1233a",
+ "sha256:6767ad399e9327bfdbaa40871be4254d1995f4a3ca3806127f10cec778bd9896",
+ "sha256:76a4f9bce0278becc2da7da3b8ef854bed41a991f4226911a24a9711baad672c",
+ "sha256:8cf33634b60c9cef346663a222d9841d3bbbc0a2f00221d6bcfd0d993d5543f6",
+ "sha256:94dd11d9f13ea1be17bac39c1942f527cbf7065f94953cf62dfe805653da2f8f",
+ "sha256:aafa46b5a39a27aca566198d3312fb3bde95ce9677085efd02c86f7ef6be4ec7",
+ "sha256:badca914580eb46385e7f7e4e426fea6de0a37b9e06bec252e481ae7ec287082",
+ "sha256:d76a26c5118c4d96e264acc9e3242d72e1a2b92e739807b3b69d8d47684b6677"
+ ],
+ "index": "pypi",
+ "version": "==1.22.2"
},
"opencv-python-headless": {
"hashes": [
@@ -1754,57 +1685,60 @@
},
"paramiko": {
"hashes": [
- "sha256:a1fdded3b55f61d23389e4fe52d9ae428960ac958d2edf50373faa5d8926edd0",
- "sha256:db5d3f19607941b1c90233588d60213c874392c4961c6297037da989c24f8070"
+ "sha256:04097dbd96871691cdb34c13db1883066b8a13a0df2afd4cb0a92221f51c2603",
+ "sha256:944a9e5dbdd413ab6c7951ea46b0ab40713235a9c4c5ca81cfe45c6f14fa677b"
],
"index": "pypi",
- "version": "==2.9.1"
+ "version": "==2.9.2"
},
"pillow": {
"hashes": [
- "sha256:03b27b197deb4ee400ed57d8d4e572d2d8d80f825b6634daf6e2c18c3c6ccfa6",
- "sha256:0b281fcadbb688607ea6ece7649c5d59d4bbd574e90db6cd030e9e85bde9fecc",
- "sha256:0ebd8b9137630a7bbbff8c4b31e774ff05bbb90f7911d93ea2c9371e41039b52",
- "sha256:113723312215b25c22df1fdf0e2da7a3b9c357a7d24a93ebbe80bfda4f37a8d4",
- "sha256:2d16b6196fb7a54aff6b5e3ecd00f7c0bab1b56eee39214b2b223a9d938c50af",
- "sha256:2fd8053e1f8ff1844419842fd474fc359676b2e2a2b66b11cc59f4fa0a301315",
- "sha256:31b265496e603985fad54d52d11970383e317d11e18e856971bdbb86af7242a4",
- "sha256:3586e12d874ce2f1bc875a3ffba98732ebb12e18fb6d97be482bd62b56803281",
- "sha256:47f5cf60bcb9fbc46011f75c9b45a8b5ad077ca352a78185bd3e7f1d294b98bb",
- "sha256:490e52e99224858f154975db61c060686df8a6b3f0212a678e5d2e2ce24675c9",
- "sha256:500d397ddf4bbf2ca42e198399ac13e7841956c72645513e8ddf243b31ad2128",
- "sha256:52abae4c96b5da630a8b4247de5428f593465291e5b239f3f843a911a3cf0105",
- "sha256:6579f9ba84a3d4f1807c4aab4be06f373017fc65fff43498885ac50a9b47a553",
- "sha256:68e06f8b2248f6dc8b899c3e7ecf02c9f413aab622f4d6190df53a78b93d97a5",
- "sha256:6c5439bfb35a89cac50e81c751317faea647b9a3ec11c039900cd6915831064d",
- "sha256:72c3110228944019e5f27232296c5923398496b28be42535e3b2dc7297b6e8b6",
- "sha256:72f649d93d4cc4d8cf79c91ebc25137c358718ad75f99e99e043325ea7d56100",
- "sha256:7aaf07085c756f6cb1c692ee0d5a86c531703b6e8c9cae581b31b562c16b98ce",
- "sha256:80fe92813d208ce8aa7d76da878bdc84b90809f79ccbad2a288e9bcbeac1d9bd",
- "sha256:95545137fc56ce8c10de646074d242001a112a92de169986abd8c88c27566a05",
- "sha256:97b6d21771da41497b81652d44191489296555b761684f82b7b544c49989110f",
- "sha256:98cb63ca63cb61f594511c06218ab4394bf80388b3d66cd61d0b1f63ee0ea69f",
- "sha256:9f3b4522148586d35e78313db4db0df4b759ddd7649ef70002b6c3767d0fdeb7",
- "sha256:a09a9d4ec2b7887f7a088bbaacfd5c07160e746e3d47ec5e8050ae3b2a229e9f",
- "sha256:b5050d681bcf5c9f2570b93bee5d3ec8ae4cf23158812f91ed57f7126df91762",
- "sha256:bb47a548cea95b86494a26c89d153fd31122ed65255db5dcbc421a2d28eb3379",
- "sha256:bc462d24500ba707e9cbdef436c16e5c8cbf29908278af053008d9f689f56dee",
- "sha256:c2067b3bb0781f14059b112c9da5a91c80a600a97915b4f48b37f197895dd925",
- "sha256:d154ed971a4cc04b93a6d5b47f37948d1f621f25de3e8fa0c26b2d44f24e3e8f",
- "sha256:d5dcea1387331c905405b09cdbfb34611050cc52c865d71f2362f354faee1e9f",
- "sha256:ee6e2963e92762923956fe5d3479b1fdc3b76c83f290aad131a2f98c3df0593e",
- "sha256:fd0e5062f11cb3e730450a7d9f323f4051b532781026395c4323b8ad055523c4"
- ],
- "index": "pypi",
- "version": "==9.0.0"
+ "sha256:011233e0c42a4a7836498e98c1acf5e744c96a67dd5032a6f666cc1fb97eab97",
+ "sha256:0f29d831e2151e0b7b39981756d201f7108d3d215896212ffe2e992d06bfe049",
+ "sha256:12875d118f21cf35604176872447cdb57b07126750a33748bac15e77f90f1f9c",
+ "sha256:14d4b1341ac07ae07eb2cc682f459bec932a380c3b122f5540432d8977e64eae",
+ "sha256:1c3c33ac69cf059bbb9d1a71eeaba76781b450bc307e2291f8a4764d779a6b28",
+ "sha256:1d19397351f73a88904ad1aee421e800fe4bbcd1aeee6435fb62d0a05ccd1030",
+ "sha256:253e8a302a96df6927310a9d44e6103055e8fb96a6822f8b7f514bb7ef77de56",
+ "sha256:2632d0f846b7c7600edf53c48f8f9f1e13e62f66a6dbc15191029d950bfed976",
+ "sha256:335ace1a22325395c4ea88e00ba3dc89ca029bd66bd5a3c382d53e44f0ccd77e",
+ "sha256:413ce0bbf9fc6278b2d63309dfeefe452835e1c78398efb431bab0672fe9274e",
+ "sha256:5100b45a4638e3c00e4d2320d3193bdabb2d75e79793af7c3eb139e4f569f16f",
+ "sha256:514ceac913076feefbeaf89771fd6febde78b0c4c1b23aaeab082c41c694e81b",
+ "sha256:528a2a692c65dd5cafc130de286030af251d2ee0483a5bf50c9348aefe834e8a",
+ "sha256:6295f6763749b89c994fcb6d8a7f7ce03c3992e695f89f00b741b4580b199b7e",
+ "sha256:6c8bc8238a7dfdaf7a75f5ec5a663f4173f8c367e5a39f87e720495e1eed75fa",
+ "sha256:718856856ba31f14f13ba885ff13874be7fefc53984d2832458f12c38205f7f7",
+ "sha256:7f7609a718b177bf171ac93cea9fd2ddc0e03e84d8fa4e887bdfc39671d46b00",
+ "sha256:80ca33961ced9c63358056bd08403ff866512038883e74f3a4bf88ad3eb66838",
+ "sha256:80fe64a6deb6fcfdf7b8386f2cf216d329be6f2781f7d90304351811fb591360",
+ "sha256:81c4b81611e3a3cb30e59b0cf05b888c675f97e3adb2c8672c3154047980726b",
+ "sha256:855c583f268edde09474b081e3ddcd5cf3b20c12f26e0d434e1386cc5d318e7a",
+ "sha256:9bfdb82cdfeccec50aad441afc332faf8606dfa5e8efd18a6692b5d6e79f00fd",
+ "sha256:a5d24e1d674dd9d72c66ad3ea9131322819ff86250b30dc5821cbafcfa0b96b4",
+ "sha256:a9f44cd7e162ac6191491d7249cceb02b8116b0f7e847ee33f739d7cb1ea1f70",
+ "sha256:b5b3f092fe345c03bca1e0b687dfbb39364b21ebb8ba90e3fa707374b7915204",
+ "sha256:b9618823bd237c0d2575283f2939655f54d51b4527ec3972907a927acbcc5bfc",
+ "sha256:cef9c85ccbe9bee00909758936ea841ef12035296c748aaceee535969e27d31b",
+ "sha256:d21237d0cd37acded35154e29aec853e945950321dd2ffd1a7d86fe686814669",
+ "sha256:d3c5c79ab7dfce6d88f1ba639b77e77a17ea33a01b07b99840d6ed08031cb2a7",
+ "sha256:d9d7942b624b04b895cb95af03a23407f17646815495ce4547f0e60e0b06f58e",
+ "sha256:db6d9fac65bd08cea7f3540b899977c6dee9edad959fa4eaf305940d9cbd861c",
+ "sha256:ede5af4a2702444a832a800b8eb7f0a7a1c0eed55b644642e049c98d589e5092",
+ "sha256:effb7749713d5317478bb3acb3f81d9d7c7f86726d41c1facca068a04cf5bb4c",
+ "sha256:f154d173286a5d1863637a7dcd8c3437bb557520b01bddb0be0258dcb72696b5",
+ "sha256:f25ed6e28ddf50de7e7ea99d7a976d6a9c415f03adcaac9c41ff6ff41b6d86ac"
+ ],
+ "index": "pypi",
+ "version": "==9.0.1"
},
"platformdirs": {
"hashes": [
- "sha256:1d7385c7db91728b83efd0ca99a5afb296cab9d0ed8313a45ed8ba17967ecfca",
- "sha256:440633ddfebcc36264232365d7840a970e75e1018d15b4327d11f91909045fda"
+ "sha256:7535e70dfa32e84d4b34996ea99c5e432fa29a708d0f4e394bbcb2a8faa4f16d",
+ "sha256:bcae7cab893c2d310a711b70b24efb93334febe65f8de776ee320b517471e227"
],
"markers": "python_version >= '3.7'",
- "version": "==2.4.1"
+ "version": "==2.5.1"
},
"pluggy": {
"hashes": [
@@ -1823,11 +1757,11 @@
},
"pre-commit": {
"hashes": [
- "sha256:758d1dc9b62c2ed8881585c254976d66eae0889919ab9b859064fc2fe3c7743e",
- "sha256:fe9897cac830aa7164dbd02a4e7b90cae49630451ce88464bca73db486ba9f65"
+ "sha256:725fa7459782d7bec5ead072810e47351de01709be838c2ce1726b9591dad616",
+ "sha256:c1a8040ff15ad3d648c70cc3e55b93e4d2d5b687320955505587fd79bbaed06a"
],
"index": "pypi",
- "version": "==2.16.0"
+ "version": "==2.17.0"
},
"py": {
"hashes": [
@@ -1917,43 +1851,35 @@
},
"pygments": {
"hashes": [
- "sha256:59b895e326f0fb0d733fd28c6839bd18ad0687ba20efc26d4277fd1d30b971f4",
- "sha256:9135c1af61eec0f650cd1ea1ed8ce298e54d56bcd8cc2ef46edd7702c171337c"
+ "sha256:44238f1b60a76d78fc8ca0528ee429702aae011c265fe6a8dd8b63049ae41c65",
+ "sha256:4e426f72023d88d03b2fa258de560726ce890ff3b630f88c21cbb8b2503b8c6a"
],
"markers": "python_version >= '3.5'",
- "version": "==2.11.1"
+ "version": "==2.11.2"
},
"pynacl": {
"hashes": [
- "sha256:06cbb4d9b2c4bd3c8dc0d267416aaed79906e7b33f114ddbf0911969794b1cc4",
- "sha256:11335f09060af52c97137d4ac54285bcb7df0cef29014a1a4efe64ac065434c4",
- "sha256:2fe0fc5a2480361dcaf4e6e7cea00e078fcda07ba45f811b167e3f99e8cff574",
- "sha256:30f9b96db44e09b3304f9ea95079b1b7316b2b4f3744fe3aaecccd95d547063d",
- "sha256:4e10569f8cbed81cb7526ae137049759d2a8d57726d52c1a000a3ce366779634",
- "sha256:511d269ee845037b95c9781aa702f90ccc36036f95d0f31373a6a79bd8242e25",
- "sha256:537a7ccbea22905a0ab36ea58577b39d1fa9b1884869d173b5cf111f006f689f",
- "sha256:54e9a2c849c742006516ad56a88f5c74bf2ce92c9f67435187c3c5953b346505",
- "sha256:757250ddb3bff1eecd7e41e65f7f833a8405fede0194319f87899690624f2122",
- "sha256:7757ae33dae81c300487591c68790dfb5145c7d03324000433d9a2c141f82af7",
- "sha256:7c6092102219f59ff29788860ccb021e80fffd953920c4a8653889c029b2d420",
- "sha256:8122ba5f2a2169ca5da936b2e5a511740ffb73979381b4229d9188f6dcb22f1f",
- "sha256:9c4a7ea4fb81536c1b1f5cc44d54a296f96ae78c1ebd2311bd0b60be45a48d96",
- "sha256:c914f78da4953b33d4685e3cdc7ce63401247a21425c16a39760e282075ac4a6",
- "sha256:cd401ccbc2a249a47a3a1724c2918fcd04be1f7b54eb2a5a71ff915db0ac51c6",
- "sha256:d452a6746f0a7e11121e64625109bc4468fc3100452817001dbe018bb8b08514",
- "sha256:ea6841bc3a76fa4942ce00f3bda7d436fda21e2d91602b9e21b7ca9ecab8f3ff",
- "sha256:f8851ab9041756003119368c1e6cd0b9c631f46d686b3904b18c0139f4419f80"
+ "sha256:06b8f6fa7f5de8d5d2f7573fe8c863c051225a27b61e6860fd047b1775807858",
+ "sha256:0c84947a22519e013607c9be43706dd42513f9e6ae5d39d3613ca1e142fba44d",
+ "sha256:20f42270d27e1b6a29f54032090b972d97f0a1b0948cc52392041ef7831fee93",
+ "sha256:401002a4aaa07c9414132aaed7f6836ff98f59277a234704ff66878c2ee4a0d1",
+ "sha256:52cb72a79269189d4e0dc537556f4740f7f0a9ec41c1322598799b0bdad4ef92",
+ "sha256:61f642bf2378713e2c2e1de73444a3778e5f0a38be6fee0fe532fe30060282ff",
+ "sha256:8ac7448f09ab85811607bdd21ec2464495ac8b7c66d146bf545b0f08fb9220ba",
+ "sha256:a36d4a9dda1f19ce6e03c9a784a2921a4b726b02e1c736600ca9c22029474394",
+ "sha256:a422368fc821589c228f4c49438a368831cb5bbc0eab5ebe1d7fac9dded6567b",
+ "sha256:e46dae94e34b085175f8abb3b0aaa7da40767865ac82c928eeb9e57e1ea8a543"
],
- "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
- "version": "==1.4.0"
+ "markers": "python_version >= '3.6'",
+ "version": "==1.5.0"
},
"pyparsing": {
"hashes": [
- "sha256:04ff808a5b90911829c55c4e26f75fa5ca8a2f5f36aa3a51f68e27033341d3e4",
- "sha256:d9bdec0013ef1eb5a84ab39a3b3868911598afa494f5faa038647101504e2b81"
+ "sha256:18ee9022775d270c55187733956460083db60b37d0d0fb357445f3094eed3eea",
+ "sha256:a6c06a88f252e6c322f65faf8f418b16213b51bdfaece0524c1c1bc30c63c484"
],
"markers": "python_version >= '3.6'",
- "version": "==3.0.6"
+ "version": "==3.0.7"
},
"pyprof2calltree": {
"hashes": [
@@ -1964,11 +1890,11 @@
},
"pytest": {
"hashes": [
- "sha256:131b36680866a76e6781d13f101efb86cf674ebb9762eb70d3082b6f29889e89",
- "sha256:7310f8d27bc79ced999e760ca304d69f6ba6c6649c0b60fb0e04a4a77cacc134"
+ "sha256:9ce3ff477af913ecf6321fe337b93a2c0dcf2a0a1439c43f5452112c1e4280db",
+ "sha256:e30905a0c131d3d94b89624a1cc5afec3e0ba2fbdb151867d8e0ebd49850f171"
],
"index": "pypi",
- "version": "==6.2.5"
+ "version": "==7.0.1"
},
"pytest-forked": {
"hashes": [
@@ -2057,46 +1983,32 @@
},
"scipy": {
"hashes": [
- "sha256:033ce76ed4e9f62923e1f8124f7e2b0800db533828c853b402c7eec6e9465d80",
- "sha256:173308efba2270dcd61cd45a30dfded6ec0085b4b6eb33b5eb11ab443005e088",
- "sha256:21b66200cf44b1c3e86495e3a436fc7a26608f92b8d43d344457c54f1c024cbc",
- "sha256:2c56b820d304dffcadbbb6cbfbc2e2c79ee46ea291db17e288e73cd3c64fefa9",
- "sha256:304dfaa7146cffdb75fbf6bb7c190fd7688795389ad060b970269c8576d038e9",
- "sha256:3f78181a153fa21c018d346f595edd648344751d7f03ab94b398be2ad083ed3e",
- "sha256:4d242d13206ca4302d83d8a6388c9dfce49fc48fdd3c20efad89ba12f785bf9e",
- "sha256:5d1cc2c19afe3b5a546ede7e6a44ce1ff52e443d12b231823268019f608b9b12",
- "sha256:5f2cfc359379c56b3a41b17ebd024109b2049f878badc1e454f31418c3a18436",
- "sha256:65bd52bf55f9a1071398557394203d881384d27b9c2cad7df9a027170aeaef93",
- "sha256:7edd9a311299a61e9919ea4192dd477395b50c014cdc1a1ac572d7c27e2207fa",
- "sha256:8499d9dd1459dc0d0fe68db0832c3d5fc1361ae8e13d05e6849b358dc3f2c279",
- "sha256:866ada14a95b083dd727a845a764cf95dd13ba3dc69a16b99038001b05439709",
- "sha256:87069cf875f0262a6e3187ab0f419f5b4280d3dcf4811ef9613c605f6e4dca95",
- "sha256:93378f3d14fff07572392ce6a6a2ceb3a1f237733bd6dcb9eb6a2b29b0d19085",
- "sha256:95c2d250074cfa76715d58830579c64dff7354484b284c2b8b87e5a38321672c",
- "sha256:ab5875facfdef77e0a47d5fd39ea178b58e60e454a4c85aa1e52fcb80db7babf",
- "sha256:b0e0aeb061a1d7dcd2ed59ea57ee56c9b23dd60100825f98238c06ee5cc4467e",
- "sha256:b78a35c5c74d336f42f44106174b9851c783184a85a3fe3e68857259b37b9ffb",
- "sha256:c9e04d7e9b03a8a6ac2045f7c5ef741be86727d8f49c45db45f244bdd2bcff17",
- "sha256:ca36e7d9430f7481fc7d11e015ae16fbd5575615a8e9060538104778be84addf",
- "sha256:ceebc3c4f6a109777c0053dfa0282fddb8893eddfb0d598574acfb734a926168",
- "sha256:e2c036492e673aad1b7b0d0ccdc0cb30a968353d2c4bf92ac8e73509e1bf212c",
- "sha256:eb326658f9b73c07081300daba90a8746543b5ea177184daed26528273157294",
- "sha256:eb7ae2c4dbdb3c9247e07acc532f91077ae6dbc40ad5bd5dca0bb5a176ee9bda",
- "sha256:edad1cf5b2ce1912c4d8ddad20e11d333165552aba262c882e28c78bbc09dbf6",
- "sha256:eef93a446114ac0193a7b714ce67659db80caf940f3232bad63f4c7a81bc18df",
- "sha256:f7eaea089345a35130bc9a39b89ec1ff69c208efa97b3f8b25ea5d4c41d88094",
- "sha256:f99d206db1f1ae735a8192ab93bd6028f3a42f6fa08467d37a14eb96c9dd34a3"
- ],
- "index": "pypi",
- "version": "==1.7.3"
- },
- "setuptools": {
- "hashes": [
- "sha256:5c89b1a14a67ac5f0956f1cb0aeb7d1d3f4c8ba4e4e1ab7bf1af4933f9a2f0fe",
- "sha256:675fcebecb43c32eb930481abf907619137547f4336206e4d673180242e1a278"
- ],
- "markers": "python_version >= '3.7'",
- "version": "==60.2.0"
+ "sha256:011d4386b53b933142f58a652aa0f149c9b9242abd4f900b9f4ea5fbafc86b89",
+ "sha256:16e09ef68b352d73befa8bcaf3ebe25d3941fe1a58c82909d5589856e6bc8174",
+ "sha256:31d4f2d6b724bc9a98e527b5849b8a7e589bf1ea630c33aa563eda912c9ff0bd",
+ "sha256:38aa39b6724cb65271e469013aeb6f2ce66fd44f093e241c28a9c6bc64fd79ed",
+ "sha256:3d573228c10a3a8c32b9037be982e6440e411b443a6267b067cac72f690b8d56",
+ "sha256:3d9dd6c8b93a22bf9a3a52d1327aca7e092b1299fb3afc4f89e8eba381be7b59",
+ "sha256:559a8a4c03a5ba9fe3232f39ed24f86457e4f3f6c0abbeae1fb945029f092720",
+ "sha256:5e73343c5e0d413c1f937302b2e04fb07872f5843041bcfd50699aef6e95e399",
+ "sha256:723b9f878095ed994756fa4ee3060c450e2db0139c5ba248ee3f9628bd64e735",
+ "sha256:87b01c7d5761e8a266a0fbdb9d88dcba0910d63c1c671bdb4d99d29f469e9e03",
+ "sha256:8f4d059a97b29c91afad46b1737274cb282357a305a80bdd9e8adf3b0ca6a3f0",
+ "sha256:92b2c2af4183ed09afb595709a8ef5783b2baf7f41e26ece24e1329c109691a7",
+ "sha256:937d28722f13302febde29847bbe554b89073fbb924a30475e5ed7b028898b5f",
+ "sha256:a279e27c7f4566ef18bab1b1e2c37d168e365080974758d107e7d237d3f0f484",
+ "sha256:ad5be4039147c808e64f99c0e8a9641eb5d2fa079ff5894dcd8240e94e347af4",
+ "sha256:ae3e327da323d82e918e593460e23babdce40d7ab21490ddf9fc06dec6b91a18",
+ "sha256:bb7088e89cd751acf66195d2f00cf009a1ea113f3019664032d9075b1e727b6c",
+ "sha256:c17a1878d00a5dd2797ccd73623ceca9d02375328f6218ee6d921e1325e61aff",
+ "sha256:c2bae431d127bf0b1da81fc24e4bba0a84d058e3a96b9dd6475dfcb3c5e8761e",
+ "sha256:de2e80ee1d925984c2504812a310841c241791c5279352be4707cdcd7c255039",
+ "sha256:e6f0cd9c0bd374ef834ee1e0f0999678d49dcc400ea6209113d81528958f97c7",
+ "sha256:f3720d0124aced49f6f2198a6900304411dbbeed12f56951d7c66ebef05e3df6",
+ "sha256:f4a6d3b9f9797eb2d43938ac2c5d96d02aed17ef170c8b38f11798717523ddba"
+ ],
+ "index": "pypi",
+ "version": "==1.8.0"
},
"six": {
"hashes": [
@@ -2122,11 +2034,11 @@
},
"sphinx": {
"hashes": [
- "sha256:0a8836751a68306b3fe97ecbe44db786f8479c3bf4b80e3a7f5c838657b4698c",
- "sha256:6a11ea5dd0bdb197f9c2abc2e0ce73e01340464feaece525e64036546d24c851"
+ "sha256:5da895959511473857b6d0200f56865ed62c31e8f82dd338063b84ec022701fe",
+ "sha256:6caad9786055cb1fa22b4a365c1775816b876f91966481765d7d50e9f0dd35cc"
],
"index": "pypi",
- "version": "==4.3.2"
+ "version": "==4.4.0"
},
"sphinx-rtd-theme": {
"hashes": [
@@ -2218,35 +2130,43 @@
},
"tomli": {
"hashes": [
- "sha256:b5bde28da1fed24b9bd1d4d2b8cba62300bfb4ec9a6187a957e8ddb9434c5224",
- "sha256:c292c34f58502a1eb2bbb9f5bbc9a5ebc37bee10ffb8c2d6bbdfa8eb13cc14e1"
+ "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc",
+ "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"
],
"markers": "python_version >= '3.7'",
- "version": "==2.0.0"
+ "version": "==2.0.1"
},
"typing-extensions": {
"hashes": [
- "sha256:4ca091dea149f945ec56afb48dae714f21e8692ef22a395223bcd328961b6a0e",
- "sha256:7f001e5ac290a0c0401508864c7ec868be4e701886d5b573a9528ed3973d9d3b"
+ "sha256:1a9462dcc3347a79b1f1c0271fbe79e844580bb598bafa1ed208b94da3cdcd42",
+ "sha256:21c85e0fe4b9a155d0799430b0ad741cdce7e359660ccbd8b530613e8df88ce2"
],
- "markers": "python_version < '3.10'",
- "version": "==4.0.1"
+ "markers": "python_version >= '3.6'",
+ "version": "==4.1.1"
},
"urllib3": {
"hashes": [
- "sha256:4987c65554f7a2dbf30c18fd48778ef124af6fab771a377103da0585e2336ece",
- "sha256:c4fdf4019605b6e5423637e01bc9fe4daef873709a7973e195ceba0a62bbc844"
+ "sha256:000ca7f471a233c2251c6c7023ee85305721bfdf18621ebff4fd17a8653427ed",
+ "sha256:0e7c33d9a63e7ddfcb86780aac87befc2fbddf46c58dbb487e0855f7ceec283c"
],
"index": "pypi",
- "version": "==1.26.7"
+ "version": "==1.26.8"
},
"virtualenv": {
"hashes": [
- "sha256:339f16c4a86b44240ba7223d0f93a7887c3ca04b5f9c8129da7958447d079b09",
- "sha256:d8458cf8d59d0ea495ad9b34c2599487f8a7772d796f9910858376d1600dd2dd"
+ "sha256:01f5f80744d24a3743ce61858123488e91cb2dd1d3bdf92adaf1bba39ffdedf0",
+ "sha256:e7b34c9474e6476ee208c43a4d9ac1510b041c68347eabfe9a9ea0c86aa0a46b"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'",
- "version": "==20.13.0"
+ "version": "==20.13.2"
+ },
+ "zipp": {
+ "hashes": [
+ "sha256:9f50f446828eb9d45b267433fd3e9da8d801f614129124863f9c51ebceafb87d",
+ "sha256:b47250dd24f92b7dd6a0a8fc5244da14608f3ca90a5efcd37a3b1642fac9a375"
+ ],
+ "markers": "python_version >= '3.7'",
+ "version": "==3.7.0"
}
}
}
diff --git a/SConstruct b/SConstruct
index ea9afc68e2..6b520bee41 100644
--- a/SConstruct
+++ b/SConstruct
@@ -89,7 +89,6 @@ if arch == "aarch64" or arch == "larch64":
"/usr/local/lib",
"/usr/lib",
"/system/vendor/lib64",
- "/system/comma/usr/lib",
f"#third_party/acados/{arch}/lib",
]
@@ -172,8 +171,8 @@ if arch != "Darwin":
ldflags += ["-Wl,--as-needed", "-Wl,--no-undefined"]
# Enable swaglog include in submodules
-cflags += ["-DSWAGLOG"]
-cxxflags += ["-DSWAGLOG"]
+cflags += ['-DSWAGLOG="\\"selfdrive/common/swaglog.h\\""']
+cxxflags += ['-DSWAGLOG="\\"selfdrive/common/swaglog.h\\""']
env = Environment(
ENV=lenv,
@@ -306,11 +305,11 @@ if arch == "Darwin":
qt_env["FRAMEWORKS"] += [f"Qt{m}" for m in qt_modules] + ["OpenGL"]
qt_env.AppendENVPath('PATH', os.path.join(qt_env['QTDIR'], "bin"))
elif arch == "aarch64":
- qt_env['QTDIR'] = "/system/comma/usr"
+ qt_env['QTDIR'] = "/usr"
qt_dirs = [
- f"/system/comma/usr/include/qt",
+ f"/usr/include/qt",
]
- qt_dirs += [f"/system/comma/usr/include/qt/Qt{m}" for m in qt_modules]
+ qt_dirs += [f"/usr/include/qt/Qt{m}" for m in qt_modules]
qt_libs = [f"Qt5{m}" for m in qt_modules]
qt_libs += ['EGL', 'GLESv3', 'c++_shared']
diff --git a/cereal b/cereal
index 28d458a9af..ad2fe885da 160000
--- a/cereal
+++ b/cereal
@@ -1 +1 @@
-Subproject commit 28d458a9af49b38bd0a9052f09fbe927324320fb
+Subproject commit ad2fe885dab99896908b88e765a5f720bfd79b3b
diff --git a/common/conversions.py b/common/conversions.py
new file mode 100644
index 0000000000..b02b33c625
--- /dev/null
+++ b/common/conversions.py
@@ -0,0 +1,19 @@
+import numpy as np
+
+class Conversions:
+ # Speed
+ MPH_TO_KPH = 1.609344
+ KPH_TO_MPH = 1. / MPH_TO_KPH
+ MS_TO_KPH = 3.6
+ KPH_TO_MS = 1. / MS_TO_KPH
+ MS_TO_MPH = MS_TO_KPH * KPH_TO_MPH
+ MPH_TO_MS = MPH_TO_KPH * KPH_TO_MS
+ MS_TO_KNOTS = 1.9438
+ KNOTS_TO_MS = 1. / MS_TO_KNOTS
+
+ # Angle
+ DEG_TO_RAD = np.pi / 180.
+ RAD_TO_DEG = 1. / DEG_TO_RAD
+
+ # Mass
+ LB_TO_KG = 0.453592
diff --git a/docs/CARS.md b/docs/CARS.md
index c32b31dbf2..c7ab9bbfde 100644
--- a/docs/CARS.md
+++ b/docs/CARS.md
@@ -44,9 +44,10 @@
| Lexus | RX Hybrid 2020-21 | All | openpilot | 0mph | 0mph |
| Lexus | UX Hybrid 2019-21 | All | openpilot | 0mph | 0mph |
| Toyota | Alphard 2019-20 | All | openpilot | 0mph | 0mph |
-| Toyota | Avalon 2016-21 | TSS-P | Stock3| 20mph1 | 0mph |
+| Toyota | Avalon 2016-18 | TSS-P | Stock3| 20mph1 | 0mph |
+| Toyota | Avalon 2019-21 | TSS-P | Stock3| 0mph | 0mph |
| Toyota | Avalon 2022 | All | openpilot | 0mph | 0mph |
-| Toyota | Avalon Hybrid 2019-21 | TSS-P | Stock3| 20mph1 | 0mph |
+| Toyota | Avalon Hybrid 2019-21 | TSS-P | Stock3| 0mph | 0mph |
| Toyota | Camry 2018-20 | All | Stock | 0mph4 | 0mph |
| Toyota | Camry 2021-22 | All | openpilot | 0mph4 | 0mph |
| Toyota | Camry Hybrid 2018-20 | All | Stock | 0mph4 | 0mph |
@@ -86,7 +87,7 @@
| Audi | A3 Sportback e-tron 2017-18 | ACC + Lane Assist | Stock | 0mph | 0mph |
| Audi | Q2 2018 | ACC + Lane Assist | Stock | 0mph | 0mph |
| Audi | Q3 2020-21 | ACC + Lane Assist | Stock | 0mph | 0mph |
-| Audi | S3 2015 | ACC + Lane Assist | Stock | 0mph | 0mph |
+| Audi | S3 2015-17 | ACC + Lane Assist | Stock | 0mph | 0mph |
| Cadillac | Escalade ESV 20161 | ACC + LKAS | openpilot | 0mph | 7mph |
| Chevrolet | Volt 2017-181 | Adaptive Cruise | openpilot | 0mph | 7mph |
| Chrysler | Pacifica 2017-18 | Adaptive Cruise | Stock | 0mph | 9mph |
@@ -123,7 +124,7 @@
| Kia | Forte 2018-21 | SCC + LKAS | Stock | 0mph | 0mph |
| Kia | K5 2021-22 | SCC + LFA | Stock | 0mph | 0mph |
| Kia | Niro EV 2019-22 | All | Stock | 0mph | 0mph |
-| Kia | Niro Hybrid 2021 | SCC + LKAS | Stock | 0mph | 0mph |
+| Kia | Niro Hybrid 2021-22 | SCC + LKAS | Stock | 0mph | 0mph |
| Kia | Niro PHEV 2019 | SCC + LKAS | Stock | 10mph | 32mph |
| Kia | Optima 2017 | SCC + LKAS | Stock | 0mph | 32mph |
| Kia | Optima 2019 | SCC + LKAS | Stock | 0mph | 0mph |
@@ -169,7 +170,7 @@
| Volkswagen| T-Cross 20214 | Driver Assistance | Stock | 0mph | 0mph |
| Volkswagen| T-Roc 20214 | Driver Assistance | Stock | 0mph | 0mph |
| Volkswagen| Taos 20224 | Driver Assistance | Stock | 0mph | 0mph |
-| Volkswagen| Tiguan 2020 | Driver Assistance | Stock | 0mph | 0mph |
+| Volkswagen| Tiguan 2020-224 | Driver Assistance | Stock | 0mph | 0mph |
| Volkswagen| Touran 2017 | Driver Assistance | Stock | 0mph | 0mph |
1Requires an [OBD-II car harness](https://comma.ai/shop/products/comma-car-harness) and [community built ASCM harness](https://github.com/commaai/openpilot/wiki/GM#hardware). ***NOTE: disconnecting the ASCM disables Automatic Emergency Braking (AEB).***
diff --git a/laika_repo b/laika_repo
index dec99a0f77..94066cb2b4 160000
--- a/laika_repo
+++ b/laika_repo
@@ -1 +1 @@
-Subproject commit dec99a0f77328f7a9f104020d98d7227345d1288
+Subproject commit 94066cb2b4ad5f2bcb8e33ce02fe15a73a00aace
diff --git a/models/big_supercombo.dlc b/models/big_supercombo.dlc
deleted file mode 100644
index a27e3d1180..0000000000
--- a/models/big_supercombo.dlc
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:ba3fe3e61853cc1434e3e220f40c8e9d1f1b9bab8458196ba3bea6a10b82c6ed
-size 72718099
diff --git a/models/big_supercombo.onnx b/models/big_supercombo.onnx
deleted file mode 100644
index 3039035fbc..0000000000
--- a/models/big_supercombo.onnx
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:bda57c1a66944f5a633ecd739a24d62702c717a234f2fdcc499dfa1d61c3c19e
-size 73147489
diff --git a/models/supercombo.dlc b/models/supercombo.dlc
index 2ebf4fa828..a27e3d1180 100644
--- a/models/supercombo.dlc
+++ b/models/supercombo.dlc
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:209e9544e456dbc2a7d60490da65154e129bc84830909d8d931f97b3df93949b
-size 56684955
+oid sha256:ba3fe3e61853cc1434e3e220f40c8e9d1f1b9bab8458196ba3bea6a10b82c6ed
+size 72718099
diff --git a/models/supercombo.onnx b/models/supercombo.onnx
index 17d233dad7..3039035fbc 100644
--- a/models/supercombo.onnx
+++ b/models/supercombo.onnx
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:2365bae967cce21ce68707c30bf2981bb7081ee5c3e6a3dff793e660f23ff622
-size 57554657
+oid sha256:bda57c1a66944f5a633ecd739a24d62702c717a234f2fdcc499dfa1d61c3c19e
+size 73147489
diff --git a/opendbc b/opendbc
index 46a942d679..eab58f6f8f 160000
--- a/opendbc
+++ b/opendbc
@@ -1 +1 @@
-Subproject commit 46a942d6790531cf5b94b14266140e43afcfda3e
+Subproject commit eab58f6f8f41f255920365ab1fd9c75e312a6869
diff --git a/panda b/panda
index 51ccb9fbd2..5a7af82f06 160000
--- a/panda
+++ b/panda
@@ -1 +1 @@
-Subproject commit 51ccb9fbd266796e1bf6ffda8b93c4119ab09ff4
+Subproject commit 5a7af82f06bf5f8039df8f58f9b1114f7d3436ee
diff --git a/pyextra/acados_template/acados_layout.json b/pyextra/acados_template/acados_layout.json
index 16fd452337..59aa13aa87 100644
--- a/pyextra/acados_template/acados_layout.json
+++ b/pyextra/acados_template/acados_layout.json
@@ -5,6 +5,9 @@
"acados_include_path": [
"str"
],
+ "cython_include_dirs": [
+ "str"
+ ],
"model": {
"name" : [
"str"
@@ -23,7 +26,15 @@
],
"dyn_disc_fun" : [
"str"
- ]
+ ],
+ "gnsf" : {
+ "nontrivial_f_LO": [
+ "int"
+ ],
+ "purely_linear": [
+ "int"
+ ]
+ }
},
"parameter_values": [
"ndarray",
@@ -693,6 +704,18 @@
"alpha_reduction": [
"float"
],
+ "line_search_use_sufficient_descent": [
+ "int"
+ ],
+ "globalization_use_SOC": [
+ "int"
+ ],
+ "full_step_dual": [
+ "int"
+ ],
+ "eps_sufficient_descent": [
+ "float"
+ ],
"sim_method_num_stages": [
"ndarray",
[
diff --git a/pyextra/acados_template/acados_model.py b/pyextra/acados_template/acados_model.py
index 4871a2c0d5..e292cc7477 100644
--- a/pyextra/acados_template/acados_model.py
+++ b/pyextra/acados_template/acados_model.py
@@ -78,6 +78,13 @@ class AcadosModel():
self.dyn_disc_fun_jac = None #: name of function discrete dyanamics + jacobian; Default: :code:`None`
self.dyn_disc_fun = None #: name of function discrete dyanamics; Default: :code:`None`
+ # for GNSF models
+ self.gnsf = {'nontrivial_f_LO': 1, 'purely_linear': 0}
+ """
+ dictionary containing information on GNSF structure needed when rendering templates.
+ Contains integers `nontrivial_f_LO`, `purely_linear`.
+ """
+
## for OCP
# constraints
self.con_h_expr = None #: CasADi expression for the constraint :math:`h`; Default: :code:`None`
diff --git a/pyextra/acados_template/acados_ocp.py b/pyextra/acados_template/acados_ocp.py
index 198ab033dc..8ea129936f 100644
--- a/pyextra/acados_template/acados_ocp.py
+++ b/pyextra/acados_template/acados_ocp.py
@@ -270,28 +270,28 @@ class AcadosOcpDims:
@nx.setter
def nx(self, nx):
- if type(nx) == int and nx > 0:
+ if isinstance(nx, int) and nx > 0:
self.__nx = nx
else:
raise Exception('Invalid nx value, expected positive integer. Exiting.')
@nz.setter
def nz(self, nz):
- if type(nz) == int and nz > -1:
+ if isinstance(nz, int) and nz > -1:
self.__nz = nz
else:
raise Exception('Invalid nz value, expected nonnegative integer. Exiting.')
@nu.setter
def nu(self, nu):
- if type(nu) == int and nu > -1:
+ if isinstance(nu, int) and nu > -1:
self.__nu = nu
else:
raise Exception('Invalid nu value, expected nonnegative integer. Exiting.')
@np.setter
def np(self, np):
- if type(np) == int and np > -1:
+ if isinstance(np, int) and np > -1:
self.__np = np
else:
raise Exception('Invalid np value, expected nonnegative integer. Exiting.')
@@ -312,49 +312,49 @@ class AcadosOcpDims:
@ny_e.setter
def ny_e(self, ny_e):
- if type(ny_e) == int and ny_e > -1:
+ if isinstance(ny_e, int) and ny_e > -1:
self.__ny_e = ny_e
else:
raise Exception('Invalid ny_e value, expected nonnegative integer. Exiting.')
@nr.setter
def nr(self, nr):
- if type(nr) == int and nr > -1:
+ if isinstance(nr, int) and nr > -1:
self.__nr = nr
else:
raise Exception('Invalid nr value, expected nonnegative integer. Exiting.')
@nr_e.setter
def nr_e(self, nr_e):
- if type(nr_e) == int and nr_e > -1:
+ if isinstance(nr_e, int) and nr_e > -1:
self.__nr_e = nr_e
else:
raise Exception('Invalid nr_e value, expected nonnegative integer. Exiting.')
@nh.setter
def nh(self, nh):
- if type(nh) == int and nh > -1:
+ if isinstance(nh, int) and nh > -1:
self.__nh = nh
else:
raise Exception('Invalid nh value, expected nonnegative integer. Exiting.')
@nh_e.setter
def nh_e(self, nh_e):
- if type(nh_e) == int and nh_e > -1:
+ if isinstance(nh_e, int) and nh_e > -1:
self.__nh_e = nh_e
else:
raise Exception('Invalid nh_e value, expected nonnegative integer. Exiting.')
@nphi.setter
def nphi(self, nphi):
- if type(nphi) == int and nphi > -1:
+ if isinstance(nphi, int) and nphi > -1:
self.__nphi = nphi
else:
raise Exception('Invalid nphi value, expected nonnegative integer. Exiting.')
@nphi_e.setter
def nphi_e(self, nphi_e):
- if type(nphi_e) == int and nphi_e > -1:
+ if isinstance(nphi_e, int) and nphi_e > -1:
self.__nphi_e = nphi_e
else:
raise Exception('Invalid nphi_e value, expected nonnegative integer. Exiting.')
@@ -375,42 +375,42 @@ class AcadosOcpDims:
@nbx_0.setter
def nbx_0(self, nbx_0):
- if type(nbx_0) == int and nbx_0 > -1:
+ if isinstance(nbx_0, int) and nbx_0 > -1:
self.__nbx_0 = nbx_0
else:
raise Exception('Invalid nbx_0 value, expected nonnegative integer. Exiting.')
@nbx_e.setter
def nbx_e(self, nbx_e):
- if type(nbx_e) == int and nbx_e > -1:
+ if isinstance(nbx_e, int) and nbx_e > -1:
self.__nbx_e = nbx_e
else:
raise Exception('Invalid nbx_e value, expected nonnegative integer. Exiting.')
@nbu.setter
def nbu(self, nbu):
- if type(nbu) == int and nbu > -1:
+ if isinstance(nbu, int) and nbu > -1:
self.__nbu = nbu
else:
raise Exception('Invalid nbu value, expected nonnegative integer. Exiting.')
@nsbx.setter
def nsbx(self, nsbx):
- if type(nsbx) == int and nsbx > -1:
+ if isinstance(nsbx, int) and nsbx > -1:
self.__nsbx = nsbx
else:
raise Exception('Invalid nsbx value, expected nonnegative integer. Exiting.')
@nsbx_e.setter
def nsbx_e(self, nsbx_e):
- if type(nsbx_e) == int and nsbx_e > -1:
+ if isinstance(nsbx_e, int) and nsbx_e > -1:
self.__nsbx_e = nsbx_e
else:
raise Exception('Invalid nsbx_e value, expected nonnegative integer. Exiting.')
@nsbu.setter
def nsbu(self, nsbu):
- if type(nsbu) == int and nsbu > -1:
+ if isinstance(nsbu, int) and nsbu > -1:
self.__nsbu = nsbu
else:
raise Exception('Invalid nsbu value, expected nonnegative integer. Exiting.')
@@ -1592,14 +1592,14 @@ class AcadosOcpConstraints:
# initial x
@lbx_0.setter
def lbx_0(self, lbx_0):
- if type(lbx_0) == np.ndarray:
+ if isinstance(lbx_0, np.ndarray):
self.__lbx_0 = lbx_0
else:
raise Exception('Invalid lbx_0 value. Exiting.')
@ubx_0.setter
def ubx_0(self, ubx_0):
- if type(ubx_0) == np.ndarray:
+ if isinstance(ubx_0, np.ndarray):
self.__ubx_0 = ubx_0
else:
raise Exception('Invalid ubx_0 value. Exiting.')
@@ -1613,7 +1613,7 @@ class AcadosOcpConstraints:
@Jbx_0.setter
def Jbx_0(self, Jbx_0):
- if type(Jbx_0) == np.ndarray:
+ if isinstance(Jbx_0, np.ndarray):
self.__idxbx_0 = J_to_idx(Jbx_0)
else:
raise Exception('Invalid Jbx_0 value. Exiting.')
@@ -1639,28 +1639,28 @@ class AcadosOcpConstraints:
# bounds on x
@lbx.setter
def lbx(self, lbx):
- if type(lbx) == np.ndarray:
+ if isinstance(lbx, np.ndarray):
self.__lbx = lbx
else:
raise Exception('Invalid lbx value. Exiting.')
@ubx.setter
def ubx(self, ubx):
- if type(ubx) == np.ndarray:
+ if isinstance(ubx, np.ndarray):
self.__ubx = ubx
else:
raise Exception('Invalid ubx value. Exiting.')
@idxbx.setter
def idxbx(self, idxbx):
- if type(idxbx) == np.ndarray:
+ if isinstance(idxbx, np.ndarray):
self.__idxbx = idxbx
else:
raise Exception('Invalid idxbx value. Exiting.')
@Jbx.setter
def Jbx(self, Jbx):
- if type(Jbx) == np.ndarray:
+ if isinstance(Jbx, np.ndarray):
self.__idxbx = J_to_idx(Jbx)
else:
raise Exception('Invalid Jbx value. Exiting.')
@@ -1668,28 +1668,28 @@ class AcadosOcpConstraints:
# bounds on u
@lbu.setter
def lbu(self, lbu):
- if type(lbu) == np.ndarray:
+ if isinstance(lbu, np.ndarray):
self.__lbu = lbu
else:
raise Exception('Invalid lbu value. Exiting.')
@ubu.setter
def ubu(self, ubu):
- if type(ubu) == np.ndarray:
+ if isinstance(ubu, np.ndarray):
self.__ubu = ubu
else:
raise Exception('Invalid ubu value. Exiting.')
@idxbu.setter
def idxbu(self, idxbu):
- if type(idxbu) == np.ndarray:
+ if isinstance(idxbu, np.ndarray):
self.__idxbu = idxbu
else:
raise Exception('Invalid idxbu value. Exiting.')
@Jbu.setter
def Jbu(self, Jbu):
- if type(Jbu) == np.ndarray:
+ if isinstance(Jbu, np.ndarray):
self.__idxbu = J_to_idx(Jbu)
else:
raise Exception('Invalid Jbu value. Exiting.')
@@ -1697,28 +1697,28 @@ class AcadosOcpConstraints:
# bounds on x at shooting node N
@lbx_e.setter
def lbx_e(self, lbx_e):
- if type(lbx_e) == np.ndarray:
+ if isinstance(lbx_e, np.ndarray):
self.__lbx_e = lbx_e
else:
raise Exception('Invalid lbx_e value. Exiting.')
@ubx_e.setter
def ubx_e(self, ubx_e):
- if type(ubx_e) == np.ndarray:
+ if isinstance(ubx_e, np.ndarray):
self.__ubx_e = ubx_e
else:
raise Exception('Invalid ubx_e value. Exiting.')
@idxbx_e.setter
def idxbx_e(self, idxbx_e):
- if type(idxbx_e) == np.ndarray:
+ if isinstance(idxbx_e, np.ndarray):
self.__idxbx_e = idxbx_e
else:
raise Exception('Invalid idxbx_e value. Exiting.')
@Jbx_e.setter
def Jbx_e(self, Jbx_e):
- if type(Jbx_e) == np.ndarray:
+ if isinstance(Jbx_e, np.ndarray):
self.__idxbx_e = J_to_idx(Jbx_e)
else:
raise Exception('Invalid Jbx_e value. Exiting.')
@@ -1742,14 +1742,14 @@ class AcadosOcpConstraints:
@lg.setter
def lg(self, lg):
- if type(lg) == np.ndarray:
+ if isinstance(lg, np.ndarray):
self.__lg = lg
else:
raise Exception('Invalid lg value. Exiting.')
@ug.setter
def ug(self, ug):
- if type(ug) == np.ndarray:
+ if isinstance(ug, np.ndarray):
self.__ug = ug
else:
raise Exception('Invalid ug value. Exiting.')
@@ -1765,14 +1765,14 @@ class AcadosOcpConstraints:
@lg_e.setter
def lg_e(self, lg_e):
- if type(lg_e) == np.ndarray:
+ if isinstance(lg_e, np.ndarray):
self.__lg_e = lg_e
else:
raise Exception('Invalid lg_e value. Exiting.')
@ug_e.setter
def ug_e(self, ug_e):
- if type(ug_e) == np.ndarray:
+ if isinstance(ug_e, np.ndarray):
self.__ug_e = ug_e
else:
raise Exception('Invalid ug_e value. Exiting.')
@@ -1780,14 +1780,14 @@ class AcadosOcpConstraints:
# nonlinear constraints
@lh.setter
def lh(self, lh):
- if type(lh) == np.ndarray:
+ if isinstance(lh, np.ndarray):
self.__lh = lh
else:
raise Exception('Invalid lh value. Exiting.')
@uh.setter
def uh(self, uh):
- if type(uh) == np.ndarray:
+ if isinstance(uh, np.ndarray):
self.__uh = uh
else:
raise Exception('Invalid uh value. Exiting.')
@@ -1795,14 +1795,14 @@ class AcadosOcpConstraints:
# convex-over-nonlinear constraints
@lphi.setter
def lphi(self, lphi):
- if type(lphi) == np.ndarray:
+ if isinstance(lphi, np.ndarray):
self.__lphi = lphi
else:
raise Exception('Invalid lphi value. Exiting.')
@uphi.setter
def uphi(self, uphi):
- if type(uphi) == np.ndarray:
+ if isinstance(uphi, np.ndarray):
self.__uphi = uphi
else:
raise Exception('Invalid uphi value. Exiting.')
@@ -1810,14 +1810,14 @@ class AcadosOcpConstraints:
# nonlinear constraints at shooting node N
@lh_e.setter
def lh_e(self, lh_e):
- if type(lh_e) == np.ndarray:
+ if isinstance(lh_e, np.ndarray):
self.__lh_e = lh_e
else:
raise Exception('Invalid lh_e value. Exiting.')
@uh_e.setter
def uh_e(self, uh_e):
- if type(uh_e) == np.ndarray:
+ if isinstance(uh_e, np.ndarray):
self.__uh_e = uh_e
else:
raise Exception('Invalid uh_e value. Exiting.')
@@ -1825,14 +1825,14 @@ class AcadosOcpConstraints:
# convex-over-nonlinear constraints at shooting node N
@lphi_e.setter
def lphi_e(self, lphi_e):
- if type(lphi_e) == np.ndarray:
+ if isinstance(lphi_e, np.ndarray):
self.__lphi_e = lphi_e
else:
raise Exception('Invalid lphi_e value. Exiting.')
@uphi_e.setter
def uphi_e(self, uphi_e):
- if type(uphi_e) == np.ndarray:
+ if isinstance(uphi_e, np.ndarray):
self.__uphi_e = uphi_e
else:
raise Exception('Invalid uphi_e value. Exiting.')
@@ -1841,21 +1841,21 @@ class AcadosOcpConstraints:
# soft bounds on x
@lsbx.setter
def lsbx(self, lsbx):
- if type(lsbx) == np.ndarray:
+ if isinstance(lsbx, np.ndarray):
self.__lsbx = lsbx
else:
raise Exception('Invalid lsbx value. Exiting.')
@usbx.setter
def usbx(self, usbx):
- if type(usbx) == np.ndarray:
+ if isinstance(usbx, np.ndarray):
self.__usbx = usbx
else:
raise Exception('Invalid usbx value. Exiting.')
@idxsbx.setter
def idxsbx(self, idxsbx):
- if type(idxsbx) == np.ndarray:
+ if isinstance(idxsbx, np.ndarray):
self.__idxsbx = idxsbx
else:
raise Exception('Invalid idxsbx value. Exiting.')
@@ -1870,28 +1870,28 @@ class AcadosOcpConstraints:
# soft bounds on u
@lsbu.setter
def lsbu(self, lsbu):
- if type(lsbu) == np.ndarray:
+ if isinstance(lsbu, np.ndarray):
self.__lsbu = lsbu
else:
raise Exception('Invalid lsbu value. Exiting.')
@usbu.setter
def usbu(self, usbu):
- if type(usbu) == np.ndarray:
+ if isinstance(usbu, np.ndarray):
self.__usbu = usbu
else:
raise Exception('Invalid usbu value. Exiting.')
@idxsbu.setter
def idxsbu(self, idxsbu):
- if type(idxsbu) == np.ndarray:
+ if isinstance(idxsbu, np.ndarray):
self.__idxsbu = idxsbu
else:
raise Exception('Invalid idxsbu value. Exiting.')
@Jsbu.setter
def Jsbu(self, Jsbu):
- if type(Jsbu) == np.ndarray:
+ if isinstance(Jsbu, np.ndarray):
self.__idxsbu = J_to_idx_slack(Jsbu)
else:
raise Exception('Invalid Jsbu value. Exiting.')
@@ -1899,28 +1899,28 @@ class AcadosOcpConstraints:
# soft bounds on x at shooting node N
@lsbx_e.setter
def lsbx_e(self, lsbx_e):
- if type(lsbx_e) == np.ndarray:
+ if isinstance(lsbx_e, np.ndarray):
self.__lsbx_e = lsbx_e
else:
raise Exception('Invalid lsbx_e value. Exiting.')
@usbx_e.setter
def usbx_e(self, usbx_e):
- if type(usbx_e) == np.ndarray:
+ if isinstance(usbx_e, np.ndarray):
self.__usbx_e = usbx_e
else:
raise Exception('Invalid usbx_e value. Exiting.')
@idxsbx_e.setter
def idxsbx_e(self, idxsbx_e):
- if type(idxsbx_e) == np.ndarray:
+ if isinstance(idxsbx_e, np.ndarray):
self.__idxsbx_e = idxsbx_e
else:
raise Exception('Invalid idxsbx_e value. Exiting.')
@Jsbx_e.setter
def Jsbx_e(self, Jsbx_e):
- if type(Jsbx_e) == np.ndarray:
+ if isinstance(Jsbx_e, np.ndarray):
self.__idxsbx_e = J_to_idx_slack(Jsbx_e)
else:
raise Exception('Invalid Jsbx_e value. Exiting.')
@@ -1959,21 +1959,21 @@ class AcadosOcpConstraints:
# soft bounds on nonlinear constraints
@lsh.setter
def lsh(self, lsh):
- if type(lsh) == np.ndarray:
+ if isinstance(lsh, np.ndarray):
self.__lsh = lsh
else:
raise Exception('Invalid lsh value. Exiting.')
@ush.setter
def ush(self, ush):
- if type(ush) == np.ndarray:
+ if isinstance(ush, np.ndarray):
self.__ush = ush
else:
raise Exception('Invalid ush value. Exiting.')
@idxsh.setter
def idxsh(self, idxsh):
- if type(idxsh) == np.ndarray:
+ if isinstance(idxsh, np.ndarray):
self.__idxsh = idxsh
else:
raise Exception('Invalid idxsh value. Exiting.')
@@ -1989,21 +1989,21 @@ class AcadosOcpConstraints:
# soft bounds on convex-over-nonlinear constraints
@lsphi.setter
def lsphi(self, lsphi):
- if type(lsphi) == np.ndarray:
+ if isinstance(lsphi, np.ndarray):
self.__lsphi = lsphi
else:
raise Exception('Invalid lsphi value. Exiting.')
@usphi.setter
def usphi(self, usphi):
- if type(usphi) == np.ndarray:
+ if isinstance(usphi, np.ndarray):
self.__usphi = usphi
else:
raise Exception('Invalid usphi value. Exiting.')
@idxsphi.setter
def idxsphi(self, idxsphi):
- if type(idxsphi) == np.ndarray:
+ if isinstance(idxsphi, np.ndarray):
self.__idxsphi = idxsphi
else:
raise Exception('Invalid idxsphi value. Exiting.')
@@ -2151,6 +2151,10 @@ class AcadosOcpOptions:
self.__ext_cost_num_hess = 0
self.__alpha_min = 0.05
self.__alpha_reduction = 0.7
+ self.__line_search_use_sufficient_descent = 0
+ self.__globalization_use_SOC = 0
+ self.__full_step_dual = 0
+ self.__eps_sufficient_descent = 1e-4
@property
@@ -2367,6 +2371,43 @@ class AcadosOcpOptions:
"""Step size reduction factor for globalization MERIT_BACKTRACKING, default: 0.7."""
return self.__alpha_reduction
+ @property
+ def line_search_use_sufficient_descent(self):
+ """
+ Determines if sufficient descent (Armijo) condition is used in line search.
+ Type: int; 0 or 1;
+ default: 0.
+ """
+ return self.__line_search_use_sufficient_descent
+
+ @property
+ def eps_sufficient_descent(self):
+ """
+ Factor for sufficient descent (Armijo) conditon, see line_search_use_sufficient_descent.
+ Type: float,
+ default: 1e-4.
+ """
+ return self.__eps_sufficient_descent
+
+ @property
+ def globalization_use_SOC(self):
+ """
+ Determines if second order correction (SOC) is done when using MERIT_BACKTRACKING.
+ SOC is done if preliminary line search does not return full step.
+ Type: int; 0 or 1;
+ default: 0.
+ """
+ return self.__globalization_use_SOC
+
+ @property
+ def full_step_dual(self):
+ """
+ Determines if dual variables are updated with full steps (alpha=1.0) when primal variables are updated with smaller step.
+ Type: int; 0 or 1;
+ default: 0.
+ """
+ return self.__full_step_dual
+
@property
def nlp_solver_tol_ineq(self):
"""NLP solver inequality tolerance"""
@@ -2524,12 +2565,23 @@ class AcadosOcpOptions:
@time_steps.setter
def time_steps(self, time_steps):
- self.__time_steps = time_steps
+ if isinstance(time_steps, np.ndarray):
+ if len(time_steps.shape) == 1:
+ self.__time_steps = time_steps
+ else:
+ raise Exception('Invalid time_steps, expected np.ndarray of shape (N,).')
+ else:
+ raise Exception('Invalid time_steps, expected np.ndarray.')
@shooting_nodes.setter
def shooting_nodes(self, shooting_nodes):
- self.__shooting_nodes = shooting_nodes
-
+ if isinstance(shooting_nodes, np.ndarray):
+ if len(shooting_nodes.shape) == 1:
+ self.__shooting_nodes = shooting_nodes
+ else:
+ raise Exception('Invalid shooting_nodes, expected np.ndarray of shape (N+1,).')
+ else:
+ raise Exception('Invalid shooting_nodes, expected np.ndarray.')
@Tsim.setter
def Tsim(self, Tsim):
@@ -2537,7 +2589,12 @@ class AcadosOcpOptions:
@globalization.setter
def globalization(self, globalization):
- self.__globalization = globalization
+ globalization_types = ('MERIT_BACKTRACKING', 'FIXED_STEP')
+ if globalization in globalization_types:
+ self.__globalization = globalization
+ else:
+ raise Exception('Invalid globalization value. Possible values are:\n\n' \
+ + ',\n'.join(globalization_types) + '.\n\nYou have: ' + globalization + '.\n\nExiting.')
@alpha_min.setter
def alpha_min(self, alpha_min):
@@ -2547,10 +2604,38 @@ class AcadosOcpOptions:
def alpha_reduction(self, alpha_reduction):
self.__alpha_reduction = alpha_reduction
+ @line_search_use_sufficient_descent.setter
+ def line_search_use_sufficient_descent(self, line_search_use_sufficient_descent):
+ if line_search_use_sufficient_descent in [0, 1]:
+ self.__line_search_use_sufficient_descent = line_search_use_sufficient_descent
+ else:
+ raise Exception(f'Invalid value for line_search_use_sufficient_descent. Possible values are 0, 1, got {line_search_use_sufficient_descent}')
+
+ @globalization_use_SOC.setter
+ def globalization_use_SOC(self, globalization_use_SOC):
+ if globalization_use_SOC in [0, 1]:
+ self.__globalization_use_SOC = globalization_use_SOC
+ else:
+ raise Exception(f'Invalid value for globalization_use_SOC. Possible values are 0, 1, got {globalization_use_SOC}')
+
+ @full_step_dual.setter
+ def full_step_dual(self, full_step_dual):
+ if full_step_dual in [0, 1]:
+ self.__full_step_dual = full_step_dual
+ else:
+ raise Exception(f'Invalid value for full_step_dual. Possible values are 0, 1, got {full_step_dual}')
+
+ @eps_sufficient_descent.setter
+ def eps_sufficient_descent(self, eps_sufficient_descent):
+ if isinstance(eps_sufficient_descent, float) and eps_sufficient_descent > 0:
+ self.__eps_sufficient_descent = eps_sufficient_descent
+ else:
+ raise Exception('Invalid eps_sufficient_descent value. eps_sufficient_descent must be a positive float. Exiting')
+
@sim_method_num_stages.setter
def sim_method_num_stages(self, sim_method_num_stages):
- # if type(sim_method_num_stages) == int:
+ # if isinstance(sim_method_num_stages, int):
# self.__sim_method_num_stages = sim_method_num_stages
# else:
# raise Exception('Invalid sim_method_num_stages value. sim_method_num_stages must be an integer. Exiting.')
@@ -2560,7 +2645,7 @@ class AcadosOcpOptions:
@sim_method_num_steps.setter
def sim_method_num_steps(self, sim_method_num_steps):
- # if type(sim_method_num_steps) == int:
+ # if isinstance(sim_method_num_steps, int):
# self.__sim_method_num_steps = sim_method_num_steps
# else:
# raise Exception('Invalid sim_method_num_steps value. sim_method_num_steps must be an integer. Exiting.')
@@ -2570,7 +2655,7 @@ class AcadosOcpOptions:
@sim_method_newton_iter.setter
def sim_method_newton_iter(self, sim_method_newton_iter):
- if type(sim_method_newton_iter) == int:
+ if isinstance(sim_method_newton_iter, int):
self.__sim_method_newton_iter = sim_method_newton_iter
else:
raise Exception('Invalid sim_method_newton_iter value. sim_method_newton_iter must be an integer. Exiting.')
@@ -2593,7 +2678,7 @@ class AcadosOcpOptions:
@nlp_solver_step_length.setter
def nlp_solver_step_length(self, nlp_solver_step_length):
- if type(nlp_solver_step_length) == float and nlp_solver_step_length > 0:
+ if isinstance(nlp_solver_step_length, float) and nlp_solver_step_length > 0:
self.__nlp_solver_step_length = nlp_solver_step_length
else:
raise Exception('Invalid nlp_solver_step_length value. nlp_solver_step_length must be a positive float. Exiting')
@@ -2614,7 +2699,7 @@ class AcadosOcpOptions:
@qp_solver_cond_N.setter
def qp_solver_cond_N(self, qp_solver_cond_N):
- if isinstance(qp_solver_cond_N, int) and qp_solver_cond_N > 0:
+ if isinstance(qp_solver_cond_N, int) and qp_solver_cond_N >= 0:
self.__qp_solver_cond_N = qp_solver_cond_N
else:
raise Exception('Invalid qp_solver_cond_N value. qp_solver_cond_N must be a positive int. Exiting')
@@ -2705,21 +2790,21 @@ class AcadosOcpOptions:
@nlp_solver_max_iter.setter
def nlp_solver_max_iter(self, nlp_solver_max_iter):
- if type(nlp_solver_max_iter) == int and nlp_solver_max_iter > 0:
+ if isinstance(nlp_solver_max_iter, int) and nlp_solver_max_iter > 0:
self.__nlp_solver_max_iter = nlp_solver_max_iter
else:
raise Exception('Invalid nlp_solver_max_iter value. nlp_solver_max_iter must be a positive int. Exiting')
@print_level.setter
def print_level(self, print_level):
- if type(print_level) == int and print_level >= 0:
+ if isinstance(print_level, int) and print_level >= 0:
self.__print_level = print_level
else:
raise Exception('Invalid print_level value. print_level takes one of the values >=0. Exiting')
@model_external_shared_lib_dir.setter
def model_external_shared_lib_dir(self, model_external_shared_lib_dir):
- if type(model_external_shared_lib_dir) == str :
+ if isinstance(model_external_shared_lib_dir, str) :
self.__model_external_shared_lib_dir = model_external_shared_lib_dir
else:
raise Exception('Invalid model_external_shared_lib_dir value. Str expected.' \
@@ -2727,7 +2812,7 @@ class AcadosOcpOptions:
@model_external_shared_lib_name.setter
def model_external_shared_lib_name(self, model_external_shared_lib_name):
- if type(model_external_shared_lib_name) == str :
+ if isinstance(model_external_shared_lib_name, str) :
if model_external_shared_lib_name[-3:] == '.so' :
raise Exception('Invalid model_external_shared_lib_name value. Remove the .so extension.' \
+ '.\n\nYou have: ' + type(model_external_shared_lib_name) + '.\n\nExiting.')
@@ -2810,6 +2895,9 @@ class AcadosOcp:
self.acados_lib_path = f'{acados_path}/lib'
"""Path to where acados library is located, type: string"""
+ import numpy
+ self.cython_include_dirs = numpy.get_include()
+
self.__parameter_values = np.array([])
self.__problem_class = 'OCP'
diff --git a/pyextra/acados_template/acados_ocp_solver.py b/pyextra/acados_template/acados_ocp_solver.py
index b34b8fa84a..6d1ff9869c 100644
--- a/pyextra/acados_template/acados_ocp_solver.py
+++ b/pyextra/acados_template/acados_ocp_solver.py
@@ -37,7 +37,7 @@ import os
import json
import numpy as np
from datetime import datetime
-import ctypes
+import importlib
from ctypes import POINTER, cast, CDLL, c_void_p, c_char_p, c_double, c_int, c_int64, byref
from copy import deepcopy
@@ -51,9 +51,9 @@ from .generate_c_code_nls_cost import generate_c_code_nls_cost
from .generate_c_code_external_cost import generate_c_code_external_cost
from .acados_ocp import AcadosOcp
from .acados_model import acados_model_strip_casadi_symbolics
-from .utils import is_column, is_empty, casadi_length, render_template, acados_class2dict,\
+from .utils import is_column, is_empty, casadi_length, render_template,\
format_class_dict, ocp_check_against_layout, np_array_to_list, make_model_consistent,\
- set_up_imported_gnsf_model, get_acados_path, get_ocp_nlp_layout, get_python_interface_path
+ set_up_imported_gnsf_model, get_ocp_nlp_layout, get_python_interface_path
def make_ocp_dims_consistent(acados_ocp):
@@ -90,7 +90,7 @@ def make_ocp_dims_consistent(acados_ocp):
raise Exception('inconsistent dimension np, regarding model.p and parameter_values.' + \
f'\nGot np = {dims.np}, acados_ocp.parameter_values.shape = {acados_ocp.parameter_values.shape[0]}\n')
- # cost
+ ## cost
# initial stage - if not set, copy fields from path constraints
if cost.cost_type_0 is None:
cost.cost_type_0 = cost.cost_type
@@ -434,18 +434,14 @@ def make_ocp_dims_consistent(acados_ocp):
if np.shape(opts.shooting_nodes)[0] != dims.N+1:
raise Exception('inconsistent dimension N, regarding shooting_nodes.')
- # time_steps = opts.shooting_nodes[1:] - opts.shooting_nodes[0:-1]
- # # identify constant time-steps: due to numerical reasons the content of time_steps might vary a bit
- # delta_time_steps = time_steps[1:] - time_steps[0:-1]
- # avg_time_steps = np.average(time_steps)
- # # criterion for constant time-step detection: the min/max difference in values normalized by the average
- # check_const_time_step = np.max(delta_time_steps)-np.min(delta_time_steps) / avg_time_steps
- # # if the criterion is small, we have a constant time-step
- # if check_const_time_step < 1e-9:
- # time_steps[:] = avg_time_steps # if we have a constant time-step: apply the average time-step
- time_steps = np.zeros((dims.N,))
- for i in range(dims.N):
- time_steps[i] = opts.shooting_nodes[i+1] - opts.shooting_nodes[i] # TODO use commented code above
+ time_steps = opts.shooting_nodes[1:] - opts.shooting_nodes[0:-1]
+ # identify constant time_steps: due to numerical reasons the content of time_steps might vary a bit
+ avg_time_steps = np.average(time_steps)
+ # criterion for constant time step detection: the min/max difference in values normalized by the average
+ check_const_time_step = (np.max(time_steps)-np.min(time_steps)) / avg_time_steps
+ # if the criterion is small, we have a constant time_step
+ if check_const_time_step < 1e-9:
+ time_steps[:] = avg_time_steps # if we have a constant time_step: apply the average time_step
opts.time_steps = time_steps
@@ -525,8 +521,7 @@ def ocp_formulation_json_dump(acados_ocp, simulink_opts, json_file='acados_ocp_n
# strip shooting_nodes
ocp_nlp_dict['solver_options'].pop('shooting_nodes', None)
-
- dims_dict = acados_class2dict(acados_ocp.dims)
+ dims_dict = format_class_dict(acados_ocp.dims.__dict__)
ocp_check_against_layout(ocp_nlp_dict, dims_dict)
@@ -782,8 +777,15 @@ class AcadosOcpSolver:
dlclose.argtypes = [c_void_p]
@classmethod
- def generate(cls, acados_ocp, json_file='acados_ocp_nlp.json', simulink_opts=None, build=True):
+ def generate(cls, acados_ocp, json_file='acados_ocp_nlp.json', simulink_opts=None):
+ """
+ Generates the code for an acados OCP solver, given the description in acados_ocp.
+ :param acados_ocp: type AcadosOcp - description of the OCP for acados
+ :param json_file: name for the json file used to render the templated code - default: acados_ocp_nlp.json
+ :param simulink_opts: Options to configure Simulink S-function blocks, mainly to activate possible Inputs and Outputs
+ """
model = acados_ocp.model
+ acados_ocp.code_export_directory = os.path.abspath(acados_ocp.code_export_directory)
if simulink_opts is None:
simulink_opts = get_simulink_default_opts()
@@ -807,24 +809,91 @@ class AcadosOcpSolver:
# dump to json
ocp_formulation_json_dump(acados_ocp, simulink_opts, json_file)
- code_export_dir = acados_ocp.code_export_directory
# render templates
ocp_render_templates(acados_ocp, json_file)
+ acados_ocp.json_file = json_file
- if build:
- ## Compile solver
- cwd=os.getcwd()
- os.chdir(code_export_dir)
- os.system('make clean_ocp_shared_lib')
- os.system('make ocp_shared_lib')
- os.chdir(cwd)
-
- def __init__(self, model_name, N, code_export_dir):
- self.model_name = model_name
- self.N = N
+
+ @classmethod
+ def build(cls, code_export_dir, with_cython=False):
+ """
+ Builds the code for an acados OCP solver, that has been generated in code_export_dir
+ :param code_export_dir: directory in which acados OCP solver has been generated, see generate()
+ :param with_cython: option indicating if the cython interface is build, default: False.
+ """
+ cwd=os.getcwd()
+ os.chdir(code_export_dir)
+ if with_cython:
+ os.system('make clean_ocp_cython')
+ os.system('make ocp_cython')
+ else:
+ os.system('make clean_ocp_shared_lib')
+ os.system('make ocp_shared_lib')
+ os.chdir(cwd)
+
+
+ @classmethod
+ def create_cython_solver(cls, json_file):
+ """
+ Returns an `AcadosOcpSolverCython` object.
+
+ This is an alternative Cython based Python wrapper to the acados OCP solver in C.
+ This offers faster interaction with the solver, because getter and setter calls, which include shape checking are done in compiled C code.
+
+ The default wrapper `AcadosOcpSolver` is based on ctypes.
+ """
+ with open(json_file, 'r') as f:
+ acados_ocp_json = json.load(f)
+ code_export_directory = acados_ocp_json['code_export_directory']
+
+ importlib.invalidate_caches()
+ rel_code_export_directory = os.path.relpath(code_export_directory)
+ acados_ocp_solver_pyx = importlib.import_module(f'{rel_code_export_directory}.acados_ocp_solver_pyx')
+
+ AcadosOcpSolverCython = getattr(acados_ocp_solver_pyx, 'AcadosOcpSolverCython')
+ return AcadosOcpSolverCython(acados_ocp_json['model']['name'],
+ acados_ocp_json['solver_options']['nlp_solver_type'],
+ acados_ocp_json['dims']['N'])
+
+
+ def __init__(self, acados_ocp, json_file='acados_ocp_nlp.json', simulink_opts=None, build=True, generate=True):
self.solver_created = False
- self.shared_lib_name = f'{code_export_dir}/libacados_ocp_solver_{self.model_name}.so'
+ if generate:
+ self.generate(acados_ocp, json_file=json_file, simulink_opts=simulink_opts)
+
+ # load json, store options in object
+ with open(json_file, 'r') as f:
+ acados_ocp_json = json.load(f)
+ self.N = acados_ocp_json['dims']['N']
+ self.model_name = acados_ocp_json['model']['name']
+ self.solver_options = acados_ocp_json['solver_options']
+
+ acados_lib_path = acados_ocp_json['acados_lib_path']
+ code_export_directory = acados_ocp_json['code_export_directory']
+
+ if build:
+ self.build(code_export_directory, with_cython=False)
+
+ # Load acados library to avoid unloading the library.
+ # This is necessary if acados was compiled with OpenMP, since the OpenMP threads can't be destroyed.
+ # Unloading a library which uses OpenMP results in a segfault (on any platform?).
+ # see [https://stackoverflow.com/questions/34439956/vc-crash-when-freeing-a-dll-built-with-openmp]
+ # or [https://python.hotexamples.com/examples/_ctypes/-/dlclose/python-dlclose-function-examples.html]
+ libacados_name = 'libacados.so'
+ libacados_filepath = os.path.join(acados_lib_path, libacados_name)
+ self.__acados_lib = CDLL(libacados_filepath)
+ # find out if acados was compiled with OpenMP
+ try:
+ self.__acados_lib_uses_omp = getattr(self.__acados_lib, 'omp_get_thread_num') is not None
+ except AttributeError as e:
+ self.__acados_lib_uses_omp = False
+ if self.__acados_lib_uses_omp:
+ print('acados was compiled with OpenMP.')
+ else:
+ print('acados was compiled without OpenMP.')
+
+ self.shared_lib_name = f'{code_export_directory}/libacados_ocp_solver_{self.model_name}.so'
# get shared_lib
self.shared_lib = CDLL(self.shared_lib_name)
@@ -842,6 +911,8 @@ class AcadosOcpSolver:
# get pointers solver
self.__get_pointers_solver()
+ self.status = 0
+
def __get_pointers_solver(self):
"""
@@ -864,6 +935,10 @@ class AcadosOcpSolver:
getattr(self.shared_lib, f"{self.model_name}_acados_get_nlp_out").restype = c_void_p
self.nlp_out = getattr(self.shared_lib, f"{self.model_name}_acados_get_nlp_out")(self.capsule)
+ getattr(self.shared_lib, f"{self.model_name}_acados_get_sens_out").argtypes = [c_void_p]
+ getattr(self.shared_lib, f"{self.model_name}_acados_get_sens_out").restype = c_void_p
+ self.sens_out = getattr(self.shared_lib, f"{self.model_name}_acados_get_sens_out")(self.capsule)
+
getattr(self.shared_lib, f"{self.model_name}_acados_get_nlp_in").argtypes = [c_void_p]
getattr(self.shared_lib, f"{self.model_name}_acados_get_nlp_in").restype = c_void_p
self.nlp_in = getattr(self.shared_lib, f"{self.model_name}_acados_get_nlp_in")(self.capsule)
@@ -872,46 +947,26 @@ class AcadosOcpSolver:
getattr(self.shared_lib, f"{self.model_name}_acados_get_nlp_solver").restype = c_void_p
self.nlp_solver = getattr(self.shared_lib, f"{self.model_name}_acados_get_nlp_solver")(self.capsule)
- # treat parameters separately
- getattr(self.shared_lib, f"{self.model_name}_acados_update_params").argtypes = [c_void_p, c_int, POINTER(c_double)]
- getattr(self.shared_lib, f"{self.model_name}_acados_update_params").restype = c_int
- self._set_param = getattr(self.shared_lib, f"{self.model_name}_acados_update_params")
-
- self.shared_lib.ocp_nlp_constraint_dims_get_from_attr.argtypes = \
- [c_void_p, c_void_p, c_void_p, c_int, c_char_p, POINTER(c_int)]
- self.shared_lib.ocp_nlp_constraint_dims_get_from_attr.restype = c_int
-
- self.shared_lib.ocp_nlp_cost_dims_get_from_attr.argtypes = \
- [c_void_p, c_void_p, c_void_p, c_int, c_char_p, POINTER(c_int)]
- self.shared_lib.ocp_nlp_cost_dims_get_from_attr.restype = c_int
-
- self.shared_lib.ocp_nlp_constraints_model_set.argtypes = \
- [c_void_p, c_void_p, c_void_p, c_int, c_char_p, c_void_p]
- self.shared_lib.ocp_nlp_cost_model_set.argtypes = \
- [c_void_p, c_void_p, c_void_p, c_int, c_char_p, c_void_p]
- self.shared_lib.ocp_nlp_out_set.argtypes = \
- [c_void_p, c_void_p, c_void_p, c_int, c_char_p, c_void_p]
- self.shared_lib.ocp_nlp_set.argtypes = \
- [c_void_p, c_void_p, c_int, c_char_p, c_void_p]
def solve(self):
"""
Solve the ocp with current input.
"""
-
getattr(self.shared_lib, f"{self.model_name}_acados_solve").argtypes = [c_void_p]
getattr(self.shared_lib, f"{self.model_name}_acados_solve").restype = c_int
- status = getattr(self.shared_lib, f"{self.model_name}_acados_solve")(self.capsule)
- return status
+ self.status = getattr(self.shared_lib, f"{self.model_name}_acados_solve")(self.capsule)
+
+ return self.status
def set_new_time_steps(self, new_time_steps):
"""
- Set new time steps before solving. Only reload library without code generation but with new time steps.
+ Set new time steps.
+ Recreates the solver if N changes.
- :param new_time_steps: vector of new time steps for the solver
+ :param new_time_steps: 1 dimensional np array of new time steps for the solver
- .. note:: This allows for different use-cases: either set a new size of time-steps or a new distribution of
+ .. note:: This allows for different use-cases: either set a new size of time_steps or a new distribution of
the shooting nodes without changing the number, e.g., to reach a different final time. Both cases
do not require a new code export and compilation.
"""
@@ -921,15 +976,14 @@ class AcadosOcpSolver:
raise Exception('Solver was not yet created!')
# check if time steps really changed in value
- if np.array_equal(self.acados_ocp.solver_options.time_steps, new_time_steps):
+ if np.array_equal(self.solver_options['time_steps'], new_time_steps):
return
N = new_time_steps.size
- model = self.acados_ocp.model
new_time_steps_data = cast(new_time_steps.ctypes.data, POINTER(c_double))
# check if recreation of acados is necessary (no need to recreate acados if sizes are identical)
- if self.acados_ocp.solver_options.time_steps.size == N:
+ if len(self.solver_options['time_steps']) == N:
getattr(self.shared_lib, f"{self.model_name}_acados_update_time_steps").argtypes = [c_void_p, c_int, c_void_p]
getattr(self.shared_lib, f"{self.model_name}_acados_update_time_steps").restype = c_int
assert getattr(self.shared_lib, f"{self.model_name}_acados_update_time_steps")(self.capsule, N, new_time_steps_data) == 0
@@ -941,11 +995,6 @@ class AcadosOcpSolver:
getattr(self.shared_lib, f"{self.model_name}_acados_free").restype = c_int
getattr(self.shared_lib, f"{self.model_name}_acados_free")(self.capsule)
- # store N and new time steps
- self.N = self.acados_ocp.dims.N = N
- self.acados_ocp.solver_options.time_steps = new_time_steps
- self.acados_ocp.solver_options.Tsim = self.acados_ocp.solver_options.time_steps[0]
-
# create solver with new time steps
getattr(self.shared_lib, f"{self.model_name}_acados_create_with_discretization").argtypes = [c_void_p, c_int, c_void_p]
getattr(self.shared_lib, f"{self.model_name}_acados_create_with_discretization").restype = c_int
@@ -956,6 +1005,75 @@ class AcadosOcpSolver:
# get pointers solver
self.__get_pointers_solver()
+ # store time_steps, N
+ self.solver_options['time_steps'] = new_time_steps
+ self.N = N
+ self.solver_options['Tsim'] = self.solver_options['time_steps'][0]
+
+
+ def update_qp_solver_cond_N(self, qp_solver_cond_N: int):
+ """
+ Recreate solver with new value `qp_solver_cond_N` with a partial condensing QP solver.
+ This function is relevant for code reuse, i.e., if either `set_new_time_steps(...)` is used or
+ the influence of a different `qp_solver_cond_N` is studied without code export and compilation.
+ :param qp_solver_cond_N: new number of condensing stages for the solver
+
+ .. note:: This function can only be used in combination with a partial condensing QP solver.
+
+ .. note:: After `set_new_time_steps(...)` is used and depending on the new number of time steps it might be
+ necessary to change `qp_solver_cond_N` as well (using this function), i.e., typically
+ `qp_solver_cond_N < N`.
+ """
+ # unlikely but still possible
+ if not self.solver_created:
+ raise Exception('Solver was not yet created!')
+ if self.N < qp_solver_cond_N:
+ raise Exception('Setting qp_solver_cond_N to be larger than N does not work!')
+ if self.solver_options['qp_solver_cond_N'] != qp_solver_cond_N:
+ self.solver_created = False
+
+ # recreate the solver
+ fun_name = f'{self.model_name}_acados_update_qp_solver_cond_N'
+ getattr(self.shared_lib, fun_name).argtypes = [c_void_p, c_int]
+ getattr(self.shared_lib, fun_name).restype = c_int
+ assert getattr(self.shared_lib, fun_name)(self.capsule, qp_solver_cond_N) == 0
+
+ # store the new value
+ self.solver_options['qp_solver_cond_N'] = qp_solver_cond_N
+ self.solver_created = True
+
+ # get pointers solver
+ self.__get_pointers_solver()
+
+
+ def eval_param_sens(self, index, stage=0, field="ex"):
+ """
+ Calculate the sensitivity of the curent solution with respect to the initial state component of index
+
+ :param index: integer corresponding to initial state index in range(nx)
+ """
+
+ field_ = field
+ field = field_.encode('utf-8')
+
+ # checks
+ if not isinstance(index, int):
+ raise Exception('AcadosOcpSolver.eval_param_sens(): index must be Integer.')
+
+ self.shared_lib.ocp_nlp_dims_get_from_attr.argtypes = [c_void_p, c_void_p, c_void_p, c_int, c_char_p]
+ self.shared_lib.ocp_nlp_dims_get_from_attr.restype = c_int
+ nx = self.shared_lib.ocp_nlp_dims_get_from_attr(self.nlp_config, self.nlp_dims, self.nlp_out, 0, "x".encode('utf-8'))
+
+ if index < 0 or index > nx:
+ raise Exception(f'AcadosOcpSolver.eval_param_sens(): index must be in [0, nx-1], got: {index}.')
+
+ # actual eval_param
+ self.shared_lib.ocp_nlp_eval_param_sens.argtypes = [c_void_p, c_char_p, c_int, c_int, c_void_p]
+ self.shared_lib.ocp_nlp_eval_param_sens.restype = None
+ self.shared_lib.ocp_nlp_eval_param_sens(self.nlp_solver, field, stage, index, self.sens_out)
+
+ return
+
def get(self, stage_, field_):
"""
@@ -978,23 +1096,30 @@ class AcadosOcpSolver:
out_fields = ['x', 'u', 'z', 'pi', 'lam', 't', 'sl', 'su']
# mem_fields = ['sl', 'su']
+ sens_fields = ['sens_u', "sens_x"]
+ all_fields = out_fields + sens_fields
+
field = field_
- field = field.encode('utf-8')
- if (field_ not in out_fields):
+ if (field_ not in all_fields):
raise Exception('AcadosOcpSolver.get(): {} is an invalid argument.\
- \n Possible values are {}. Exiting.'.format(field_, out_fields))
+ \n Possible values are {}. Exiting.'.format(field_, all_fields))
if not isinstance(stage_, int):
raise Exception('AcadosOcpSolver.get(): stage index must be Integer.')
if stage_ < 0 or stage_ > self.N:
- raise Exception('AcadosOcpSolver.get(): stage index must be in [0, N], got: {}.'.format(self.N))
+ raise Exception('AcadosOcpSolver.get(): stage index must be in [0, N], got: {}.'.format(stage_))
if stage_ == self.N and field_ == 'pi':
raise Exception('AcadosOcpSolver.get(): field {} does not exist at final stage {}.'\
.format(field_, stage_))
+ if field_ in sens_fields:
+ field = field_.replace('sens_', '')
+
+ field = field.encode('utf-8')
+
self.shared_lib.ocp_nlp_dims_get_from_attr.argtypes = \
[c_void_p, c_void_p, c_void_p, c_int, c_char_p]
self.shared_lib.ocp_nlp_dims_get_from_attr.restype = c_int
@@ -1015,6 +1140,11 @@ class AcadosOcpSolver:
# [c_void_p, c_void_p, c_void_p, c_int, c_char_p, c_void_p]
# self.shared_lib.ocp_nlp_get_at_stage(self.nlp_config, \
# self.nlp_dims, self.nlp_solver, stage_, field, out_data)
+ elif field_ in sens_fields:
+ self.shared_lib.ocp_nlp_out_get.argtypes = \
+ [c_void_p, c_void_p, c_void_p, c_int, c_char_p, c_void_p]
+ self.shared_lib.ocp_nlp_out_get(self.nlp_config, \
+ self.nlp_dims, self.sens_out, stage_, field, out_data)
return out
@@ -1029,6 +1159,7 @@ class AcadosOcpSolver:
- res_comp: residual wrt complementarity conditions
- qp_stat: status of QP solver
- qp_iter: number of QP iterations
+ - alpha: SQP step size
- qp_res_stat: stationarity residual of the last QP solution
- qp_res_eq: residual wrt equality constraints (dynamics) of the last QP solution
- qp_res_ineq: residual wrt inequality constraints (constraints) of the last QP solution
@@ -1036,19 +1167,18 @@ class AcadosOcpSolver:
"""
stat = self.get_stats("statistics")
- if self.acados_ocp.solver_options.nlp_solver_type == 'SQP':
- print('\niter\tres_stat\tres_eq\t\tres_ineq\tres_comp\tqp_stat\tqp_iter')
- if stat.shape[0]>7:
+ if self.solver_options['nlp_solver_type'] == 'SQP':
+ print('\niter\tres_stat\tres_eq\t\tres_ineq\tres_comp\tqp_stat\tqp_iter\talpha')
+ if stat.shape[0]>8:
print('\tqp_res_stat\tqp_res_eq\tqp_res_ineq\tqp_res_comp')
for jj in range(stat.shape[1]):
- print('{:d}\t{:e}\t{:e}\t{:e}\t{:e}\t{:d}\t{:d}'.format( \
- int(stat[0][jj]), stat[1][jj], stat[2][jj], \
- stat[3][jj], stat[4][jj], int(stat[5][jj]), int(stat[6][jj])))
- if stat.shape[0]>7:
+ print(f'{int(stat[0][jj]):d}\t{stat[1][jj]:e}\t{stat[2][jj]:e}\t{stat[3][jj]:e}\t' +
+ f'{stat[4][jj]:e}\t{int(stat[5][jj]):d}\t{int(stat[6][jj]):d}\t{stat[7][jj]:e}\t')
+ if stat.shape[0]>8:
print('\t{:e}\t{:e}\t{:e}\t{:e}'.format( \
- stat[7][jj], stat[8][jj], stat[9][jj], stat[10][jj]))
+ stat[8][jj], stat[9][jj], stat[10][jj], stat[11][jj]))
print('\n')
- elif self.acados_ocp.solver_options.nlp_solver_type == 'SQP_RTI':
+ elif self.solver_options['nlp_solver_type'] == 'SQP_RTI':
print('\niter\tqp_stat\tqp_iter')
if stat.shape[0]>3:
print('\tqp_res_stat\tqp_res_eq\tqp_res_ineq\tqp_res_comp')
@@ -1108,6 +1238,7 @@ class AcadosOcpSolver:
with open(filename, 'r') as f:
solution = json.load(f)
+ print(f"loading iterate {filename}")
for key in solution.keys():
(field, stage) = key.split('_')
self.set(int(stage), field, np.array(solution[key]))
@@ -1117,62 +1248,99 @@ class AcadosOcpSolver:
"""
Get the information of the last solver call.
- :param field: string in ['statistics', 'time_tot', 'time_lin', 'time_sim', 'time_sim_ad', 'time_sim_la', 'time_qp', 'time_qp_solver_call', 'time_reg', 'sqp_iter']
+ :param field: string in ['statistics', 'time_tot', 'time_lin', 'time_sim', 'time_sim_ad', 'time_sim_la', 'time_qp', 'time_qp_solver_call', 'time_reg', 'sqp_iter', 'residuals', 'qp_iter', 'alpha']
+
+ Available fileds:
+ - time_tot: total CPU time previous call
+ - time_lin: CPU time for linearization
+ - time_sim: CPU time for integrator
+ - time_sim_ad: CPU time for integrator contribution of external function calls
+ - time_sim_la: CPU time for integrator contribution of linear algebra
+ - time_qp: CPU time qp solution
+ - time_qp_solver_call: CPU time inside qp solver (without converting the QP)
+ - time_qp_xcond: time_glob: CPU time globalization
+ - time_solution_sensitivities: CPU time for previous call to eval_param_sens
+ - time_reg: CPU time regularization
+ - sqp_iter: number of SQP iterations
+ - qp_iter: vector of QP iterations for last SQP call
+ - statistics: table with info about last iteration
+ - stat_m: number of rows in statistics matrix
+ - stat_n: number of columns in statistics matrix
+ - residuals: residuals of last iterate
+ - alpha: step sizes of SQP iterations
"""
- fields = ['time_tot', # total cpu time previous call
- 'time_lin', # cpu time for linearization
- 'time_sim', # cpu time for integrator
- 'time_sim_ad', # cpu time for integrator contribution of external function calls
- 'time_sim_la', # cpu time for integrator contribution of linear algebra
- 'time_qp', # cpu time qp solution
- 'time_qp_solver_call', # cpu time inside qp solver (without converting the QP)
+ double_fields = ['time_tot',
+ 'time_lin',
+ 'time_sim',
+ 'time_sim_ad',
+ 'time_sim_la',
+ 'time_qp',
+ 'time_qp_solver_call',
'time_qp_xcond',
- 'time_glob', # cpu time globalization
- 'time_reg', # cpu time regularization
- 'sqp_iter', # number of SQP iterations
- 'qp_iter', # vector of QP iterations for last SQP call
- 'statistics', # table with info about last iteration
+ 'time_glob',
+ 'time_solution_sensitivities',
+ 'time_reg'
+ ]
+ fields = double_fields + [
+ 'sqp_iter',
+ 'qp_iter',
+ 'statistics',
'stat_m',
- 'stat_n',]
+ 'stat_n',
+ 'residuals',
+ 'alpha',
+ ]
+ field = field_.encode('utf-8')
- field = field_
- field = field.encode('utf-8')
- if (field_ not in fields):
- raise Exception('AcadosOcpSolver.get_stats(): {} is not a valid argument.\
- \n Possible values are {}. Exiting.'.format(fields, fields))
if field_ in ['sqp_iter', 'stat_m', 'stat_n']:
out = np.ascontiguousarray(np.zeros((1,)), dtype=np.int64)
out_data = cast(out.ctypes.data, POINTER(c_int64))
+ self.shared_lib.ocp_nlp_get.argtypes = [c_void_p, c_void_p, c_char_p, c_void_p]
+ self.shared_lib.ocp_nlp_get(self.nlp_config, self.nlp_solver, field, out_data)
+ return out
+
+ # TODO: just return double instead of np.
+ elif field_ in double_fields:
+ out = np.zeros((1,))
+ out_data = cast(out.ctypes.data, POINTER(c_double))
+ self.shared_lib.ocp_nlp_get.argtypes = [c_void_p, c_void_p, c_char_p, c_void_p]
+ self.shared_lib.ocp_nlp_get(self.nlp_config, self.nlp_solver, field, out_data)
+ return out
elif field_ == 'statistics':
sqp_iter = self.get_stats("sqp_iter")
stat_m = self.get_stats("stat_m")
stat_n = self.get_stats("stat_n")
-
min_size = min([stat_m, sqp_iter+1])
-
out = np.ascontiguousarray(
np.zeros((stat_n[0]+1, min_size[0])), dtype=np.float64)
out_data = cast(out.ctypes.data, POINTER(c_double))
+ self.shared_lib.ocp_nlp_get.argtypes = [c_void_p, c_void_p, c_char_p, c_void_p]
+ self.shared_lib.ocp_nlp_get(self.nlp_config, self.nlp_solver, field, out_data)
+ return out
elif field_ == 'qp_iter':
full_stats = self.get_stats('statistics')
- if self.acados_ocp.solver_options.nlp_solver_type == 'SQP':
- out = full_stats[6, :]
- elif self.acados_ocp.solver_options.nlp_solver_type == 'SQP_RTI':
- out = full_stats[2, :]
+ if self.solver_options['nlp_solver_type'] == 'SQP':
+ return full_stats[6, :]
+ elif self.solver_options['nlp_solver_type'] == 'SQP_RTI':
+ return full_stats[2, :]
- else:
- out = np.ascontiguousarray(np.zeros((1,)), dtype=np.float64)
- out_data = cast(out.ctypes.data, POINTER(c_double))
+ elif field_ == 'alpha':
+ full_stats = self.get_stats('statistics')
+ if self.solver_options['nlp_solver_type'] == 'SQP':
+ return full_stats[7, :]
+ else: # self.solver_options['nlp_solver_type'] == 'SQP_RTI':
+ raise Exception("alpha values are not available for SQP_RTI")
- if not field_ == 'qp_iter':
- self.shared_lib.ocp_nlp_get.argtypes = [c_void_p, c_void_p, c_char_p, c_void_p]
- self.shared_lib.ocp_nlp_get(self.nlp_config, self.nlp_solver, field, out_data)
+ elif field_ == 'residuals':
+ return self.get_residuals()
- return out
+ else:
+ raise Exception(f'AcadosOcpSolver.get_stats(): {field} is not a valid argument.'
+ + f'\n Possible values are {fields}.')
def get_cost(self):
@@ -1201,7 +1369,7 @@ class AcadosOcpSolver:
Returns an array of the form [res_stat, res_eq, res_ineq, res_comp].
"""
# compute residuals if RTI
- if self.acados_ocp.solver_options.nlp_solver_type == 'SQP_RTI':
+ if self.solver_options['nlp_solver_type'] == 'SQP_RTI':
self.shared_lib.ocp_nlp_eval_residuals.argtypes = [c_void_p, c_void_p, c_void_p]
self.shared_lib.ocp_nlp_eval_residuals(self.nlp_solver, self.nlp_in, self.nlp_out)
@@ -1230,9 +1398,7 @@ class AcadosOcpSolver:
# Note: this function should not be used anymore, better use cost_set, constraints_set
-
def set(self, stage_, field_, value_):
-
"""
Set numerical data inside the solver.
@@ -1253,6 +1419,7 @@ class AcadosOcpSolver:
cost_fields = ['y_ref', 'yref']
constraints_fields = ['lbx', 'ubx', 'lbu', 'ubu']
out_fields = ['x', 'u', 'pi', 'lam', 't', 'z', 'sl', 'su']
+ mem_fields = ['xdot_guess']
# cast value_ to avoid conversion issues
if isinstance(value_, (float, int)):
@@ -1294,18 +1461,25 @@ class AcadosOcpSolver:
value_data_p = cast((value_data), c_void_p)
if field_ in constraints_fields:
+ self.shared_lib.ocp_nlp_constraints_model_set.argtypes = \
+ [c_void_p, c_void_p, c_void_p, c_int, c_char_p, c_void_p]
self.shared_lib.ocp_nlp_constraints_model_set(self.nlp_config, \
self.nlp_dims, self.nlp_in, stage, field, value_data_p)
elif field_ in cost_fields:
+ self.shared_lib.ocp_nlp_cost_model_set.argtypes = \
+ [c_void_p, c_void_p, c_void_p, c_int, c_char_p, c_void_p]
self.shared_lib.ocp_nlp_cost_model_set(self.nlp_config, \
self.nlp_dims, self.nlp_in, stage, field, value_data_p)
elif field_ in out_fields:
+ self.shared_lib.ocp_nlp_out_set.argtypes = \
+ [c_void_p, c_void_p, c_void_p, c_int, c_char_p, c_void_p]
self.shared_lib.ocp_nlp_out_set(self.nlp_config, \
self.nlp_dims, self.nlp_out, stage, field, value_data_p)
- # elif field_ in mem_fields:
- # self.shared_lib.ocp_nlp_set(self.nlp_config, \
- # self.nlp_solver, stage, field, value_data_p)
-
+ elif field_ in mem_fields:
+ self.shared_lib.ocp_nlp_set.argtypes = \
+ [c_void_p, c_void_p, c_int, c_char_p, c_void_p]
+ self.shared_lib.ocp_nlp_set(self.nlp_config, \
+ self.nlp_solver, stage, field, value_data_p)
return
@@ -1364,9 +1538,8 @@ class AcadosOcpSolver:
raise Exception("Unknown api: '{}'".format(api))
if value_shape != tuple(dims):
- raise Exception('AcadosOcpSolver.cost_set(): mismatching dimension', \
- ' for field "{}" with dimension {} (you have {})'.format( \
- field_, tuple(dims), value_shape))
+ raise Exception('AcadosOcpSolver.cost_set(): mismatching dimension' +
+ f' for field "{field_}" at stage {stage} with dimension {tuple(dims)} (you have {value_shape})')
value_data = cast(value_.ctypes.data, POINTER(c_double))
value_data_p = cast((value_data), c_void_p)
@@ -1433,8 +1606,8 @@ class AcadosOcpSolver:
raise Exception("Unknown api: '{}'".format(api))
if value_shape != tuple(dims):
- raise Exception('AcadosOcpSolver.constraints_set(): mismatching dimension' \
- ' for field "{}" with dimension {} (you have {})'.format(field_, tuple(dims), value_shape))
+ raise Exception(f'AcadosOcpSolver.constraints_set(): mismatching dimension' +
+ f' for field "{field_}" at stage {stage} with dimension {tuple(dims)} (you have {value_shape})')
value_data = cast(value_.ctypes.data, POINTER(c_double))
value_data_p = cast((value_data), c_void_p)
@@ -1490,11 +1663,11 @@ class AcadosOcpSolver:
"""
Set options of the solver.
- :param field: string, e.g. 'print_level', 'rti_phase', 'initialize_t_slacks', 'step_length', 'alpha_min', 'alpha_reduction'
+ :param field: string, e.g. 'print_level', 'rti_phase', 'initialize_t_slacks', 'step_length', 'alpha_min', 'alpha_reduction', 'qp_warm_start', 'line_search_use_sufficient_descent', 'full_step_dual', 'globalization_use_SOC'
:param value: of type int, float
"""
- int_fields = ['print_level', 'rti_phase', 'initialize_t_slacks']
- double_fields = ['step_length', 'tol_eq', 'tol_stat', 'tol_ineq', 'tol_comp', 'alpha_min', 'alpha_reduction']
+ int_fields = ['print_level', 'rti_phase', 'initialize_t_slacks', 'qp_warm_start', 'line_search_use_sufficient_descent', 'full_step_dual', 'globalization_use_SOC']
+ double_fields = ['step_length', 'tol_eq', 'tol_stat', 'tol_ineq', 'tol_comp', 'alpha_min', 'alpha_reduction', 'eps_sufficient_descent']
string_fields = ['globalization']
# check field availability and type
@@ -1522,10 +1695,10 @@ class AcadosOcpSolver:
if field_ == 'rti_phase':
if value_ < 0 or value_ > 2:
- raise Exception('AcadosOcpSolver.solve(): argument \'rti_phase\' can '
+ raise Exception('AcadosOcpSolver.options_set(): argument \'rti_phase\' can '
'take only values 0, 1, 2 for SQP-RTI-type solvers')
- if self.acados_ocp.solver_options.nlp_solver_type != 'SQP_RTI' and value_ > 0:
- raise Exception('AcadosOcpSolver.solve(): argument \'rti_phase\' can '
+ if self.solver_options['nlp_solver_type'] != 'SQP_RTI' and value_ > 0:
+ raise Exception('AcadosOcpSolver.options_set(): argument \'rti_phase\' can '
'take only value 0 for SQP-type solvers')
# encode
diff --git a/pyextra/acados_template/acados_ocp_solver_fast.py b/pyextra/acados_template/acados_ocp_solver_fast.py
deleted file mode 100644
index 656d288f1c..0000000000
--- a/pyextra/acados_template/acados_ocp_solver_fast.py
+++ /dev/null
@@ -1,402 +0,0 @@
-import sys
-import os
-import json
-import numpy as np
-from datetime import datetime
-
-from ctypes import POINTER, CDLL, c_void_p, c_int, cast, c_double, c_char_p
-
-from copy import deepcopy
-
-from .generate_c_code_explicit_ode import generate_c_code_explicit_ode
-from .generate_c_code_implicit_ode import generate_c_code_implicit_ode
-from .generate_c_code_gnsf import generate_c_code_gnsf
-from .generate_c_code_discrete_dynamics import generate_c_code_discrete_dynamics
-from .generate_c_code_constraint import generate_c_code_constraint
-from .generate_c_code_nls_cost import generate_c_code_nls_cost
-from .generate_c_code_external_cost import generate_c_code_external_cost
-from .acados_ocp import AcadosOcp
-from .acados_model import acados_model_strip_casadi_symbolics
-from .utils import is_column, is_empty, casadi_length, render_template, acados_class2dict,\
- format_class_dict, ocp_check_against_layout, np_array_to_list, make_model_consistent,\
- set_up_imported_gnsf_model, get_acados_path
-
-
-class AcadosOcpSolverFast:
- dlclose = CDLL(None).dlclose
- dlclose.argtypes = [c_void_p]
-
- def __init__(self, model_name, N, code_export_dir):
-
- self.solver_created = False
- self.N = N
- self.model_name = model_name
-
- self.shared_lib_name = f'{code_export_dir}/libacados_ocp_solver_{model_name}.so'
-
- # get shared_lib
- self.shared_lib = CDLL(self.shared_lib_name)
-
- # create capsule
- getattr(self.shared_lib, f"{model_name}_acados_create_capsule").restype = c_void_p
- self.capsule = getattr(self.shared_lib, f"{model_name}_acados_create_capsule")()
-
- # create solver
- getattr(self.shared_lib, f"{model_name}_acados_create").argtypes = [c_void_p]
- getattr(self.shared_lib, f"{model_name}_acados_create").restype = c_int
- assert getattr(self.shared_lib, f"{model_name}_acados_create")(self.capsule)==0
- self.solver_created = True
-
- # get pointers solver
- getattr(self.shared_lib, f"{model_name}_acados_get_nlp_opts").argtypes = [c_void_p]
- getattr(self.shared_lib, f"{model_name}_acados_get_nlp_opts").restype = c_void_p
- self.nlp_opts = getattr(self.shared_lib, f"{model_name}_acados_get_nlp_opts")(self.capsule)
-
- getattr(self.shared_lib, f"{model_name}_acados_get_nlp_dims").argtypes = [c_void_p]
- getattr(self.shared_lib, f"{model_name}_acados_get_nlp_dims").restype = c_void_p
- self.nlp_dims = getattr(self.shared_lib, f"{model_name}_acados_get_nlp_dims")(self.capsule)
-
- getattr(self.shared_lib, f"{model_name}_acados_get_nlp_config").argtypes = [c_void_p]
- getattr(self.shared_lib, f"{model_name}_acados_get_nlp_config").restype = c_void_p
- self.nlp_config = getattr(self.shared_lib, f"{model_name}_acados_get_nlp_config")(self.capsule)
-
- getattr(self.shared_lib, f"{model_name}_acados_get_nlp_out").argtypes = [c_void_p]
- getattr(self.shared_lib, f"{model_name}_acados_get_nlp_out").restype = c_void_p
- self.nlp_out = getattr(self.shared_lib, f"{model_name}_acados_get_nlp_out")(self.capsule)
-
- getattr(self.shared_lib, f"{model_name}_acados_get_nlp_in").argtypes = [c_void_p]
- getattr(self.shared_lib, f"{model_name}_acados_get_nlp_in").restype = c_void_p
- self.nlp_in = getattr(self.shared_lib, f"{model_name}_acados_get_nlp_in")(self.capsule)
-
- getattr(self.shared_lib, f"{model_name}_acados_get_nlp_solver").argtypes = [c_void_p]
- getattr(self.shared_lib, f"{model_name}_acados_get_nlp_solver").restype = c_void_p
- self.nlp_solver = getattr(self.shared_lib, f"{model_name}_acados_get_nlp_solver")(self.capsule)
-
-
- def solve(self):
- """
- Solve the ocp with current input.
- """
- model_name = self.model_name
-
- getattr(self.shared_lib, f"{model_name}_acados_solve").argtypes = [c_void_p]
- getattr(self.shared_lib, f"{model_name}_acados_solve").restype = c_int
- status = getattr(self.shared_lib, f"{model_name}_acados_solve")(self.capsule)
- return status
-
- def cost_set(self, start_stage_, field_, value_, api='warn'):
- self.cost_set_slice(start_stage_, start_stage_+1, field_, value_[None], api='warn')
- return
-
- def cost_set_slice(self, start_stage_, end_stage_, field_, value_, api='warn'):
- """
- Set numerical data in the cost module of the solver.
-
- :param stage: integer corresponding to shooting node
- :param field: string, e.g. 'yref', 'W', 'ext_cost_num_hess'
- :param value: of appropriate size
- """
- # cast value_ to avoid conversion issues
- if isinstance(value_, (float, int)):
- value_ = np.array([value_])
- value_ = np.ascontiguousarray(np.copy(value_), dtype=np.float64)
- field = field_
- field = field.encode('utf-8')
- dim = np.product(value_.shape[1:])
-
- start_stage = c_int(start_stage_)
- end_stage = c_int(end_stage_)
- self.shared_lib.ocp_nlp_cost_dims_get_from_attr.argtypes = \
- [c_void_p, c_void_p, c_void_p, c_int, c_char_p, POINTER(c_int)]
- self.shared_lib.ocp_nlp_cost_dims_get_from_attr.restype = c_int
-
- dims = np.ascontiguousarray(np.zeros((2,)), dtype=np.intc)
- dims_data = cast(dims.ctypes.data, POINTER(c_int))
-
- self.shared_lib.ocp_nlp_cost_dims_get_from_attr(self.nlp_config,
- self.nlp_dims, self.nlp_out, start_stage_, field, dims_data)
-
- value_shape = value_.shape
- expected_shape = tuple(np.concatenate([np.array([end_stage_ - start_stage_]), dims]))
- if len(value_shape) == 2:
- value_shape = (value_shape[0], value_shape[1], 0)
-
- elif len(value_shape) == 3:
- if api=='old':
- pass
- elif api=='warn':
- if not np.all(np.ravel(value_, order='F')==np.ravel(value_, order='K')):
- raise Exception("Ambiguity in API detected.\n"
- "Are you making an acados model from scrach? Add api='new' to cost_set and carry on.\n"
- "Are you seeing this error suddenly in previously running code? Read on.\n"
- " You are relying on a now-fixed bug in cost_set for field '{}'.\n".format(field_) +
- " acados_template now correctly passes on any matrices to acados in column major format.\n" +
- " Two options to fix this error: \n" +
- " * Add api='old' to cost_set to restore old incorrect behaviour\n" +
- " * Add api='new' to cost_set and remove any unnatural manipulation of the value argument " +
- "such as non-mathematical transposes, reshaping, casting to fortran order, etc... " +
- "If there is no such manipulation, then you have probably been getting an incorrect solution before.")
- # Get elements in column major order
- value_ = np.ravel(value_, order='F')
- elif api=='new':
- # Get elements in column major order
- value_ = np.ravel(value_, order='F')
- else:
- raise Exception("Unknown api: '{}'".format(api))
-
- if value_shape != expected_shape:
- raise Exception('AcadosOcpSolver.cost_set(): mismatching dimension',
- ' for field "{}" with dimension {} (you have {})'.format(
- field_, expected_shape, value_shape))
-
-
- value_data = cast(value_.ctypes.data, POINTER(c_double))
- value_data_p = cast((value_data), c_void_p)
-
- self.shared_lib.ocp_nlp_cost_model_set_slice.argtypes = \
- [c_void_p, c_void_p, c_void_p, c_int, c_int, c_char_p, c_void_p, c_int]
- self.shared_lib.ocp_nlp_cost_model_set_slice(self.nlp_config,
- self.nlp_dims, self.nlp_in, start_stage, end_stage, field, value_data_p, dim)
- return
-
- def constraints_set(self, start_stage_, field_, value_, api='warn'):
- self.constraints_set_slice(start_stage_, start_stage_+1, field_, value_[None], api='warn')
- return
-
- def constraints_set_slice(self, start_stage_, end_stage_, field_, value_, api='warn'):
- """
- Set numerical data in the constraint module of the solver.
-
- :param stage: integer corresponding to shooting node
- :param field: string in ['lbx', 'ubx', 'lbu', 'ubu', 'lg', 'ug', 'lh', 'uh', 'uphi']
- :param value: of appropriate size
- """
- # cast value_ to avoid conversion issues
- if isinstance(value_, (float, int)):
- value_ = np.array([value_])
- value_ = value_.astype(float)
-
- field = field_
- field = field.encode('utf-8')
- dim = np.product(value_.shape[1:])
-
- start_stage = c_int(start_stage_)
- end_stage = c_int(end_stage_)
- self.shared_lib.ocp_nlp_constraint_dims_get_from_attr.argtypes = \
- [c_void_p, c_void_p, c_void_p, c_int, c_char_p, POINTER(c_int)]
- self.shared_lib.ocp_nlp_constraint_dims_get_from_attr.restype = c_int
-
- dims = np.ascontiguousarray(np.zeros((2,)), dtype=np.intc)
- dims_data = cast(dims.ctypes.data, POINTER(c_int))
-
- self.shared_lib.ocp_nlp_constraint_dims_get_from_attr(self.nlp_config, \
- self.nlp_dims, self.nlp_out, start_stage_, field, dims_data)
-
- value_shape = value_.shape
- expected_shape = tuple(np.concatenate([np.array([end_stage_ - start_stage_]), dims]))
- if len(value_shape) == 2:
- value_shape = (value_shape[0], value_shape[1], 0)
- elif len(value_shape) == 3:
- if api=='old':
- pass
- elif api=='warn':
- if not np.all(np.ravel(value_, order='F')==np.ravel(value_, order='K')):
- raise Exception("Ambiguity in API detected.\n"
- "Are you making an acados model from scrach? Add api='new' to constraints_set and carry on.\n"
- "Are you seeing this error suddenly in previously running code? Read on.\n"
- " You are relying on a now-fixed bug in constraints_set for field '{}'.\n".format(field_) +
- " acados_template now correctly passes on any matrices to acados in column major format.\n" +
- " Two options to fix this error: \n" +
- " * Add api='old' to constraints_set to restore old incorrect behaviour\n" +
- " * Add api='new' to constraints_set and remove any unnatural manipulation of the value argument " +
- "such as non-mathematical transposes, reshaping, casting to fortran order, etc... " +
- "If there is no such manipulation, then you have probably been getting an incorrect solution before.")
- # Get elements in column major order
- value_ = np.ravel(value_, order='F')
- elif api=='new':
- # Get elements in column major order
- value_ = np.ravel(value_, order='F')
- else:
- raise Exception("Unknown api: '{}'".format(api))
- if value_shape != expected_shape:
- raise Exception('AcadosOcpSolver.constraints_set(): mismatching dimension' \
- ' for field "{}" with dimension {} (you have {})'.format(field_, expected_shape, value_shape))
-
- value_data = cast(value_.ctypes.data, POINTER(c_double))
- value_data_p = cast((value_data), c_void_p)
-
- self.shared_lib.ocp_nlp_constraints_model_set_slice.argtypes = \
- [c_void_p, c_void_p, c_void_p, c_int, c_int, c_char_p, c_void_p, c_int]
- self.shared_lib.ocp_nlp_constraints_model_set_slice(self.nlp_config, \
- self.nlp_dims, self.nlp_in, start_stage, end_stage, field, value_data_p, dim)
- return
-
- # Note: this function should not be used anymore, better use cost_set, constraints_set
- def set(self, stage_, field_, value_):
- """
- Set numerical data inside the solver.
-
- :param stage: integer corresponding to shooting node
- :param field: string in ['x', 'u', 'pi', 'lam', 't', 'p']
-
- .. note:: regarding lam, t: \n
- the inequalities are internally organized in the following order: \n
- [ lbu lbx lg lh lphi ubu ubx ug uh uphi; \n
- lsbu lsbx lsg lsh lsphi usbu usbx usg ush usphi]
-
- .. note:: pi: multipliers for dynamics equality constraints \n
- lam: multipliers for inequalities \n
- t: slack variables corresponding to evaluation of all inequalities (at the solution) \n
- sl: slack variables of soft lower inequality constraints \n
- su: slack variables of soft upper inequality constraints \n
- """
- cost_fields = ['y_ref', 'yref']
- constraints_fields = ['lbx', 'ubx', 'lbu', 'ubu']
- out_fields = ['x', 'u', 'pi', 'lam', 't', 'z']
- mem_fields = ['sl', 'su']
-
- # cast value_ to avoid conversion issues
- if isinstance(value_, (float, int)):
- value_ = np.array([value_])
- value_ = value_.astype(float)
-
- model_name = self.model_name
-
- field = field_
- field = field.encode('utf-8')
-
- stage = c_int(stage_)
-
- # treat parameters separately
- if field_ == 'p':
- getattr(self.shared_lib, f"{model_name}_acados_update_params").argtypes = [c_void_p, c_int, POINTER(c_double)]
- getattr(self.shared_lib, f"{model_name}_acados_update_params").restype = c_int
-
- value_data = cast(value_.ctypes.data, POINTER(c_double))
-
- assert getattr(self.shared_lib, f"{model_name}_acados_update_params")(self.capsule, stage, value_data, value_.shape[0])==0
- else:
- if field_ not in constraints_fields + cost_fields + out_fields + mem_fields:
- raise Exception("AcadosOcpSolver.set(): {} is not a valid argument.\
- \nPossible values are {}. Exiting.".format(field, \
- constraints_fields + cost_fields + out_fields + ['p']))
-
- self.shared_lib.ocp_nlp_dims_get_from_attr.argtypes = \
- [c_void_p, c_void_p, c_void_p, c_int, c_char_p]
- self.shared_lib.ocp_nlp_dims_get_from_attr.restype = c_int
-
- dims = self.shared_lib.ocp_nlp_dims_get_from_attr(self.nlp_config, \
- self.nlp_dims, self.nlp_out, stage_, field)
-
- if value_.shape[0] != dims:
- msg = 'AcadosOcpSolver.set(): mismatching dimension for field "{}" '.format(field_)
- msg += 'with dimension {} (you have {})'.format(dims, value_.shape)
- raise Exception(msg)
-
- value_data = cast(value_.ctypes.data, POINTER(c_double))
- value_data_p = cast((value_data), c_void_p)
-
- if field_ in constraints_fields:
- self.shared_lib.ocp_nlp_constraints_model_set.argtypes = \
- [c_void_p, c_void_p, c_void_p, c_int, c_char_p, c_void_p]
- self.shared_lib.ocp_nlp_constraints_model_set(self.nlp_config, \
- self.nlp_dims, self.nlp_in, stage, field, value_data_p)
- elif field_ in cost_fields:
- self.shared_lib.ocp_nlp_cost_model_set.argtypes = \
- [c_void_p, c_void_p, c_void_p, c_int, c_char_p, c_void_p]
- self.shared_lib.ocp_nlp_cost_model_set(self.nlp_config, \
- self.nlp_dims, self.nlp_in, stage, field, value_data_p)
- elif field_ in out_fields:
- self.shared_lib.ocp_nlp_out_set.argtypes = \
- [c_void_p, c_void_p, c_void_p, c_int, c_char_p, c_void_p]
- self.shared_lib.ocp_nlp_out_set(self.nlp_config, \
- self.nlp_dims, self.nlp_out, stage, field, value_data_p)
- elif field_ in mem_fields:
- self.shared_lib.ocp_nlp_set.argtypes = \
- [c_void_p, c_void_p, c_int, c_char_p, c_void_p]
- self.shared_lib.ocp_nlp_set(self.nlp_config, \
- self.nlp_solver, stage, field, value_data_p)
- return
-
-
- def get_slice(self, start_stage_, end_stage_, field_):
- """
- Get the last solution of the solver:
-
- :param start_stage: integer corresponding to shooting node that indicates start of slice
- :param end_stage: integer corresponding to shooting node that indicates end of slice
- :param field: string in ['x', 'u', 'z', 'pi', 'lam', 't', 'sl', 'su',]
-
- .. note:: regarding lam, t: \n
- the inequalities are internally organized in the following order: \n
- [ lbu lbx lg lh lphi ubu ubx ug uh uphi; \n
- lsbu lsbx lsg lsh lsphi usbu usbx usg ush usphi]
-
- .. note:: pi: multipliers for dynamics equality constraints \n
- lam: multipliers for inequalities \n
- t: slack variables corresponding to evaluation of all inequalities (at the solution) \n
- sl: slack variables of soft lower inequality constraints \n
- su: slack variables of soft upper inequality constraints \n
- """
- out_fields = ['x', 'u', 'z', 'pi', 'lam', 't']
- mem_fields = ['sl', 'su']
- field = field_
- field = field.encode('utf-8')
-
- if (field_ not in out_fields + mem_fields):
- raise Exception('AcadosOcpSolver.get_slice(): {} is an invalid argument.\
- \n Possible values are {}. Exiting.'.format(field_, out_fields))
-
- if not isinstance(start_stage_, int):
- raise Exception('AcadosOcpSolver.get_slice(): stage index must be Integer.')
-
- if not isinstance(end_stage_, int):
- raise Exception('AcadosOcpSolver.get_slice(): stage index must be Integer.')
-
- if start_stage_ >= end_stage_:
- raise Exception('AcadosOcpSolver.get_slice(): end stage index must be larger than start stage index')
-
- if start_stage_ < 0 or end_stage_ > self.N + 1:
- raise Exception('AcadosOcpSolver.get_slice(): stage index must be in [0, N], got: {}.'.format(self.N))
- self.shared_lib.ocp_nlp_dims_get_from_attr.argtypes = \
- [c_void_p, c_void_p, c_void_p, c_int, c_char_p]
- self.shared_lib.ocp_nlp_dims_get_from_attr.restype = c_int
-
- dims = self.shared_lib.ocp_nlp_dims_get_from_attr(self.nlp_config, \
- self.nlp_dims, self.nlp_out, start_stage_, field)
-
- out = np.ascontiguousarray(np.zeros((end_stage_ - start_stage_, dims)), dtype=np.float64)
- out_data = cast(out.ctypes.data, POINTER(c_double))
-
- if (field_ in out_fields):
- self.shared_lib.ocp_nlp_out_get_slice.argtypes = \
- [c_void_p, c_void_p, c_void_p, c_int, c_int, c_char_p, c_void_p]
- self.shared_lib.ocp_nlp_out_get_slice(self.nlp_config, \
- self.nlp_dims, self.nlp_out, start_stage_, end_stage_, field, out_data)
- elif field_ in mem_fields:
- self.shared_lib.ocp_nlp_get_at_stage.argtypes = \
- [c_void_p, c_void_p, c_void_p, c_int, c_char_p, c_void_p]
- self.shared_lib.ocp_nlp_get_at_stage(self.nlp_config, \
- self.nlp_dims, self.nlp_solver, start_stage_, end_stage_, field, out_data)
-
- return out
-
- def get_cost(self):
- """
- Returns the cost value of the current solution.
- """
- # compute cost internally
- self.shared_lib.ocp_nlp_eval_cost.argtypes = [c_void_p, c_void_p, c_void_p]
- self.shared_lib.ocp_nlp_eval_cost(self.nlp_solver, self.nlp_in, self.nlp_out)
-
- # create output array
- out = np.ascontiguousarray(np.zeros((1,)), dtype=np.float64)
- out_data = cast(out.ctypes.data, POINTER(c_double))
-
- # call getter
- self.shared_lib.ocp_nlp_get.argtypes = [c_void_p, c_void_p, c_char_p, c_void_p]
-
- field = "cost_value".encode('utf-8')
- self.shared_lib.ocp_nlp_get(self.nlp_config, self.nlp_solver, field, out_data)
-
- return out[0]
diff --git a/pyextra/acados_template/acados_ocp_solver_pyx.pyx b/pyextra/acados_template/acados_ocp_solver_pyx.pyx
index 9bcf5bb46a..97d5b2855f 100644
--- a/pyextra/acados_template/acados_ocp_solver_pyx.pyx
+++ b/pyextra/acados_template/acados_ocp_solver_pyx.pyx
@@ -39,21 +39,19 @@ cimport cython
from libc cimport string
cimport acados_solver_common
+# TODO: make this import more clear? it is not a general solver, but problem specific.
cimport acados_solver
cimport numpy as cnp
import os
+from datetime import datetime
import numpy as np
-cdef class AcadosOcpSolverFast:
+cdef class AcadosOcpSolverCython:
"""
Class to interact with the acados ocp solver C object.
-
- :param acados_ocp: type AcadosOcp - description of the OCP for acados
- :param json_file: name for the json file used to render the templated code - default: acados_ocp_nlp.json
- :param simulink_opts: Options to configure Simulink S-function blocks, mainly to activate possible Inputs and Outputs
"""
cdef acados_solver.nlp_solver_capsule *capsule
@@ -61,19 +59,26 @@ cdef class AcadosOcpSolverFast:
cdef acados_solver_common.ocp_nlp_dims *nlp_dims
cdef acados_solver_common.ocp_nlp_config *nlp_config
cdef acados_solver_common.ocp_nlp_out *nlp_out
+ cdef acados_solver_common.ocp_nlp_out *sens_out
cdef acados_solver_common.ocp_nlp_in *nlp_in
cdef acados_solver_common.ocp_nlp_solver *nlp_solver
+ cdef int status
+ cdef bint solver_created
+
cdef str model_name
cdef int N
- cdef bint solver_created
- def __cinit__(self, str model_name, int N, str code_export_dir):
- self.model_name = model_name
- self.N = N
+ cdef str nlp_solver_type
+
+ def __cinit__(self, model_name, nlp_solver_type, N):
self.solver_created = False
+ self.N = N
+ self.model_name = model_name
+ self.nlp_solver_type = nlp_solver_type
+
# create capsule
self.capsule = acados_solver.acados_create_capsule()
@@ -81,11 +86,21 @@ cdef class AcadosOcpSolverFast:
assert acados_solver.acados_create(self.capsule) == 0
self.solver_created = True
+ # get pointers solver
+ self.__get_pointers_solver()
+ self.status = 0
+
+
+ def __get_pointers_solver(self):
+ """
+ Private function to get the pointers for solver
+ """
# get pointers solver
self.nlp_opts = acados_solver.acados_get_nlp_opts(self.capsule)
self.nlp_dims = acados_solver.acados_get_nlp_dims(self.capsule)
self.nlp_config = acados_solver.acados_get_nlp_config(self.capsule)
self.nlp_out = acados_solver.acados_get_nlp_out(self.capsule)
+ self.sens_out = acados_solver.acados_get_sens_out(self.capsule)
self.nlp_in = acados_solver.acados_get_nlp_in(self.capsule)
self.nlp_solver = acados_solver.acados_get_nlp_solver(self.capsule)
@@ -99,15 +114,112 @@ cdef class AcadosOcpSolverFast:
def set_new_time_steps(self, new_time_steps):
"""
- Set new time steps before solving. Only reload library without code generation but with new time steps.
+ Set new time steps.
+ Recreates the solver if N changes.
- :param new_time_steps: vector of new time steps for the solver
+ :param new_time_steps: 1 dimensional np array of new time steps for the solver
.. note:: This allows for different use-cases: either set a new size of time-steps or a new distribution of
the shooting nodes without changing the number, e.g., to reach a different final time. Both cases
do not require a new code export and compilation.
"""
- raise NotImplementedError()
+
+ raise NotImplementedError("AcadosOcpSolverCython: does not support set_new_time_steps() since it is only a prototyping feature")
+ # # unlikely but still possible
+ # if not self.solver_created:
+ # raise Exception('Solver was not yet created!')
+
+ # ## check if time steps really changed in value
+ # # get time steps
+ # cdef cnp.ndarray[cnp.float64_t, ndim=1] old_time_steps = np.ascontiguousarray(np.zeros((self.N,)), dtype=np.float64)
+ # assert acados_solver.acados_get_time_steps(self.capsule, self.N, old_time_steps.data)
+
+ # if np.array_equal(old_time_steps, new_time_steps):
+ # return
+
+ # N = new_time_steps.size
+ # cdef cnp.ndarray[cnp.float64_t, ndim=1] value = np.ascontiguousarray(new_time_steps, dtype=np.float64)
+
+ # # check if recreation of acados is necessary (no need to recreate acados if sizes are identical)
+ # if len(old_time_steps) == N:
+ # assert acados_solver.acados_update_time_steps(self.capsule, N, value.data) == 0
+
+ # else: # recreate the solver with the new time steps
+ # self.solver_created = False
+
+ # # delete old memory (analog to __del__)
+ # acados_solver.acados_free(self.capsule)
+
+ # # create solver with new time steps
+ # assert acados_solver.acados_create_with_discretization(self.capsule, N, value.data) == 0
+
+ # self.solver_created = True
+
+ # # get pointers solver
+ # self.__get_pointers_solver()
+
+ # # store time_steps, N
+ # self.time_steps = new_time_steps
+ # self.N = N
+
+
+ def update_qp_solver_cond_N(self, qp_solver_cond_N: int):
+ """
+ Recreate solver with new value `qp_solver_cond_N` with a partial condensing QP solver.
+ This function is relevant for code reuse, i.e., if either `set_new_time_steps(...)` is used or
+ the influence of a different `qp_solver_cond_N` is studied without code export and compilation.
+ :param qp_solver_cond_N: new number of condensing stages for the solver
+
+ .. note:: This function can only be used in combination with a partial condensing QP solver.
+
+ .. note:: After `set_new_time_steps(...)` is used and depending on the new number of time steps it might be
+ necessary to change `qp_solver_cond_N` as well (using this function), i.e., typically
+ `qp_solver_cond_N < N`.
+ """
+ raise NotImplementedError("AcadosOcpSolverCython: does not support update_qp_solver_cond_N() since it is only a prototyping feature")
+
+ # # unlikely but still possible
+ # if not self.solver_created:
+ # raise Exception('Solver was not yet created!')
+ # if self.N < qp_solver_cond_N:
+ # raise Exception('Setting qp_solver_cond_N to be larger than N does not work!')
+ # if self.qp_solver_cond_N != qp_solver_cond_N:
+ # self.solver_created = False
+
+ # # recreate the solver
+ # acados_solver.acados_update_qp_solver_cond_N(self.capsule, qp_solver_cond_N)
+
+ # # store the new value
+ # self.qp_solver_cond_N = qp_solver_cond_N
+ # self.solver_created = True
+
+ # # get pointers solver
+ # self.__get_pointers_solver()
+
+
+ def eval_param_sens(self, index, stage=0, field="ex"):
+ """
+ Calculate the sensitivity of the curent solution with respect to the initial state component of index
+
+ :param index: integer corresponding to initial state index in range(nx)
+ """
+
+ field_ = field
+ field = field_.encode('utf-8')
+
+ # checks
+ if not isinstance(index, int):
+ raise Exception('AcadosOcpSolverCython.eval_param_sens(): index must be Integer.')
+
+ cdef int nx = acados_solver_common.ocp_nlp_dims_get_from_attr(self.nlp_config, self.nlp_dims, self.nlp_out, 0, "x".encode('utf-8'))
+
+ if index < 0 or index > nx:
+ raise Exception(f'AcadosOcpSolverCython.eval_param_sens(): index must be in [0, nx-1], got: {index}.')
+
+ # actual eval_param
+ acados_solver_common.ocp_nlp_eval_param_sens(self.nlp_solver, field, stage, index, self.sens_out)
+
+ return
def get(self, int stage, str field_):
@@ -133,14 +245,14 @@ cdef class AcadosOcpSolverFast:
field = field_.encode('utf-8')
if field_ not in out_fields:
- raise Exception('AcadosOcpSolver.get(): {} is an invalid argument.\
+ raise Exception('AcadosOcpSolverCython.get(): {} is an invalid argument.\
\n Possible values are {}. Exiting.'.format(field_, out_fields))
if stage < 0 or stage > self.N:
- raise Exception('AcadosOcpSolver.get(): stage index must be in [0, N], got: {}.'.format(self.N))
+ raise Exception('AcadosOcpSolverCython.get(): stage index must be in [0, N], got: {}.'.format(self.N))
if stage == self.N and field_ == 'pi':
- raise Exception('AcadosOcpSolver.get(): field {} does not exist at final stage {}.'\
+ raise Exception('AcadosOcpSolverCython.get(): field {} does not exist at final stage {}.'\
.format(field_, stage))
cdef int dims = acados_solver_common.ocp_nlp_dims_get_from_attr(self.nlp_config,
@@ -168,7 +280,7 @@ cdef class AcadosOcpSolverFast:
- qp_res_ineq: residual wrt inequality constraints (constraints) of the last QP solution
- qp_res_comp: residual wrt complementarity conditions of the last QP solution
"""
- raise NotImplementedError()
+ acados_solver.acados_print_stats(self.capsule)
def store_iterate(self, filename='', overwrite=False):
@@ -178,14 +290,50 @@ cdef class AcadosOcpSolverFast:
:param filename: if not set, use model_name + timestamp + '.json'
:param overwrite: if false and filename exists add timestamp to filename
"""
- raise NotImplementedError()
+ import json
+ if filename == '':
+ filename += self.model_name + '_' + 'iterate' + '.json'
+
+ if not overwrite:
+ # append timestamp
+ if os.path.isfile(filename):
+ filename = filename[:-5]
+ filename += datetime.utcnow().strftime('%Y-%m-%d-%H:%M:%S.%f') + '.json'
+
+ # get iterate:
+ solution = dict()
+
+ for i in range(self.N+1):
+ solution['x_'+str(i)] = self.get(i,'x')
+ solution['u_'+str(i)] = self.get(i,'u')
+ solution['z_'+str(i)] = self.get(i,'z')
+ solution['lam_'+str(i)] = self.get(i,'lam')
+ solution['t_'+str(i)] = self.get(i, 't')
+ solution['sl_'+str(i)] = self.get(i, 'sl')
+ solution['su_'+str(i)] = self.get(i, 'su')
+ for i in range(self.N):
+ solution['pi_'+str(i)] = self.get(i,'pi')
+
+ # save
+ with open(filename, 'w') as f:
+ json.dump(solution, f, default=lambda x: x.tolist(), indent=4, sort_keys=True)
+ print("stored current iterate in ", os.path.join(os.getcwd(), filename))
def load_iterate(self, filename):
"""
Loads the iterate stored in json file with filename into the ocp solver.
"""
- raise NotImplementedError()
+ import json
+ if not os.path.isfile(filename):
+ raise Exception('load_iterate: failed, file does not exist: ' + os.path.join(os.getcwd(), filename))
+
+ with open(filename, 'r') as f:
+ solution = json.load(f)
+
+ for key in solution.keys():
+ (field, stage) = key.split('_')
+ self.set(int(stage), field, np.array(solution[key]))
def get_stats(self, field_):
@@ -193,8 +341,97 @@ cdef class AcadosOcpSolverFast:
Get the information of the last solver call.
:param field: string in ['statistics', 'time_tot', 'time_lin', 'time_sim', 'time_sim_ad', 'time_sim_la', 'time_qp', 'time_qp_solver_call', 'time_reg', 'sqp_iter']
+ Available fileds:
+ - time_tot: total CPU time previous call
+ - time_lin: CPU time for linearization
+ - time_sim: CPU time for integrator
+ - time_sim_ad: CPU time for integrator contribution of external function calls
+ - time_sim_la: CPU time for integrator contribution of linear algebra
+ - time_qp: CPU time qp solution
+ - time_qp_solver_call: CPU time inside qp solver (without converting the QP)
+ - time_qp_xcond: time_glob: CPU time globalization
+ - time_solution_sensitivities: CPU time for previous call to eval_param_sens
+ - time_reg: CPU time regularization
+ - sqp_iter: number of SQP iterations
+ - qp_iter: vector of QP iterations for last SQP call
+ - statistics: table with info about last iteration
+ - stat_m: number of rows in statistics matrix
+ - stat_n: number of columns in statistics matrix
+ - residuals: residuals of last iterate
+ - alpha: step sizes of SQP iterations
"""
- raise NotImplementedError()
+
+ double_fields = ['time_tot',
+ 'time_lin',
+ 'time_sim',
+ 'time_sim_ad',
+ 'time_sim_la',
+ 'time_qp',
+ 'time_qp_solver_call',
+ 'time_qp_xcond',
+ 'time_glob',
+ 'time_solution_sensitivities',
+ 'time_reg'
+ ]
+ fields = double_fields + [
+ 'sqp_iter',
+ 'qp_iter',
+ 'statistics',
+ 'stat_m',
+ 'stat_n',
+ 'residuals',
+ 'alpha',
+ ]
+ field = field_.encode('utf-8')
+
+ if field_ in ['sqp_iter', 'stat_m', 'stat_n']:
+ return self.__get_stat_int(field)
+
+ elif field_ in double_fields:
+ return self.__get_stat_double(field)
+
+ elif field_ == 'statistics':
+ sqp_iter = self.get_stats("sqp_iter")
+ stat_m = self.get_stats("stat_m")
+ stat_n = self.get_stats("stat_n")
+ min_size = min([stat_m, sqp_iter+1])
+ return self.__get_stat_matrix(field, stat_n+1, min_size)
+
+ elif field_ == 'qp_iter':
+ full_stats = self.get_stats('statistics')
+ if self.nlp_solver_type == 'SQP':
+ return full_stats[6, :]
+ elif self.nlp_solver_type == 'SQP_RTI':
+ return full_stats[2, :]
+
+ elif field_ == 'alpha':
+ full_stats = self.get_stats('statistics')
+ if self.nlp_solver_type == 'SQP':
+ return full_stats[7, :]
+ else: # self.nlp_solver_type == 'SQP_RTI':
+ raise Exception("alpha values are not available for SQP_RTI")
+
+ elif field_ == 'residuals':
+ return self.get_residuals()
+
+ else:
+ raise NotImplementedError("TODO!")
+
+
+ def __get_stat_int(self, field):
+ cdef int out
+ acados_solver_common.ocp_nlp_get(self.nlp_config, self.nlp_solver, field, &out)
+ return out
+
+ def __get_stat_double(self, field):
+ cdef cnp.ndarray[cnp.float64_t, ndim=1] out = np.zeros((1,))
+ acados_solver_common.ocp_nlp_get(self.nlp_config, self.nlp_solver, field, out.data)
+ return out
+
+ def __get_stat_matrix(self, field, n, m):
+ cdef cnp.ndarray[cnp.float64_t, ndim=2] out_mat = np.ascontiguousarray(np.zeros((n, m)), dtype=np.float64)
+ acados_solver_common.ocp_nlp_get(self.nlp_config, self.nlp_solver, field, out_mat.data)
+ return out_mat
def get_cost(self):
@@ -217,7 +454,31 @@ cdef class AcadosOcpSolverFast:
"""
Returns an array of the form [res_stat, res_eq, res_ineq, res_comp].
"""
- raise NotImplementedError()
+ # compute residuals if RTI
+ if self.nlp_solver_type == 'SQP_RTI':
+ acados_solver_common.ocp_nlp_eval_residuals(self.nlp_solver, self.nlp_in, self.nlp_out)
+
+ # create output array
+ cdef cnp.ndarray[cnp.float64_t, ndim=1] out = np.ascontiguousarray(np.zeros((4,), dtype=np.float64))
+ cdef double double_value
+
+ field = "res_stat".encode('utf-8')
+ acados_solver_common.ocp_nlp_get(self.nlp_config, self.nlp_solver, field, &double_value)
+ out[0] = double_value
+
+ field = "res_eq".encode('utf-8')
+ acados_solver_common.ocp_nlp_get(self.nlp_config, self.nlp_solver, field, &double_value)
+ out[1] = double_value
+
+ field = "res_ineq".encode('utf-8')
+ acados_solver_common.ocp_nlp_get(self.nlp_config, self.nlp_solver, field, &double_value)
+ out[2] = double_value
+
+ field = "res_comp".encode('utf-8')
+ acados_solver_common.ocp_nlp_get(self.nlp_config, self.nlp_solver, field, &double_value)
+ out[3] = double_value
+
+ return out
# Note: this function should not be used anymore, better use cost_set, constraints_set
@@ -243,18 +504,18 @@ cdef class AcadosOcpSolverFast:
cost_fields = ['y_ref', 'yref']
constraints_fields = ['lbx', 'ubx', 'lbu', 'ubu']
out_fields = ['x', 'u', 'pi', 'lam', 't', 'z', 'sl', 'su']
+ mem_fields = ['xdot_guess']
field = field_.encode('utf-8')
- cdef double[::1] value
+ cdef cnp.ndarray[cnp.float64_t, ndim=1] value = np.ascontiguousarray(value_, dtype=np.float64)
# treat parameters separately
if field_ == 'p':
- value = np.ascontiguousarray(value_, dtype=np.double)
- assert acados_solver.acados_update_params(self.capsule, stage, &value[0], value.shape[0]) == 0
+ assert acados_solver.acados_update_params(self.capsule, stage, value.data, value.shape[0]) == 0
else:
if field_ not in constraints_fields + cost_fields + out_fields:
- raise Exception("AcadosOcpSolver.set(): {} is not a valid argument.\
+ raise Exception("AcadosOcpSolverCython.set(): {} is not a valid argument.\
\nPossible values are {}. Exiting.".format(field, \
constraints_fields + cost_fields + out_fields + ['p']))
@@ -262,20 +523,22 @@ cdef class AcadosOcpSolverFast:
self.nlp_dims, self.nlp_out, stage, field)
if value_.shape[0] != dims:
- msg = 'AcadosOcpSolver.set(): mismatching dimension for field "{}" '.format(field_)
+ msg = 'AcadosOcpSolverCython.set(): mismatching dimension for field "{}" '.format(field_)
msg += 'with dimension {} (you have {})'.format(dims, value_.shape[0])
raise Exception(msg)
- value = np.ascontiguousarray(value_, dtype=np.double)
if field_ in constraints_fields:
acados_solver_common.ocp_nlp_constraints_model_set(self.nlp_config,
- self.nlp_dims, self.nlp_in, stage, field, &value[0])
+ self.nlp_dims, self.nlp_in, stage, field, value.data)
elif field_ in cost_fields:
acados_solver_common.ocp_nlp_cost_model_set(self.nlp_config,
- self.nlp_dims, self.nlp_in, stage, field, &value[0])
+ self.nlp_dims, self.nlp_in, stage, field, value.data)
elif field_ in out_fields:
acados_solver_common.ocp_nlp_out_set(self.nlp_config,
- self.nlp_dims, self.nlp_out, stage, field, &value[0])
+ self.nlp_dims, self.nlp_out, stage, field, value.data)
+ elif field_ in mem_fields:
+ acados_solver_common.ocp_nlp_set(self.nlp_config, \
+ self.nlp_solver, stage, field, value.data)
def cost_set(self, int stage, str field_, value_):
@@ -304,9 +567,8 @@ cdef class AcadosOcpSolverFast:
value = np.asfortranarray(value_)
if value_shape[0] != dims[0] or value_shape[1] != dims[1]:
- raise Exception('AcadosOcpSolver.cost_set(): mismatching dimension', \
- ' for field "{}" with dimension {} (you have {})'.format( \
- field_, tuple(dims), value_shape))
+ raise Exception('AcadosOcpSolverCython.cost_set(): mismatching dimension' +
+ f' for field "{field_}" at stage {stage} with dimension {tuple(dims)} (you have {value_shape})')
acados_solver_common.ocp_nlp_cost_model_set(self.nlp_config, \
self.nlp_dims, self.nlp_in, stage, field, &value[0][0])
@@ -338,8 +600,8 @@ cdef class AcadosOcpSolverFast:
value = np.asfortranarray(value_)
if value_shape[0] != dims[0] or value_shape[1] != dims[1]:
- raise Exception('AcadosOcpSolver.constraints_set(): mismatching dimension' \
- ' for field "{}" with dimension {} (you have {})'.format(field_, tuple(dims), value_shape))
+ raise Exception(f'AcadosOcpSolverCython.constraints_set(): mismatching dimension' +
+ f' for field "{field_}" at stage {stage} with dimension {tuple(dims)} (you have {value_shape})')
acados_solver_common.ocp_nlp_constraints_model_set(self.nlp_config, \
self.nlp_dims, self.nlp_in, stage, field, &value[0][0])
@@ -361,7 +623,7 @@ cdef class AcadosOcpSolverFast:
acados_solver_common.ocp_nlp_dynamics_dims_get_from_attr(self.nlp_config, self.nlp_dims, self.nlp_out, stage, field, &dims[0])
# create output data
- out = np.zeros((dims[0], dims[1]), order='F', dtype=np.float64)
+ cdef cnp.ndarray[cnp.float64_t, ndim=2] out = np.zeros((dims[0], dims[1]), order='F')
# call getter
acados_solver_common.ocp_nlp_get_at_stage(self.nlp_config, self.nlp_dims, self.nlp_solver, stage, field, out.data)
@@ -376,8 +638,8 @@ cdef class AcadosOcpSolverFast:
:param field: string, e.g. 'print_level', 'rti_phase', 'initialize_t_slacks', 'step_length', 'alpha_min', 'alpha_reduction'
:param value: of type int, float
"""
- int_fields = ['print_level', 'rti_phase', 'initialize_t_slacks']
- double_fields = ['step_length', 'tol_eq', 'tol_stat', 'tol_ineq', 'tol_comp', 'alpha_min', 'alpha_reduction']
+ int_fields = ['print_level', 'rti_phase', 'initialize_t_slacks', 'qp_warm_start', 'line_search_use_sufficient_descent', 'full_step_dual', 'globalization_use_SOC']
+ double_fields = ['step_length', 'tol_eq', 'tol_stat', 'tol_ineq', 'tol_comp', 'alpha_min', 'alpha_reduction', 'eps_sufficient_descent']
string_fields = ['globalization']
# encode
@@ -394,10 +656,10 @@ cdef class AcadosOcpSolverFast:
if field_ == 'rti_phase':
if value_ < 0 or value_ > 2:
- raise Exception('AcadosOcpSolver.solve(): argument \'rti_phase\' can '
+ raise Exception('AcadosOcpSolverCython.solve(): argument \'rti_phase\' can '
'take only values 0, 1, 2 for SQP-RTI-type solvers')
- if self.acados_ocp.solver_options.nlp_solver_type != 'SQP_RTI' and value_ > 0:
- raise Exception('AcadosOcpSolver.solve(): argument \'rti_phase\' can '
+ if self.nlp_solver_type != 'SQP_RTI' and value_ > 0:
+ raise Exception('AcadosOcpSolverCython.solve(): argument \'rti_phase\' can '
'take only value 0 for SQP-type solvers')
int_value = value_
@@ -418,7 +680,7 @@ cdef class AcadosOcpSolverFast:
acados_solver_common.ocp_nlp_solver_opts_set(self.nlp_config, self.nlp_opts, field, &string_value[0])
else:
- raise Exception('AcadosOcpSolver.options_set() does not support field {}.'\
+ raise Exception('AcadosOcpSolverCython.options_set() does not support field {}.'\
'\n Possible values are {}.'.format(field_, ', '.join(int_fields + double_fields + string_fields)))
diff --git a/pyextra/acados_template/acados_sim.py b/pyextra/acados_template/acados_sim.py
index d7ad1487dc..c63cffc316 100644
--- a/pyextra/acados_template/acados_sim.py
+++ b/pyextra/acados_template/acados_sim.py
@@ -70,28 +70,28 @@ class AcadosSimDims:
@nx.setter
def nx(self, nx):
- if type(nx) == int and nx > 0:
+ if isinstance(nx, int) and nx > 0:
self.__nx = nx
else:
raise Exception('Invalid nx value, expected positive integer. Exiting.')
@nz.setter
def nz(self, nz):
- if type(nz) == int and nz > -1:
+ if isinstance(nz, int) and nz > -1:
self.__nz = nz
else:
raise Exception('Invalid nz value, expected nonnegative integer. Exiting.')
@nu.setter
def nu(self, nu):
- if type(nu) == int and nu > -1:
+ if isinstance(nu, int) and nu > -1:
self.__nu = nu
else:
raise Exception('Invalid nu value, expected nonnegative integer. Exiting.')
@np.setter
def np(self, np):
- if type(np) == int and np > -1:
+ if isinstance(np, int) and np > -1:
self.__np = np
else:
raise Exception('Invalid np value, expected nonnegative integer. Exiting.')
@@ -302,6 +302,7 @@ class AcadosSim:
self.code_export_directory = 'c_generated_code'
"""Path to where code will be exported. Default: `c_generated_code`."""
+ self.cython_include_dirs = ''
self.__parameter_values = np.array([])
@property
diff --git a/pyextra/acados_template/acados_sim_solver.py b/pyextra/acados_template/acados_sim_solver.py
index 145f90293e..a12ecb1765 100644
--- a/pyextra/acados_template/acados_sim_solver.py
+++ b/pyextra/acados_template/acados_sim_solver.py
@@ -215,6 +215,24 @@ class AcadosSimSolver:
model_name = self.sim_struct.model.name
self.model_name = model_name
+ # Load acados library to avoid unloading the library.
+ # This is necessary if acados was compiled with OpenMP, since the OpenMP threads can't be destroyed.
+ # Unloading a library which uses OpenMP results in a segfault (on any platform?).
+ # see [https://stackoverflow.com/questions/34439956/vc-crash-when-freeing-a-dll-built-with-openmp]
+ # or [https://python.hotexamples.com/examples/_ctypes/-/dlclose/python-dlclose-function-examples.html]
+ libacados_name = 'libacados.so'
+ libacados_filepath = os.path.join(acados_sim.acados_lib_path, libacados_name)
+ self.__acados_lib = CDLL(libacados_filepath)
+ # find out if acados was compiled with OpenMP
+ try:
+ self.__acados_lib_uses_omp = getattr(self.__acados_lib, 'omp_get_thread_num') is not None
+ except AttributeError as e:
+ self.__acados_lib_uses_omp = False
+ if self.__acados_lib_uses_omp:
+ print('acados was compiled with OpenMP.')
+ else:
+ print('acados was compiled without OpenMP.')
+
# Ctypes
shared_lib = f'{code_export_dir}/libacados_sim_solver_{model_name}.so'
self.shared_lib = CDLL(shared_lib)
diff --git a/pyextra/acados_template/acados_solver_common.pxd b/pyextra/acados_template/acados_solver_common.pxd
index 9314802e61..fedd7190d9 100644
--- a/pyextra/acados_template/acados_solver_common.pxd
+++ b/pyextra/acados_template/acados_solver_common.pxd
@@ -95,6 +95,7 @@ cdef extern from "acados_c/ocp_nlp_interface.h":
# solver
void ocp_nlp_eval_residuals(ocp_nlp_solver *solver, ocp_nlp_in *nlp_in, ocp_nlp_out *nlp_out)
+ void ocp_nlp_eval_param_sens(ocp_nlp_solver *solver, char *field, int stage, int index, ocp_nlp_out *sens_nlp_out)
void ocp_nlp_eval_cost(ocp_nlp_solver *solver, ocp_nlp_in *nlp_in_, ocp_nlp_out *nlp_out)
# get/set
diff --git a/pyextra/acados_template/c_templates_tera/Makefile.in b/pyextra/acados_template/c_templates_tera/Makefile.in
index 487e66ab07..d45be0a9c7 100644
--- a/pyextra/acados_template/c_templates_tera/Makefile.in
+++ b/pyextra/acados_template/c_templates_tera/Makefile.in
@@ -125,134 +125,134 @@
{%- endif %}
{%- endif %}
-{# acados flags #}
-ACADOS_FLAGS = -fPIC -std=c99 {{ openmp_flag }} #-fno-diagnostics-show-line-numbers -g
-{%- if qp_solver == "FULL_CONDENSING_QPOASES" %}
-ACADOS_FLAGS += -DACADOS_WITH_QPOASES
-{%- endif %}
-{%- if qp_solver == "PARTIAL_CONDENSING_OSQP" %}
-ACADOS_FLAGS += -DACADOS_WITH_OSQP
-{%- endif %}
-{%- if qp_solver == "PARTIAL_CONDENSING_QPDUNES" %}
-ACADOS_FLAGS += -DACADOS_WITH_QPDUNES
-{%- endif %}
-# # Debugging
-# ACADOS_FLAGS += -g3
+# define sources and use make's implicit rules to generate object files (*.o)
-MODEL_OBJ=
+# model
+MODEL_SRC=
{%- if solver_options.integrator_type == "ERK" %}
-MODEL_OBJ+= {{ model.name }}_model/{{ model.name }}_expl_ode_fun.o
-MODEL_OBJ+= {{ model.name }}_model/{{ model.name }}_expl_vde_forw.o
-{%- if hessian_approx == "EXACT" %}
-MODEL_OBJ+= {{ model.name }}_model/{{ model.name }}_expl_ode_hess.o
-{%- endif %}
+MODEL_SRC+= {{ model.name }}_model/{{ model.name }}_expl_ode_fun.c
+MODEL_SRC+= {{ model.name }}_model/{{ model.name }}_expl_vde_forw.c
+ {%- if hessian_approx == "EXACT" %}
+MODEL_SRC+= {{ model.name }}_model/{{ model.name }}_expl_ode_hess.c
+ {%- endif %}
{%- elif solver_options.integrator_type == "IRK" %}
-MODEL_OBJ+= {{ model.name }}_model/{{ model.name }}_impl_dae_fun.o
-MODEL_OBJ+= {{ model.name }}_model/{{ model.name }}_impl_dae_fun_jac_x_xdot_z.o
-MODEL_OBJ+= {{ model.name }}_model/{{ model.name }}_impl_dae_jac_x_xdot_u_z.o
-{%- if hessian_approx == "EXACT" %}
-MODEL_OBJ+= {{ model.name }}_model/{{ model.name }}_impl_dae_hess.o
-{%- endif %}
+MODEL_SRC+= {{ model.name }}_model/{{ model.name }}_impl_dae_fun.c
+MODEL_SRC+= {{ model.name }}_model/{{ model.name }}_impl_dae_fun_jac_x_xdot_z.c
+MODEL_SRC+= {{ model.name }}_model/{{ model.name }}_impl_dae_jac_x_xdot_u_z.c
+ {%- if hessian_approx == "EXACT" %}
+MODEL_SRC+= {{ model.name }}_model/{{ model.name }}_impl_dae_hess.c
+ {%- endif %}
{%- elif solver_options.integrator_type == "LIFTED_IRK" %}
-MODEL_OBJ+= {{ model.name }}_model/{{ model.name }}_impl_dae_fun.o
-MODEL_OBJ+= {{ model.name }}_model/{{ model.name }}_impl_dae_fun_jac_x_xdot_u.o
-{%- if hessian_approx == "EXACT" %}
-MODEL_OBJ+= {{ model.name }}_model/{{ model.name }}_impl_dae_hess.o
-{%- endif %}
+MODEL_SRC+= {{ model.name }}_model/{{ model.name }}_impl_dae_fun.c
+MODEL_SRC+= {{ model.name }}_model/{{ model.name }}_impl_dae_fun_jac_x_xdot_u.c
+ {%- if hessian_approx == "EXACT" %}
+MODEL_SRC+= {{ model.name }}_model/{{ model.name }}_impl_dae_hess.c
+ {%- endif %}
{%- elif solver_options.integrator_type == "GNSF" %}
-MODEL_OBJ+= {{ model.name }}_model/{{ model.name }}_gnsf_phi_fun.o
-MODEL_OBJ+= {{ model.name }}_model/{{ model.name }}_gnsf_phi_fun_jac_y.o
-MODEL_OBJ+= {{ model.name }}_model/{{ model.name }}_gnsf_phi_jac_y_uhat.o
-MODEL_OBJ+= {{ model.name }}_model/{{ model.name }}_gnsf_f_lo_fun_jac_x1k1uz.o
-MODEL_OBJ+= {{ model.name }}_model/{{ model.name }}_gnsf_get_matrices_fun.o
+ {% if model.gnsf.purely_linear != 1 %}
+MODEL_SRC+= {{ model.name }}_model/{{ model.name }}_gnsf_phi_fun.c
+MODEL_SRC+= {{ model.name }}_model/{{ model.name }}_gnsf_phi_fun_jac_y.c
+MODEL_SRC+= {{ model.name }}_model/{{ model.name }}_gnsf_phi_jac_y_uhat.c
+ {% if model.gnsf.nontrivial_f_LO == 1 %}
+MODEL_SRC+= {{ model.name }}_model/{{ model.name }}_gnsf_f_lo_fun_jac_x1k1uz.c
+ {%- endif %}
+ {%- endif %}
+MODEL_SRC+= {{ model.name }}_model/{{ model.name }}_gnsf_get_matrices_fun.c
{%- elif solver_options.integrator_type == "DISCRETE" %}
-{%- if model.dyn_ext_fun_type == "casadi" %}
-MODEL_OBJ+= {{ model.name }}_model/{{ model.name }}_dyn_disc_phi_fun.o
-MODEL_OBJ+= {{ model.name }}_model/{{ model.name }}_dyn_disc_phi_fun_jac.o
-{%- if hessian_approx == "EXACT" %}
-MODEL_OBJ+= {{ model.name }}_model/{{ model.name }}_dyn_disc_phi_fun_jac_hess.o
-{%- endif %}
-{%- else %}
-MODEL_OBJ+= {{ model.name }}_model/{{ model.dyn_source_discrete }}
-{%- endif %}
+ {%- if model.dyn_ext_fun_type == "casadi" %}
+MODEL_SRC+= {{ model.name }}_model/{{ model.name }}_dyn_disc_phi_fun.c
+MODEL_SRC+= {{ model.name }}_model/{{ model.name }}_dyn_disc_phi_fun_jac.c
+ {%- if hessian_approx == "EXACT" %}
+MODEL_SRC+= {{ model.name }}_model/{{ model.name }}_dyn_disc_phi_fun_jac_hess.c
+ {%- endif %}
+ {%- else %}
+MODEL_SRC+= {{ model.name }}_model/{{ model.dyn_source_discrete }}
+ {%- endif %}
{%- endif %}
+MODEL_OBJ := $(MODEL_SRC:.c=.o)
-
-OCP_OBJ=
+# optimal control problem - mostly CasADi exports
+OCP_SRC=
{%- if constr_type == "BGP" and dims_nphi > 0 %}
-OCP_OBJ+= {{ model.name }}_constraints/{{ model.name }}_phi_constraint.o
+OCP_SRC+= {{ model.name }}_constraints/{{ model.name }}_phi_constraint.c
{%- endif %}
{%- if constr_type_e == "BGP" and dims_nphi_e > 0 %}
-OCP_OBJ+= {{ model.name }}_constraints/{{ model.name }}_phi_e_constraint.o
+OCP_SRC+= {{ model.name }}_constraints/{{ model.name }}_phi_e_constraint.c
{%- endif %}
{%- if constr_type == "BGH" and dims_nh > 0 %}
-OCP_OBJ+= {{ model.name }}_constraints/{{ model.name }}_constr_h_fun_jac_uxt_zt.o
-OCP_OBJ+= {{ model.name }}_constraints/{{ model.name }}_constr_h_fun.o
-{%- if hessian_approx == "EXACT" %}
-OCP_OBJ+= {{ model.name }}_constraints/{{ model.name }}_constr_h_fun_jac_uxt_zt_hess.o
-{%- endif %}
+OCP_SRC+= {{ model.name }}_constraints/{{ model.name }}_constr_h_fun_jac_uxt_zt.c
+OCP_SRC+= {{ model.name }}_constraints/{{ model.name }}_constr_h_fun.c
+ {%- if hessian_approx == "EXACT" %}
+OCP_SRC+= {{ model.name }}_constraints/{{ model.name }}_constr_h_fun_jac_uxt_zt_hess.c
+ {%- endif %}
{%- endif %}
{%- if constr_type_e == "BGH" and dims_nh_e > 0 %}
-OCP_OBJ+= {{ model.name }}_constraints/{{ model.name }}_constr_h_e_fun_jac_uxt_zt.o
-OCP_OBJ+= {{ model.name }}_constraints/{{ model.name }}_constr_h_e_fun.o
-{%- if hessian_approx == "EXACT" %}
-OCP_OBJ+= {{ model.name }}_constraints/{{ model.name }}_constr_h_e_fun_jac_uxt_zt_hess.o
-{%- endif %}
+OCP_SRC+= {{ model.name }}_constraints/{{ model.name }}_constr_h_e_fun_jac_uxt_zt.c
+OCP_SRC+= {{ model.name }}_constraints/{{ model.name }}_constr_h_e_fun.c
+ {%- if hessian_approx == "EXACT" %}
+OCP_SRC+= {{ model.name }}_constraints/{{ model.name }}_constr_h_e_fun_jac_uxt_zt_hess.c
+ {%- endif %}
{%- endif %}
{%- if cost_type_0 == "NONLINEAR_LS" %}
-OCP_OBJ+= {{ model.name }}_cost/{{ model.name }}_cost_y_0_fun.c
-OCP_OBJ+= {{ model.name }}_cost/{{ model.name }}_cost_y_0_fun_jac_ut_xt.c
-OCP_OBJ+= {{ model.name }}_cost/{{ model.name }}_cost_y_0_hess.c
+OCP_SRC+= {{ model.name }}_cost/{{ model.name }}_cost_y_0_fun.c
+OCP_SRC+= {{ model.name }}_cost/{{ model.name }}_cost_y_0_fun_jac_ut_xt.c
+OCP_SRC+= {{ model.name }}_cost/{{ model.name }}_cost_y_0_hess.c
{%- elif cost_type_0 == "EXTERNAL" %}
-{% if cost.cost_ext_fun_type_0 == "casadi" %}
-OCP_OBJ+= {{ model.name }}_cost/{{ model.name }}_cost_ext_cost_0_fun.c
-OCP_OBJ+= {{ model.name }}_cost/{{ model.name }}_cost_ext_cost_0_fun_jac.c
-OCP_OBJ+= {{ model.name }}_cost/{{ model.name }}_cost_ext_cost_0_fun_jac_hess.c
-{% else %}
-OCP_OBJ+= {{ model.name }}_cost/{{ cost.cost_source_ext_cost_0 }}
-{% endif %}
+ {%- if cost.cost_ext_fun_type_0 == "casadi" %}
+OCP_SRC+= {{ model.name }}_cost/{{ model.name }}_cost_ext_cost_0_fun.c
+OCP_SRC+= {{ model.name }}_cost/{{ model.name }}_cost_ext_cost_0_fun_jac.c
+OCP_SRC+= {{ model.name }}_cost/{{ model.name }}_cost_ext_cost_0_fun_jac_hess.c
+ {%- else %}
+OCP_SRC+= {{ model.name }}_cost/{{ cost.cost_source_ext_cost_0 }}
+ {%- endif %}
{%- endif %}
{%- if cost_type == "NONLINEAR_LS" %}
-OCP_OBJ+= {{ model.name }}_cost/{{ model.name }}_cost_y_fun.c
-OCP_OBJ+= {{ model.name }}_cost/{{ model.name }}_cost_y_fun_jac_ut_xt.c
-OCP_OBJ+= {{ model.name }}_cost/{{ model.name }}_cost_y_hess.c
+OCP_SRC+= {{ model.name }}_cost/{{ model.name }}_cost_y_fun.c
+OCP_SRC+= {{ model.name }}_cost/{{ model.name }}_cost_y_fun_jac_ut_xt.c
+OCP_SRC+= {{ model.name }}_cost/{{ model.name }}_cost_y_hess.c
{%- elif cost_type == "EXTERNAL" %}
-{% if cost.cost_ext_fun_type == "casadi" %}
-OCP_OBJ+= {{ model.name }}_cost/{{ model.name }}_cost_ext_cost_fun.c
-OCP_OBJ+= {{ model.name }}_cost/{{ model.name }}_cost_ext_cost_fun_jac.c
-OCP_OBJ+= {{ model.name }}_cost/{{ model.name }}_cost_ext_cost_fun_jac_hess.c
-{% elif cost.cost_source_ext_cost != cost.cost_source_ext_cost_0 %}
-OCP_OBJ+= {{ model.name }}_cost/{{ cost.cost_source_ext_cost }}
-{% endif %}
+ {%- if cost.cost_ext_fun_type == "casadi" %}
+OCP_SRC+= {{ model.name }}_cost/{{ model.name }}_cost_ext_cost_fun.c
+OCP_SRC+= {{ model.name }}_cost/{{ model.name }}_cost_ext_cost_fun_jac.c
+OCP_SRC+= {{ model.name }}_cost/{{ model.name }}_cost_ext_cost_fun_jac_hess.c
+ {%- elif cost.cost_source_ext_cost != cost.cost_source_ext_cost_0 %}
+OCP_SRC+= {{ model.name }}_cost/{{ cost.cost_source_ext_cost }}
+ {%- endif %}
{%- endif %}
{%- if cost_type_e == "NONLINEAR_LS" %}
-OCP_OBJ+= {{ model.name }}_cost/{{ model.name }}_cost_y_e_fun.c
-OCP_OBJ+= {{ model.name }}_cost/{{ model.name }}_cost_y_e_fun_jac_ut_xt.c
-OCP_OBJ+= {{ model.name }}_cost/{{ model.name }}_cost_y_e_hess.c
+OCP_SRC+= {{ model.name }}_cost/{{ model.name }}_cost_y_e_fun.c
+OCP_SRC+= {{ model.name }}_cost/{{ model.name }}_cost_y_e_fun_jac_ut_xt.c
+OCP_SRC+= {{ model.name }}_cost/{{ model.name }}_cost_y_e_hess.c
{%- elif cost_type_e == "EXTERNAL" %}
-{% if cost.cost_ext_fun_type_e == "casadi" %}
-OCP_OBJ+= {{ model.name }}_cost/{{ model.name }}_cost_ext_cost_e_fun.c
-OCP_OBJ+= {{ model.name }}_cost/{{ model.name }}_cost_ext_cost_e_fun_jac.c
-OCP_OBJ+= {{ model.name }}_cost/{{ model.name }}_cost_ext_cost_e_fun_jac_hess.c
-{% elif cost.cost_source_ext_cost_e != cost.cost_source_ext_cost_0 %}
-OCP_OBJ+= {{ model.name }}_cost/{{ cost.cost_source_ext_cost_e }}
-{% endif %}
+ {%- if cost.cost_ext_fun_type_e == "casadi" %}
+OCP_SRC+= {{ model.name }}_cost/{{ model.name }}_cost_ext_cost_e_fun.c
+OCP_SRC+= {{ model.name }}_cost/{{ model.name }}_cost_ext_cost_e_fun_jac.c
+OCP_SRC+= {{ model.name }}_cost/{{ model.name }}_cost_ext_cost_e_fun_jac_hess.c
+ {%- elif cost.cost_source_ext_cost_e != cost.cost_source_ext_cost_0 %}
+OCP_SRC+= {{ model.name }}_cost/{{ cost.cost_source_ext_cost_e }}
+ {%- endif %}
{%- endif %}
-OCP_OBJ+= acados_solver_{{ model.name }}.o
+OCP_SRC+= acados_solver_{{ model.name }}.c
+OCP_OBJ := $(OCP_SRC:.c=.o)
+# for sim solver
+SIM_SRC= acados_sim_solver_{{ model.name }}.c
+SIM_OBJ := $(SIM_SRC:.c=.o)
-SIM_OBJ=
-SIM_OBJ+= acados_sim_solver_{{ model.name }}.o
+# for target example
+EX_SRC= main_{{ model.name }}.c
+EX_OBJ := $(EX_SRC:.c=.o)
+EX_EXE := $(EX_SRC:.c=)
-EX_OBJ=
-EX_OBJ+= main_{{ model.name }}.o
-
-EX_SIM_OBJ=
-EX_SIM_OBJ+= main_sim_{{ model.name }}.o
+# for target example_sim
+EX_SIM_SRC= main_sim_{{ model.name }}.c
+EX_SIM_OBJ := $(EX_SIM_SRC:.c=.o)
+EX_SIM_EXE := $(EX_SIM_SRC:.c=)
+# combine model, sim and ocp object files
OBJ=
OBJ+= $(MODEL_OBJ)
{%- if solver_options.integrator_type != "DISCRETE" %}
@@ -271,233 +271,103 @@ EXTERNAL_LIB+= {{ model_external_shared_lib_name }}
INCLUDE_PATH = {{ acados_include_path }}
LIB_PATH = {{ acados_lib_path }}
-{%- if solver_options.integrator_type == "DISCRETE" %}
-all: clean casadi_fun example
-shared_lib: ocp_shared_lib
-{%- else %}
-all: clean casadi_fun example_sim example
-shared_lib: bundled_shared_lib ocp_shared_lib sim_shared_lib
-{%- endif %}
-
-CASADI_MODEL_SOURCE=
-{%- if solver_options.integrator_type == "ERK" %}
-CASADI_MODEL_SOURCE+= {{ model.name }}_expl_ode_fun.c
-CASADI_MODEL_SOURCE+= {{ model.name }}_expl_vde_forw.c
-{%- if hessian_approx == "EXACT" %}
-CASADI_MODEL_SOURCE+= {{ model.name }}_expl_ode_hess.c
-{%- endif %}
-{%- elif solver_options.integrator_type == "IRK" %}
-CASADI_MODEL_SOURCE+= {{ model.name }}_impl_dae_fun.c
-CASADI_MODEL_SOURCE+= {{ model.name }}_impl_dae_fun_jac_x_xdot_z.c
-CASADI_MODEL_SOURCE+= {{ model.name }}_impl_dae_jac_x_xdot_u_z.c
-{%- if hessian_approx == "EXACT" %}
-CASADI_MODEL_SOURCE+= {{ model.name }}_impl_dae_hess.c
-{%- endif %}
-{%- elif solver_options.integrator_type == "LIFTED_IRK" %}
-CASADI_MODEL_SOURCE+= {{ model.name }}_impl_dae_fun.c
-# CASADI_MODEL_SOURCE+= {{ model.name }}_impl_dae_fun_jac_x_xdot_z.c
-# CASADI_MODEL_SOURCE+= {{ model.name }}_impl_dae_jac_x_xdot_u_z.c
-CASADI_MODEL_SOURCE+= {{ model.name }}_impl_dae_fun_jac_x_xdot_u.c
-{%- if hessian_approx == "EXACT" %}
-CASADI_MODEL_SOURCE+= {{ model.name }}_impl_dae_hess.c
-{%- endif %}
-{%- elif solver_options.integrator_type == "GNSF" %}
-CASADI_MODEL_SOURCE+= {{ model.name }}_gnsf_phi_fun.c
-CASADI_MODEL_SOURCE+= {{ model.name }}_gnsf_phi_fun_jac_y.c
-CASADI_MODEL_SOURCE+= {{ model.name }}_gnsf_phi_jac_y_uhat.c
-CASADI_MODEL_SOURCE+= {{ model.name }}_gnsf_f_lo_fun_jac_x1k1uz.c
-CASADI_MODEL_SOURCE+= {{ model.name }}_gnsf_get_matrices_fun.c
-{%- elif solver_options.integrator_type == "DISCRETE" and model.dyn_ext_fun_type == "casadi" %}
-CASADI_MODEL_SOURCE+= {{ model.name }}_dyn_disc_phi_fun.c
-CASADI_MODEL_SOURCE+= {{ model.name }}_dyn_disc_phi_fun_jac.c
-{%- if hessian_approx == "EXACT" %}
-CASADI_MODEL_SOURCE+= {{ model.name }}_dyn_disc_phi_fun_jac_hess.c
-{%- endif %}
-{%- endif %}
-{%- if constr_type == "BGP" and dims_nphi > 0 %}
-CASADI_CON_PHI_SOURCE=
-CASADI_CON_PHI_SOURCE+= {{ model.name }}_phi_constraint.c
-{%- endif %}
-{%- if constr_type_e == "BGP" and dims_nphi_e > 0 %}
-CASADI_CON_PHI_E_SOURCE=
-CASADI_CON_PHI_E_SOURCE+= {{ model.name }}_phi_e_constraint.c
-{%- endif %}
-{%- if constr_type == "BGH" and dims_nh > 0 %}
-CASADI_CON_H_SOURCE=
-CASADI_CON_H_SOURCE+= {{ model.name }}_constr_h_fun_jac_uxt_zt.c
-CASADI_CON_H_SOURCE+= {{ model.name }}_constr_h_fun.c
-{%- if hessian_approx == "EXACT" %}
-CASADI_CON_H_SOURCE+= {{ model.name }}_constr_h_fun_jac_uxt_zt_hess.c
-{%- endif %}
-{%- endif %}
-
-{%- if dims_nh_e > 0 %}
-CASADI_CON_H_E_SOURCE=
-CASADI_CON_H_E_SOURCE+= {{ model.name }}_constr_h_e_fun_jac_uxt_zt.c
-CASADI_CON_H_E_SOURCE+= {{ model.name }}_constr_h_e_fun.c
-{%- if hessian_approx == "EXACT" %}
-CASADI_CON_H_E_SOURCE+= {{ model.name }}_constr_h_e_fun_jac_uxt_zt_hess.c
-{%- endif %}
-{%- endif %}
-
-{%- if cost_type == "NONLINEAR_LS" %}
-CASADI_COST_Y_SOURCE=
-CASADI_COST_Y_SOURCE+= {{ model.name }}_cost_y_fun.c
-CASADI_COST_Y_SOURCE+= {{ model.name }}_cost_y_fun_jac_ut_xt.c
-CASADI_COST_Y_SOURCE+= {{ model.name }}_cost_y_hess.c
-{%- endif %}
-{%- if cost_type_e == "NONLINEAR_LS" %}
-CASADI_COST_Y_E_SOURCE=
-CASADI_COST_Y_E_SOURCE+= {{ model.name }}_cost_y_e_fun.c
-CASADI_COST_Y_E_SOURCE+= {{ model.name }}_cost_y_e_fun_jac_ut_xt.c
-CASADI_COST_Y_E_SOURCE+= {{ model.name }}_cost_y_e_hess.c
+# preprocessor flags for make's implicit rules
+{%- if qp_solver == "FULL_CONDENSING_QPOASES" %}
+CPPFLAGS += -DACADOS_WITH_QPOASES
{%- endif %}
-{%- if cost_type_0 == "NONLINEAR_LS" %}
-CASADI_COST_Y_0_SOURCE=
-CASADI_COST_Y_0_SOURCE+= {{ model.name }}_cost_y_0_fun.c
-CASADI_COST_Y_0_SOURCE+= {{ model.name }}_cost_y_0_fun_jac_ut_xt.c
-CASADI_COST_Y_0_SOURCE+= {{ model.name }}_cost_y_0_hess.c
+{%- if qp_solver == "PARTIAL_CONDENSING_OSQP" %}
+CPPFLAGS += -DACADOS_WITH_OSQP
{%- endif %}
+{%- if qp_solver == "PARTIAL_CONDENSING_QPDUNES" %}
+CPPFLAGS += -DACADOS_WITH_QPDUNES
+{%- endif %}
+CPPFLAGS+= -I$(INCLUDE_PATH)
+CPPFLAGS+= -I$(INCLUDE_PATH)/acados
+CPPFLAGS+= -I$(INCLUDE_PATH)/blasfeo/include
+CPPFLAGS+= -I$(INCLUDE_PATH)/hpipm/include
+ {%- if qp_solver == "FULL_CONDENSING_QPOASES" %}
+CPPFLAGS+= -I $(INCLUDE_PATH)/qpOASES_e/
+ {%- endif %}
+
+{# c-compiler flags #}
+# define the c-compiler flags for make's implicit rules
+CFLAGS = -fPIC -std=c99 {{ openmp_flag }} #-fno-diagnostics-show-line-numbers -g
+# # Debugging
+# CFLAGS += -g3
-casadi_fun:
- {%- if model.dyn_ext_fun_type == "casadi" %}
- ( cd {{ model.name }}_model {{ control }} gcc $(ACADOS_FLAGS) -c $(CASADI_MODEL_SOURCE))
- {%- endif %}
- {%- if constr_type == "BGP" and dims_nphi > 0 %}
- ( cd {{ model.name }}_constraints {{ control }} gcc $(ACADOS_FLAGS) -c $(CASADI_CON_PHI_SOURCE))
- {%- endif %}
- {%- if constr_type_e == "BGP" and dims_nphi_e > 0 %}
- ( cd {{ model.name }}_constraints {{ control }} gcc $(ACADOS_FLAGS) -c $(CASADI_CON_PHI_E_SOURCE))
- {%- endif %}
- {%- if constr_type == "BGH" and dims_nh > 0 %}
- ( cd {{ model.name }}_constraints {{ control }} gcc $(ACADOS_FLAGS) -c $(CASADI_CON_H_SOURCE))
- {%- endif %}
- {%- if constr_type_e == "BGH" and dims_nh_e > 0 %}
- ( cd {{ model.name }}_constraints {{ control }} gcc $(ACADOS_FLAGS) -c $(CASADI_CON_H_E_SOURCE))
- {%- endif %}
- {%- if cost_type == "NONLINEAR_LS" %}
- ( cd {{ model.name }}_cost {{ control }} gcc $(ACADOS_FLAGS) -c $(CASADI_COST_Y_SOURCE))
- {%- endif %}
- {%- if cost_type_e == "NONLINEAR_LS" %}
- ( cd {{ model.name }}_cost {{ control }} gcc $(ACADOS_FLAGS) -c $(CASADI_COST_Y_E_SOURCE))
- {%- endif %}
- {%- if cost_type_0 == "NONLINEAR_LS" %}
- ( cd {{ model.name }}_cost {{ control }} gcc $(ACADOS_FLAGS) -c $(CASADI_COST_Y_0_SOURCE))
- {%- endif %}
-
-main:
- gcc $(ACADOS_FLAGS) -c main_{{ model.name }}.c -I $(INCLUDE_PATH)/blasfeo/include/ -I $(INCLUDE_PATH)/hpipm/include/ \
- -I $(INCLUDE_PATH) -I $(INCLUDE_PATH)/acados/ \
- {%- if qp_solver == "FULL_CONDENSING_QPOASES" %}
- -I $(INCLUDE_PATH)/qpOASES_e/
- {%- endif %}
+# linker flags
+LDFLAGS+= -L$(LIB_PATH)
-main_sim:
- gcc $(ACADOS_FLAGS) -c main_sim_{{ model.name }}.c -I $(INCLUDE_PATH)/blasfeo/include/ -I $(INCLUDE_PATH)/hpipm/include/ \
- -I $(INCLUDE_PATH) -I $(INCLUDE_PATH)/acados/
+# link to libraries
+LDLIBS+= -lacados
+LDLIBS+= -lhpipm
+LDLIBS+= -lblasfeo
+LDLIBS+= -lm
+LDLIBS+= {{ link_libs }}
-ocp_solver:
- gcc $(ACADOS_FLAGS) -c acados_solver_{{ model.name }}.c -I $(INCLUDE_PATH)/blasfeo/include/ -I $(INCLUDE_PATH)/hpipm/include/ \
- -I $(INCLUDE_PATH) -I $(INCLUDE_PATH)/acados/ \
- {%- if qp_solver == "FULL_CONDENSING_QPOASES" %}
- -I $(INCLUDE_PATH)/qpOASES_e/
- {%- endif %}
+# libraries
+LIBACADOS_SOLVER=libacados_solver_{{ model.name }}.so
+LIBACADOS_OCP_SOLVER=libacados_ocp_solver_{{ model.name }}.so
+LIBACADOS_SIM_SOLVER=lib$(SIM_SRC:.c=.so)
-sim_solver:
- gcc $(ACADOS_FLAGS) -c acados_sim_solver_{{ model.name }}.c -I $(INCLUDE_PATH)/blasfeo/include/ -I $(INCLUDE_PATH)/hpipm/include/ \
- -I $(INCLUDE_PATH) -I $(INCLUDE_PATH)/acados/ \
- {%- if qp_solver == "FULL_CONDENSING_QPOASES" %}
- -I $(INCLUDE_PATH)/qpOASES_e/
- {%- endif %}
+# virtual targets
+.PHONY : all clean
-example: ocp_solver main
- gcc $(ACADOS_FLAGS) -o main_{{ model.name }} $(EX_OBJ) $(OBJ) -L $(LIB_PATH) \
- -lacados -lhpipm -lblasfeo \
- {{ link_libs }} \
- -lm \
- -I $(INCLUDE_PATH)/blasfeo/include/ \
- -I $(INCLUDE_PATH)/hpipm/include/ \
- -I $(INCLUDE_PATH) \
- -I $(INCLUDE_PATH)/acados/ \
- {%- if qp_solver == "FULL_CONDENSING_QPOASES" %}
- -I $(INCLUDE_PATH)/qpOASES_e/
- {%- endif %}
-
-
-example_sim: sim_solver main_sim
- gcc $(ACADOS_FLAGS) -o main_sim_{{ model.name }} $(EX_SIM_OBJ) $(MODEL_OBJ) $(SIM_OBJ) -L $(LIB_PATH) \
- -lacados -lhpipm -lblasfeo \
- {{ link_libs }} \
- -lm \
- -I $(INCLUDE_PATH)/blasfeo/include/ \
- -I $(INCLUDE_PATH)/acados/ \
+#all: clean example_sim example shared_lib
+{% if solver_options.integrator_type == "DISCRETE" -%}
+all: clean example
+shared_lib: ocp_shared_lib
+{%- else %}
+all: clean example_sim example
+shared_lib: bundled_shared_lib ocp_shared_lib sim_shared_lib
+{%- endif %}
-{%- if solver_options.integrator_type != "DISCRETE" %}
+# some linker targets
+example: $(EX_OBJ) $(OBJ)
+ $(CC) $^ -o $(EX_EXE) $(LDFLAGS) $(LDLIBS)
-bundled_shared_lib: casadi_fun ocp_solver sim_solver
- gcc $(ACADOS_FLAGS) -shared -o libacados_solver_{{ model.name }}.so $(OBJ) \
- -I $(INCLUDE_PATH)/blasfeo/include/ \
- -I $(INCLUDE_PATH)/hpipm/include/ \
- -I $(INCLUDE_PATH) \
- -L $(LIB_PATH) \
- -lacados -lhpipm -lblasfeo \
- {{ link_libs }} \
- -lm \
+example_sim: $(EX_SIM_OBJ) $(MODEL_OBJ) $(SIM_OBJ)
+ $(CC) $^ -o $(EX_SIM_EXE) $(LDFLAGS) $(LDLIBS)
-ocp_shared_lib: casadi_fun ocp_solver
- gcc $(ACADOS_FLAGS) -shared -o libacados_ocp_solver_{{ model.name }}.so $(OCP_OBJ) $(MODEL_OBJ) \
- -I $(INCLUDE_PATH)/blasfeo/include/ \
- -I $(INCLUDE_PATH)/hpipm/include/ \
- -I $(INCLUDE_PATH) \
- -L$(EXTERNAL_DIR) -l$(EXTERNAL_LIB) \
- -L $(LIB_PATH) -lacados -lhpipm -lblasfeo \
- {{ link_libs }} \
- -lm \
+{% if solver_options.integrator_type != "DISCRETE" -%}
+bundled_shared_lib: $(OBJ)
+ $(CC) -shared $^ -o $(LIBACADOS_SOLVER) $(LDFLAGS) $(LDLIBS)
+{%- endif %}
-{%- else %}
+ocp_shared_lib: $(OCP_OBJ) $(MODEL_OBJ)
+ $(CC) -shared $^ -o $(LIBACADOS_OCP_SOLVER) $(LDFLAGS) $(LDLIBS) \
+ -L$(EXTERNAL_DIR) -l$(EXTERNAL_LIB)
-ocp_shared_lib: casadi_fun ocp_solver
- gcc $(ACADOS_FLAGS) -shared -o libacados_ocp_solver_{{ model.name }}.so $(OCP_OBJ) $(MODEL_OBJ) \
- -I $(INCLUDE_PATH)/blasfeo/include/ \
- -I $(INCLUDE_PATH)/hpipm/include/ \
- -I $(INCLUDE_PATH) \
- -L$(EXTERNAL_DIR) -l$(EXTERNAL_LIB) \
- -L $(LIB_PATH) -lacados -lhpipm -lblasfeo \
- {{ link_libs }} \
- -lm \
+sim_shared_lib: $(SIM_OBJ) $(MODEL_OBJ)
+ $(CC) -shared $^ -o $(LIBACADOS_SIM_SOLVER) $(LDFLAGS) $(LDLIBS)
-{%- endif %}
+# Cython targets
ocp_cython_c: ocp_shared_lib
cython \
-o acados_ocp_solver_pyx.c \
-I $(INCLUDE_PATH)/../interfaces/acados_template/acados_template \
$(INCLUDE_PATH)/../interfaces/acados_template/acados_template/acados_ocp_solver_pyx.pyx \
+ -I {{ code_export_directory }} \
ocp_cython_o: ocp_cython_c
- clang $(ACADOS_FLAGS) -c -O2 \
+ $(CC) $(ACADOS_FLAGS) -c -O2 \
+ -fPIC \
-o acados_ocp_solver_pyx.o \
-I /usr/include/python3.8 \
-I $(INCLUDE_PATH)/blasfeo/include/ \
-I $(INCLUDE_PATH)/hpipm/include/ \
-I $(INCLUDE_PATH) \
+ -I {{ cython_include_dirs }} \
acados_ocp_solver_pyx.c \
ocp_cython: ocp_cython_o
- clang $(ACADOS_FLAGS) -shared \
+ $(CC) $(ACADOS_FLAGS) -shared \
-o acados_ocp_solver_pyx.so \
-Wl,-rpath=$(LIB_PATH) \
acados_ocp_solver_pyx.o \
$(abspath .)/libacados_ocp_solver_{{ model.name }}.so \
- -L $(LIB_PATH) -lacados -lhpipm -lblasfeo -lqpOASES_e \
- {{ link_libs }} \
- -lm \
-
-sim_shared_lib: casadi_fun sim_solver
- gcc $(ACADOS_FLAGS) -shared -o libacados_sim_solver_{{ model.name }}.so $(SIM_OBJ) $(MODEL_OBJ) -L$(EXTERNAL_DIR) -l$(EXTERNAL_LIB) \
- -L $(LIB_PATH) -lacados -lhpipm -lblasfeo \
- {{ link_libs }} \
- -lm \
+ $(LDFLAGS) $(LDLIBS)
{%- if os and os == "pc" %}
@@ -510,15 +380,27 @@ clean_ocp_shared_lib:
del \Q libacados_ocp_solver_{{ model.name }}.so 2>nul
del \Q acados_solver_{{ model.name }}.o 2>nul
+clean_ocp_cython:
+ del \Q libacados_ocp_solver_{{ model.name }}.so 2>nul
+ del \Q acados_solver_{{ model.name }}.o 2>nul
+ del \Q acados_ocp_solver_pyx.so 2>nul
+ del \Q acados_ocp_solver_pyx.o 2>nul
+
{%- else %}
clean:
- rm -f *.o
- rm -f *.so
- rm -f main_{{ model.name }}
+ $(RM) $(OBJ) $(EX_OBJ) $(EX_SIM_OBJ)
+ $(RM) $(LIBACADOS_SOLVER) $(LIBACADOS_OCP_SOLVER) $(LIBACADOS_SIM_SOLVER)
+ $(RM) $(EX_EXE) $(EX_SIM_EXE)
clean_ocp_shared_lib:
- rm -f libacados_ocp_solver_{{ model.name }}.so
- rm -f acados_solver_{{ model.name }}.o
+ $(RM) $(LIBACADOS_OCP_SOLVER)
+ $(RM) $(OCP_OBJ)
+
+clean_ocp_cython:
+ $(RM) libacados_ocp_solver_{{ model.name }}.so
+ $(RM) acados_solver_{{ model.name }}.o
+ $(RM) acados_ocp_solver_pyx.so
+ $(RM) acados_ocp_solver_pyx.o
{%- endif %}
diff --git a/pyextra/acados_template/c_templates_tera/acados_mex_create.in.c b/pyextra/acados_template/c_templates_tera/acados_mex_create.in.c
index 251b249b2f..e67a51567a 100644
--- a/pyextra/acados_template/c_templates_tera/acados_mex_create.in.c
+++ b/pyextra/acados_template/c_templates_tera/acados_mex_create.in.c
@@ -63,7 +63,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
mexPrintf("{{ model.name }}_acados_create() -> success!\n");
// get pointers to nlp solver related objects
- ocp_nlp_plan *nlp_plan = {{ model.name }}_acados_get_nlp_plan(acados_ocp_capsule);
+ ocp_nlp_plan_t *nlp_plan = {{ model.name }}_acados_get_nlp_plan(acados_ocp_capsule);
ocp_nlp_config *nlp_config = {{ model.name }}_acados_get_nlp_config(acados_ocp_capsule);
ocp_nlp_dims *nlp_dims = {{ model.name }}_acados_get_nlp_dims(acados_ocp_capsule);
ocp_nlp_in *nlp_in = {{ model.name }}_acados_get_nlp_in(acados_ocp_capsule);
@@ -238,14 +238,18 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
l_ptr[0] = (long long) acados_ocp_capsule->impl_dae_hess;
{%- endif %}
{% elif solver_options.integrator_type == "GNSF" %}
+ {% if model.gnsf.purely_linear != 1 %}
l_ptr = mxGetData(gnsf_phi_fun_mat);
l_ptr[0] = (long long) acados_ocp_capsule->gnsf_phi_fun;
l_ptr = mxGetData(gnsf_phi_fun_jac_y_mat);
l_ptr[0] = (long long) acados_ocp_capsule->gnsf_phi_fun_jac_y;
l_ptr = mxGetData(gnsf_phi_jac_y_uhat_mat);
l_ptr[0] = (long long) acados_ocp_capsule->gnsf_phi_jac_y_uhat;
+ {% if model.gnsf.nontrivial_f_LO == 1 %}
l_ptr = mxGetData(gnsf_f_lo_jac_x1_x1dot_u_z_mat);
l_ptr[0] = (long long) acados_ocp_capsule->gnsf_f_lo_jac_x1_x1dot_u_z;
+ {%- endif %}
+ {%- endif %}
l_ptr = mxGetData(gnsf_get_matrices_fun_mat);
l_ptr[0] = (long long) acados_ocp_capsule->gnsf_get_matrices_fun;
{% elif solver_options.integrator_type == "DISCRETE" %}
diff --git a/pyextra/acados_template/c_templates_tera/acados_mex_set.in.c b/pyextra/acados_template/c_templates_tera/acados_mex_set.in.c
index ae8c311557..f8e1e5e445 100644
--- a/pyextra/acados_template/c_templates_tera/acados_mex_set.in.c
+++ b/pyextra/acados_template/c_templates_tera/acados_mex_set.in.c
@@ -69,7 +69,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{{ model.name }}_solver_capsule *capsule = ({{ model.name }}_solver_capsule *) ptr[0];
// plan
ptr = (long long *) mxGetData( mxGetField( C_ocp, 0, "plan" ) );
- ocp_nlp_plan *plan = (ocp_nlp_plan *) ptr[0];
+ ocp_nlp_plan_t *plan = (ocp_nlp_plan_t *) ptr[0];
// config
ptr = (long long *) mxGetData( mxGetField( C_ocp, 0, "config" ) );
ocp_nlp_config *config = (ocp_nlp_config *) ptr[0];
@@ -404,7 +404,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
}
else if (!strcmp(field, "init_z"))
{
- sim_solver_plan sim_plan = plan->sim_solver_plan[0];
+ sim_solver_plan_t sim_plan = plan->sim_solver_plan[0];
sim_solver_t type = sim_plan.sim_solver;
if (type == IRK)
{
@@ -426,7 +426,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
}
else if (!strcmp(field, "init_xdot"))
{
- sim_solver_plan sim_plan = plan->sim_solver_plan[0];
+ sim_solver_plan_t sim_plan = plan->sim_solver_plan[0];
sim_solver_t type = sim_plan.sim_solver;
if (type == IRK)
{
@@ -448,7 +448,7 @@ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
}
else if (!strcmp(field, "init_gnsf_phi"))
{
- sim_solver_plan sim_plan = plan->sim_solver_plan[0];
+ sim_solver_plan_t sim_plan = plan->sim_solver_plan[0];
sim_solver_t type = sim_plan.sim_solver;
if (type == GNSF)
{
diff --git a/pyextra/acados_template/c_templates_tera/acados_sim_solver.in.c b/pyextra/acados_template/c_templates_tera/acados_sim_solver.in.c
index 971fb8a78f..f2e75058c1 100644
--- a/pyextra/acados_template/c_templates_tera/acados_sim_solver.in.c
+++ b/pyextra/acados_template/c_templates_tera/acados_sim_solver.in.c
@@ -164,12 +164,17 @@ int {{ model.name }}_acados_sim_create(sim_solver_capsule * capsule)
{%- endif %}
{% elif solver_options.integrator_type == "GNSF" -%}
+ {% if model.gnsf.purely_linear != 1 %}
capsule->sim_gnsf_phi_fun = (external_function_param_casadi *) malloc(sizeof(external_function_param_casadi));
capsule->sim_gnsf_phi_fun_jac_y = (external_function_param_casadi *) malloc(sizeof(external_function_param_casadi));
capsule->sim_gnsf_phi_jac_y_uhat = (external_function_param_casadi *) malloc(sizeof(external_function_param_casadi));
+ {% if model.gnsf.nontrivial_f_LO == 1 %}
capsule->sim_gnsf_f_lo_jac_x1_x1dot_u_z = (external_function_param_casadi *) malloc(sizeof(external_function_param_casadi));
+ {%- endif %}
+ {%- endif %}
capsule->sim_gnsf_get_matrices_fun = (external_function_param_casadi *) malloc(sizeof(external_function_param_casadi));
+ {% if model.gnsf.purely_linear != 1 %}
capsule->sim_gnsf_phi_fun->casadi_fun = &{{ model.name }}_gnsf_phi_fun;
capsule->sim_gnsf_phi_fun->casadi_n_in = &{{ model.name }}_gnsf_phi_fun_n_in;
capsule->sim_gnsf_phi_fun->casadi_n_out = &{{ model.name }}_gnsf_phi_fun_n_out;
@@ -194,6 +199,7 @@ int {{ model.name }}_acados_sim_create(sim_solver_capsule * capsule)
capsule->sim_gnsf_phi_jac_y_uhat->casadi_work = &{{ model.name }}_gnsf_phi_jac_y_uhat_work;
external_function_param_casadi_create(capsule->sim_gnsf_phi_jac_y_uhat, np);
+ {% if model.gnsf.nontrivial_f_LO == 1 %}
capsule->sim_gnsf_f_lo_jac_x1_x1dot_u_z->casadi_fun = &{{ model.name }}_gnsf_f_lo_fun_jac_x1k1uz;
capsule->sim_gnsf_f_lo_jac_x1_x1dot_u_z->casadi_n_in = &{{ model.name }}_gnsf_f_lo_fun_jac_x1k1uz_n_in;
capsule->sim_gnsf_f_lo_jac_x1_x1dot_u_z->casadi_n_out = &{{ model.name }}_gnsf_f_lo_fun_jac_x1k1uz_n_out;
@@ -201,6 +207,8 @@ int {{ model.name }}_acados_sim_create(sim_solver_capsule * capsule)
capsule->sim_gnsf_f_lo_jac_x1_x1dot_u_z->casadi_sparsity_out = &{{ model.name }}_gnsf_f_lo_fun_jac_x1k1uz_sparsity_out;
capsule->sim_gnsf_f_lo_jac_x1_x1dot_u_z->casadi_work = &{{ model.name }}_gnsf_f_lo_fun_jac_x1k1uz_work;
external_function_param_casadi_create(capsule->sim_gnsf_f_lo_jac_x1_x1dot_u_z, np);
+ {%- endif %}
+ {%- endif %}
capsule->sim_gnsf_get_matrices_fun->casadi_fun = &{{ model.name }}_gnsf_get_matrices_fun;
capsule->sim_gnsf_get_matrices_fun->casadi_n_in = &{{ model.name }}_gnsf_get_matrices_fun_n_in;
@@ -212,7 +220,7 @@ int {{ model.name }}_acados_sim_create(sim_solver_capsule * capsule)
{% endif %}
// sim plan & config
- sim_solver_plan plan;
+ sim_solver_plan_t plan;
plan.sim_solver = {{ solver_options.integrator_type }};
// create correct config based on plan
@@ -307,14 +315,18 @@ int {{ model.name }}_acados_sim_create(sim_solver_capsule * capsule)
"expl_ode_hess", capsule->sim_expl_ode_hess);
{%- endif %}
{%- elif solver_options.integrator_type == "GNSF" %}
+ {% if model.gnsf.purely_linear != 1 %}
{{ model.name }}_sim_config->model_set({{ model.name }}_sim_in->model,
"phi_fun", capsule->sim_gnsf_phi_fun);
{{ model.name }}_sim_config->model_set({{ model.name }}_sim_in->model,
"phi_fun_jac_y", capsule->sim_gnsf_phi_fun_jac_y);
{{ model.name }}_sim_config->model_set({{ model.name }}_sim_in->model,
"phi_jac_y_uhat", capsule->sim_gnsf_phi_jac_y_uhat);
+ {% if model.gnsf.nontrivial_f_LO == 1 %}
{{ model.name }}_sim_config->model_set({{ model.name }}_sim_in->model,
"f_lo_jac_x1_x1dot_u_z", capsule->sim_gnsf_f_lo_jac_x1_x1dot_u_z);
+ {%- endif %}
+ {%- endif %}
{{ model.name }}_sim_config->model_set({{ model.name }}_sim_in->model,
"gnsf_get_matrices_fun", capsule->sim_gnsf_get_matrices_fun);
{%- endif %}
@@ -409,10 +421,14 @@ int {{ model.name }}_acados_sim_free(sim_solver_capsule *capsule)
external_function_param_casadi_free(capsule->sim_expl_ode_hess);
{%- endif %}
{%- elif solver_options.integrator_type == "GNSF" %}
+ {% if model.gnsf.purely_linear != 1 %}
external_function_param_casadi_free(capsule->sim_gnsf_phi_fun);
external_function_param_casadi_free(capsule->sim_gnsf_phi_fun_jac_y);
external_function_param_casadi_free(capsule->sim_gnsf_phi_jac_y_uhat);
+ {% if model.gnsf.nontrivial_f_LO == 1 %}
external_function_param_casadi_free(capsule->sim_gnsf_f_lo_jac_x1_x1dot_u_z);
+ {%- endif %}
+ {%- endif %}
external_function_param_casadi_free(capsule->sim_gnsf_get_matrices_fun);
{% endif %}
@@ -445,10 +461,14 @@ int {{ model.name }}_acados_sim_update_params(sim_solver_capsule *capsule, doubl
capsule->sim_impl_dae_hess[0].set_param(capsule->sim_impl_dae_hess, p);
{%- endif %}
{%- elif solver_options.integrator_type == "GNSF" %}
+ {% if model.gnsf.purely_linear != 1 %}
capsule->sim_gnsf_phi_fun[0].set_param(capsule->sim_gnsf_phi_fun, p);
capsule->sim_gnsf_phi_fun_jac_y[0].set_param(capsule->sim_gnsf_phi_fun_jac_y, p);
capsule->sim_gnsf_phi_jac_y_uhat[0].set_param(capsule->sim_gnsf_phi_jac_y_uhat, p);
+ {% if model.gnsf.nontrivial_f_LO == 1 %}
capsule->sim_gnsf_f_lo_jac_x1_x1dot_u_z[0].set_param(capsule->sim_gnsf_f_lo_jac_x1_x1dot_u_z, p);
+ {%- endif %}
+ {%- endif %}
capsule->sim_gnsf_get_matrices_fun[0].set_param(capsule->sim_gnsf_get_matrices_fun, p);
{% endif %}
diff --git a/pyextra/acados_template/c_templates_tera/acados_sim_solver_sfun.in.c b/pyextra/acados_template/c_templates_tera/acados_sim_solver_sfun.in.c
index 234295fa29..68a6a3f80f 100644
--- a/pyextra/acados_template/c_templates_tera/acados_sim_solver_sfun.in.c
+++ b/pyextra/acados_template/c_templates_tera/acados_sim_solver_sfun.in.c
@@ -37,7 +37,7 @@
#define MDL_START
// acados
-#include "acados/utils/print.h"
+// #include "acados/utils/print.h"
#include "acados_c/ocp_nlp_interface.h"
#include "acados_c/external_function_interface.h"
diff --git a/pyextra/acados_template/c_templates_tera/acados_solver.in.c b/pyextra/acados_template/c_templates_tera/acados_solver.in.c
index 6e13242a41..a42937ed28 100644
--- a/pyextra/acados_template/c_templates_tera/acados_solver.in.c
+++ b/pyextra/acados_template/c_templates_tera/acados_solver.in.c
@@ -34,8 +34,9 @@
// standard
#include
#include
+#include
// acados
-#include "acados/utils/print.h"
+// #include "acados/utils/print.h"
#include "acados_c/ocp_nlp_interface.h"
#include "acados_c/external_function_interface.h"
@@ -121,14 +122,15 @@ int {{ model.name }}_acados_free_capsule({{ model.name }}_solver_capsule *capsul
}
-int {{ model.name }}_acados_create({{ model.name }}_solver_capsule * capsule)
+int {{ model.name }}_acados_create({{ model.name }}_solver_capsule* capsule)
{
int N_shooting_intervals = {{ model.name | upper }}_N;
double* new_time_steps = NULL; // NULL -> don't alter the code generated time-steps
return {{ model.name }}_acados_create_with_discretization(capsule, N_shooting_intervals, new_time_steps);
}
-int {{ model.name }}_acados_update_time_steps({{ model.name }}_solver_capsule * capsule, int N, double* new_time_steps)
+
+int {{ model.name }}_acados_update_time_steps({{ model.name }}_solver_capsule* capsule, int N, double* new_time_steps)
{
if (N != capsule->nlp_solver_plan->N) {
fprintf(stderr, "{{ model.name }}_acados_update_time_steps: given number of time steps (= %d) " \
@@ -151,30 +153,20 @@ int {{ model.name }}_acados_update_time_steps({{ model.name }}_solver_capsule *
return 0;
}
-int {{ model.name }}_acados_create_with_discretization({{ model.name }}_solver_capsule * capsule, int N, double* new_time_steps)
+/**
+ * Internal function for {{ model.name }}_acados_create: step 1
+ */
+void {{ model.name }}_acados_create_1_set_plan(ocp_nlp_plan_t* nlp_solver_plan, const int N)
{
- int status = 0;
- // If N does not match the number of shooting intervals used for code generation, new_time_steps must be given.
- if (N != {{ model.name | upper }}_N && !new_time_steps) {
- fprintf(stderr, "{{ model.name }}_acados_create_with_discretization: new_time_steps is NULL " \
- "but the number of shooting intervals (= %d) differs from the number of " \
- "shooting intervals (= %d) during code generation! Please provide a new vector of time_stamps!\n", \
- N, {{ model.name | upper }}_N);
- return 1;
- }
-
- // number of expected runtime parameters
- capsule->nlp_np = NP;
+ assert(N == nlp_solver_plan->N);
/************************************************
- * plan & config
+ * plan
************************************************/
- ocp_nlp_plan * nlp_solver_plan = ocp_nlp_plan_create(N);
- capsule->nlp_solver_plan = nlp_solver_plan;
{%- if solver_options.nlp_solver_type == "SQP" %}
nlp_solver_plan->nlp_solver = SQP;
- {% else %}
+ {%- else %}
nlp_solver_plan->nlp_solver = SQP_RTI;
{%- endif %}
@@ -188,11 +180,11 @@ int {{ model.name }}_acados_create_with_discretization({{ model.name }}_solver_c
for (int i = 0; i < N; i++)
{
- {% if solver_options.integrator_type == "DISCRETE" %}
+ {%- if solver_options.integrator_type == "DISCRETE" %}
nlp_solver_plan->nlp_dynamics[i] = DISCRETE_MODEL;
// discrete dynamics does not need sim solver option, this field is ignored
nlp_solver_plan->sim_solver_plan[i].sim_solver = INVALID_SIM_SOLVER;
- {% else %}
+ {%- else %}
nlp_solver_plan->nlp_dynamics[i] = CONTINUOUS_MODEL;
nlp_solver_plan->sim_solver_plan[i].sim_solver = {{ solver_options.integrator_type }};
{%- endif %}
@@ -200,7 +192,7 @@ int {{ model.name }}_acados_create_with_discretization({{ model.name }}_solver_c
for (int i = 0; i < N; i++)
{
- {% if constraints.constr_type == "BGP" %}
+ {%- if constraints.constr_type == "BGP" %}
nlp_solver_plan->nlp_constraints[i] = BGP;
{%- else -%}
nlp_solver_plan->nlp_constraints[i] = BGH;
@@ -209,7 +201,7 @@ int {{ model.name }}_acados_create_with_discretization({{ model.name }}_solver_c
{%- if constraints.constr_type_e == "BGP" %}
nlp_solver_plan->nlp_constraints[N] = BGP;
- {% else %}
+ {%- else %}
nlp_solver_plan->nlp_constraints[N] = BGH;
{%- endif %}
@@ -226,10 +218,18 @@ int {{ model.name }}_acados_create_with_discretization({{ model.name }}_solver_c
nlp_solver_plan->regularization = CONVEXIFY;
{%- endif %}
{%- endif %}
- ocp_nlp_config * nlp_config = ocp_nlp_config_create(*nlp_solver_plan);
- capsule->nlp_config = nlp_config;
+}
+/**
+ * Internal function for {{ model.name }}_acados_create: step 2
+ */
+ocp_nlp_dims* {{ model.name }}_acados_create_2_create_and_set_dimensions({{ model.name }}_solver_capsule* capsule)
+{
+ ocp_nlp_plan_t* nlp_solver_plan = capsule->nlp_solver_plan;
+ const int N = nlp_solver_plan->N;
+ ocp_nlp_config* nlp_config = capsule->nlp_config;
+
/************************************************
* dimensions
************************************************/
@@ -307,7 +307,6 @@ int {{ model.name }}_acados_create_with_discretization({{ model.name }}_solver_c
/* create and set ocp_nlp_dims */
ocp_nlp_dims * nlp_dims = ocp_nlp_dims_create(nlp_config);
- capsule->nlp_dims = nlp_dims;
ocp_nlp_dims_set_opt_vars(nlp_config, nlp_dims, "nx", nx);
ocp_nlp_dims_set_opt_vars(nlp_config, nlp_dims, "nu", nu);
@@ -325,14 +324,14 @@ int {{ model.name }}_acados_create_with_discretization({{ model.name }}_solver_c
ocp_nlp_dims_set_constraints(nlp_config, nlp_dims, i, "nbxe", &nbxe[i]);
}
- {%- if cost.cost_type_0 == "NONLINEAR_LS" or cost.cost_type_0 == "LINEAR_LS" %}
+{%- if cost.cost_type_0 == "NONLINEAR_LS" or cost.cost_type_0 == "LINEAR_LS" %}
ocp_nlp_dims_set_cost(nlp_config, nlp_dims, 0, "ny", &ny[0]);
- {%- endif %}
+{%- endif %}
- {%- if cost.cost_type == "NONLINEAR_LS" or cost.cost_type == "LINEAR_LS" %}
+{%- if cost.cost_type == "NONLINEAR_LS" or cost.cost_type == "LINEAR_LS" %}
for (int i = 1; i < N; i++)
ocp_nlp_dims_set_cost(nlp_config, nlp_dims, i, "ny", &ny[i]);
- {%- endif %}
+{%- endif %}
for (int i = 0; i < N; i++)
{
@@ -346,21 +345,20 @@ int {{ model.name }}_acados_create_with_discretization({{ model.name }}_solver_c
{%- endif %}
}
- {%- if constraints.constr_type_e == "BGH" %}
+{%- if constraints.constr_type_e == "BGH" %}
ocp_nlp_dims_set_constraints(nlp_config, nlp_dims, N, "nh", &nh[N]);
ocp_nlp_dims_set_constraints(nlp_config, nlp_dims, N, "nsh", &nsh[N]);
- {%- elif constraints.constr_type_e == "BGP" %}
+{%- elif constraints.constr_type_e == "BGP" %}
ocp_nlp_dims_set_constraints(nlp_config, nlp_dims, N, "nr", &nr[N]);
ocp_nlp_dims_set_constraints(nlp_config, nlp_dims, N, "nphi", &nphi[N]);
ocp_nlp_dims_set_constraints(nlp_config, nlp_dims, N, "nsphi", &nsphi[N]);
- {%- endif %}
- {%- if cost.cost_type_e == "NONLINEAR_LS" or cost.cost_type_e == "LINEAR_LS" %}
+{%- endif %}
+{%- if cost.cost_type_e == "NONLINEAR_LS" or cost.cost_type_e == "LINEAR_LS" %}
ocp_nlp_dims_set_cost(nlp_config, nlp_dims, N, "ny", &ny[N]);
- {%- endif %}
-
+{%- endif %}
free(intNp1mem);
-{% if solver_options.integrator_type == "GNSF" -%}
+{%- if solver_options.integrator_type == "GNSF" -%}
// GNSF specific dimensions
int gnsf_nx1 = {{ dims.gnsf_nx1 }};
int gnsf_nz1 = {{ dims.gnsf_nz1 }};
@@ -380,136 +378,91 @@ int {{ model.name }}_acados_create_with_discretization({{ model.name }}_solver_c
}
}
{%- endif %}
+return nlp_dims;
+}
+
+
+/**
+ * Internal function for {{ model.name }}_acados_create: step 3
+ */
+void {{ model.name }}_acados_create_3_create_and_set_functions({{ model.name }}_solver_capsule* capsule)
+{
+ const int N = capsule->nlp_solver_plan->N;
+ ocp_nlp_config* nlp_config = capsule->nlp_config;
/************************************************
* external functions
************************************************/
- {%- if constraints.constr_type == "BGP" %}
+
+#define MAP_CASADI_FNC(__CAPSULE_FNC__, __MODEL_BASE_FNC__) do{ \
+ capsule->__CAPSULE_FNC__.casadi_fun = & __MODEL_BASE_FNC__ ;\
+ capsule->__CAPSULE_FNC__.casadi_n_in = & __MODEL_BASE_FNC__ ## _n_in; \
+ capsule->__CAPSULE_FNC__.casadi_n_out = & __MODEL_BASE_FNC__ ## _n_out; \
+ capsule->__CAPSULE_FNC__.casadi_sparsity_in = & __MODEL_BASE_FNC__ ## _sparsity_in; \
+ capsule->__CAPSULE_FNC__.casadi_sparsity_out = & __MODEL_BASE_FNC__ ## _sparsity_out; \
+ capsule->__CAPSULE_FNC__.casadi_work = & __MODEL_BASE_FNC__ ## _work; \
+ external_function_param_casadi_create(&capsule->__CAPSULE_FNC__ , {{ dims.np }}); \
+ }while(false)
+
+{% if constraints.constr_type == "BGP" %}
+ // constraints.constr_type == "BGP"
capsule->phi_constraint = (external_function_param_casadi *) malloc(sizeof(external_function_param_casadi)*N);
for (int i = 0; i < N; i++)
{
// nonlinear part of convex-composite constraint
- capsule->phi_constraint[i].casadi_fun = &{{ model.name }}_phi_constraint;
- capsule->phi_constraint[i].casadi_n_in = &{{ model.name }}_phi_constraint_n_in;
- capsule->phi_constraint[i].casadi_n_out = &{{ model.name }}_phi_constraint_n_out;
- capsule->phi_constraint[i].casadi_sparsity_in = &{{ model.name }}_phi_constraint_sparsity_in;
- capsule->phi_constraint[i].casadi_sparsity_out = &{{ model.name }}_phi_constraint_sparsity_out;
- capsule->phi_constraint[i].casadi_work = &{{ model.name }}_phi_constraint_work;
-
- external_function_param_casadi_create(&capsule->phi_constraint[i], {{ dims.np }});
+ MAP_CASADI_FNC(phi_constraint[i], {{ model.name }}_phi_constraint);
}
- {%- endif %}
+{%- endif %}
- {%- if constraints.constr_type_e == "BGP" %}
+{%- if constraints.constr_type_e == "BGP" %}
+ // constraints.constr_type_e == "BGP"
// nonlinear part of convex-composite constraint
- capsule->phi_e_constraint.casadi_fun = &{{ model.name }}_phi_e_constraint;
- capsule->phi_e_constraint.casadi_n_in = &{{ model.name }}_phi_e_constraint_n_in;
- capsule->phi_e_constraint.casadi_n_out = &{{ model.name }}_phi_e_constraint_n_out;
- capsule->phi_e_constraint.casadi_sparsity_in = &{{ model.name }}_phi_e_constraint_sparsity_in;
- capsule->phi_e_constraint.casadi_sparsity_out = &{{ model.name }}_phi_e_constraint_sparsity_out;
- capsule->phi_e_constraint.casadi_work = &{{ model.name }}_phi_e_constraint_work;
-
- external_function_param_casadi_create(&capsule->phi_e_constraint, {{ dims.np }});
- {% endif %}
+ MAP_CASADI_FNC(phi_e_constraint, {{ model.name }}_phi_e_constraint);
+{%- endif %}
- {%- if constraints.constr_type == "BGH" and dims.nh > 0 %}
+{%- if constraints.constr_type == "BGH" and dims.nh > 0 %}
+ // constraints.constr_type == "BGH" and dims.nh > 0
capsule->nl_constr_h_fun_jac = (external_function_param_casadi *) malloc(sizeof(external_function_param_casadi)*N);
for (int i = 0; i < N; i++) {
- capsule->nl_constr_h_fun_jac[i].casadi_fun = &{{ model.name }}_constr_h_fun_jac_uxt_zt;
- capsule->nl_constr_h_fun_jac[i].casadi_n_in = &{{ model.name }}_constr_h_fun_jac_uxt_zt_n_in;
- capsule->nl_constr_h_fun_jac[i].casadi_n_out = &{{ model.name }}_constr_h_fun_jac_uxt_zt_n_out;
- capsule->nl_constr_h_fun_jac[i].casadi_sparsity_in = &{{ model.name }}_constr_h_fun_jac_uxt_zt_sparsity_in;
- capsule->nl_constr_h_fun_jac[i].casadi_sparsity_out = &{{ model.name }}_constr_h_fun_jac_uxt_zt_sparsity_out;
- capsule->nl_constr_h_fun_jac[i].casadi_work = &{{ model.name }}_constr_h_fun_jac_uxt_zt_work;
- external_function_param_casadi_create(&capsule->nl_constr_h_fun_jac[i], {{ dims.np }});
+ MAP_CASADI_FNC(nl_constr_h_fun_jac[i], {{ model.name }}_constr_h_fun_jac_uxt_zt);
}
capsule->nl_constr_h_fun = (external_function_param_casadi *) malloc(sizeof(external_function_param_casadi)*N);
for (int i = 0; i < N; i++) {
- capsule->nl_constr_h_fun[i].casadi_fun = &{{ model.name }}_constr_h_fun;
- capsule->nl_constr_h_fun[i].casadi_n_in = &{{ model.name }}_constr_h_fun_n_in;
- capsule->nl_constr_h_fun[i].casadi_n_out = &{{ model.name }}_constr_h_fun_n_out;
- capsule->nl_constr_h_fun[i].casadi_sparsity_in = &{{ model.name }}_constr_h_fun_sparsity_in;
- capsule->nl_constr_h_fun[i].casadi_sparsity_out = &{{ model.name }}_constr_h_fun_sparsity_out;
- capsule->nl_constr_h_fun[i].casadi_work = &{{ model.name }}_constr_h_fun_work;
- external_function_param_casadi_create(&capsule->nl_constr_h_fun[i], {{ dims.np }});
+ MAP_CASADI_FNC(nl_constr_h_fun[i], {{ model.name }}_constr_h_fun);
}
{% if solver_options.hessian_approx == "EXACT" %}
capsule->nl_constr_h_fun_jac_hess = (external_function_param_casadi *) malloc(sizeof(external_function_param_casadi)*N);
for (int i = 0; i < N; i++) {
- capsule->nl_constr_h_fun_jac_hess[i].casadi_fun = &{{ model.name }}_constr_h_fun_jac_uxt_zt_hess;
- capsule->nl_constr_h_fun_jac_hess[i].casadi_n_in = &{{ model.name }}_constr_h_fun_jac_uxt_zt_hess_n_in;
- capsule->nl_constr_h_fun_jac_hess[i].casadi_n_out = &{{ model.name }}_constr_h_fun_jac_uxt_zt_hess_n_out;
- capsule->nl_constr_h_fun_jac_hess[i].casadi_sparsity_in = &{{ model.name }}_constr_h_fun_jac_uxt_zt_hess_sparsity_in;
- capsule->nl_constr_h_fun_jac_hess[i].casadi_sparsity_out = &{{ model.name }}_constr_h_fun_jac_uxt_zt_hess_sparsity_out;
- capsule->nl_constr_h_fun_jac_hess[i].casadi_work = &{{ model.name }}_constr_h_fun_jac_uxt_zt_hess_work;
-
- external_function_param_casadi_create(&capsule->nl_constr_h_fun_jac_hess[i], {{ dims.np }});
+ MAP_CASADI_FNC(nl_constr_h_fun_jac_hess[i], {{ model.name }}_constr_h_fun_jac_uxt_zt_hess);
}
{% endif %}
- {% endif %}
+{% endif %}
- {%- if constraints.constr_type_e == "BGH" and dims.nh_e > 0 %}
- capsule->nl_constr_h_e_fun_jac.casadi_fun = &{{ model.name }}_constr_h_e_fun_jac_uxt_zt;
- capsule->nl_constr_h_e_fun_jac.casadi_n_in = &{{ model.name }}_constr_h_e_fun_jac_uxt_zt_n_in;
- capsule->nl_constr_h_e_fun_jac.casadi_n_out = &{{ model.name }}_constr_h_e_fun_jac_uxt_zt_n_out;
- capsule->nl_constr_h_e_fun_jac.casadi_sparsity_in = &{{ model.name }}_constr_h_e_fun_jac_uxt_zt_sparsity_in;
- capsule->nl_constr_h_e_fun_jac.casadi_sparsity_out = &{{ model.name }}_constr_h_e_fun_jac_uxt_zt_sparsity_out;
- capsule->nl_constr_h_e_fun_jac.casadi_work = &{{ model.name }}_constr_h_e_fun_jac_uxt_zt_work;
- external_function_param_casadi_create(&capsule->nl_constr_h_e_fun_jac, {{ dims.np }});
-
- capsule->nl_constr_h_e_fun.casadi_fun = &{{ model.name }}_constr_h_e_fun;
- capsule->nl_constr_h_e_fun.casadi_n_in = &{{ model.name }}_constr_h_e_fun_n_in;
- capsule->nl_constr_h_e_fun.casadi_n_out = &{{ model.name }}_constr_h_e_fun_n_out;
- capsule->nl_constr_h_e_fun.casadi_sparsity_in = &{{ model.name }}_constr_h_e_fun_sparsity_in;
- capsule->nl_constr_h_e_fun.casadi_sparsity_out = &{{ model.name }}_constr_h_e_fun_sparsity_out;
- capsule->nl_constr_h_e_fun.casadi_work = &{{ model.name }}_constr_h_e_fun_work;
- external_function_param_casadi_create(&capsule->nl_constr_h_e_fun, {{ dims.np }});
+{%- if constraints.constr_type_e == "BGH" and dims.nh_e > 0 %}
+ MAP_CASADI_FNC(nl_constr_h_e_fun_jac, {{ model.name }}_constr_h_e_fun_jac_uxt_zt);
+ MAP_CASADI_FNC(nl_constr_h_e_fun, {{ model.name }}_constr_h_e_fun);
- {% if solver_options.hessian_approx == "EXACT" %}
- capsule->nl_constr_h_e_fun_jac_hess.casadi_fun = &{{ model.name }}_constr_h_e_fun_jac_uxt_zt_hess;
- capsule->nl_constr_h_e_fun_jac_hess.casadi_n_in = &{{ model.name }}_constr_h_e_fun_jac_uxt_zt_hess_n_in;
- capsule->nl_constr_h_e_fun_jac_hess.casadi_n_out = &{{ model.name }}_constr_h_e_fun_jac_uxt_zt_hess_n_out;
- capsule->nl_constr_h_e_fun_jac_hess.casadi_sparsity_in = &{{ model.name }}_constr_h_e_fun_jac_uxt_zt_hess_sparsity_in;
- capsule->nl_constr_h_e_fun_jac_hess.casadi_sparsity_out = &{{ model.name }}_constr_h_e_fun_jac_uxt_zt_hess_sparsity_out;
- capsule->nl_constr_h_e_fun_jac_hess.casadi_work = &{{ model.name }}_constr_h_e_fun_jac_uxt_zt_hess_work;
- external_function_param_casadi_create(&capsule->nl_constr_h_e_fun_jac_hess, {{ dims.np }});
+ {%- if solver_options.hessian_approx == "EXACT" %}
+ MAP_CASADI_FNC(nl_constr_h_e_fun_jac_hess, {{ model.name }}_constr_h_e_fun_jac_uxt_zt_hess);
{% endif %}
- {%- endif %}
+{%- endif %}
{% if solver_options.integrator_type == "ERK" %}
// explicit ode
capsule->forw_vde_casadi = (external_function_param_casadi *) malloc(sizeof(external_function_param_casadi)*N);
for (int i = 0; i < N; i++) {
- capsule->forw_vde_casadi[i].casadi_fun = &{{ model.name }}_expl_vde_forw;
- capsule->forw_vde_casadi[i].casadi_n_in = &{{ model.name }}_expl_vde_forw_n_in;
- capsule->forw_vde_casadi[i].casadi_n_out = &{{ model.name }}_expl_vde_forw_n_out;
- capsule->forw_vde_casadi[i].casadi_sparsity_in = &{{ model.name }}_expl_vde_forw_sparsity_in;
- capsule->forw_vde_casadi[i].casadi_sparsity_out = &{{ model.name }}_expl_vde_forw_sparsity_out;
- capsule->forw_vde_casadi[i].casadi_work = &{{ model.name }}_expl_vde_forw_work;
- external_function_param_casadi_create(&capsule->forw_vde_casadi[i], {{ dims.np }});
+ MAP_CASADI_FNC(forw_vde_casadi[i], {{ model.name }}_expl_vde_forw);
}
capsule->expl_ode_fun = (external_function_param_casadi *) malloc(sizeof(external_function_param_casadi)*N);
for (int i = 0; i < N; i++) {
- capsule->expl_ode_fun[i].casadi_fun = &{{ model.name }}_expl_ode_fun;
- capsule->expl_ode_fun[i].casadi_n_in = &{{ model.name }}_expl_ode_fun_n_in;
- capsule->expl_ode_fun[i].casadi_n_out = &{{ model.name }}_expl_ode_fun_n_out;
- capsule->expl_ode_fun[i].casadi_sparsity_in = &{{ model.name }}_expl_ode_fun_sparsity_in;
- capsule->expl_ode_fun[i].casadi_sparsity_out = &{{ model.name }}_expl_ode_fun_sparsity_out;
- capsule->expl_ode_fun[i].casadi_work = &{{ model.name }}_expl_ode_fun_work;
- external_function_param_casadi_create(&capsule->expl_ode_fun[i], {{ dims.np }});
+ MAP_CASADI_FNC(expl_ode_fun[i], {{ model.name }}_expl_ode_fun);
}
{%- if solver_options.hessian_approx == "EXACT" %}
capsule->hess_vde_casadi = (external_function_param_casadi *) malloc(sizeof(external_function_param_casadi)*N);
for (int i = 0; i < N; i++) {
- capsule->hess_vde_casadi[i].casadi_fun = &{{ model.name }}_expl_ode_hess;
- capsule->hess_vde_casadi[i].casadi_n_in = &{{ model.name }}_expl_ode_hess_n_in;
- capsule->hess_vde_casadi[i].casadi_n_out = &{{ model.name }}_expl_ode_hess_n_out;
- capsule->hess_vde_casadi[i].casadi_sparsity_in = &{{ model.name }}_expl_ode_hess_sparsity_in;
- capsule->hess_vde_casadi[i].casadi_sparsity_out = &{{ model.name }}_expl_ode_hess_sparsity_out;
- capsule->hess_vde_casadi[i].casadi_work = &{{ model.name }}_expl_ode_hess_work;
- external_function_param_casadi_create(&capsule->hess_vde_casadi[i], {{ dims.np }});
+ MAP_CASADI_FNC(hess_vde_casadi[i], {{ model.name }}_expl_ode_hess);
}
{%- endif %}
@@ -517,126 +470,64 @@ int {{ model.name }}_acados_create_with_discretization({{ model.name }}_solver_c
// implicit dae
capsule->impl_dae_fun = (external_function_param_casadi *) malloc(sizeof(external_function_param_casadi)*N);
for (int i = 0; i < N; i++) {
- capsule->impl_dae_fun[i].casadi_fun = &{{ model.name }}_impl_dae_fun;
- capsule->impl_dae_fun[i].casadi_work = &{{ model.name }}_impl_dae_fun_work;
- capsule->impl_dae_fun[i].casadi_sparsity_in = &{{ model.name }}_impl_dae_fun_sparsity_in;
- capsule->impl_dae_fun[i].casadi_sparsity_out = &{{ model.name }}_impl_dae_fun_sparsity_out;
- capsule->impl_dae_fun[i].casadi_n_in = &{{ model.name }}_impl_dae_fun_n_in;
- capsule->impl_dae_fun[i].casadi_n_out = &{{ model.name }}_impl_dae_fun_n_out;
- external_function_param_casadi_create(&capsule->impl_dae_fun[i], {{ dims.np }});
+ MAP_CASADI_FNC(impl_dae_fun[i], {{ model.name }}_impl_dae_fun);
}
capsule->impl_dae_fun_jac_x_xdot_z = (external_function_param_casadi *) malloc(sizeof(external_function_param_casadi)*N);
for (int i = 0; i < N; i++) {
- capsule->impl_dae_fun_jac_x_xdot_z[i].casadi_fun = &{{ model.name }}_impl_dae_fun_jac_x_xdot_z;
- capsule->impl_dae_fun_jac_x_xdot_z[i].casadi_work = &{{ model.name }}_impl_dae_fun_jac_x_xdot_z_work;
- capsule->impl_dae_fun_jac_x_xdot_z[i].casadi_sparsity_in = &{{ model.name }}_impl_dae_fun_jac_x_xdot_z_sparsity_in;
- capsule->impl_dae_fun_jac_x_xdot_z[i].casadi_sparsity_out = &{{ model.name }}_impl_dae_fun_jac_x_xdot_z_sparsity_out;
- capsule->impl_dae_fun_jac_x_xdot_z[i].casadi_n_in = &{{ model.name }}_impl_dae_fun_jac_x_xdot_z_n_in;
- capsule->impl_dae_fun_jac_x_xdot_z[i].casadi_n_out = &{{ model.name }}_impl_dae_fun_jac_x_xdot_z_n_out;
- external_function_param_casadi_create(&capsule->impl_dae_fun_jac_x_xdot_z[i], {{ dims.np }});
+ MAP_CASADI_FNC(impl_dae_fun_jac_x_xdot_z[i], {{ model.name }}_impl_dae_fun_jac_x_xdot_z);
}
capsule->impl_dae_jac_x_xdot_u_z = (external_function_param_casadi *) malloc(sizeof(external_function_param_casadi)*N);
for (int i = 0; i < N; i++) {
- capsule->impl_dae_jac_x_xdot_u_z[i].casadi_fun = &{{ model.name }}_impl_dae_jac_x_xdot_u_z;
- capsule->impl_dae_jac_x_xdot_u_z[i].casadi_work = &{{ model.name }}_impl_dae_jac_x_xdot_u_z_work;
- capsule->impl_dae_jac_x_xdot_u_z[i].casadi_sparsity_in = &{{ model.name }}_impl_dae_jac_x_xdot_u_z_sparsity_in;
- capsule->impl_dae_jac_x_xdot_u_z[i].casadi_sparsity_out = &{{ model.name }}_impl_dae_jac_x_xdot_u_z_sparsity_out;
- capsule->impl_dae_jac_x_xdot_u_z[i].casadi_n_in = &{{ model.name }}_impl_dae_jac_x_xdot_u_z_n_in;
- capsule->impl_dae_jac_x_xdot_u_z[i].casadi_n_out = &{{ model.name }}_impl_dae_jac_x_xdot_u_z_n_out;
- external_function_param_casadi_create(&capsule->impl_dae_jac_x_xdot_u_z[i], {{ dims.np }});
+ MAP_CASADI_FNC(impl_dae_jac_x_xdot_u_z[i], {{ model.name }}_impl_dae_jac_x_xdot_u_z);
}
{%- if solver_options.hessian_approx == "EXACT" %}
capsule->impl_dae_hess = (external_function_param_casadi *) malloc(sizeof(external_function_param_casadi)*N);
for (int i = 0; i < N; i++) {
- capsule->impl_dae_hess[i].casadi_fun = &{{ model.name }}_impl_dae_hess;
- capsule->impl_dae_hess[i].casadi_work = &{{ model.name }}_impl_dae_hess_work;
- capsule->impl_dae_hess[i].casadi_sparsity_in = &{{ model.name }}_impl_dae_hess_sparsity_in;
- capsule->impl_dae_hess[i].casadi_sparsity_out = &{{ model.name }}_impl_dae_hess_sparsity_out;
- capsule->impl_dae_hess[i].casadi_n_in = &{{ model.name }}_impl_dae_hess_n_in;
- capsule->impl_dae_hess[i].casadi_n_out = &{{ model.name }}_impl_dae_hess_n_out;
- external_function_param_casadi_create(&capsule->impl_dae_hess[i], {{ dims.np }});
+ MAP_CASADI_FNC(impl_dae_hess[i], {{ model.name }}_impl_dae_hess);
}
{%- endif %}
{% elif solver_options.integrator_type == "LIFTED_IRK" %}
// external functions (implicit model)
capsule->impl_dae_fun = (external_function_param_casadi *) malloc(sizeof(external_function_param_casadi)*N);
for (int i = 0; i < N; i++) {
- capsule->impl_dae_fun[i].casadi_fun = &{{ model.name }}_impl_dae_fun;
- capsule->impl_dae_fun[i].casadi_work = &{{ model.name }}_impl_dae_fun_work;
- capsule->impl_dae_fun[i].casadi_sparsity_in = &{{ model.name }}_impl_dae_fun_sparsity_in;
- capsule->impl_dae_fun[i].casadi_sparsity_out = &{{ model.name }}_impl_dae_fun_sparsity_out;
- capsule->impl_dae_fun[i].casadi_n_in = &{{ model.name }}_impl_dae_fun_n_in;
- capsule->impl_dae_fun[i].casadi_n_out = &{{ model.name }}_impl_dae_fun_n_out;
- external_function_param_casadi_create(&capsule->impl_dae_fun[i], {{ dims.np }});
+ MAP_CASADI_FNC(impl_dae_fun[i], {{ model.name }}_impl_dae_fun);
}
- capsule->impl_dae_fun_jac_x_xdot_u = (external_function_param_casadi *) malloc(sizeof(external_function_param_casadi)*N); for (int i = 0; i < N; i++) {
- capsule->impl_dae_fun_jac_x_xdot_u[i].casadi_fun = &{{ model.name }}_impl_dae_fun_jac_x_xdot_u;
- capsule->impl_dae_fun_jac_x_xdot_u[i].casadi_work = &{{ model.name }}_impl_dae_fun_jac_x_xdot_u_work;
- capsule->impl_dae_fun_jac_x_xdot_u[i].casadi_sparsity_in = &{{ model.name }}_impl_dae_fun_jac_x_xdot_u_sparsity_in;
- capsule->impl_dae_fun_jac_x_xdot_u[i].casadi_sparsity_out = &{{ model.name }}_impl_dae_fun_jac_x_xdot_u_sparsity_out;
- capsule->impl_dae_fun_jac_x_xdot_u[i].casadi_n_in = &{{ model.name }}_impl_dae_fun_jac_x_xdot_u_n_in;
- capsule->impl_dae_fun_jac_x_xdot_u[i].casadi_n_out = &{{ model.name }}_impl_dae_fun_jac_x_xdot_u_n_out;
- external_function_param_casadi_create(&capsule->impl_dae_fun_jac_x_xdot_u[i], {{ dims.np }});
+ capsule->impl_dae_fun_jac_x_xdot_u = (external_function_param_casadi *) malloc(sizeof(external_function_param_casadi)*N);
+ for (int i = 0; i < N; i++) {
+ MAP_CASADI_FNC(impl_dae_fun_jac_x_xdot_u[i], {{ model.name }}_impl_dae_fun_jac_x_xdot_u);
}
{% elif solver_options.integrator_type == "GNSF" %}
+ {% if model.gnsf.purely_linear != 1 %}
capsule->gnsf_phi_fun = (external_function_param_casadi *) malloc(sizeof(external_function_param_casadi)*N);
for (int i = 0; i < N; i++) {
- capsule->gnsf_phi_fun[i].casadi_fun = &{{ model.name }}_gnsf_phi_fun;
- capsule->gnsf_phi_fun[i].casadi_work = &{{ model.name }}_gnsf_phi_fun_work;
- capsule->gnsf_phi_fun[i].casadi_sparsity_in = &{{ model.name }}_gnsf_phi_fun_sparsity_in;
- capsule->gnsf_phi_fun[i].casadi_sparsity_out = &{{ model.name }}_gnsf_phi_fun_sparsity_out;
- capsule->gnsf_phi_fun[i].casadi_n_in = &{{ model.name }}_gnsf_phi_fun_n_in;
- capsule->gnsf_phi_fun[i].casadi_n_out = &{{ model.name }}_gnsf_phi_fun_n_out;
- external_function_param_casadi_create(&capsule->gnsf_phi_fun[i], {{ dims.np }});
+ MAP_CASADI_FNC(gnsf_phi_fun[i], {{ model.name }}_gnsf_phi_fun);
}
capsule->gnsf_phi_fun_jac_y = (external_function_param_casadi *) malloc(sizeof(external_function_param_casadi)*N);
for (int i = 0; i < N; i++) {
- capsule->gnsf_phi_fun_jac_y[i].casadi_fun = &{{ model.name }}_gnsf_phi_fun_jac_y;
- capsule->gnsf_phi_fun_jac_y[i].casadi_work = &{{ model.name }}_gnsf_phi_fun_jac_y_work;
- capsule->gnsf_phi_fun_jac_y[i].casadi_sparsity_in = &{{ model.name }}_gnsf_phi_fun_jac_y_sparsity_in;
- capsule->gnsf_phi_fun_jac_y[i].casadi_sparsity_out = &{{ model.name }}_gnsf_phi_fun_jac_y_sparsity_out;
- capsule->gnsf_phi_fun_jac_y[i].casadi_n_in = &{{ model.name }}_gnsf_phi_fun_jac_y_n_in;
- capsule->gnsf_phi_fun_jac_y[i].casadi_n_out = &{{ model.name }}_gnsf_phi_fun_jac_y_n_out;
- external_function_param_casadi_create(&capsule->gnsf_phi_fun_jac_y[i], {{ dims.np }});
+ MAP_CASADI_FNC(gnsf_phi_fun_jac_y[i], {{ model.name }}_gnsf_phi_fun_jac_y);
}
capsule->gnsf_phi_jac_y_uhat = (external_function_param_casadi *) malloc(sizeof(external_function_param_casadi)*N);
for (int i = 0; i < N; i++) {
- capsule->gnsf_phi_jac_y_uhat[i].casadi_fun = &{{ model.name }}_gnsf_phi_jac_y_uhat;
- capsule->gnsf_phi_jac_y_uhat[i].casadi_work = &{{ model.name }}_gnsf_phi_jac_y_uhat_work;
- capsule->gnsf_phi_jac_y_uhat[i].casadi_sparsity_in = &{{ model.name }}_gnsf_phi_jac_y_uhat_sparsity_in;
- capsule->gnsf_phi_jac_y_uhat[i].casadi_sparsity_out = &{{ model.name }}_gnsf_phi_jac_y_uhat_sparsity_out;
- capsule->gnsf_phi_jac_y_uhat[i].casadi_n_in = &{{ model.name }}_gnsf_phi_jac_y_uhat_n_in;
- capsule->gnsf_phi_jac_y_uhat[i].casadi_n_out = &{{ model.name }}_gnsf_phi_jac_y_uhat_n_out;
- external_function_param_casadi_create(&capsule->gnsf_phi_jac_y_uhat[i], {{ dims.np }});
+ MAP_CASADI_FNC(gnsf_phi_jac_y_uhat[i], {{ model.name }}_gnsf_phi_jac_y_uhat);
}
+ {% if model.gnsf.nontrivial_f_LO == 1 %}
capsule->gnsf_f_lo_jac_x1_x1dot_u_z = (external_function_param_casadi *) malloc(sizeof(external_function_param_casadi)*N);
for (int i = 0; i < N; i++) {
- capsule->gnsf_f_lo_jac_x1_x1dot_u_z[i].casadi_fun = &{{ model.name }}_gnsf_f_lo_fun_jac_x1k1uz;
- capsule->gnsf_f_lo_jac_x1_x1dot_u_z[i].casadi_work = &{{ model.name }}_gnsf_f_lo_fun_jac_x1k1uz_work;
- capsule->gnsf_f_lo_jac_x1_x1dot_u_z[i].casadi_sparsity_in = &{{ model.name }}_gnsf_f_lo_fun_jac_x1k1uz_sparsity_in;
- capsule->gnsf_f_lo_jac_x1_x1dot_u_z[i].casadi_sparsity_out = &{{ model.name }}_gnsf_f_lo_fun_jac_x1k1uz_sparsity_out;
- capsule->gnsf_f_lo_jac_x1_x1dot_u_z[i].casadi_n_in = &{{ model.name }}_gnsf_f_lo_fun_jac_x1k1uz_n_in;
- capsule->gnsf_f_lo_jac_x1_x1dot_u_z[i].casadi_n_out = &{{ model.name }}_gnsf_f_lo_fun_jac_x1k1uz_n_out;
- external_function_param_casadi_create(&capsule->gnsf_f_lo_jac_x1_x1dot_u_z[i], {{ dims.np }});
+ MAP_CASADI_FNC(gnsf_f_lo_jac_x1_x1dot_u_z[i], {{ model.name }}_gnsf_f_lo_fun_jac_x1k1uz);
}
-
+ {%- endif %}
+ {%- endif %}
capsule->gnsf_get_matrices_fun = (external_function_param_casadi *) malloc(sizeof(external_function_param_casadi)*N);
for (int i = 0; i < N; i++) {
- capsule->gnsf_get_matrices_fun[i].casadi_fun = &{{ model.name }}_gnsf_get_matrices_fun;
- capsule->gnsf_get_matrices_fun[i].casadi_work = &{{ model.name }}_gnsf_get_matrices_fun_work;
- capsule->gnsf_get_matrices_fun[i].casadi_sparsity_in = &{{ model.name }}_gnsf_get_matrices_fun_sparsity_in;
- capsule->gnsf_get_matrices_fun[i].casadi_sparsity_out = &{{ model.name }}_gnsf_get_matrices_fun_sparsity_out;
- capsule->gnsf_get_matrices_fun[i].casadi_n_in = &{{ model.name }}_gnsf_get_matrices_fun_n_in;
- capsule->gnsf_get_matrices_fun[i].casadi_n_out = &{{ model.name }}_gnsf_get_matrices_fun_n_out;
- external_function_param_casadi_create(&capsule->gnsf_get_matrices_fun[i], {{ dims.np }});
+ MAP_CASADI_FNC(gnsf_get_matrices_fun[i], {{ model.name }}_gnsf_get_matrices_fun);
}
{% elif solver_options.integrator_type == "DISCRETE" %}
// discrete dynamics
@@ -644,32 +535,22 @@ int {{ model.name }}_acados_create_with_discretization({{ model.name }}_solver_c
for (int i = 0; i < N; i++)
{
{%- if model.dyn_ext_fun_type == "casadi" %}
- capsule->discr_dyn_phi_fun[i].casadi_fun = &{{ model.name }}_dyn_disc_phi_fun;
- capsule->discr_dyn_phi_fun[i].casadi_n_in = &{{ model.name }}_dyn_disc_phi_fun_n_in;
- capsule->discr_dyn_phi_fun[i].casadi_n_out = &{{ model.name }}_dyn_disc_phi_fun_n_out;
- capsule->discr_dyn_phi_fun[i].casadi_sparsity_in = &{{ model.name }}_dyn_disc_phi_fun_sparsity_in;
- capsule->discr_dyn_phi_fun[i].casadi_sparsity_out = &{{ model.name }}_dyn_disc_phi_fun_sparsity_out;
- capsule->discr_dyn_phi_fun[i].casadi_work = &{{ model.name }}_dyn_disc_phi_fun_work;
+ MAP_CASADI_FNC(discr_dyn_phi_fun[i], {{ model.name }}_dyn_disc_phi_fun);
{%- else %}
capsule->discr_dyn_phi_fun[i].fun = &{{ model.dyn_disc_fun }};
- {%- endif %}
external_function_param_{{ model.dyn_ext_fun_type }}_create(&capsule->discr_dyn_phi_fun[i], {{ dims.np }});
+ {%- endif %}
}
capsule->discr_dyn_phi_fun_jac_ut_xt = (external_function_param_{{ model.dyn_ext_fun_type }} *) malloc(sizeof(external_function_param_{{ model.dyn_ext_fun_type }})*N);
for (int i = 0; i < N; i++)
{
{%- if model.dyn_ext_fun_type == "casadi" %}
- capsule->discr_dyn_phi_fun_jac_ut_xt[i].casadi_fun = &{{ model.name }}_dyn_disc_phi_fun_jac;
- capsule->discr_dyn_phi_fun_jac_ut_xt[i].casadi_n_in = &{{ model.name }}_dyn_disc_phi_fun_jac_n_in;
- capsule->discr_dyn_phi_fun_jac_ut_xt[i].casadi_n_out = &{{ model.name }}_dyn_disc_phi_fun_jac_n_out;
- capsule->discr_dyn_phi_fun_jac_ut_xt[i].casadi_sparsity_in = &{{ model.name }}_dyn_disc_phi_fun_jac_sparsity_in;
- capsule->discr_dyn_phi_fun_jac_ut_xt[i].casadi_sparsity_out = &{{ model.name }}_dyn_disc_phi_fun_jac_sparsity_out;
- capsule->discr_dyn_phi_fun_jac_ut_xt[i].casadi_work = &{{ model.name }}_dyn_disc_phi_fun_jac_work;
+ MAP_CASADI_FNC(discr_dyn_phi_fun_jac_ut_xt[i], {{ model.name }}_dyn_disc_phi_fun_jac);
{%- else %}
capsule->discr_dyn_phi_fun_jac_ut_xt[i].fun = &{{ model.dyn_disc_fun_jac }};
- {%- endif %}
external_function_param_{{ model.dyn_ext_fun_type }}_create(&capsule->discr_dyn_phi_fun_jac_ut_xt[i], {{ dims.np }});
+ {%- endif %}
}
{%- if solver_options.hessian_approx == "EXACT" %}
@@ -677,86 +558,46 @@ int {{ model.name }}_acados_create_with_discretization({{ model.name }}_solver_c
for (int i = 0; i < N; i++)
{
{%- if model.dyn_ext_fun_type == "casadi" %}
- capsule->discr_dyn_phi_fun_jac_ut_xt_hess[i].casadi_fun = &{{ model.name }}_dyn_disc_phi_fun_jac_hess;
- capsule->discr_dyn_phi_fun_jac_ut_xt_hess[i].casadi_n_in = &{{ model.name }}_dyn_disc_phi_fun_jac_hess_n_in;
- capsule->discr_dyn_phi_fun_jac_ut_xt_hess[i].casadi_n_out = &{{ model.name }}_dyn_disc_phi_fun_jac_hess_n_out;
- capsule->discr_dyn_phi_fun_jac_ut_xt_hess[i].casadi_sparsity_in = &{{ model.name }}_dyn_disc_phi_fun_jac_hess_sparsity_in;
- capsule->discr_dyn_phi_fun_jac_ut_xt_hess[i].casadi_sparsity_out = &{{ model.name }}_dyn_disc_phi_fun_jac_hess_sparsity_out;
- capsule->discr_dyn_phi_fun_jac_ut_xt_hess[i].casadi_work = &{{ model.name }}_dyn_disc_phi_fun_jac_hess_work;
+ MAP_CASADI_FNC(discr_dyn_phi_fun_jac_ut_xt_hess[i], {{ model.name }}_dyn_disc_phi_fun_jac_hess);
{%- else %}
capsule->discr_dyn_phi_fun_jac_ut_xt_hess[i].fun = &{{ model.dyn_disc_fun_jac_hess }};
- {%- endif %}
external_function_param_{{ model.dyn_ext_fun_type }}_create(&capsule->discr_dyn_phi_fun_jac_ut_xt_hess[i], {{ dims.np }});
+ {%- endif %}
}
{%- endif %}
{%- endif %}
{%- if cost.cost_type_0 == "NONLINEAR_LS" %}
- // nonlinear least square function
- capsule->cost_y_0_fun.casadi_fun = &{{ model.name }}_cost_y_0_fun;
- capsule->cost_y_0_fun.casadi_n_in = &{{ model.name }}_cost_y_0_fun_n_in;
- capsule->cost_y_0_fun.casadi_n_out = &{{ model.name }}_cost_y_0_fun_n_out;
- capsule->cost_y_0_fun.casadi_sparsity_in = &{{ model.name }}_cost_y_0_fun_sparsity_in;
- capsule->cost_y_0_fun.casadi_sparsity_out = &{{ model.name }}_cost_y_0_fun_sparsity_out;
- capsule->cost_y_0_fun.casadi_work = &{{ model.name }}_cost_y_0_fun_work;
- external_function_param_casadi_create(&capsule->cost_y_0_fun, {{ dims.np }});
-
- capsule->cost_y_0_fun_jac_ut_xt.casadi_fun = &{{ model.name }}_cost_y_0_fun_jac_ut_xt;
- capsule->cost_y_0_fun_jac_ut_xt.casadi_n_in = &{{ model.name }}_cost_y_0_fun_jac_ut_xt_n_in;
- capsule->cost_y_0_fun_jac_ut_xt.casadi_n_out = &{{ model.name }}_cost_y_0_fun_jac_ut_xt_n_out;
- capsule->cost_y_0_fun_jac_ut_xt.casadi_sparsity_in = &{{ model.name }}_cost_y_0_fun_jac_ut_xt_sparsity_in;
- capsule->cost_y_0_fun_jac_ut_xt.casadi_sparsity_out = &{{ model.name }}_cost_y_0_fun_jac_ut_xt_sparsity_out;
- capsule->cost_y_0_fun_jac_ut_xt.casadi_work = &{{ model.name }}_cost_y_0_fun_jac_ut_xt_work;
- external_function_param_casadi_create(&capsule->cost_y_0_fun_jac_ut_xt, {{ dims.np }});
-
- capsule->cost_y_0_hess.casadi_fun = &{{ model.name }}_cost_y_0_hess;
- capsule->cost_y_0_hess.casadi_n_in = &{{ model.name }}_cost_y_0_hess_n_in;
- capsule->cost_y_0_hess.casadi_n_out = &{{ model.name }}_cost_y_0_hess_n_out;
- capsule->cost_y_0_hess.casadi_sparsity_in = &{{ model.name }}_cost_y_0_hess_sparsity_in;
- capsule->cost_y_0_hess.casadi_sparsity_out = &{{ model.name }}_cost_y_0_hess_sparsity_out;
- capsule->cost_y_0_hess.casadi_work = &{{ model.name }}_cost_y_0_hess_work;
- external_function_param_casadi_create(&capsule->cost_y_0_hess, {{ dims.np }});
+ // nonlinear least squares function
+ MAP_CASADI_FNC(cost_y_0_fun, {{ model.name }}_cost_y_0_fun);
+ MAP_CASADI_FNC(cost_y_0_fun_jac_ut_xt, {{ model.name }}_cost_y_0_fun_jac_ut_xt);
+ MAP_CASADI_FNC(cost_y_0_hess, {{ model.name }}_cost_y_0_hess);
{%- elif cost.cost_type_0 == "EXTERNAL" %}
// external cost
- {% if cost.cost_ext_fun_type_0 == "casadi" %}
- capsule->ext_cost_0_fun.casadi_fun = &{{ model.name }}_cost_ext_cost_0_fun;
- capsule->ext_cost_0_fun.casadi_n_in = &{{ model.name }}_cost_ext_cost_0_fun_n_in;
- capsule->ext_cost_0_fun.casadi_n_out = &{{ model.name }}_cost_ext_cost_0_fun_n_out;
- capsule->ext_cost_0_fun.casadi_sparsity_in = &{{ model.name }}_cost_ext_cost_0_fun_sparsity_in;
- capsule->ext_cost_0_fun.casadi_sparsity_out = &{{ model.name }}_cost_ext_cost_0_fun_sparsity_out;
- capsule->ext_cost_0_fun.casadi_work = &{{ model.name }}_cost_ext_cost_0_fun_work;
- {% else %}
+ {%- if cost.cost_ext_fun_type_0 == "casadi" %}
+ MAP_CASADI_FNC(ext_cost_0_fun, {{ model.name }}_cost_ext_cost_0_fun);
+ {%- else %}
capsule->ext_cost_0_fun.fun = &{{ cost.cost_function_ext_cost_0 }};
- {% endif %}
external_function_param_{{ cost.cost_ext_fun_type_0 }}_create(&capsule->ext_cost_0_fun, {{ dims.np }});
+ {%- endif %}
// external cost
- {% if cost.cost_ext_fun_type_0 == "casadi" %}
- capsule->ext_cost_0_fun_jac.casadi_fun = &{{ model.name }}_cost_ext_cost_0_fun_jac;
- capsule->ext_cost_0_fun_jac.casadi_n_in = &{{ model.name }}_cost_ext_cost_0_fun_jac_n_in;
- capsule->ext_cost_0_fun_jac.casadi_n_out = &{{ model.name }}_cost_ext_cost_0_fun_jac_n_out;
- capsule->ext_cost_0_fun_jac.casadi_sparsity_in = &{{ model.name }}_cost_ext_cost_0_fun_jac_sparsity_in;
- capsule->ext_cost_0_fun_jac.casadi_sparsity_out = &{{ model.name }}_cost_ext_cost_0_fun_jac_sparsity_out;
- capsule->ext_cost_0_fun_jac.casadi_work = &{{ model.name }}_cost_ext_cost_0_fun_jac_work;
- {% else %}
+ {%- if cost.cost_ext_fun_type_0 == "casadi" %}
+ MAP_CASADI_FNC(ext_cost_0_fun_jac, {{ model.name }}_cost_ext_cost_0_fun_jac);
+ {%- else %}
capsule->ext_cost_0_fun_jac.fun = &{{ cost.cost_function_ext_cost_0 }};
- {% endif %}
external_function_param_{{ cost.cost_ext_fun_type_0 }}_create(&capsule->ext_cost_0_fun_jac, {{ dims.np }});
+ {%- endif %}
// external cost
- {% if cost.cost_ext_fun_type_0 == "casadi" %}
- capsule->ext_cost_0_fun_jac_hess.casadi_fun = &{{ model.name }}_cost_ext_cost_0_fun_jac_hess;
- capsule->ext_cost_0_fun_jac_hess.casadi_n_in = &{{ model.name }}_cost_ext_cost_0_fun_jac_hess_n_in;
- capsule->ext_cost_0_fun_jac_hess.casadi_n_out = &{{ model.name }}_cost_ext_cost_0_fun_jac_hess_n_out;
- capsule->ext_cost_0_fun_jac_hess.casadi_sparsity_in = &{{ model.name }}_cost_ext_cost_0_fun_jac_hess_sparsity_in;
- capsule->ext_cost_0_fun_jac_hess.casadi_sparsity_out = &{{ model.name }}_cost_ext_cost_0_fun_jac_hess_sparsity_out;
- capsule->ext_cost_0_fun_jac_hess.casadi_work = &{{ model.name }}_cost_ext_cost_0_fun_jac_hess_work;
- {% else %}
+ {%- if cost.cost_ext_fun_type_0 == "casadi" %}
+ MAP_CASADI_FNC(ext_cost_0_fun_jac_hess, {{ model.name }}_cost_ext_cost_0_fun_jac_hess);
+ {%- else %}
capsule->ext_cost_0_fun_jac_hess.fun = &{{ cost.cost_function_ext_cost_0 }};
- {% endif %}
external_function_param_{{ cost.cost_ext_fun_type_0 }}_create(&capsule->ext_cost_0_fun_jac_hess, {{ dims.np }});
+ {%- endif %}
{%- endif %}
{%- if cost.cost_type == "NONLINEAR_LS" %}
@@ -764,164 +605,130 @@ int {{ model.name }}_acados_create_with_discretization({{ model.name }}_solver_c
capsule->cost_y_fun = (external_function_param_casadi *) malloc(sizeof(external_function_param_casadi)*N);
for (int i = 0; i < N-1; i++)
{
- capsule->cost_y_fun[i].casadi_fun = &{{ model.name }}_cost_y_fun;
- capsule->cost_y_fun[i].casadi_n_in = &{{ model.name }}_cost_y_fun_n_in;
- capsule->cost_y_fun[i].casadi_n_out = &{{ model.name }}_cost_y_fun_n_out;
- capsule->cost_y_fun[i].casadi_sparsity_in = &{{ model.name }}_cost_y_fun_sparsity_in;
- capsule->cost_y_fun[i].casadi_sparsity_out = &{{ model.name }}_cost_y_fun_sparsity_out;
- capsule->cost_y_fun[i].casadi_work = &{{ model.name }}_cost_y_fun_work;
-
- external_function_param_casadi_create(&capsule->cost_y_fun[i], {{ dims.np }});
+ MAP_CASADI_FNC(cost_y_fun[i], {{ model.name }}_cost_y_fun);
}
capsule->cost_y_fun_jac_ut_xt = (external_function_param_casadi *) malloc(sizeof(external_function_param_casadi)*N);
for (int i = 0; i < N-1; i++)
{
- capsule->cost_y_fun_jac_ut_xt[i].casadi_fun = &{{ model.name }}_cost_y_fun_jac_ut_xt;
- capsule->cost_y_fun_jac_ut_xt[i].casadi_n_in = &{{ model.name }}_cost_y_fun_jac_ut_xt_n_in;
- capsule->cost_y_fun_jac_ut_xt[i].casadi_n_out = &{{ model.name }}_cost_y_fun_jac_ut_xt_n_out;
- capsule->cost_y_fun_jac_ut_xt[i].casadi_sparsity_in = &{{ model.name }}_cost_y_fun_jac_ut_xt_sparsity_in;
- capsule->cost_y_fun_jac_ut_xt[i].casadi_sparsity_out = &{{ model.name }}_cost_y_fun_jac_ut_xt_sparsity_out;
- capsule->cost_y_fun_jac_ut_xt[i].casadi_work = &{{ model.name }}_cost_y_fun_jac_ut_xt_work;
-
- external_function_param_casadi_create(&capsule->cost_y_fun_jac_ut_xt[i], {{ dims.np }});
+ MAP_CASADI_FNC(cost_y_fun_jac_ut_xt[i], {{ model.name }}_cost_y_fun_jac_ut_xt);
}
capsule->cost_y_hess = (external_function_param_casadi *) malloc(sizeof(external_function_param_casadi)*N);
for (int i = 0; i < N-1; i++)
{
- capsule->cost_y_hess[i].casadi_fun = &{{ model.name }}_cost_y_hess;
- capsule->cost_y_hess[i].casadi_n_in = &{{ model.name }}_cost_y_hess_n_in;
- capsule->cost_y_hess[i].casadi_n_out = &{{ model.name }}_cost_y_hess_n_out;
- capsule->cost_y_hess[i].casadi_sparsity_in = &{{ model.name }}_cost_y_hess_sparsity_in;
- capsule->cost_y_hess[i].casadi_sparsity_out = &{{ model.name }}_cost_y_hess_sparsity_out;
- capsule->cost_y_hess[i].casadi_work = &{{ model.name }}_cost_y_hess_work;
-
- external_function_param_casadi_create(&capsule->cost_y_hess[i], {{ dims.np }});
+ MAP_CASADI_FNC(cost_y_hess[i], {{ model.name }}_cost_y_hess);
}
{%- elif cost.cost_type == "EXTERNAL" %}
// external cost
capsule->ext_cost_fun = (external_function_param_{{ cost.cost_ext_fun_type }} *) malloc(sizeof(external_function_param_{{ cost.cost_ext_fun_type }})*N);
for (int i = 0; i < N-1; i++)
{
- {% if cost.cost_ext_fun_type == "casadi" %}
- capsule->ext_cost_fun[i].casadi_fun = &{{ model.name }}_cost_ext_cost_fun;
- capsule->ext_cost_fun[i].casadi_n_in = &{{ model.name }}_cost_ext_cost_fun_n_in;
- capsule->ext_cost_fun[i].casadi_n_out = &{{ model.name }}_cost_ext_cost_fun_n_out;
- capsule->ext_cost_fun[i].casadi_sparsity_in = &{{ model.name }}_cost_ext_cost_fun_sparsity_in;
- capsule->ext_cost_fun[i].casadi_sparsity_out = &{{ model.name }}_cost_ext_cost_fun_sparsity_out;
- capsule->ext_cost_fun[i].casadi_work = &{{ model.name }}_cost_ext_cost_fun_work;
- {% else %}
+ {%- if cost.cost_ext_fun_type == "casadi" %}
+ MAP_CASADI_FNC(ext_cost_fun[i], {{ model.name }}_cost_ext_cost_fun);
+ {%- else %}
capsule->ext_cost_fun[i].fun = &{{ cost.cost_function_ext_cost }};
- {% endif %}
external_function_param_{{ cost.cost_ext_fun_type }}_create(&capsule->ext_cost_fun[i], {{ dims.np }});
+ {%- endif %}
}
capsule->ext_cost_fun_jac = (external_function_param_{{ cost.cost_ext_fun_type }} *) malloc(sizeof(external_function_param_{{ cost.cost_ext_fun_type }})*N);
for (int i = 0; i < N-1; i++)
{
- {% if cost.cost_ext_fun_type == "casadi" %}
- capsule->ext_cost_fun_jac[i].casadi_fun = &{{ model.name }}_cost_ext_cost_fun_jac;
- capsule->ext_cost_fun_jac[i].casadi_n_in = &{{ model.name }}_cost_ext_cost_fun_jac_n_in;
- capsule->ext_cost_fun_jac[i].casadi_n_out = &{{ model.name }}_cost_ext_cost_fun_jac_n_out;
- capsule->ext_cost_fun_jac[i].casadi_sparsity_in = &{{ model.name }}_cost_ext_cost_fun_jac_sparsity_in;
- capsule->ext_cost_fun_jac[i].casadi_sparsity_out = &{{ model.name }}_cost_ext_cost_fun_jac_sparsity_out;
- capsule->ext_cost_fun_jac[i].casadi_work = &{{ model.name }}_cost_ext_cost_fun_jac_work;
- {% else %}
+ {%- if cost.cost_ext_fun_type == "casadi" %}
+ MAP_CASADI_FNC(ext_cost_fun_jac[i], {{ model.name }}_cost_ext_cost_fun_jac);
+ {%- else %}
capsule->ext_cost_fun_jac[i].fun = &{{ cost.cost_function_ext_cost }};
- {% endif %}
external_function_param_{{ cost.cost_ext_fun_type }}_create(&capsule->ext_cost_fun_jac[i], {{ dims.np }});
+ {%- endif %}
}
capsule->ext_cost_fun_jac_hess = (external_function_param_{{ cost.cost_ext_fun_type }} *) malloc(sizeof(external_function_param_{{ cost.cost_ext_fun_type }})*N);
for (int i = 0; i < N-1; i++)
{
- {% if cost.cost_ext_fun_type == "casadi" %}
- capsule->ext_cost_fun_jac_hess[i].casadi_fun = &{{ model.name }}_cost_ext_cost_fun_jac_hess;
- capsule->ext_cost_fun_jac_hess[i].casadi_n_in = &{{ model.name }}_cost_ext_cost_fun_jac_hess_n_in;
- capsule->ext_cost_fun_jac_hess[i].casadi_n_out = &{{ model.name }}_cost_ext_cost_fun_jac_hess_n_out;
- capsule->ext_cost_fun_jac_hess[i].casadi_sparsity_in = &{{ model.name }}_cost_ext_cost_fun_jac_hess_sparsity_in;
- capsule->ext_cost_fun_jac_hess[i].casadi_sparsity_out = &{{ model.name }}_cost_ext_cost_fun_jac_hess_sparsity_out;
- capsule->ext_cost_fun_jac_hess[i].casadi_work = &{{ model.name }}_cost_ext_cost_fun_jac_hess_work;
- {% else %}
+ {%- if cost.cost_ext_fun_type == "casadi" %}
+ MAP_CASADI_FNC(ext_cost_fun_jac_hess[i], {{ model.name }}_cost_ext_cost_fun_jac_hess);
+ {%- else %}
capsule->ext_cost_fun_jac_hess[i].fun = &{{ cost.cost_function_ext_cost }};
- {% endif %}
external_function_param_{{ cost.cost_ext_fun_type }}_create(&capsule->ext_cost_fun_jac_hess[i], {{ dims.np }});
+ {%- endif %}
}
{%- endif %}
{%- if cost.cost_type_e == "NONLINEAR_LS" %}
// nonlinear least square function
- capsule->cost_y_e_fun.casadi_fun = &{{ model.name }}_cost_y_e_fun;
- capsule->cost_y_e_fun.casadi_n_in = &{{ model.name }}_cost_y_e_fun_n_in;
- capsule->cost_y_e_fun.casadi_n_out = &{{ model.name }}_cost_y_e_fun_n_out;
- capsule->cost_y_e_fun.casadi_sparsity_in = &{{ model.name }}_cost_y_e_fun_sparsity_in;
- capsule->cost_y_e_fun.casadi_sparsity_out = &{{ model.name }}_cost_y_e_fun_sparsity_out;
- capsule->cost_y_e_fun.casadi_work = &{{ model.name }}_cost_y_e_fun_work;
- external_function_param_casadi_create(&capsule->cost_y_e_fun, {{ dims.np }});
-
- capsule->cost_y_e_fun_jac_ut_xt.casadi_fun = &{{ model.name }}_cost_y_e_fun_jac_ut_xt;
- capsule->cost_y_e_fun_jac_ut_xt.casadi_n_in = &{{ model.name }}_cost_y_e_fun_jac_ut_xt_n_in;
- capsule->cost_y_e_fun_jac_ut_xt.casadi_n_out = &{{ model.name }}_cost_y_e_fun_jac_ut_xt_n_out;
- capsule->cost_y_e_fun_jac_ut_xt.casadi_sparsity_in = &{{ model.name }}_cost_y_e_fun_jac_ut_xt_sparsity_in;
- capsule->cost_y_e_fun_jac_ut_xt.casadi_sparsity_out = &{{ model.name }}_cost_y_e_fun_jac_ut_xt_sparsity_out;
- capsule->cost_y_e_fun_jac_ut_xt.casadi_work = &{{ model.name }}_cost_y_e_fun_jac_ut_xt_work;
- external_function_param_casadi_create(&capsule->cost_y_e_fun_jac_ut_xt, {{ dims.np }});
-
- capsule->cost_y_e_hess.casadi_fun = &{{ model.name }}_cost_y_e_hess;
- capsule->cost_y_e_hess.casadi_n_in = &{{ model.name }}_cost_y_e_hess_n_in;
- capsule->cost_y_e_hess.casadi_n_out = &{{ model.name }}_cost_y_e_hess_n_out;
- capsule->cost_y_e_hess.casadi_sparsity_in = &{{ model.name }}_cost_y_e_hess_sparsity_in;
- capsule->cost_y_e_hess.casadi_sparsity_out = &{{ model.name }}_cost_y_e_hess_sparsity_out;
- capsule->cost_y_e_hess.casadi_work = &{{ model.name }}_cost_y_e_hess_work;
- external_function_param_casadi_create(&capsule->cost_y_e_hess, {{ dims.np }});
-
+ MAP_CASADI_FNC(cost_y_e_fun, {{ model.name }}_cost_y_e_fun);
+ MAP_CASADI_FNC(cost_y_e_fun_jac_ut_xt, {{ model.name }}_cost_y_e_fun_jac_ut_xt);
+ MAP_CASADI_FNC(cost_y_e_hess, {{ model.name }}_cost_y_e_hess);
{%- elif cost.cost_type_e == "EXTERNAL" %}
- // external cost
- {% if cost.cost_ext_fun_type_e == "casadi" %}
- capsule->ext_cost_e_fun.casadi_fun = &{{ model.name }}_cost_ext_cost_e_fun;
- capsule->ext_cost_e_fun.casadi_n_in = &{{ model.name }}_cost_ext_cost_e_fun_n_in;
- capsule->ext_cost_e_fun.casadi_n_out = &{{ model.name }}_cost_ext_cost_e_fun_n_out;
- capsule->ext_cost_e_fun.casadi_sparsity_in = &{{ model.name }}_cost_ext_cost_e_fun_sparsity_in;
- capsule->ext_cost_e_fun.casadi_sparsity_out = &{{ model.name }}_cost_ext_cost_e_fun_sparsity_out;
- capsule->ext_cost_e_fun.casadi_work = &{{ model.name }}_cost_ext_cost_e_fun_work;
+ // external cost - function
+ {%- if cost.cost_ext_fun_type_e == "casadi" %}
+ MAP_CASADI_FNC(ext_cost_e_fun, {{ model.name }}_cost_ext_cost_e_fun);
{% else %}
capsule->ext_cost_e_fun.fun = &{{ cost.cost_function_ext_cost_e }};
- {% endif %}
external_function_param_{{ cost.cost_ext_fun_type_e }}_create(&capsule->ext_cost_e_fun, {{ dims.np }});
+ {%- endif %}
- // external cost
- {% if cost.cost_ext_fun_type_e == "casadi" %}
- capsule->ext_cost_e_fun_jac.casadi_fun = &{{ model.name }}_cost_ext_cost_e_fun_jac;
- capsule->ext_cost_e_fun_jac.casadi_n_in = &{{ model.name }}_cost_ext_cost_e_fun_jac_n_in;
- capsule->ext_cost_e_fun_jac.casadi_n_out = &{{ model.name }}_cost_ext_cost_e_fun_jac_n_out;
- capsule->ext_cost_e_fun_jac.casadi_sparsity_in = &{{ model.name }}_cost_ext_cost_e_fun_jac_sparsity_in;
- capsule->ext_cost_e_fun_jac.casadi_sparsity_out = &{{ model.name }}_cost_ext_cost_e_fun_jac_sparsity_out;
- capsule->ext_cost_e_fun_jac.casadi_work = &{{ model.name }}_cost_ext_cost_e_fun_jac_work;
- {% else %}
+ // external cost - jacobian
+ {%- if cost.cost_ext_fun_type_e == "casadi" %}
+ MAP_CASADI_FNC(ext_cost_e_fun_jac, {{ model.name }}_cost_ext_cost_e_fun_jac);
+ {%- else %}
capsule->ext_cost_e_fun_jac.fun = &{{ cost.cost_function_ext_cost_e }};
- {% endif %}
external_function_param_{{ cost.cost_ext_fun_type_e }}_create(&capsule->ext_cost_e_fun_jac, {{ dims.np }});
+ {%- endif %}
- // external cost
- {% if cost.cost_ext_fun_type_e == "casadi" %}
- capsule->ext_cost_e_fun_jac_hess.casadi_fun = &{{ model.name }}_cost_ext_cost_e_fun_jac_hess;
- capsule->ext_cost_e_fun_jac_hess.casadi_n_in = &{{ model.name }}_cost_ext_cost_e_fun_jac_hess_n_in;
- capsule->ext_cost_e_fun_jac_hess.casadi_n_out = &{{ model.name }}_cost_ext_cost_e_fun_jac_hess_n_out;
- capsule->ext_cost_e_fun_jac_hess.casadi_sparsity_in = &{{ model.name }}_cost_ext_cost_e_fun_jac_hess_sparsity_in;
- capsule->ext_cost_e_fun_jac_hess.casadi_sparsity_out = &{{ model.name }}_cost_ext_cost_e_fun_jac_hess_sparsity_out;
- capsule->ext_cost_e_fun_jac_hess.casadi_work = &{{ model.name }}_cost_ext_cost_e_fun_jac_hess_work;
- {% else %}
+ // external cost - hessian
+ {%- if cost.cost_ext_fun_type_e == "casadi" %}
+ MAP_CASADI_FNC(ext_cost_e_fun_jac_hess, {{ model.name }}_cost_ext_cost_e_fun_jac_hess);
+ {%- else %}
capsule->ext_cost_e_fun_jac_hess.fun = &{{ cost.cost_function_ext_cost_e }};
- {% endif %}
external_function_param_{{ cost.cost_ext_fun_type_e }}_create(&capsule->ext_cost_e_fun_jac_hess, {{ dims.np }});
+ {%- endif %}
{%- endif %}
+#undef MAP_CASADI_FNC
+}
+
+
+/**
+ * Internal function for {{ model.name }}_acados_create: step 4
+ */
+void {{ model.name }}_acados_create_4_set_default_parameters({{ model.name }}_solver_capsule* capsule) {
+{%- if dims.np > 0 %}
+ const int N = capsule->nlp_solver_plan->N;
+ // initialize parameters to nominal value
+ double* p = calloc(NP, sizeof(double));
+ {%- for item in parameter_values %}
+ {%- if item != 0 %}
+ p[{{ loop.index0 }}] = {{ item }};
+ {%- endif %}
+ {%- endfor %}
+
+ for (int i = 0; i <= N; i++) {
+ {{ model.name }}_acados_update_params(capsule, i, p, NP);
+ }
+ free(p);
+{%- else %}
+ // no parameters defined
+{%- endif %}{# if dims.np #}
+}
+
+
+/**
+ * Internal function for {{ model.name }}_acados_create: step 5
+ */
+void {{ model.name }}_acados_create_5_set_nlp_in({{ model.name }}_solver_capsule* capsule, const int N, double* new_time_steps)
+{
+ assert(N == capsule->nlp_solver_plan->N);
+ ocp_nlp_config* nlp_config = capsule->nlp_config;
+ ocp_nlp_dims* nlp_dims = capsule->nlp_dims;
+
/************************************************
* nlp_in
************************************************/
- ocp_nlp_in * nlp_in = ocp_nlp_in_create(nlp_config, nlp_dims);
- capsule->nlp_in = nlp_in;
+// ocp_nlp_in * nlp_in = ocp_nlp_in_create(nlp_config, nlp_dims);
+// capsule->nlp_in = nlp_in;
+ ocp_nlp_in * nlp_in = capsule->nlp_in;
// set up time_steps
{% set all_equal = true -%}
@@ -978,11 +785,15 @@ int {{ model.name }}_acados_create_with_discretization({{ model.name }}_solver_c
ocp_nlp_dynamics_model_set(nlp_config, nlp_dims, nlp_in, i,
"impl_dae_fun_jac_x_xdot_u", &capsule->impl_dae_fun_jac_x_xdot_u[i]);
{% elif solver_options.integrator_type == "GNSF" %}
+ {% if model.gnsf.purely_linear != 1 %}
ocp_nlp_dynamics_model_set(nlp_config, nlp_dims, nlp_in, i, "phi_fun", &capsule->gnsf_phi_fun[i]);
ocp_nlp_dynamics_model_set(nlp_config, nlp_dims, nlp_in, i, "phi_fun_jac_y", &capsule->gnsf_phi_fun_jac_y[i]);
ocp_nlp_dynamics_model_set(nlp_config, nlp_dims, nlp_in, i, "phi_jac_y_uhat", &capsule->gnsf_phi_jac_y_uhat[i]);
+ {% if model.gnsf.nontrivial_f_LO == 1 %}
ocp_nlp_dynamics_model_set(nlp_config, nlp_dims, nlp_in, i, "f_lo_jac_x1_x1dot_u_z",
&capsule->gnsf_f_lo_jac_x1_x1dot_u_z[i]);
+ {%- endif %}
+ {%- endif %}
ocp_nlp_dynamics_model_set(nlp_config, nlp_dims, nlp_in, i, "gnsf_get_matrices_fun",
&capsule->gnsf_get_matrices_fun[i]);
{% elif solver_options.integrator_type == "DISCRETE" %}
@@ -996,10 +807,9 @@ int {{ model.name }}_acados_create_with_discretization({{ model.name }}_solver_c
{%- endif %}
}
-
/**** Cost ****/
{%- if cost.cost_type_0 == "NONLINEAR_LS" or cost.cost_type_0 == "LINEAR_LS" %}
-{% if dims.ny_0 > 0 %}
+ {%- if dims.ny_0 > 0 %}
double* W_0 = calloc(NY0*NY0, sizeof(double));
// change only the non-zero elements:
{%- for j in range(end=dims.ny_0) %}
@@ -1021,14 +831,14 @@ int {{ model.name }}_acados_create_with_discretization({{ model.name }}_solver_c
{%- endfor %}
ocp_nlp_cost_model_set(nlp_config, nlp_dims, nlp_in, 0, "yref", yref_0);
free(yref_0);
-{% endif %}
-{% endif %}
+ {%- endif %}
+{%- endif %}
{%- if cost.cost_type == "NONLINEAR_LS" or cost.cost_type == "LINEAR_LS" %}
-{% if dims.ny > 0 %}
+ {%- if dims.ny > 0 %}
double* W = calloc(NY*NY, sizeof(double));
// change only the non-zero elements:
- {% for j in range(end=dims.ny) %}
+ {%- for j in range(end=dims.ny) %}
{%- for k in range(end=dims.ny) %}
{%- if cost.W[j][k] != 0 %}
W[{{ j }}+(NY) * {{ k }}] = {{ cost.W[j][k] }};
@@ -1051,13 +861,13 @@ int {{ model.name }}_acados_create_with_discretization({{ model.name }}_solver_c
}
free(W);
free(yref);
-{% endif %}
-{% endif %}
+ {%- endif %}
+{%- endif %}
{%- if cost.cost_type_0 == "LINEAR_LS" %}
double* Vx_0 = calloc(NY0*NX, sizeof(double));
// change only the non-zero elements:
- {% for j in range(end=dims.ny_0) %}
+ {%- for j in range(end=dims.ny_0) %}
{%- for k in range(end=dims.nx) %}
{%- if cost.Vx_0[j][k] != 0 %}
Vx_0[{{ j }}+(NY0) * {{ k }}] = {{ cost.Vx_0[j][k] }};
@@ -1067,10 +877,10 @@ int {{ model.name }}_acados_create_with_discretization({{ model.name }}_solver_c
ocp_nlp_cost_model_set(nlp_config, nlp_dims, nlp_in, 0, "Vx", Vx_0);
free(Vx_0);
-{% if dims.ny_0 > 0 and dims.nu > 0 %}
+ {%- if dims.ny_0 > 0 and dims.nu > 0 %}
double* Vu_0 = calloc(NY0*NU, sizeof(double));
// change only the non-zero elements:
- {% for j in range(end=dims.ny_0) %}
+ {%- for j in range(end=dims.ny_0) %}
{%- for k in range(end=dims.nu) %}
{%- if cost.Vu_0[j][k] != 0 %}
Vu_0[{{ j }}+(NY0) * {{ k }}] = {{ cost.Vu_0[j][k] }};
@@ -1079,8 +889,9 @@ int {{ model.name }}_acados_create_with_discretization({{ model.name }}_solver_c
{%- endfor %}
ocp_nlp_cost_model_set(nlp_config, nlp_dims, nlp_in, 0, "Vu", Vu_0);
free(Vu_0);
-{% endif %}
-{% if dims.ny_0 > 0 and dims.nz > 0 %}
+ {%- endif %}
+
+ {%- if dims.ny_0 > 0 and dims.nz > 0 %}
double* Vz_0 = calloc(NY0*NZ, sizeof(double));
// change only the non-zero elements:
{% for j in range(end=dims.ny_0) %}
@@ -1092,14 +903,14 @@ int {{ model.name }}_acados_create_with_discretization({{ model.name }}_solver_c
{%- endfor %}
ocp_nlp_cost_model_set(nlp_config, nlp_dims, nlp_in, 0, "Vz", Vz_0);
free(Vz_0);
-{%- endif %}
+ {%- endif %}
{%- endif %}{# LINEAR LS #}
{%- if cost.cost_type == "LINEAR_LS" %}
double* Vx = calloc(NY*NX, sizeof(double));
// change only the non-zero elements:
- {% for j in range(end=dims.ny) %}
+ {%- for j in range(end=dims.ny) %}
{%- for k in range(end=dims.nx) %}
{%- if cost.Vx[j][k] != 0 %}
Vx[{{ j }}+(NY) * {{ k }}] = {{ cost.Vx[j][k] }};
@@ -1112,7 +923,7 @@ int {{ model.name }}_acados_create_with_discretization({{ model.name }}_solver_c
}
free(Vx);
-{% if dims.ny > 0 and dims.nu > 0 %}
+ {% if dims.ny > 0 and dims.nu > 0 %}
double* Vu = calloc(NY*NU, sizeof(double));
// change only the non-zero elements:
{% for j in range(end=dims.ny) %}
@@ -1128,9 +939,9 @@ int {{ model.name }}_acados_create_with_discretization({{ model.name }}_solver_c
ocp_nlp_cost_model_set(nlp_config, nlp_dims, nlp_in, i, "Vu", Vu);
}
free(Vu);
-{% endif %}
+ {%- endif %}
-{% if dims.ny > 0 and dims.nz > 0 %}
+ {%- if dims.ny > 0 and dims.nz > 0 %}
double* Vz = calloc(NY*NZ, sizeof(double));
// change only the non-zero elements:
{% for j in range(end=dims.ny) %}
@@ -1146,7 +957,7 @@ int {{ model.name }}_acados_create_with_discretization({{ model.name }}_solver_c
ocp_nlp_cost_model_set(nlp_config, nlp_dims, nlp_in, i, "Vz", Vz);
}
free(Vz);
-{%- endif %}
+ {%- endif %}
{%- endif %}{# LINEAR LS #}
@@ -1176,8 +987,7 @@ int {{ model.name }}_acados_create_with_discretization({{ model.name }}_solver_c
}
{%- endif %}
-
-{% if dims.ns > 0 %}
+{%- if dims.ns > 0 %}
double* zlumem = calloc(4*NS, sizeof(double));
double* Zl = zlumem+NS*0;
double* Zu = zlumem+NS*1;
@@ -1216,14 +1026,14 @@ int {{ model.name }}_acados_create_with_discretization({{ model.name }}_solver_c
ocp_nlp_cost_model_set(nlp_config, nlp_dims, nlp_in, i, "zu", zu);
}
free(zlumem);
-{% endif %}
+{%- endif %}
// terminal cost
-{% if cost.cost_type_e == "LINEAR_LS" or cost.cost_type_e == "NONLINEAR_LS" %}
-{% if dims.ny_e > 0 %}
+{%- if cost.cost_type_e == "LINEAR_LS" or cost.cost_type_e == "NONLINEAR_LS" %}
+ {%- if dims.ny_e > 0 %}
double* yref_e = calloc(NYN, sizeof(double));
// change only the non-zero elements:
- {% for j in range(end=dims.ny_e) %}
+ {%- for j in range(end=dims.ny_e) %}
{%- if cost.yref_e[j] != 0 %}
yref_e[{{ j }}] = {{ cost.yref_e[j] }};
{%- endif %}
@@ -1233,7 +1043,7 @@ int {{ model.name }}_acados_create_with_discretization({{ model.name }}_solver_c
double* W_e = calloc(NYN*NYN, sizeof(double));
// change only the non-zero elements:
- {% for j in range(end=dims.ny_e) %}
+ {%- for j in range(end=dims.ny_e) %}
{%- for k in range(end=dims.ny_e) %}
{%- if cost.W_e[j][k] != 0 %}
W_e[{{ j }}+(NYN) * {{ k }}] = {{ cost.W_e[j][k] }};
@@ -1243,7 +1053,7 @@ int {{ model.name }}_acados_create_with_discretization({{ model.name }}_solver_c
ocp_nlp_cost_model_set(nlp_config, nlp_dims, nlp_in, N, "W", W_e);
free(W_e);
- {%- if cost.cost_type_e == "LINEAR_LS" %}
+ {%- if cost.cost_type_e == "LINEAR_LS" %}
double* Vx_e = calloc(NYN*NX, sizeof(double));
// change only the non-zero elements:
{% for j in range(end=dims.ny_e) %}
@@ -1255,14 +1065,14 @@ int {{ model.name }}_acados_create_with_discretization({{ model.name }}_solver_c
{%- endfor %}
ocp_nlp_cost_model_set(nlp_config, nlp_dims, nlp_in, N, "Vx", Vx_e);
free(Vx_e);
- {%- endif %}
+ {%- endif %}
- {%- if cost.cost_type_e == "NONLINEAR_LS" %}
+ {%- if cost.cost_type_e == "NONLINEAR_LS" %}
ocp_nlp_cost_model_set(nlp_config, nlp_dims, nlp_in, N, "nls_y_fun", &capsule->cost_y_e_fun);
ocp_nlp_cost_model_set(nlp_config, nlp_dims, nlp_in, N, "nls_y_fun_jac", &capsule->cost_y_e_fun_jac_ut_xt);
ocp_nlp_cost_model_set(nlp_config, nlp_dims, nlp_in, N, "nls_y_hess", &capsule->cost_y_e_hess);
- {%- endif %}
-{%- endif %}{# ny_e > 0 #}
+ {%- endif %}
+ {%- endif %}{# ny_e > 0 #}
{%- elif cost.cost_type_e == "EXTERNAL" %}
ocp_nlp_cost_model_set(nlp_config, nlp_dims, nlp_in, N, "ext_cost_fun", &capsule->ext_cost_e_fun);
@@ -1312,7 +1122,7 @@ int {{ model.name }}_acados_create_with_discretization({{ model.name }}_solver_c
/**** Constraints ****/
// bounds for initial stage
-{% if dims.nbx_0 > 0 %}
+{%- if dims.nbx_0 > 0 %}
// x0
int* idxbx0 = malloc(NBX0 * sizeof(int));
{%- for i in range(end=dims.nbx_0) %}
@@ -1337,8 +1147,9 @@ int {{ model.name }}_acados_create_with_discretization({{ model.name }}_solver_c
ocp_nlp_constraints_model_set(nlp_config, nlp_dims, nlp_in, 0, "ubx", ubx0);
free(idxbx0);
free(lubx0);
-{% endif %}
-{% if dims.nbxe_0 > 0 %}
+{%- endif %}
+
+{%- if dims.nbxe_0 > 0 %}
// idxbxe_0
int* idxbxe_0 = malloc({{ dims.nbxe_0 }} * sizeof(int));
{% for i in range(end=dims.nbxe_0) %}
@@ -1346,7 +1157,7 @@ int {{ model.name }}_acados_create_with_discretization({{ model.name }}_solver_c
{%- endfor %}
ocp_nlp_constraints_model_set(nlp_config, nlp_dims, nlp_in, 0, "idxbxe", idxbxe_0);
free(idxbxe_0);
-{% endif %}
+{%- endif %}
/* constraints that are the same for initial and intermediate */
{%- if dims.nsbx > 0 %}
@@ -1357,14 +1168,14 @@ int {{ model.name }}_acados_create_with_discretization({{ model.name }}_solver_c
// soft bounds on x
int* idxsbx = malloc(NSBX * sizeof(int));
- {% for i in range(end=dims.nsbx) %}
+ {%- for i in range(end=dims.nsbx) %}
idxsbx[{{ i }}] = {{ constraints.idxsbx[i] }};
{%- endfor %}
double* lusbx = calloc(2*NSBX, sizeof(double));
double* lsbx = lusbx;
double* usbx = lusbx + NSBX;
- {% for i in range(end=dims.nsbx) %}
+ {%- for i in range(end=dims.nsbx) %}
{%- if constraints.lsbx[i] != 0 %}
lsbx[{{ i }}] = {{ constraints.lsbx[i] }};
{%- endif %}
@@ -1384,7 +1195,7 @@ int {{ model.name }}_acados_create_with_discretization({{ model.name }}_solver_c
{%- endif %}
-{% if dims.nbu > 0 %}
+{%- if dims.nbu > 0 %}
// u
int* idxbu = malloc(NBU * sizeof(int));
{% for i in range(end=dims.nbu) %}
@@ -1410,9 +1221,9 @@ int {{ model.name }}_acados_create_with_discretization({{ model.name }}_solver_c
}
free(idxbu);
free(lubu);
-{% endif %}
+{%- endif %}
-{% if dims.nsbu > 0 %}
+{%- if dims.nsbu > 0 %}
// set up soft bounds for u
int* idxsbu = malloc(NSBU * sizeof(int));
{% for i in range(end=dims.nsbu) %}
@@ -1437,7 +1248,7 @@ int {{ model.name }}_acados_create_with_discretization({{ model.name }}_solver_c
}
free(idxsbu);
free(lusbu);
-{% endif %}
+{%- endif %}
{% if dims.nsg > 0 %}
// set up soft bounds for general linear constraints
@@ -1465,7 +1276,7 @@ int {{ model.name }}_acados_create_with_discretization({{ model.name }}_solver_c
}
free(idxsg);
free(lusg);
-{% endif %}
+{%- endif %}
{% if dims.nsh > 0 %}
// set up soft bounds for nonlinear constraints
@@ -1493,7 +1304,7 @@ int {{ model.name }}_acados_create_with_discretization({{ model.name }}_solver_c
}
free(idxsh);
free(lush);
-{% endif %}
+{%- endif %}
{% if dims.nsphi > 0 %}
// set up soft bounds for convex-over-nonlinear constraints
@@ -1521,7 +1332,7 @@ int {{ model.name }}_acados_create_with_discretization({{ model.name }}_solver_c
}
free(idxsphi);
free(lusphi);
-{% endif %}
+{%- endif %}
{% if dims.nbx > 0 %}
// x
@@ -1549,7 +1360,7 @@ int {{ model.name }}_acados_create_with_discretization({{ model.name }}_solver_c
}
free(idxbx);
free(lubx);
-{% endif %}
+{%- endif %}
{% if dims.ng > 0 %}
// set up general constraints for stage 0 to N-1
@@ -1597,7 +1408,7 @@ int {{ model.name }}_acados_create_with_discretization({{ model.name }}_solver_c
free(D);
free(C);
free(lug);
-{% endif %}
+{%- endif %}
{% if dims.nh > 0 %}
// set up nonlinear constraints for stage 0 to N-1
@@ -1632,7 +1443,7 @@ int {{ model.name }}_acados_create_with_discretization({{ model.name }}_solver_c
ocp_nlp_constraints_model_set(nlp_config, nlp_dims, nlp_in, i, "uh", uh);
}
free(luh);
-{% endif %}
+{%- endif %}
{% if dims.nphi > 0 and constraints.constr_type == "BGP" %}
// set up convex-over-nonlinear constraints for stage 0 to N-1
@@ -1659,7 +1470,7 @@ int {{ model.name }}_acados_create_with_discretization({{ model.name }}_solver_c
ocp_nlp_constraints_model_set(nlp_config, nlp_dims, nlp_in, i, "uphi", uphi);
}
free(luphi);
-{% endif %}
+{%- endif %}
/* terminal constraints */
{% if dims.nbx_e > 0 %}
@@ -1866,42 +1677,62 @@ int {{ model.name }}_acados_create_with_discretization({{ model.name }}_solver_c
"nl_constr_phi_o_r_fun_phi_jac_ux_z_phi_hess_r_jac_ux", &capsule->phi_e_constraint);
free(luphi_e);
{% endif %}
+}
+
+/**
+ * Internal function for {{ model.name }}_acados_create: step 6
+ */
+void {{ model.name }}_acados_create_6_set_opts({{ model.name }}_solver_capsule* capsule)
+{
+ const int N = capsule->nlp_solver_plan->N;
+ ocp_nlp_config* nlp_config = capsule->nlp_config;
+ ocp_nlp_dims* nlp_dims = capsule->nlp_dims;
+ void *nlp_opts = capsule->nlp_opts;
/************************************************
* opts
************************************************/
- capsule->nlp_opts = ocp_nlp_solver_opts_create(nlp_config, nlp_dims);
-
{% if solver_options.hessian_approx == "EXACT" %}
bool nlp_solver_exact_hessian = true;
// TODO: this if should not be needed! however, calling the setter with false leads to weird behavior. Investigate!
if (nlp_solver_exact_hessian)
{
- ocp_nlp_solver_opts_set(nlp_config, capsule->nlp_opts, "exact_hess", &nlp_solver_exact_hessian);
+ ocp_nlp_solver_opts_set(nlp_config, nlp_opts, "exact_hess", &nlp_solver_exact_hessian);
}
int exact_hess_dyn = {{ solver_options.exact_hess_dyn }};
- ocp_nlp_solver_opts_set(nlp_config, capsule->nlp_opts, "exact_hess_dyn", &exact_hess_dyn);
+ ocp_nlp_solver_opts_set(nlp_config, nlp_opts, "exact_hess_dyn", &exact_hess_dyn);
int exact_hess_cost = {{ solver_options.exact_hess_cost }};
- ocp_nlp_solver_opts_set(nlp_config, capsule->nlp_opts, "exact_hess_cost", &exact_hess_cost);
+ ocp_nlp_solver_opts_set(nlp_config, nlp_opts, "exact_hess_cost", &exact_hess_cost);
int exact_hess_constr = {{ solver_options.exact_hess_constr }};
- ocp_nlp_solver_opts_set(nlp_config, capsule->nlp_opts, "exact_hess_constr", &exact_hess_constr);
+ ocp_nlp_solver_opts_set(nlp_config, nlp_opts, "exact_hess_constr", &exact_hess_constr);
{%- endif -%}
{%- if solver_options.globalization == "FIXED_STEP" %}
- ocp_nlp_solver_opts_set(nlp_config, capsule->nlp_opts, "globalization", "fixed_step");
+ ocp_nlp_solver_opts_set(nlp_config, nlp_opts, "globalization", "fixed_step");
{%- elif solver_options.globalization == "MERIT_BACKTRACKING" %}
- ocp_nlp_solver_opts_set(nlp_config, capsule->nlp_opts, "globalization", "merit_backtracking");
+ ocp_nlp_solver_opts_set(nlp_config, nlp_opts, "globalization", "merit_backtracking");
double alpha_min = {{ solver_options.alpha_min }};
- ocp_nlp_solver_opts_set(nlp_config, capsule->nlp_opts, "alpha_min", &alpha_min);
+ ocp_nlp_solver_opts_set(nlp_config, nlp_opts, "alpha_min", &alpha_min);
double alpha_reduction = {{ solver_options.alpha_reduction }};
- ocp_nlp_solver_opts_set(nlp_config, capsule->nlp_opts, "alpha_reduction", &alpha_reduction);
+ ocp_nlp_solver_opts_set(nlp_config, nlp_opts, "alpha_reduction", &alpha_reduction);
+
+ int line_search_use_sufficient_descent = {{ solver_options.line_search_use_sufficient_descent }};
+ ocp_nlp_solver_opts_set(nlp_config, capsule->nlp_opts, "line_search_use_sufficient_descent", &line_search_use_sufficient_descent);
+
+ int globalization_use_SOC = {{ solver_options.globalization_use_SOC }};
+ ocp_nlp_solver_opts_set(nlp_config, capsule->nlp_opts, "globalization_use_SOC", &globalization_use_SOC);
+
+ double eps_sufficient_descent = {{ solver_options.eps_sufficient_descent }};
+ ocp_nlp_solver_opts_set(nlp_config, capsule->nlp_opts, "eps_sufficient_descent", &eps_sufficient_descent);
{%- endif -%}
+ int full_step_dual = {{ solver_options.full_step_dual }};
+ ocp_nlp_solver_opts_set(nlp_config, capsule->nlp_opts, "full_step_dual", &full_step_dual);
{%- if dims.nz > 0 %}
// TODO: these options are lower level -> should be encapsulated! maybe through hessian approx option.
@@ -1909,9 +1740,9 @@ int {{ model.name }}_acados_create_with_discretization({{ model.name }}_solver_c
bool sens_algebraic_val = true;
for (int i = 0; i < N; i++)
- ocp_nlp_solver_opts_set_at_stage(nlp_config, capsule->nlp_opts, i, "dynamics_output_z", &output_z_val);
+ ocp_nlp_solver_opts_set_at_stage(nlp_config, nlp_opts, i, "dynamics_output_z", &output_z_val);
for (int i = 0; i < N; i++)
- ocp_nlp_solver_opts_set_at_stage(nlp_config, capsule->nlp_opts, i, "dynamics_sens_algebraic", &sens_algebraic_val);
+ ocp_nlp_solver_opts_set_at_stage(nlp_config, nlp_opts, i, "dynamics_sens_algebraic", &sens_algebraic_val);
{%- endif %}
{%- if solver_options.integrator_type != "DISCRETE" %}
@@ -1919,7 +1750,7 @@ int {{ model.name }}_acados_create_with_discretization({{ model.name }}_solver_c
// set collocation type (relevant for implicit integrators)
sim_collocation_type collocation_type = {{ solver_options.collocation_type }};
for (int i = 0; i < N; i++)
- ocp_nlp_solver_opts_set_at_stage(nlp_config, capsule->nlp_opts, i, "dynamics_collocation_type", &collocation_type);
+ ocp_nlp_solver_opts_set_at_stage(nlp_config, nlp_opts, i, "dynamics_collocation_type", &collocation_type);
// set up sim_method_num_steps
{%- set all_equal = true %}
@@ -1935,7 +1766,7 @@ int {{ model.name }}_acados_create_with_discretization({{ model.name }}_solver_c
// all sim_method_num_steps are identical
int sim_method_num_steps = {{ solver_options.sim_method_num_steps[0] }};
for (int i = 0; i < N; i++)
- ocp_nlp_solver_opts_set_at_stage(nlp_config, capsule->nlp_opts, i, "dynamics_num_steps", &sim_method_num_steps);
+ ocp_nlp_solver_opts_set_at_stage(nlp_config, nlp_opts, i, "dynamics_num_steps", &sim_method_num_steps);
{%- else %}
// sim_method_num_steps are different
int* sim_method_num_steps = malloc(N*sizeof(int));
@@ -1944,7 +1775,7 @@ int {{ model.name }}_acados_create_with_discretization({{ model.name }}_solver_c
{%- endfor %}
for (int i = 0; i < N; i++)
- ocp_nlp_solver_opts_set_at_stage(nlp_config, capsule->nlp_opts, i, "dynamics_num_steps", &sim_method_num_steps[i]);
+ ocp_nlp_solver_opts_set_at_stage(nlp_config, nlp_opts, i, "dynamics_num_steps", &sim_method_num_steps[i]);
free(sim_method_num_steps);
{%- endif %}
@@ -1962,7 +1793,7 @@ int {{ model.name }}_acados_create_with_discretization({{ model.name }}_solver_c
// all sim_method_num_stages are identical
int sim_method_num_stages = {{ solver_options.sim_method_num_stages[0] }};
for (int i = 0; i < N; i++)
- ocp_nlp_solver_opts_set_at_stage(nlp_config, capsule->nlp_opts, i, "dynamics_num_stages", &sim_method_num_stages);
+ ocp_nlp_solver_opts_set_at_stage(nlp_config, nlp_opts, i, "dynamics_num_stages", &sim_method_num_stages);
{%- else %}
int* sim_method_num_stages = malloc(N*sizeof(int));
{%- for j in range(end=dims.N) %}
@@ -1970,13 +1801,13 @@ int {{ model.name }}_acados_create_with_discretization({{ model.name }}_solver_c
{%- endfor %}
for (int i = 0; i < N; i++)
- ocp_nlp_solver_opts_set_at_stage(nlp_config, capsule->nlp_opts, i, "dynamics_num_stages", &sim_method_num_stages[i]);
+ ocp_nlp_solver_opts_set_at_stage(nlp_config, nlp_opts, i, "dynamics_num_stages", &sim_method_num_stages[i]);
free(sim_method_num_stages);
{%- endif %}
int newton_iter_val = {{ solver_options.sim_method_newton_iter }};
for (int i = 0; i < N; i++)
- ocp_nlp_solver_opts_set_at_stage(nlp_config, capsule->nlp_opts, i, "dynamics_newton_iter", &newton_iter_val);
+ ocp_nlp_solver_opts_set_at_stage(nlp_config, nlp_opts, i, "dynamics_newton_iter", &newton_iter_val);
// set up sim_method_jac_reuse
@@ -1991,7 +1822,7 @@ int {{ model.name }}_acados_create_with_discretization({{ model.name }}_solver_c
{%- if all_equal == true %}
bool tmp_bool = (bool) {{ solver_options.sim_method_jac_reuse[0] }};
for (int i = 0; i < N; i++)
- ocp_nlp_solver_opts_set_at_stage(nlp_config, capsule->nlp_opts, i, "dynamics_jac_reuse", &tmp_bool);
+ ocp_nlp_solver_opts_set_at_stage(nlp_config, nlp_opts, i, "dynamics_jac_reuse", &tmp_bool);
{%- else %}
bool* sim_method_jac_reuse = malloc(N*sizeof(bool));
{%- for j in range(end=dims.N) %}
@@ -1999,104 +1830,114 @@ int {{ model.name }}_acados_create_with_discretization({{ model.name }}_solver_c
{%- endfor %}
for (int i = 0; i < N; i++)
- ocp_nlp_solver_opts_set_at_stage(nlp_config, capsule->nlp_opts, i, "dynamics_jac_reuse", &sim_method_jac_reuse[i]);
+ ocp_nlp_solver_opts_set_at_stage(nlp_config, nlp_opts, i, "dynamics_jac_reuse", &sim_method_jac_reuse[i]);
free(sim_method_jac_reuse);
{%- endif %}
{%- endif %}
double nlp_solver_step_length = {{ solver_options.nlp_solver_step_length }};
- ocp_nlp_solver_opts_set(nlp_config, capsule->nlp_opts, "step_length", &nlp_solver_step_length);
+ ocp_nlp_solver_opts_set(nlp_config, nlp_opts, "step_length", &nlp_solver_step_length);
{%- if solver_options.nlp_solver_warm_start_first_qp %}
int nlp_solver_warm_start_first_qp = {{ solver_options.nlp_solver_warm_start_first_qp }};
- ocp_nlp_solver_opts_set(nlp_config, capsule->nlp_opts, "warm_start_first_qp", &nlp_solver_warm_start_first_qp);
+ ocp_nlp_solver_opts_set(nlp_config, nlp_opts, "warm_start_first_qp", &nlp_solver_warm_start_first_qp);
{%- endif %}
double levenberg_marquardt = {{ solver_options.levenberg_marquardt }};
- ocp_nlp_solver_opts_set(nlp_config, capsule->nlp_opts, "levenberg_marquardt", &levenberg_marquardt);
+ ocp_nlp_solver_opts_set(nlp_config, nlp_opts, "levenberg_marquardt", &levenberg_marquardt);
/* options QP solver */
{%- if solver_options.qp_solver is starting_with("PARTIAL_CONDENSING") %}
int qp_solver_cond_N;
- {%- if solver_options.qp_solver_cond_N %}
- qp_solver_cond_N = {{ solver_options.qp_solver_cond_N }};
- {% else %}
+ {% if solver_options.qp_solver_cond_N -%}
+ const int qp_solver_cond_N_ori = {{ solver_options.qp_solver_cond_N }};
+ qp_solver_cond_N = N < qp_solver_cond_N_ori ? N : qp_solver_cond_N_ori; // use the minimum value here
+ {%- else %}
// NOTE: there is no condensing happening here!
qp_solver_cond_N = N;
{%- endif %}
- ocp_nlp_solver_opts_set(nlp_config, capsule->nlp_opts, "qp_cond_N", &qp_solver_cond_N);
-{% endif %}
+ ocp_nlp_solver_opts_set(nlp_config, nlp_opts, "qp_cond_N", &qp_solver_cond_N);
+{%- endif %}
+
+
+{% if solver_options.nlp_solver_type == "SQP" %}
+ // set SQP specific options
+ double nlp_solver_tol_stat = {{ solver_options.nlp_solver_tol_stat }};
+ ocp_nlp_solver_opts_set(nlp_config, nlp_opts, "tol_stat", &nlp_solver_tol_stat);
+
+ double nlp_solver_tol_eq = {{ solver_options.nlp_solver_tol_eq }};
+ ocp_nlp_solver_opts_set(nlp_config, nlp_opts, "tol_eq", &nlp_solver_tol_eq);
+
+ double nlp_solver_tol_ineq = {{ solver_options.nlp_solver_tol_ineq }};
+ ocp_nlp_solver_opts_set(nlp_config, nlp_opts, "tol_ineq", &nlp_solver_tol_ineq);
+
+ double nlp_solver_tol_comp = {{ solver_options.nlp_solver_tol_comp }};
+ ocp_nlp_solver_opts_set(nlp_config, nlp_opts, "tol_comp", &nlp_solver_tol_comp);
+
+ int nlp_solver_max_iter = {{ solver_options.nlp_solver_max_iter }};
+ ocp_nlp_solver_opts_set(nlp_config, nlp_opts, "max_iter", &nlp_solver_max_iter);
+
+ int initialize_t_slacks = {{ solver_options.initialize_t_slacks }};
+ ocp_nlp_solver_opts_set(nlp_config, nlp_opts, "initialize_t_slacks", &initialize_t_slacks);
+{%- endif %}
int qp_solver_iter_max = {{ solver_options.qp_solver_iter_max }};
- ocp_nlp_solver_opts_set(nlp_config, capsule->nlp_opts, "qp_iter_max", &qp_solver_iter_max);
+ ocp_nlp_solver_opts_set(nlp_config, nlp_opts, "qp_iter_max", &qp_solver_iter_max);
+{# NOTE: qp_solver tolerances must be set after NLP ones, since the setter for NLP tolerances sets the QP tolerances to the sam values. #}
{%- if solver_options.qp_solver_tol_stat %}
double qp_solver_tol_stat = {{ solver_options.qp_solver_tol_stat }};
- ocp_nlp_solver_opts_set(nlp_config, capsule->nlp_opts, "qp_tol_stat", &qp_solver_tol_stat);
+ ocp_nlp_solver_opts_set(nlp_config, nlp_opts, "qp_tol_stat", &qp_solver_tol_stat);
{%- endif -%}
{%- if solver_options.qp_solver_tol_eq %}
double qp_solver_tol_eq = {{ solver_options.qp_solver_tol_eq }};
- ocp_nlp_solver_opts_set(nlp_config, capsule->nlp_opts, "qp_tol_eq", &qp_solver_tol_eq);
+ ocp_nlp_solver_opts_set(nlp_config, nlp_opts, "qp_tol_eq", &qp_solver_tol_eq);
{%- endif -%}
{%- if solver_options.qp_solver_tol_ineq %}
double qp_solver_tol_ineq = {{ solver_options.qp_solver_tol_ineq }};
- ocp_nlp_solver_opts_set(nlp_config, capsule->nlp_opts, "qp_tol_ineq", &qp_solver_tol_ineq);
+ ocp_nlp_solver_opts_set(nlp_config, nlp_opts, "qp_tol_ineq", &qp_solver_tol_ineq);
{%- endif -%}
{%- if solver_options.qp_solver_tol_comp %}
double qp_solver_tol_comp = {{ solver_options.qp_solver_tol_comp }};
- ocp_nlp_solver_opts_set(nlp_config, capsule->nlp_opts, "qp_tol_comp", &qp_solver_tol_comp);
+ ocp_nlp_solver_opts_set(nlp_config, nlp_opts, "qp_tol_comp", &qp_solver_tol_comp);
{%- endif -%}
{%- if solver_options.qp_solver_warm_start %}
int qp_solver_warm_start = {{ solver_options.qp_solver_warm_start }};
- ocp_nlp_solver_opts_set(nlp_config, capsule->nlp_opts, "qp_warm_start", &qp_solver_warm_start);
+ ocp_nlp_solver_opts_set(nlp_config, nlp_opts, "qp_warm_start", &qp_solver_warm_start);
{%- endif -%}
-
-{% if solver_options.nlp_solver_type == "SQP" %}
- // set SQP specific options
- double nlp_solver_tol_stat = {{ solver_options.nlp_solver_tol_stat }};
- ocp_nlp_solver_opts_set(nlp_config, capsule->nlp_opts, "tol_stat", &nlp_solver_tol_stat);
-
- double nlp_solver_tol_eq = {{ solver_options.nlp_solver_tol_eq }};
- ocp_nlp_solver_opts_set(nlp_config, capsule->nlp_opts, "tol_eq", &nlp_solver_tol_eq);
-
- double nlp_solver_tol_ineq = {{ solver_options.nlp_solver_tol_ineq }};
- ocp_nlp_solver_opts_set(nlp_config, capsule->nlp_opts, "tol_ineq", &nlp_solver_tol_ineq);
-
- double nlp_solver_tol_comp = {{ solver_options.nlp_solver_tol_comp }};
- ocp_nlp_solver_opts_set(nlp_config, capsule->nlp_opts, "tol_comp", &nlp_solver_tol_comp);
-
- int nlp_solver_max_iter = {{ solver_options.nlp_solver_max_iter }};
- ocp_nlp_solver_opts_set(nlp_config, capsule->nlp_opts, "max_iter", &nlp_solver_max_iter);
-
- int initialize_t_slacks = {{ solver_options.initialize_t_slacks }};
- ocp_nlp_solver_opts_set(nlp_config, capsule->nlp_opts, "initialize_t_slacks", &initialize_t_slacks);
-{%- endif %}
int print_level = {{ solver_options.print_level }};
- ocp_nlp_solver_opts_set(nlp_config, capsule->nlp_opts, "print_level", &print_level);
+ ocp_nlp_solver_opts_set(nlp_config, nlp_opts, "print_level", &print_level);
int ext_cost_num_hess = {{ solver_options.ext_cost_num_hess }};
{%- if cost.cost_type == "EXTERNAL" %}
for (int i = 0; i < N; i++)
{
- ocp_nlp_solver_opts_set_at_stage(nlp_config, capsule->nlp_opts, i, "cost_numerical_hessian", &ext_cost_num_hess);
+ ocp_nlp_solver_opts_set_at_stage(nlp_config, nlp_opts, i, "cost_numerical_hessian", &ext_cost_num_hess);
}
{%- endif %}
{%- if cost.cost_type_e == "EXTERNAL" %}
- ocp_nlp_solver_opts_set_at_stage(nlp_config, capsule->nlp_opts, N, "cost_numerical_hessian", &ext_cost_num_hess);
+ ocp_nlp_solver_opts_set_at_stage(nlp_config, nlp_opts, N, "cost_numerical_hessian", &ext_cost_num_hess);
{%- endif %}
+}
- /* out */
- ocp_nlp_out * nlp_out = ocp_nlp_out_create(nlp_config, nlp_dims);
- capsule->nlp_out = nlp_out;
+/**
+ * Internal function for {{ model.name }}_acados_create: step 7
+ */
+void {{ model.name }}_acados_create_7_set_nlp_out({{ model.name }}_solver_capsule* capsule)
+{
+ const int N = capsule->nlp_solver_plan->N;
+ ocp_nlp_config* nlp_config = capsule->nlp_config;
+ ocp_nlp_dims* nlp_dims = capsule->nlp_dims;
+ ocp_nlp_out* nlp_out = capsule->nlp_out;
// initialize primal solution
double* xu0 = calloc(NX+NU, sizeof(double));
@@ -2123,39 +1964,114 @@ int {{ model.name }}_acados_create_with_discretization({{ model.name }}_solver_c
}
ocp_nlp_out_set(nlp_config, nlp_dims, nlp_out, N, "x", x0);
free(xu0);
-
- capsule->nlp_solver = ocp_nlp_solver_create(nlp_config, nlp_dims, capsule->nlp_opts);
+}
-{% if dims.np > 0 %}
- // initialize parameters to nominal value
- double* p = calloc(NP, sizeof(double));
- {% for item in parameter_values %}
- {%- if item != 0 %}
- p[{{ loop.index0 }}] = {{ item }};
- {%- endif %}
- {%- endfor %}
+/**
+ * Internal function for {{ model.name }}_acados_create: step 8
+ */
+//void {{ model.name }}_acados_create_8_create_solver({{ model.name }}_solver_capsule* capsule)
+//{
+// capsule->nlp_solver = ocp_nlp_solver_create(capsule->nlp_config, capsule->nlp_dims, capsule->nlp_opts);
+//}
- for (int i = 0; i <= N; i++)
- {
- {{ model.name }}_acados_update_params(capsule, i, p, NP);
+/**
+ * Internal function for {{ model.name }}_acados_create: step 9
+ */
+int {{ model.name }}_acados_create_9_precompute({{ model.name }}_solver_capsule* capsule) {
+ int status = ocp_nlp_precompute(capsule->nlp_solver, capsule->nlp_in, capsule->nlp_out);
+
+ if (status != ACADOS_SUCCESS) {
+ printf("\nocp_nlp_precompute failed!\n\n");
+ exit(1);
}
- free(p);
-{%- endif %}{# if dims.np #}
- status = ocp_nlp_precompute(capsule->nlp_solver, nlp_in, nlp_out);
+ return status;
+}
- if (status != ACADOS_SUCCESS)
- {
- printf("\nocp_precompute failed!\n\n");
- exit(1);
+
+int {{ model.name }}_acados_create_with_discretization({{ model.name }}_solver_capsule* capsule, int N, double* new_time_steps)
+{
+ // If N does not match the number of shooting intervals used for code generation, new_time_steps must be given.
+ if (N != {{ model.name | upper }}_N && !new_time_steps) {
+ fprintf(stderr, "{{ model.name }}_acados_create_with_discretization: new_time_steps is NULL " \
+ "but the number of shooting intervals (= %d) differs from the number of " \
+ "shooting intervals (= %d) during code generation! Please provide a new vector of time_stamps!\n", \
+ N, {{ model.name | upper }}_N);
+ return 1;
}
+ // number of expected runtime parameters
+ capsule->nlp_np = NP;
+
+ // 1) create and set nlp_solver_plan; create nlp_config
+ capsule->nlp_solver_plan = ocp_nlp_plan_create(N);
+ {{ model.name }}_acados_create_1_set_plan(capsule->nlp_solver_plan, N);
+ capsule->nlp_config = ocp_nlp_config_create(*capsule->nlp_solver_plan);
+
+ // 3) create and set dimensions
+ capsule->nlp_dims = {{ model.name }}_acados_create_2_create_and_set_dimensions(capsule);
+ {{ model.name }}_acados_create_3_create_and_set_functions(capsule);
+
+ // 4) set default parameters in functions
+ {{ model.name }}_acados_create_4_set_default_parameters(capsule);
+
+ // 5) create and set nlp_in
+ capsule->nlp_in = ocp_nlp_in_create(capsule->nlp_config, capsule->nlp_dims);
+ {{ model.name }}_acados_create_5_set_nlp_in(capsule, N, new_time_steps);
+
+ // 6) create and set nlp_opts
+ capsule->nlp_opts = ocp_nlp_solver_opts_create(capsule->nlp_config, capsule->nlp_dims);
+ {{ model.name }}_acados_create_6_set_opts(capsule);
+
+ // 7) create and set nlp_out
+ // 7.1) nlp_out
+ capsule->nlp_out = ocp_nlp_out_create(capsule->nlp_config, capsule->nlp_dims);
+ // 7.2) sens_out
+ capsule->sens_out = ocp_nlp_out_create(capsule->nlp_config, capsule->nlp_dims);
+ {{ model.name }}_acados_create_7_set_nlp_out(capsule);
+
+ // 8) create solver
+ capsule->nlp_solver = ocp_nlp_solver_create(capsule->nlp_config, capsule->nlp_dims, capsule->nlp_opts);
+ //{{ model.name }}_acados_create_8_create_solver(capsule);
+
+ // 9) do precomputations
+ int status = {{ model.name }}_acados_create_9_precompute(capsule);
+ return status;
+}
+
+/**
+ * This function is for updating an already initialized solver with a different number of qp_cond_N. It is useful for code reuse after code export.
+ */
+int {{ model.name }}_acados_update_qp_solver_cond_N({{ model.name }}_solver_capsule* capsule, int qp_solver_cond_N)
+{
+{%- if solver_options.qp_solver is starting_with("PARTIAL_CONDENSING") %}
+ // 1) destroy solver
+ ocp_nlp_solver_destroy(capsule->nlp_solver);
+
+ // 2) set new value for "qp_cond_N"
+ const int N = capsule->nlp_solver_plan->N;
+ if(qp_solver_cond_N > N)
+ printf("Warning: qp_solver_cond_N = %d > N = %d\n", qp_solver_cond_N, N);
+ ocp_nlp_solver_opts_set(capsule->nlp_config, capsule->nlp_opts, "qp_cond_N", &qp_solver_cond_N);
+
+ // 3) continue with the remaining steps from {{ model.name }}_acados_create_with_discretization(...):
+ // -> 8) create solver
+ capsule->nlp_solver = ocp_nlp_solver_create(capsule->nlp_config, capsule->nlp_dims, capsule->nlp_opts);
+
+ // -> 9) do precomputations
+ int status = {{ model.name }}_acados_create_9_precompute(capsule);
return status;
+{%- else %}
+ printf("\nacados_update_qp_solver_cond_N() failed, since no partial condensing solver is used!\n\n");
+ // Todo: what is an adequate behavior here?
+ exit(1);
+ return -1;
+{%- endif %}
}
-int {{ model.name }}_acados_update_params({{ model.name }}_solver_capsule * capsule, int stage, double *p, int np)
+int {{ model.name }}_acados_update_params({{ model.name }}_solver_capsule* capsule, int stage, double *p, int np)
{
int solver_status = 0;
@@ -2189,11 +2105,14 @@ int {{ model.name }}_acados_update_params({{ model.name }}_solver_capsule * caps
capsule->hess_vde_casadi[stage].set_param(capsule->hess_vde_casadi+stage, p);
{%- endif %}
{% elif solver_options.integrator_type == "GNSF" %}
+ {% if model.gnsf.purely_linear != 1 %}
capsule->gnsf_phi_fun[stage].set_param(capsule->gnsf_phi_fun+stage, p);
capsule->gnsf_phi_fun_jac_y[stage].set_param(capsule->gnsf_phi_fun_jac_y+stage, p);
capsule->gnsf_phi_jac_y_uhat[stage].set_param(capsule->gnsf_phi_jac_y_uhat+stage, p);
-
- capsule->gnsf_f_lo_jac_x1_x1dot_u_z[stage].set_param(capsule->gnsf_f_lo_jac_x1_x1dot_u_z+stage, p);
+ {% if model.gnsf.nontrivial_f_LO == 1 %}
+ capsule->gnsf_f_lo_jac_x1_x1dot_u_z[stage].set_param(capsule->gnsf_f_lo_jac_x1_x1dot_u_z+stage, p);
+ {%- endif %}
+ {%- endif %}
{% elif solver_options.integrator_type == "DISCRETE" %}
capsule->discr_dyn_phi_fun[stage].set_param(capsule->discr_dyn_phi_fun+stage, p);
capsule->discr_dyn_phi_fun_jac_ut_xt[stage].set_param(capsule->discr_dyn_phi_fun_jac_ut_xt+stage, p);
@@ -2271,7 +2190,7 @@ int {{ model.name }}_acados_update_params({{ model.name }}_solver_capsule * caps
-int {{ model.name }}_acados_solve({{ model.name }}_solver_capsule * capsule)
+int {{ model.name }}_acados_solve({{ model.name }}_solver_capsule* capsule)
{
// solve NLP
int solver_status = ocp_nlp_solve(capsule->nlp_solver, capsule->nlp_in, capsule->nlp_out);
@@ -2280,7 +2199,7 @@ int {{ model.name }}_acados_solve({{ model.name }}_solver_capsule * capsule)
}
-int {{ model.name }}_acados_free({{ model.name }}_solver_capsule * capsule)
+int {{ model.name }}_acados_free({{ model.name }}_solver_capsule* capsule)
{
// before destroying, keep some info
const int N = capsule->nlp_solver_plan->N;
@@ -2288,6 +2207,7 @@ int {{ model.name }}_acados_free({{ model.name }}_solver_capsule * capsule)
ocp_nlp_solver_opts_destroy(capsule->nlp_opts);
ocp_nlp_in_destroy(capsule->nlp_in);
ocp_nlp_out_destroy(capsule->nlp_out);
+ ocp_nlp_out_destroy(capsule->sens_out);
ocp_nlp_solver_destroy(capsule->nlp_solver);
ocp_nlp_dims_destroy(capsule->nlp_dims);
ocp_nlp_config_destroy(capsule->nlp_config);
@@ -2339,16 +2259,24 @@ int {{ model.name }}_acados_free({{ model.name }}_solver_capsule * capsule)
{%- elif solver_options.integrator_type == "GNSF" %}
for (int i = 0; i < N; i++)
{
+ {% if model.gnsf.purely_linear != 1 %}
external_function_param_casadi_free(&capsule->gnsf_phi_fun[i]);
external_function_param_casadi_free(&capsule->gnsf_phi_fun_jac_y[i]);
external_function_param_casadi_free(&capsule->gnsf_phi_jac_y_uhat[i]);
+ {% if model.gnsf.nontrivial_f_LO == 1 %}
external_function_param_casadi_free(&capsule->gnsf_f_lo_jac_x1_x1dot_u_z[i]);
+ {%- endif %}
+ {%- endif %}
external_function_param_casadi_free(&capsule->gnsf_get_matrices_fun[i]);
}
+ {% if model.gnsf.purely_linear != 1 %}
free(capsule->gnsf_phi_fun);
free(capsule->gnsf_phi_fun_jac_y);
free(capsule->gnsf_phi_jac_y_uhat);
+ {% if model.gnsf.nontrivial_f_LO == 1 %}
free(capsule->gnsf_f_lo_jac_x1_x1dot_u_z);
+ {%- endif %}
+ {%- endif %}
free(capsule->gnsf_get_matrices_fun);
{%- elif solver_options.integrator_type == "DISCRETE" %}
for (int i = 0; i < N; i++)
@@ -2448,34 +2376,36 @@ int {{ model.name }}_acados_free({{ model.name }}_solver_capsule * capsule)
return 0;
}
-ocp_nlp_in *{{ model.name }}_acados_get_nlp_in({{ model.name }}_solver_capsule * capsule) { return capsule->nlp_in; }
-ocp_nlp_out *{{ model.name }}_acados_get_nlp_out({{ model.name }}_solver_capsule * capsule) { return capsule->nlp_out; }
-ocp_nlp_solver *{{ model.name }}_acados_get_nlp_solver({{ model.name }}_solver_capsule * capsule) { return capsule->nlp_solver; }
-ocp_nlp_config *{{ model.name }}_acados_get_nlp_config({{ model.name }}_solver_capsule * capsule) { return capsule->nlp_config; }
-void *{{ model.name }}_acados_get_nlp_opts({{ model.name }}_solver_capsule * capsule) { return capsule->nlp_opts; }
-ocp_nlp_dims *{{ model.name }}_acados_get_nlp_dims({{ model.name }}_solver_capsule * capsule) { return capsule->nlp_dims; }
-ocp_nlp_plan *{{ model.name }}_acados_get_nlp_plan({{ model.name }}_solver_capsule * capsule) { return capsule->nlp_solver_plan; }
+ocp_nlp_in *{{ model.name }}_acados_get_nlp_in({{ model.name }}_solver_capsule* capsule) { return capsule->nlp_in; }
+ocp_nlp_out *{{ model.name }}_acados_get_nlp_out({{ model.name }}_solver_capsule* capsule) { return capsule->nlp_out; }
+ocp_nlp_out *{{ model.name }}_acados_get_sens_out({{ model.name }}_solver_capsule* capsule) { return capsule->sens_out; }
+ocp_nlp_solver *{{ model.name }}_acados_get_nlp_solver({{ model.name }}_solver_capsule* capsule) { return capsule->nlp_solver; }
+ocp_nlp_config *{{ model.name }}_acados_get_nlp_config({{ model.name }}_solver_capsule* capsule) { return capsule->nlp_config; }
+void *{{ model.name }}_acados_get_nlp_opts({{ model.name }}_solver_capsule* capsule) { return capsule->nlp_opts; }
+ocp_nlp_dims *{{ model.name }}_acados_get_nlp_dims({{ model.name }}_solver_capsule* capsule) { return capsule->nlp_dims; }
+ocp_nlp_plan_t *{{ model.name }}_acados_get_nlp_plan({{ model.name }}_solver_capsule* capsule) { return capsule->nlp_solver_plan; }
-void {{ model.name }}_acados_print_stats({{ model.name }}_solver_capsule * capsule)
+void {{ model.name }}_acados_print_stats({{ model.name }}_solver_capsule* capsule)
{
int sqp_iter, stat_m, stat_n, tmp_int;
ocp_nlp_get(capsule->nlp_config, capsule->nlp_solver, "sqp_iter", &sqp_iter);
ocp_nlp_get(capsule->nlp_config, capsule->nlp_solver, "stat_n", &stat_n);
ocp_nlp_get(capsule->nlp_config, capsule->nlp_solver, "stat_m", &stat_m);
- {% set stat_n_max = 10 %}
+ {% set stat_n_max = 12 %}
double stat[{{ solver_options.nlp_solver_max_iter * stat_n_max }}];
ocp_nlp_get(capsule->nlp_config, capsule->nlp_solver, "statistics", stat);
int nrow = sqp_iter+1 < stat_m ? sqp_iter+1 : stat_m;
- printf("iter\tres_stat\tres_eq\t\tres_ineq\tres_comp\tqp_stat\tqp_iter\n");
+{%- if solver_options.nlp_solver_type == "SQP" %}
+ printf("iter\tres_stat\tres_eq\t\tres_ineq\tres_comp\tqp_stat\tqp_iter\talpha\n");
for (int i = 0; i < nrow; i++)
{
for (int j = 0; j < stat_n + 1; j++)
{
- if (j == 0 || j > 4)
+ if (j == 0 || j == 5 || j == 6)
{
tmp_int = (int) stat[i + j * nrow];
printf("%d\t", tmp_int);
@@ -2487,5 +2417,17 @@ void {{ model.name }}_acados_print_stats({{ model.name }}_solver_capsule * capsu
}
printf("\n");
}
+{% else %}
+ printf("iter\tqp_stat\tqp_iter\n");
+ for (int i = 0; i < nrow; i++)
+ {
+ for (int j = 0; j < stat_n + 1; j++)
+ {
+ tmp_int = (int) stat[i + j * nrow];
+ printf("%d\t", tmp_int);
+ }
+ printf("\n");
+ }
+{%- endif %}
}
diff --git a/pyextra/acados_template/c_templates_tera/acados_solver.in.h b/pyextra/acados_template/c_templates_tera/acados_solver.in.h
index e8c0a38ca3..2efc9e5157 100644
--- a/pyextra/acados_template/c_templates_tera/acados_solver.in.h
+++ b/pyextra/acados_template/c_templates_tera/acados_solver.in.h
@@ -78,9 +78,10 @@ typedef struct {{ model.name }}_solver_capsule
// acados objects
ocp_nlp_in *nlp_in;
ocp_nlp_out *nlp_out;
+ ocp_nlp_out *sens_out;
ocp_nlp_solver *nlp_solver;
void *nlp_opts;
- ocp_nlp_plan *nlp_solver_plan;
+ ocp_nlp_plan_t *nlp_solver_plan;
ocp_nlp_config *nlp_config;
ocp_nlp_dims *nlp_dims;
@@ -186,6 +187,10 @@ int {{ model.name }}_acados_create_with_discretization({{ model.name }}_solver_c
* nlp_solver_plan. Returns 0 if no error occurred and a otherwise a value other than 0.
*/
int {{ model.name }}_acados_update_time_steps({{ model.name }}_solver_capsule * capsule, int N, double* new_time_steps);
+/**
+ * This function is used for updating an already initialized solver with a different number of qp_cond_N.
+ */
+int {{ model.name }}_acados_update_qp_solver_cond_N({{ model.name }}_solver_capsule * capsule, int qp_solver_cond_N);
int {{ model.name }}_acados_update_params({{ model.name }}_solver_capsule * capsule, int stage, double *value, int np);
int {{ model.name }}_acados_solve({{ model.name }}_solver_capsule * capsule);
int {{ model.name }}_acados_free({{ model.name }}_solver_capsule * capsule);
@@ -193,11 +198,12 @@ void {{ model.name }}_acados_print_stats({{ model.name }}_solver_capsule * capsu
ocp_nlp_in *{{ model.name }}_acados_get_nlp_in({{ model.name }}_solver_capsule * capsule);
ocp_nlp_out *{{ model.name }}_acados_get_nlp_out({{ model.name }}_solver_capsule * capsule);
+ocp_nlp_out *{{ model.name }}_acados_get_sens_out({{ model.name }}_solver_capsule * capsule);
ocp_nlp_solver *{{ model.name }}_acados_get_nlp_solver({{ model.name }}_solver_capsule * capsule);
ocp_nlp_config *{{ model.name }}_acados_get_nlp_config({{ model.name }}_solver_capsule * capsule);
void *{{ model.name }}_acados_get_nlp_opts({{ model.name }}_solver_capsule * capsule);
ocp_nlp_dims *{{ model.name }}_acados_get_nlp_dims({{ model.name }}_solver_capsule * capsule);
-ocp_nlp_plan *{{ model.name }}_acados_get_nlp_plan({{ model.name }}_solver_capsule * capsule);
+ocp_nlp_plan_t *{{ model.name }}_acados_get_nlp_plan({{ model.name }}_solver_capsule * capsule);
#ifdef __cplusplus
} /* extern "C" */
diff --git a/pyextra/acados_template/c_templates_tera/acados_solver.in.pxd b/pyextra/acados_template/c_templates_tera/acados_solver.in.pxd
index 8387980c24..2cc5ee3910 100644
--- a/pyextra/acados_template/c_templates_tera/acados_solver.in.pxd
+++ b/pyextra/acados_template/c_templates_tera/acados_solver.in.pxd
@@ -1,3 +1,36 @@
+#
+# Copyright 2019 Gianluca Frison, Dimitris Kouzoupis, Robin Verschueren,
+# Andrea Zanelli, Niels van Duijkeren, Jonathan Frey, Tommaso Sartor,
+# Branimir Novoselnik, Rien Quirynen, Rezart Qelibari, Dang Doan,
+# Jonas Koenemann, Yutao Chen, Tobias Schöls, Jonas Schlagenhauf, Moritz Diehl
+#
+# This file is part of acados.
+#
+# The 2-Clause BSD License
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.;
+#
+
cimport acados_solver_common
cdef extern from "acados_solver_{{ model.name }}.h":
@@ -8,6 +41,11 @@ cdef extern from "acados_solver_{{ model.name }}.h":
int acados_free_capsule "{{ model.name }}_acados_free_capsule"(nlp_solver_capsule *capsule)
int acados_create "{{ model.name }}_acados_create"(nlp_solver_capsule * capsule)
+
+ int acados_create_with_discretization "{{ model.name }}_acados_create_with_discretization"(nlp_solver_capsule * capsule, int n_time_steps, double* new_time_steps)
+ int acados_update_time_steps "{{ model.name }}_acados_update_time_steps"(nlp_solver_capsule * capsule, int N, double* new_time_steps)
+ int acados_update_qp_solver_cond_N "{{ model.name }}_acados_update_qp_solver_cond_N"(nlp_solver_capsule * capsule, int qp_solver_cond_N)
+
int acados_update_params "{{ model.name }}_acados_update_params"(nlp_solver_capsule * capsule, int stage, double *value, int np_)
int acados_solve "{{ model.name }}_acados_solve"(nlp_solver_capsule * capsule)
int acados_free "{{ model.name }}_acados_free"(nlp_solver_capsule * capsule)
@@ -15,6 +53,7 @@ cdef extern from "acados_solver_{{ model.name }}.h":
acados_solver_common.ocp_nlp_in *acados_get_nlp_in "{{ model.name }}_acados_get_nlp_in"(nlp_solver_capsule * capsule)
acados_solver_common.ocp_nlp_out *acados_get_nlp_out "{{ model.name }}_acados_get_nlp_out"(nlp_solver_capsule * capsule)
+ acados_solver_common.ocp_nlp_out *acados_get_sens_out "{{ model.name }}_acados_get_sens_out"(nlp_solver_capsule * capsule)
acados_solver_common.ocp_nlp_solver *acados_get_nlp_solver "{{ model.name }}_acados_get_nlp_solver"(nlp_solver_capsule * capsule)
acados_solver_common.ocp_nlp_config *acados_get_nlp_config "{{ model.name }}_acados_get_nlp_config"(nlp_solver_capsule * capsule)
void *acados_get_nlp_opts "{{ model.name }}_acados_get_nlp_opts"(nlp_solver_capsule * capsule)
diff --git a/pyextra/acados_template/c_templates_tera/acados_solver_sfun.in.c b/pyextra/acados_template/c_templates_tera/acados_solver_sfun.in.c
index a6cd1faa8c..a27ba8837f 100644
--- a/pyextra/acados_template/c_templates_tera/acados_solver_sfun.in.c
+++ b/pyextra/acados_template/c_templates_tera/acados_solver_sfun.in.c
@@ -37,7 +37,7 @@
#define MDL_START
// acados
-#include "acados/utils/print.h"
+// #include "acados/utils/print.h"
#include "acados_c/sim_interface.h"
#include "acados_c/external_function_interface.h"
diff --git a/pyextra/acados_template/c_templates_tera/main.in.c b/pyextra/acados_template/c_templates_tera/main.in.c
index 3348eea5cb..99c4f13be1 100644
--- a/pyextra/acados_template/c_templates_tera/main.in.c
+++ b/pyextra/acados_template/c_templates_tera/main.in.c
@@ -156,11 +156,12 @@ int main()
for (int ii = 0; ii < NTIMINGS; ii++)
{
// initialize solution
- for (int i = 0; i <= nlp_dims->N; i++)
+ for (int i = 0; i < N; i++)
{
ocp_nlp_out_set(nlp_config, nlp_dims, nlp_out, i, "x", x_init);
ocp_nlp_out_set(nlp_config, nlp_dims, nlp_out, i, "u", u0);
}
+ ocp_nlp_out_set(nlp_config, nlp_dims, nlp_out, N, "x", x_init);
ocp_nlp_solver_opts_set(nlp_config, nlp_opts, "rti_phase", &rti_phase);
status = {{ model.name }}_acados_solve(acados_ocp_capsule);
ocp_nlp_get(nlp_config, nlp_solver, "time_tot", &elapsed_time);
diff --git a/pyextra/acados_template/c_templates_tera/make_sfun.in.m b/pyextra/acados_template/c_templates_tera/make_sfun.in.m
index 172da654ee..30339bf5dc 100644
--- a/pyextra/acados_template/c_templates_tera/make_sfun.in.m
+++ b/pyextra/acados_template/c_templates_tera/make_sfun.in.m
@@ -46,10 +46,14 @@ SOURCES = { ...
'{{ model.name }}_model/{{ model.name }}_impl_dae_hess.c',...
{%- endif %}
{%- elif solver_options.integrator_type == "GNSF" %}
+ {% if model.gnsf.purely_linear != 1 %}
'{{ model.name }}_model/{{ model.name }}_gnsf_phi_fun.c',...
'{{ model.name }}_model/{{ model.name }}_gnsf_phi_fun_jac_y.c',...
'{{ model.name }}_model/{{ model.name }}_gnsf_phi_jac_y_uhat.c',...
+ {% if model.gnsf.nontrivial_f_LO == 1 %}
'{{ model.name }}_model/{{ model.name }}_gnsf_f_lo_fun_jac_x1k1uz.c',...
+ {%- endif %}
+ {%- endif %}
'{{ model.name }}_model/{{ model.name }}_gnsf_get_matrices_fun.c',...
{%- elif solver_options.integrator_type == "DISCRETE" %}
'{{ model.name }}_model/{{ model.name }}_dyn_disc_phi_fun.c',...
diff --git a/pyextra/acados_template/c_templates_tera/make_sfun_sim.in.m b/pyextra/acados_template/c_templates_tera/make_sfun_sim.in.m
index 1c5cf0b123..a0c503e41a 100644
--- a/pyextra/acados_template/c_templates_tera/make_sfun_sim.in.m
+++ b/pyextra/acados_template/c_templates_tera/make_sfun_sim.in.m
@@ -47,10 +47,14 @@ SOURCES = [ 'acados_sim_solver_sfunction_{{ model.name }}.c ', ...
'{{ model.name }}_model/{{ model.name }}_impl_dae_hess.c ',...
{%- endif %}
{%- elif solver_options.integrator_type == "GNSF" %}
+ {% if model.gnsf.purely_linear != 1 %}
'{{ model.name }}_model/{{ model.name }}_gnsf_phi_fun.c '
'{{ model.name }}_model/{{ model.name }}_gnsf_phi_fun_jac_y.c '
'{{ model.name }}_model/{{ model.name }}_gnsf_phi_jac_y_uhat.c '
+ {% if model.gnsf.nontrivial_f_LO == 1 %}
'{{ model.name }}_model/{{ model.name }}_gnsf_f_lo_fun_jac_x1k1uz.c '
+ {%- endif %}
+ {%- endif %}
'{{ model.name }}_model/{{ model.name }}_gnsf_get_matrices_fun.c '
{%- endif %}
];
diff --git a/pyextra/acados_template/c_templates_tera/mex_solver.in.m b/pyextra/acados_template/c_templates_tera/mex_solver.in.m
index 728741a46e..278e0a605c 100644
--- a/pyextra/acados_template/c_templates_tera/mex_solver.in.m
+++ b/pyextra/acados_template/c_templates_tera/mex_solver.in.m
@@ -125,15 +125,15 @@ classdef {{ model.name }}_mex_solver < handle
if strcmp(field, 'stat')
stat = obj.get('stat');
{%- if solver_options.nlp_solver_type == "SQP" %}
- fprintf('\niter\tres_stat\tres_eq\t\tres_ineq\tres_comp\tqp_stat\tqp_iter');
- if size(stat,2)>7
+ fprintf('\niter\tres_stat\tres_eq\t\tres_ineq\tres_comp\tqp_stat\tqp_iter\talpha');
+ if size(stat,2)>8
fprintf('\tqp_res_stat\tqp_res_eq\tqp_res_ineq\tqp_res_comp');
end
fprintf('\n');
for jj=1:size(stat,1)
- fprintf('%d\t%e\t%e\t%e\t%e\t%d\t%d', stat(jj,1), stat(jj,2), stat(jj,3), stat(jj,4), stat(jj,5), stat(jj,6), stat(jj,7));
- if size(stat,2)>7
- fprintf('\t%e\t%e\t%e\t%e', stat(jj,8), stat(jj,9), stat(jj,10), stat(jj,11));
+ fprintf('%d\t%e\t%e\t%e\t%e\t%d\t%d\t%e', stat(jj,1), stat(jj,2), stat(jj,3), stat(jj,4), stat(jj,5), stat(jj,6), stat(jj,7), stat(jj, 8));
+ if size(stat,2)>8
+ fprintf('\t%e\t%e\t%e\t%e', stat(jj,9), stat(jj,10), stat(jj,11), stat(jj,12));
end
fprintf('\n');
end
diff --git a/pyextra/acados_template/c_templates_tera/model.in.h b/pyextra/acados_template/c_templates_tera/model.in.h
index 661811232c..918e2bc29e 100644
--- a/pyextra/acados_template/c_templates_tera/model.in.h
+++ b/pyextra/acados_template/c_templates_tera/model.in.h
@@ -90,14 +90,7 @@ int {{ model.name }}_impl_dae_hess_n_out(void);
{% elif solver_options.integrator_type == "GNSF" %}
/* GNSF Functions */
-// used to import model matrices
-int {{ model.name }}_gnsf_get_matrices_fun(const double** arg, double** res, int* iw, double* w, void *mem);
-int {{ model.name }}_gnsf_get_matrices_fun_work(int *, int *, int *, int *);
-const int *{{ model.name }}_gnsf_get_matrices_fun_sparsity_in(int);
-const int *{{ model.name }}_gnsf_get_matrices_fun_sparsity_out(int);
-int {{ model.name }}_gnsf_get_matrices_fun_n_in(void);
-int {{ model.name }}_gnsf_get_matrices_fun_n_out(void);
-
+ {% if model.gnsf.purely_linear != 1 %}
// phi_fun
int {{ model.name }}_gnsf_phi_fun(const double** arg, double** res, int* iw, double* w, void *mem);
int {{ model.name }}_gnsf_phi_fun_work(int *, int *, int *, int *);
@@ -121,7 +114,7 @@ const int *{{ model.name }}_gnsf_phi_jac_y_uhat_sparsity_in(int);
const int *{{ model.name }}_gnsf_phi_jac_y_uhat_sparsity_out(int);
int {{ model.name }}_gnsf_phi_jac_y_uhat_n_in(void);
int {{ model.name }}_gnsf_phi_jac_y_uhat_n_out(void);
-
+ {% if model.gnsf.nontrivial_f_LO == 1 %}
// f_lo_fun_jac_x1k1uz
int {{ model.name }}_gnsf_f_lo_fun_jac_x1k1uz(const double** arg, double** res, int* iw, double* w, void *mem);
int {{ model.name }}_gnsf_f_lo_fun_jac_x1k1uz_work(int *, int *, int *, int *);
@@ -129,6 +122,15 @@ const int *{{ model.name }}_gnsf_f_lo_fun_jac_x1k1uz_sparsity_in(int);
const int *{{ model.name }}_gnsf_f_lo_fun_jac_x1k1uz_sparsity_out(int);
int {{ model.name }}_gnsf_f_lo_fun_jac_x1k1uz_n_in(void);
int {{ model.name }}_gnsf_f_lo_fun_jac_x1k1uz_n_out(void);
+ {%- endif %}
+ {%- endif %}
+// used to import model matrices
+int {{ model.name }}_gnsf_get_matrices_fun(const double** arg, double** res, int* iw, double* w, void *mem);
+int {{ model.name }}_gnsf_get_matrices_fun_work(int *, int *, int *, int *);
+const int *{{ model.name }}_gnsf_get_matrices_fun_sparsity_in(int);
+const int *{{ model.name }}_gnsf_get_matrices_fun_sparsity_out(int);
+int {{ model.name }}_gnsf_get_matrices_fun_n_in(void);
+int {{ model.name }}_gnsf_get_matrices_fun_n_out(void);
{% elif solver_options.integrator_type == "ERK" %}
/* explicit ODE */
diff --git a/pyextra/acados_template/utils.py b/pyextra/acados_template/utils.py
index bf8ae4d5db..a60e99fc75 100644
--- a/pyextra/acados_template/utils.py
+++ b/pyextra/acados_template/utils.py
@@ -254,22 +254,6 @@ def format_class_dict(d):
return out
-def acados_class2dict(class_instance):
- """
- removes the __ artifact from class to dict conversion
- """
-
- d = dict(class_instance.__dict__)
- out = {}
- for k, v in d.items():
- if isinstance(v, dict):
- v = format_class_dict(v)
-
- out_key = k.split('__', 1)[-1]
- out[k.replace(k, out_key)] = v
- return out
-
-
def get_ocp_nlp_layout():
python_interface_path = get_python_interface_path()
abs_path = os.path.join(python_interface_path, 'acados_layout.json')
@@ -433,6 +417,13 @@ def set_up_imported_gnsf_model(acados_formulation):
acados_formulation.model.phi_jac_y_uhat = phi_jac_y_uhat
acados_formulation.model.get_matrices_fun = get_matrices_fun
+ # get_matrices_fun = Function([model_name,'_gnsf_get_matrices_fun'], {dummy},...
+ # {A, B, C, E, L_x, L_xdot, L_z, L_u, A_LO, c, E_LO, B_LO,...
+ # nontrivial_f_LO, purely_linear, ipiv_x, ipiv_z, c_LO});
+ get_matrices_out = get_matrices_fun(0)
+ acados_formulation.model.gnsf['nontrivial_f_LO'] = int(get_matrices_out[12])
+ acados_formulation.model.gnsf['purely_linear'] = int(get_matrices_out[13])
+
if "f_lo_fun_jac_x1k1uz" in gnsf:
f_lo_fun_jac_x1k1uz = Function.deserialize(gnsf['f_lo_fun_jac_x1k1uz'])
acados_formulation.model.f_lo_fun_jac_x1k1uz = f_lo_fun_jac_x1k1uz
diff --git a/rednose_repo b/rednose_repo
index 5b526a8e00..7663289f1e 160000
--- a/rednose_repo
+++ b/rednose_repo
@@ -1 +1 @@
-Subproject commit 5b526a8e00bdc1c3922be470af1602cf9dc72dde
+Subproject commit 7663289f1e68860f53dc34337ef080dde69a2586
diff --git a/release/files_common b/release/files_common
index cfc8150e3b..d2d5f14ae4 100644
--- a/release/files_common
+++ b/release/files_common
@@ -17,6 +17,7 @@ site_scons/site_tools/cython.py
common/.gitignore
common/__init__.py
+common/conversions.py
common/gpio.py
common/realtime.py
common/clock.pyx
@@ -58,7 +59,6 @@ common/transformations/transformations.pyx
common/api/__init__.py
models/supercombo.dlc
-models/big_supercombo.dlc
models/dmonitoring_model_q.dlc
release/*
@@ -70,12 +70,10 @@ installer/updater/updater
selfdrive/version.py
selfdrive/__init__.py
-selfdrive/config.py
selfdrive/sentry.py
selfdrive/swaglog.py
selfdrive/logmessaged.py
selfdrive/tombstoned.py
-selfdrive/pandad.py
selfdrive/updated.py
selfdrive/rtshield.py
selfdrive/statsd.py
@@ -99,6 +97,7 @@ selfdrive/boardd/panda.h
selfdrive/boardd/pigeon.cc
selfdrive/boardd/pigeon.h
selfdrive/boardd/set_time.py
+selfdrive/boardd/pandad.py
selfdrive/car/__init__.py
selfdrive/car/car_helpers.py
@@ -337,11 +336,11 @@ selfdrive/sensord/sensord
selfdrive/thermald/thermald.py
selfdrive/thermald/power_monitoring.py
+selfdrive/thermald/fan_controller.py
selfdrive/test/__init__.py
selfdrive/test/helpers.py
selfdrive/test/setup_device_ci.sh
-selfdrive/test/test_fingerprints.py
selfdrive/test/test_onroad.py
selfdrive/ui/.gitignore
@@ -424,6 +423,7 @@ selfdrive/modeld/transforms/transform.cc
selfdrive/modeld/transforms/transform.h
selfdrive/modeld/transforms/transform.cl
+selfdrive/modeld/thneed/*.py
selfdrive/modeld/thneed/thneed.*
selfdrive/modeld/thneed/serialize.cc
selfdrive/modeld/thneed/compile.cc
diff --git a/selfdrive/athena/athenad.py b/selfdrive/athena/athenad.py
index 7250754d54..1bb99bf2d1 100755
--- a/selfdrive/athena/athenad.py
+++ b/selfdrive/athena/athenad.py
@@ -163,8 +163,6 @@ def upload_handler(end_event: threading.Event) -> None:
sm = messaging.SubMaster(['deviceState'])
tid = threading.get_ident()
- cellular_unmetered = Params().get_bool("CellularUnmetered")
-
while not end_event.is_set():
cur_upload_items[tid] = None
@@ -181,46 +179,45 @@ def upload_handler(end_event: threading.Event) -> None:
cloudlog.event("athena.upload_handler.expired", item=cur_upload_items[tid], error=True)
continue
- # Check if uploading over cell is allowed
+ # Check if uploading over metered connection is allowed
sm.update(0)
- cell = sm['deviceState'].networkType not in [NetworkType.wifi, NetworkType.ethernet]
- if cell and (not cur_upload_items[tid].allow_cellular) and (not cellular_unmetered):
+ metered = sm['deviceState'].networkMetered
+ network_type = sm['deviceState'].networkType.raw
+ if metered and (not cur_upload_items[tid].allow_cellular):
retry_upload(tid, end_event, False)
continue
try:
def cb(sz, cur):
- # Abort transfer if connection changed to cell after starting upload
+ # Abort transfer if connection changed to metered after starting upload
sm.update(0)
- cell = sm['deviceState'].networkType not in [NetworkType.wifi, NetworkType.ethernet]
- if cell and (not cur_upload_items[tid].allow_cellular) and (not cellular_unmetered):
+ metered = sm['deviceState'].networkMetered
+ if metered and (not cur_upload_items[tid].allow_cellular):
raise AbortTransferException
cur_upload_items[tid] = cur_upload_items[tid]._replace(progress=cur / sz if sz else 1)
-
- network_type = sm['deviceState'].networkType.raw
fn = cur_upload_items[tid].path
try:
sz = os.path.getsize(fn)
except OSError:
sz = -1
- cloudlog.event("athena.upload_handler.upload_start", fn=fn, sz=sz, network_type=network_type)
+ cloudlog.event("athena.upload_handler.upload_start", fn=fn, sz=sz, network_type=network_type, metered=metered)
response = _do_upload(cur_upload_items[tid], cb)
if response.status_code not in (200, 201, 403, 412):
- cloudlog.event("athena.upload_handler.retry", status_code=response.status_code, fn=fn, sz=sz, network_type=network_type)
+ cloudlog.event("athena.upload_handler.retry", status_code=response.status_code, fn=fn, sz=sz, network_type=network_type, metered=metered)
retry_upload(tid, end_event)
else:
- cloudlog.event("athena.upload_handler.success", fn=fn, sz=sz, network_type=network_type)
+ cloudlog.event("athena.upload_handler.success", fn=fn, sz=sz, network_type=network_type, metered=metered)
UploadQueueCache.cache(upload_queue)
except (requests.exceptions.Timeout, requests.exceptions.ConnectionError, requests.exceptions.SSLError):
- cloudlog.event("athena.upload_handler.timeout", fn=fn, sz=sz, network_type=network_type)
+ cloudlog.event("athena.upload_handler.timeout", fn=fn, sz=sz, network_type=network_type, metered=metered)
retry_upload(tid, end_event)
except AbortTransferException:
- cloudlog.event("athena.upload_handler.abort", fn=fn, sz=sz, network_type=network_type)
+ cloudlog.event("athena.upload_handler.abort", fn=fn, sz=sz, network_type=network_type, metered=metered)
retry_upload(tid, end_event, False)
except queue.Empty:
@@ -459,6 +456,12 @@ def getNetworkType():
return HARDWARE.get_network_type()
+@dispatcher.add_method
+def getNetworkMetered():
+ network_type = HARDWARE.get_network_type()
+ return HARDWARE.get_network_metered(network_type)
+
+
@dispatcher.add_method
def getNetworks():
return HARDWARE.get_networks()
diff --git a/selfdrive/boardd/boardd.cc b/selfdrive/boardd/boardd.cc
index d7e1adf1eb..9ae00d4e90 100644
--- a/selfdrive/boardd/boardd.cc
+++ b/selfdrive/boardd/boardd.cc
@@ -371,7 +371,7 @@ std::optional send_panda_states(PubMaster *pm, const std::vector
size_t j = 0;
for (size_t f = size_t(cereal::PandaState::FaultType::RELAY_MALFUNCTION);
- f <= size_t(cereal::PandaState::FaultType::INTERRUPT_RATE_TICK); f++) {
+ f <= size_t(cereal::PandaState::FaultType::INTERRUPT_RATE_EXTI); f++) {
if (fault_bits.test(f)) {
faults.set(j, cereal::PandaState::FaultType(f));
j++;
diff --git a/selfdrive/boardd/panda.cc b/selfdrive/boardd/panda.cc
index 5e621b12cd..4a7af2b718 100644
--- a/selfdrive/boardd/panda.cc
+++ b/selfdrive/boardd/panda.cc
@@ -338,6 +338,10 @@ void Panda::set_power_saving(bool power_saving) {
usb_write(0xe7, power_saving, 0);
}
+void Panda::enable_deepsleep() {
+ usb_write(0xfb, 0, 0);
+}
+
void Panda::set_usb_power_mode(cereal::PeripheralState::UsbPowerMode power_mode) {
usb_write(0xe6, (uint16_t)power_mode, 0);
}
diff --git a/selfdrive/boardd/panda.h b/selfdrive/boardd/panda.h
index dbd866adf4..279c96a6a6 100644
--- a/selfdrive/boardd/panda.h
+++ b/selfdrive/boardd/panda.h
@@ -85,6 +85,7 @@ class Panda {
std::optional> get_firmware_version();
std::optional get_serial();
void set_power_saving(bool power_saving);
+ void enable_deepsleep();
void set_usb_power_mode(cereal::PeripheralState::UsbPowerMode power_mode);
void send_heartbeat(bool engaged);
void set_can_speed_kbps(uint16_t bus, uint16_t speed);
diff --git a/selfdrive/pandad.py b/selfdrive/boardd/pandad.py
similarity index 100%
rename from selfdrive/pandad.py
rename to selfdrive/boardd/pandad.py
diff --git a/selfdrive/camerad/cameras/camera_common.cc b/selfdrive/camerad/cameras/camera_common.cc
index f534cad99c..20edab14ea 100644
--- a/selfdrive/camerad/cameras/camera_common.cc
+++ b/selfdrive/camerad/cameras/camera_common.cc
@@ -161,6 +161,8 @@ bool CameraBuf::acquire() {
cl_mem camrabuf_cl = camera_bufs[cur_buf_idx].buf_cl;
cl_event event;
+ float start_time = millis_since_boot();
+
if (debayer) {
float gain = 0.0;
@@ -181,6 +183,8 @@ bool CameraBuf::acquire() {
cur_yuv_buf = vipc_server->get_buffer(yuv_type);
rgb2yuv->queue(q, cur_rgb_buf->buf_cl, cur_yuv_buf->buf_cl);
+ cur_frame_data.processing_time = (millis_since_boot() - start_time) / 1000.0;
+
VisionIpcBufExtra extra = {
cur_frame_data.frame_id,
cur_frame_data.timestamp_sof,
@@ -219,6 +223,7 @@ void fill_frame_data(cereal::FrameData::Builder &framed, const FrameMetadata &fr
framed.setLensPos(frame_data.lens_pos);
framed.setLensErr(frame_data.lens_err);
framed.setLensTruePos(frame_data.lens_true_pos);
+ framed.setProcessingTime(frame_data.processing_time);
}
kj::Array get_frame_image(const CameraBuf *b) {
diff --git a/selfdrive/camerad/cameras/camera_common.h b/selfdrive/camerad/cameras/camera_common.h
index c2d2904f54..d3cdc67b91 100644
--- a/selfdrive/camerad/cameras/camera_common.h
+++ b/selfdrive/camerad/cameras/camera_common.h
@@ -75,6 +75,8 @@ typedef struct FrameMetadata {
unsigned int lens_pos;
float lens_err;
float lens_true_pos;
+
+ float processing_time;
} FrameMetadata;
typedef struct CameraExpInfo {
diff --git a/selfdrive/camerad/cameras/camera_qcom.cc b/selfdrive/camerad/cameras/camera_qcom.cc
index da01b94177..411ff0aec4 100644
--- a/selfdrive/camerad/cameras/camera_qcom.cc
+++ b/selfdrive/camerad/cameras/camera_qcom.cc
@@ -211,12 +211,12 @@ void cameras_init(VisionIpcServer *v, MultiCameraState *s, cl_device_id device_i
/*fps*/ 20,
#endif
device_id, ctx,
- VISION_STREAM_RGB_BACK, VISION_STREAM_ROAD);
+ VISION_STREAM_RGB_ROAD, VISION_STREAM_ROAD);
camera_init(v, &s->driver_cam, CAMERA_ID_OV8865, 1,
/*pixel_clock=*/72000000, /*line_length_pclk=*/1602,
/*max_gain=*/510, 10, device_id, ctx,
- VISION_STREAM_RGB_FRONT, VISION_STREAM_DRIVER);
+ VISION_STREAM_RGB_DRIVER, VISION_STREAM_DRIVER);
s->sm = new SubMaster({"driverState"});
s->pm = new PubMaster({"roadCameraState", "driverCameraState", "thumbnail"});
diff --git a/selfdrive/camerad/cameras/camera_qcom2.cc b/selfdrive/camerad/cameras/camera_qcom2.cc
index f75e982be2..2e810e4202 100644
--- a/selfdrive/camerad/cameras/camera_qcom2.cc
+++ b/selfdrive/camerad/cameras/camera_qcom2.cc
@@ -26,7 +26,7 @@ extern ExitHandler do_exit;
const size_t FRAME_WIDTH = 1928;
const size_t FRAME_HEIGHT = 1208;
-const size_t FRAME_STRIDE = 2416; // for 10 bit output
+const size_t FRAME_STRIDE = 2896; // for 12 bit output. 1928 * 12 / 8 + 4 (alignment)
const int MIPI_SETTLE_CNT = 33; // Calculated by camera_freqs.py
@@ -56,7 +56,7 @@ const int EXPOSURE_TIME_MIN = 2; // with HDR, fastest ss
const int EXPOSURE_TIME_MAX = 1904; // with HDR, slowest ss
// ************** low level camera helpers ****************
-int cam_control(int fd, int op_code, void *handle, int size) {
+int do_cam_control(int fd, int op_code, void *handle, int size) {
struct cam_control camcontrol = {0};
camcontrol.op_code = op_code;
camcontrol.handle = (uint64_t)handle;
@@ -83,7 +83,7 @@ std::optional device_acquire(int fd, int32_t session_handle, void *data
.num_resources = (uint32_t)(data ? 1 : 0),
.resource_hdl = (uint64_t)data,
};
- int err = cam_control(fd, CAM_ACQUIRE_DEV, &cmd, sizeof(cmd));
+ int err = do_cam_control(fd, CAM_ACQUIRE_DEV, &cmd, sizeof(cmd));
return err == 0 ? std::make_optional(cmd.dev_handle) : std::nullopt;
};
@@ -93,13 +93,13 @@ int device_config(int fd, int32_t session_handle, int32_t dev_handle, uint64_t p
.dev_handle = dev_handle,
.packet_handle = packet_handle,
};
- return cam_control(fd, CAM_CONFIG_DEV, &cmd, sizeof(cmd));
+ return do_cam_control(fd, CAM_CONFIG_DEV, &cmd, sizeof(cmd));
}
int device_control(int fd, int op_code, int session_handle, int dev_handle) {
// start stop and release are all the same
struct cam_start_stop_dev_cmd cmd { .session_handle = session_handle, .dev_handle = dev_handle };
- return cam_control(fd, op_code, &cmd, sizeof(cmd));
+ return do_cam_control(fd, op_code, &cmd, sizeof(cmd));
}
void *alloc_w_mmu_hdl(int video0_fd, int len, uint32_t *handle, int align = 8, int flags = CAM_MEM_FLAG_KMD_ACCESS | CAM_MEM_FLAG_UMD_ACCESS | CAM_MEM_FLAG_CMD_BUF_TYPE,
@@ -118,7 +118,7 @@ void *alloc_w_mmu_hdl(int video0_fd, int len, uint32_t *handle, int align = 8, i
mem_mgr_alloc_cmd.num_hdl++;
}
- cam_control(video0_fd, CAM_REQ_MGR_ALLOC_BUF, &mem_mgr_alloc_cmd, sizeof(mem_mgr_alloc_cmd));
+ do_cam_control(video0_fd, CAM_REQ_MGR_ALLOC_BUF, &mem_mgr_alloc_cmd, sizeof(mem_mgr_alloc_cmd));
*handle = mem_mgr_alloc_cmd.out.buf_handle;
void *ptr = NULL;
@@ -137,7 +137,7 @@ void release(int video0_fd, uint32_t handle) {
struct cam_mem_mgr_release_cmd mem_mgr_release_cmd = {0};
mem_mgr_release_cmd.buf_handle = handle;
- ret = cam_control(video0_fd, CAM_REQ_MGR_RELEASE_BUF, &mem_mgr_release_cmd, sizeof(mem_mgr_release_cmd));
+ ret = do_cam_control(video0_fd, CAM_REQ_MGR_RELEASE_BUF, &mem_mgr_release_cmd, sizeof(mem_mgr_release_cmd));
assert(ret == 0);
}
@@ -153,34 +153,39 @@ void clear_req_queue(int fd, int32_t session_hdl, int32_t link_hdl) {
req_mgr_flush_request.link_hdl = link_hdl;
req_mgr_flush_request.flush_type = CAM_REQ_MGR_FLUSH_TYPE_ALL;
int ret;
- ret = cam_control(fd, CAM_REQ_MGR_FLUSH_REQ, &req_mgr_flush_request, sizeof(req_mgr_flush_request));
+ ret = do_cam_control(fd, CAM_REQ_MGR_FLUSH_REQ, &req_mgr_flush_request, sizeof(req_mgr_flush_request));
// LOGD("flushed all req: %d", ret);
}
// ************** high level camera helpers ****************
-void sensors_poke(struct CameraState *s, int request_id) {
+void CameraState::sensors_start() {
+ int start_reg_len = sizeof(start_reg_array) / sizeof(struct i2c_random_wr_payload);
+ sensors_i2c(start_reg_array, start_reg_len, CAM_SENSOR_PACKET_OPCODE_SENSOR_CONFIG);
+}
+
+void CameraState::sensors_poke(int request_id) {
uint32_t cam_packet_handle = 0;
int size = sizeof(struct cam_packet);
- struct cam_packet *pkt = (struct cam_packet *)alloc_w_mmu_hdl(s->multi_cam_state->video0_fd, size, &cam_packet_handle);
+ struct cam_packet *pkt = (struct cam_packet *)alloc_w_mmu_hdl(multi_cam_state->video0_fd, size, &cam_packet_handle);
pkt->num_cmd_buf = 0;
pkt->kmd_cmd_buf_index = -1;
pkt->header.size = size;
pkt->header.op_code = 0x7f;
pkt->header.request_id = request_id;
- int ret = device_config(s->sensor_fd, s->session_handle, s->sensor_dev_handle, cam_packet_handle);
+ int ret = device_config(sensor_fd, session_handle, sensor_dev_handle, cam_packet_handle);
assert(ret == 0);
munmap(pkt, size);
- release_fd(s->multi_cam_state->video0_fd, cam_packet_handle);
+ release_fd(multi_cam_state->video0_fd, cam_packet_handle);
}
-void sensors_i2c(struct CameraState *s, struct i2c_random_wr_payload* dat, int len, int op_code) {
+void CameraState::sensors_i2c(struct i2c_random_wr_payload* dat, int len, int op_code) {
// LOGD("sensors_i2c: %d", len);
uint32_t cam_packet_handle = 0;
int size = sizeof(struct cam_packet)+sizeof(struct cam_cmd_buf_desc)*1;
- struct cam_packet *pkt = (struct cam_packet *)alloc_w_mmu_hdl(s->multi_cam_state->video0_fd, size, &cam_packet_handle);
+ struct cam_packet *pkt = (struct cam_packet *)alloc_w_mmu_hdl(multi_cam_state->video0_fd, size, &cam_packet_handle);
pkt->num_cmd_buf = 1;
pkt->kmd_cmd_buf_index = -1;
pkt->header.size = size;
@@ -190,7 +195,7 @@ void sensors_i2c(struct CameraState *s, struct i2c_random_wr_payload* dat, int l
buf_desc[0].size = buf_desc[0].length = sizeof(struct i2c_rdwr_header) + len*sizeof(struct i2c_random_wr_payload);
buf_desc[0].type = CAM_CMD_BUF_I2C;
- struct cam_cmd_i2c_random_wr *i2c_random_wr = (struct cam_cmd_i2c_random_wr *)alloc_w_mmu_hdl(s->multi_cam_state->video0_fd, buf_desc[0].size, (uint32_t*)&buf_desc[0].mem_handle);
+ struct cam_cmd_i2c_random_wr *i2c_random_wr = (struct cam_cmd_i2c_random_wr *)alloc_w_mmu_hdl(multi_cam_state->video0_fd, buf_desc[0].size, (uint32_t*)&buf_desc[0].mem_handle);
i2c_random_wr->header.count = len;
i2c_random_wr->header.op_code = 1;
i2c_random_wr->header.cmd_type = CAMERA_SENSOR_CMD_TYPE_I2C_RNDM_WR;
@@ -198,14 +203,15 @@ void sensors_i2c(struct CameraState *s, struct i2c_random_wr_payload* dat, int l
i2c_random_wr->header.addr_type = CAMERA_SENSOR_I2C_TYPE_WORD;
memcpy(i2c_random_wr->random_wr_payload, dat, len*sizeof(struct i2c_random_wr_payload));
- int ret = device_config(s->sensor_fd, s->session_handle, s->sensor_dev_handle, cam_packet_handle);
+ int ret = device_config(sensor_fd, session_handle, sensor_dev_handle, cam_packet_handle);
assert(ret == 0);
munmap(i2c_random_wr, buf_desc[0].size);
- release_fd(s->multi_cam_state->video0_fd, buf_desc[0].mem_handle);
+ release_fd(multi_cam_state->video0_fd, buf_desc[0].mem_handle);
munmap(pkt, size);
- release_fd(s->multi_cam_state->video0_fd, cam_packet_handle);
+ release_fd(multi_cam_state->video0_fd, cam_packet_handle);
}
+
static cam_cmd_power *power_set_wait(cam_cmd_power *power, int16_t delay_ms) {
cam_cmd_unconditional_wait *unconditional_wait = (cam_cmd_unconditional_wait *)((char *)power + (sizeof(struct cam_cmd_power) + (power->count - 1) * sizeof(struct cam_power_settings)));
unconditional_wait->cmd_type = CAMERA_SENSOR_CMD_TYPE_WAIT;
@@ -214,7 +220,8 @@ static cam_cmd_power *power_set_wait(cam_cmd_power *power, int16_t delay_ms) {
return (struct cam_cmd_power *)(unconditional_wait + 1);
};
-void sensors_init(int video0_fd, int sensor_fd, int camera_num) {
+void CameraState::sensors_init() {
+ int video0_fd = multi_cam_state->video0_fd;
uint32_t cam_packet_handle = 0;
int size = sizeof(struct cam_packet)+sizeof(struct cam_cmd_buf_desc)*2;
struct cam_packet *pkt = (struct cam_packet *)alloc_w_mmu_hdl(video0_fd, size, &cam_packet_handle);
@@ -333,7 +340,7 @@ void sensors_init(int video0_fd, int sensor_fd, int camera_num) {
power->power_settings[2].power_seq_type = 3;
LOGD("probing the sensor");
- int ret = cam_control(sensor_fd, CAM_SENSOR_PROBE_CMD, (void *)(uintptr_t)cam_packet_handle, 0);
+ int ret = do_cam_control(sensor_fd, CAM_SENSOR_PROBE_CMD, (void *)(uintptr_t)cam_packet_handle, 0);
assert(ret == 0);
munmap(i2c_info, buf_desc[0].size);
@@ -344,13 +351,13 @@ void sensors_init(int video0_fd, int sensor_fd, int camera_num) {
release_fd(video0_fd, cam_packet_handle);
}
-void config_isp(struct CameraState *s, int io_mem_handle, int fence, int request_id, int buf0_mem_handle, int buf0_offset) {
+void CameraState::config_isp(int io_mem_handle, int fence, int request_id, int buf0_mem_handle, int buf0_offset) {
uint32_t cam_packet_handle = 0;
int size = sizeof(struct cam_packet)+sizeof(struct cam_cmd_buf_desc)*2;
if (io_mem_handle != 0) {
size += sizeof(struct cam_buf_io_cfg);
}
- struct cam_packet *pkt = (struct cam_packet *)alloc_w_mmu_hdl(s->multi_cam_state->video0_fd, size, &cam_packet_handle);
+ struct cam_packet *pkt = (struct cam_packet *)alloc_w_mmu_hdl(multi_cam_state->video0_fd, size, &cam_packet_handle);
pkt->num_cmd_buf = 2;
pkt->kmd_cmd_buf_index = 0;
// YUV has kmd_cmd_buf_offset = 1780
@@ -445,7 +452,7 @@ void config_isp(struct CameraState *s, int io_mem_handle, int fence, int request
buf_desc[1].length = buf_desc[1].size - buf_desc[1].offset;
buf_desc[1].type = CAM_CMD_BUF_GENERIC;
buf_desc[1].meta_data = CAM_ISP_PACKET_META_GENERIC_BLOB_COMMON;
- uint32_t *buf2 = (uint32_t *)alloc_w_mmu_hdl(s->multi_cam_state->video0_fd, buf_desc[1].size, (uint32_t*)&buf_desc[1].mem_handle, 0x20);
+ uint32_t *buf2 = (uint32_t *)alloc_w_mmu_hdl(multi_cam_state->video0_fd, buf_desc[1].size, (uint32_t*)&buf_desc[1].mem_handle, 0x20);
memcpy(buf2, &tmp, sizeof(tmp));
if (io_mem_handle != 0) {
@@ -464,10 +471,10 @@ void config_isp(struct CameraState *s, int io_mem_handle, int fence, int request
.h_init = 0x0,
.v_init = 0x0,
};
- io_cfg[0].format = CAM_FORMAT_MIPI_RAW_10; // CAM_FORMAT_UBWC_TP10 for YUV
+ io_cfg[0].format = CAM_FORMAT_MIPI_RAW_12; // CAM_FORMAT_UBWC_TP10 for YUV
io_cfg[0].color_space = CAM_COLOR_SPACE_BASE; // CAM_COLOR_SPACE_BT601_FULL for YUV
io_cfg[0].color_pattern = 0x5; // 0x0 for YUV
- io_cfg[0].bpp = 0xa;
+ io_cfg[0].bpp = 0xc;
io_cfg[0].resource_type = CAM_ISP_IFE_OUT_RES_RDI_0; // CAM_ISP_IFE_OUT_RES_FULL for YUV
io_cfg[0].fence = fence;
io_cfg[0].direction = CAM_BUF_OUTPUT;
@@ -475,142 +482,141 @@ void config_isp(struct CameraState *s, int io_mem_handle, int fence, int request
io_cfg[0].framedrop_pattern = 0x1;
}
- int ret = device_config(s->multi_cam_state->isp_fd, s->session_handle, s->isp_dev_handle, cam_packet_handle);
+ int ret = device_config(multi_cam_state->isp_fd, session_handle, isp_dev_handle, cam_packet_handle);
assert(ret == 0);
if (ret != 0) {
printf("ISP CONFIG FAILED\n");
}
munmap(buf2, buf_desc[1].size);
- release_fd(s->multi_cam_state->video0_fd, buf_desc[1].mem_handle);
- // release_fd(s->multi_cam_state->video0_fd, buf_desc[0].mem_handle);
+ release_fd(multi_cam_state->video0_fd, buf_desc[1].mem_handle);
+ // release_fd(multi_cam_state->video0_fd, buf_desc[0].mem_handle);
munmap(pkt, size);
- release_fd(s->multi_cam_state->video0_fd, cam_packet_handle);
+ release_fd(multi_cam_state->video0_fd, cam_packet_handle);
}
-void enqueue_buffer(struct CameraState *s, int i, bool dp) {
+void CameraState::enqueue_buffer(int i, bool dp) {
int ret;
- int request_id = s->request_ids[i];
+ int request_id = request_ids[i];
- if (s->buf_handle[i]) {
- release(s->multi_cam_state->video0_fd, s->buf_handle[i]);
+ if (buf_handle[i]) {
+ release(multi_cam_state->video0_fd, buf_handle[i]);
// wait
struct cam_sync_wait sync_wait = {0};
- sync_wait.sync_obj = s->sync_objs[i];
+ sync_wait.sync_obj = sync_objs[i];
sync_wait.timeout_ms = 50; // max dt tolerance, typical should be 23
- ret = cam_control(s->multi_cam_state->video1_fd, CAM_SYNC_WAIT, &sync_wait, sizeof(sync_wait));
+ ret = do_cam_control(multi_cam_state->video1_fd, CAM_SYNC_WAIT, &sync_wait, sizeof(sync_wait));
// LOGD("fence wait: %d %d", ret, sync_wait.sync_obj);
- s->buf.camera_bufs_metadata[i].timestamp_eof = (uint64_t)nanos_since_boot(); // set true eof
- if (dp) s->buf.queue(i);
+ buf.camera_bufs_metadata[i].timestamp_eof = (uint64_t)nanos_since_boot(); // set true eof
+ if (dp) buf.queue(i);
// destroy old output fence
struct cam_sync_info sync_destroy = {0};
strcpy(sync_destroy.name, "NodeOutputPortFence");
- sync_destroy.sync_obj = s->sync_objs[i];
- ret = cam_control(s->multi_cam_state->video1_fd, CAM_SYNC_DESTROY, &sync_destroy, sizeof(sync_destroy));
+ sync_destroy.sync_obj = sync_objs[i];
+ ret = do_cam_control(multi_cam_state->video1_fd, CAM_SYNC_DESTROY, &sync_destroy, sizeof(sync_destroy));
// LOGD("fence destroy: %d %d", ret, sync_destroy.sync_obj);
}
// do stuff
struct cam_req_mgr_sched_request req_mgr_sched_request = {0};
- req_mgr_sched_request.session_hdl = s->session_handle;
- req_mgr_sched_request.link_hdl = s->link_handle;
+ req_mgr_sched_request.session_hdl = session_handle;
+ req_mgr_sched_request.link_hdl = link_handle;
req_mgr_sched_request.req_id = request_id;
- ret = cam_control(s->multi_cam_state->video0_fd, CAM_REQ_MGR_SCHED_REQ, &req_mgr_sched_request, sizeof(req_mgr_sched_request));
+ ret = do_cam_control(multi_cam_state->video0_fd, CAM_REQ_MGR_SCHED_REQ, &req_mgr_sched_request, sizeof(req_mgr_sched_request));
// LOGD("sched req: %d %d", ret, request_id);
// create output fence
struct cam_sync_info sync_create = {0};
strcpy(sync_create.name, "NodeOutputPortFence");
- ret = cam_control(s->multi_cam_state->video1_fd, CAM_SYNC_CREATE, &sync_create, sizeof(sync_create));
+ ret = do_cam_control(multi_cam_state->video1_fd, CAM_SYNC_CREATE, &sync_create, sizeof(sync_create));
// LOGD("fence req: %d %d", ret, sync_create.sync_obj);
- s->sync_objs[i] = sync_create.sync_obj;
+ sync_objs[i] = sync_create.sync_obj;
// configure ISP to put the image in place
struct cam_mem_mgr_map_cmd mem_mgr_map_cmd = {0};
- mem_mgr_map_cmd.mmu_hdls[0] = s->multi_cam_state->device_iommu;
+ mem_mgr_map_cmd.mmu_hdls[0] = multi_cam_state->device_iommu;
mem_mgr_map_cmd.num_hdl = 1;
mem_mgr_map_cmd.flags = CAM_MEM_FLAG_HW_READ_WRITE;
- mem_mgr_map_cmd.fd = s->buf.camera_bufs[i].fd;
- ret = cam_control(s->multi_cam_state->video0_fd, CAM_REQ_MGR_MAP_BUF, &mem_mgr_map_cmd, sizeof(mem_mgr_map_cmd));
- // LOGD("map buf req: (fd: %d) 0x%x %d", s->bufs[i].fd, mem_mgr_map_cmd.out.buf_handle, ret);
- s->buf_handle[i] = mem_mgr_map_cmd.out.buf_handle;
+ mem_mgr_map_cmd.fd = buf.camera_bufs[i].fd;
+ ret = do_cam_control(multi_cam_state->video0_fd, CAM_REQ_MGR_MAP_BUF, &mem_mgr_map_cmd, sizeof(mem_mgr_map_cmd));
+ // LOGD("map buf req: (fd: %d) 0x%x %d", bufs[i].fd, mem_mgr_map_cmd.out.buf_handle, ret);
+ buf_handle[i] = mem_mgr_map_cmd.out.buf_handle;
// poke sensor
- sensors_poke(s, request_id);
+ sensors_poke(request_id);
// LOGD("Poked sensor");
// push the buffer
- config_isp(s, s->buf_handle[i], s->sync_objs[i], request_id, s->buf0_handle, 65632*(i+1));
+ config_isp(buf_handle[i], sync_objs[i], request_id, buf0_handle, 65632*(i+1));
}
-void enqueue_req_multi(struct CameraState *s, int start, int n, bool dp) {
+void CameraState::enqueue_req_multi(int start, int n, bool dp) {
for (int i=start;irequest_ids[(i - 1) % FRAME_BUF_COUNT] = i;
- enqueue_buffer(s, (i - 1) % FRAME_BUF_COUNT, dp);
+ request_ids[(i - 1) % FRAME_BUF_COUNT] = i;
+ enqueue_buffer((i - 1) % FRAME_BUF_COUNT, dp);
}
}
// ******************* camera *******************
-static void camera_init(MultiCameraState *multi_cam_state, VisionIpcServer * v, CameraState *s, int camera_id, int camera_num, unsigned int fps, cl_device_id device_id, cl_context ctx, VisionStreamType rgb_type, VisionStreamType yuv_type) {
+void CameraState::camera_init(MultiCameraState *multi_cam_state_, VisionIpcServer * v, int camera_id, int camera_num_, unsigned int fps, cl_device_id device_id, cl_context ctx, VisionStreamType rgb_type, VisionStreamType yuv_type) {
LOGD("camera init %d", camera_num);
- s->multi_cam_state = multi_cam_state;
+ multi_cam_state = multi_cam_state_;
assert(camera_id < std::size(cameras_supported));
- s->ci = cameras_supported[camera_id];
- assert(s->ci.frame_width != 0);
+ ci = cameras_supported[camera_id];
+ assert(ci.frame_width != 0);
- s->camera_num = camera_num;
+ camera_num = camera_num_;
- s->request_id_last = 0;
- s->skipped = true;
+ request_id_last = 0;
+ skipped = true;
- s->min_ev = EXPOSURE_TIME_MIN * sensor_analog_gains[ANALOG_GAIN_MIN_IDX];
- s->max_ev = EXPOSURE_TIME_MAX * sensor_analog_gains[ANALOG_GAIN_MAX_IDX] * DC_GAIN;
- s->target_grey_fraction = 0.3;
+ min_ev = EXPOSURE_TIME_MIN * sensor_analog_gains[ANALOG_GAIN_MIN_IDX];
+ max_ev = EXPOSURE_TIME_MAX * sensor_analog_gains[ANALOG_GAIN_MAX_IDX] * DC_GAIN;
+ target_grey_fraction = 0.3;
- s->dc_gain_enabled = false;
- s->gain_idx = ANALOG_GAIN_REC_IDX;
- s->exposure_time = 5;
- s->cur_ev[0] = s->cur_ev[1] = s->cur_ev[2] = (s->dc_gain_enabled ? DC_GAIN : 1) * sensor_analog_gains[s->gain_idx] * s->exposure_time;
+ dc_gain_enabled = false;
+ gain_idx = ANALOG_GAIN_REC_IDX;
+ exposure_time = 5;
+ cur_ev[0] = cur_ev[1] = cur_ev[2] = (dc_gain_enabled ? DC_GAIN : 1) * sensor_analog_gains[gain_idx] * exposure_time;
- s->buf.init(device_id, ctx, s, v, FRAME_BUF_COUNT, rgb_type, yuv_type);
+ buf.init(device_id, ctx, this, v, FRAME_BUF_COUNT, rgb_type, yuv_type);
}
-static void camera_open(CameraState *s) {
- s->sensor_fd = open_v4l_by_name_and_index("cam-sensor-driver", s->camera_num);
- assert(s->sensor_fd >= 0);
- LOGD("opened sensor for %d", s->camera_num);
+void CameraState::camera_open() {
+ sensor_fd = open_v4l_by_name_and_index("cam-sensor-driver", camera_num);
+ assert(sensor_fd >= 0);
+ LOGD("opened sensor for %d", camera_num);
// probe the sensor
- LOGD("-- Probing sensor %d", s->camera_num);
- sensors_init(s->multi_cam_state->video0_fd, s->sensor_fd, s->camera_num);
+ LOGD("-- Probing sensor %d", camera_num);
+ sensors_init();
// create session
struct cam_req_mgr_session_info session_info = {};
- int ret = cam_control(s->multi_cam_state->video0_fd, CAM_REQ_MGR_CREATE_SESSION, &session_info, sizeof(session_info));
+ int ret = do_cam_control(multi_cam_state->video0_fd, CAM_REQ_MGR_CREATE_SESSION, &session_info, sizeof(session_info));
LOGD("get session: %d 0x%X", ret, session_info.session_hdl);
- s->session_handle = session_info.session_hdl;
+ session_handle = session_info.session_hdl;
// access the sensor
LOGD("-- Accessing sensor");
- auto sensor_dev_handle = device_acquire(s->sensor_fd, s->session_handle, nullptr);
- assert(sensor_dev_handle);
- s->sensor_dev_handle = *sensor_dev_handle;
+ auto sensor_dev_handle_ = device_acquire(sensor_fd, session_handle, nullptr);
+ assert(sensor_dev_handle_);
+ sensor_dev_handle = *sensor_dev_handle_;
LOGD("acquire sensor dev");
struct cam_isp_in_port_info in_port_info = {
- .res_type = (uint32_t[]){CAM_ISP_IFE_IN_RES_PHY_0, CAM_ISP_IFE_IN_RES_PHY_1, CAM_ISP_IFE_IN_RES_PHY_2}[s->camera_num],
+ .res_type = (uint32_t[]){CAM_ISP_IFE_IN_RES_PHY_0, CAM_ISP_IFE_IN_RES_PHY_1, CAM_ISP_IFE_IN_RES_PHY_2}[camera_num],
.lane_type = CAM_ISP_LANE_TYPE_DPHY,
.lane_num = 4,
.lane_cfg = 0x3210,
.vc = 0x0,
- // .dt = 0x2C; //CSI_RAW12
- .dt = 0x2B, //CSI_RAW10
- .format = CAM_FORMAT_MIPI_RAW_10,
+ .dt = 0x2C, // CSI_RAW12
+ .format = CAM_FORMAT_MIPI_RAW_12,
.test_pattern = 0x2, // 0x3?
.usage_type = 0x0,
@@ -636,7 +642,7 @@ static void camera_open(CameraState *s) {
.num_out_res = 0x1,
.data[0] = (struct cam_isp_out_port_info){
.res_type = CAM_ISP_IFE_OUT_RES_RDI_0,
- .format = CAM_FORMAT_MIPI_RAW_10,
+ .format = CAM_FORMAT_MIPI_RAW_12,
.width = FRAME_WIDTH,
.height = FRAME_HEIGHT,
.comp_grp_id = 0x0, .split_point = 0x0, .secure_mode = 0x0,
@@ -649,29 +655,29 @@ static void camera_open(CameraState *s) {
.length = sizeof(in_port_info),
};
- auto isp_dev_handle = device_acquire(s->multi_cam_state->isp_fd, s->session_handle, &isp_resource);
- assert(isp_dev_handle);
- s->isp_dev_handle = *isp_dev_handle;
+ auto isp_dev_handle_ = device_acquire(multi_cam_state->isp_fd, session_handle, &isp_resource);
+ assert(isp_dev_handle_);
+ isp_dev_handle = *isp_dev_handle_;
LOGD("acquire isp dev");
- s->csiphy_fd = open_v4l_by_name_and_index("cam-csiphy-driver", s->camera_num);
- assert(s->csiphy_fd >= 0);
- LOGD("opened csiphy for %d", s->camera_num);
+ csiphy_fd = open_v4l_by_name_and_index("cam-csiphy-driver", camera_num);
+ assert(csiphy_fd >= 0);
+ LOGD("opened csiphy for %d", camera_num);
struct cam_csiphy_acquire_dev_info csiphy_acquire_dev_info = {.combo_mode = 0};
- auto csiphy_dev_handle = device_acquire(s->csiphy_fd, s->session_handle, &csiphy_acquire_dev_info);
- assert(csiphy_dev_handle);
- s->csiphy_dev_handle = *csiphy_dev_handle;
+ auto csiphy_dev_handle_ = device_acquire(csiphy_fd, session_handle, &csiphy_acquire_dev_info);
+ assert(csiphy_dev_handle_);
+ csiphy_dev_handle = *csiphy_dev_handle_;
LOGD("acquire csiphy dev");
// config ISP
- alloc_w_mmu_hdl(s->multi_cam_state->video0_fd, 984480, (uint32_t*)&s->buf0_handle, 0x20, CAM_MEM_FLAG_HW_READ_WRITE | CAM_MEM_FLAG_KMD_ACCESS | CAM_MEM_FLAG_UMD_ACCESS | CAM_MEM_FLAG_CMD_BUF_TYPE, s->multi_cam_state->device_iommu, s->multi_cam_state->cdm_iommu);
- config_isp(s, 0, 0, 1, s->buf0_handle, 0);
+ alloc_w_mmu_hdl(multi_cam_state->video0_fd, 984480, (uint32_t*)&buf0_handle, 0x20, CAM_MEM_FLAG_HW_READ_WRITE | CAM_MEM_FLAG_KMD_ACCESS | CAM_MEM_FLAG_UMD_ACCESS | CAM_MEM_FLAG_CMD_BUF_TYPE, multi_cam_state->device_iommu, multi_cam_state->cdm_iommu);
+ config_isp(0, 0, 1, buf0_handle, 0);
LOG("-- Configuring sensor");
- sensors_i2c(s, init_array_ar0231, std::size(init_array_ar0231), CAM_SENSOR_PACKET_OPCODE_SENSOR_CONFIG);
- //sensors_i2c(s, start_reg_array, std::size(start_reg_array), CAM_SENSOR_PACKET_OPCODE_SENSOR_STREAMON);
- //sensors_i2c(s, stop_reg_array, std::size(stop_reg_array), CAM_SENSOR_PACKET_OPCODE_SENSOR_STREAMOFF);
+ sensors_i2c(init_array_ar0231, std::size(init_array_ar0231), CAM_SENSOR_PACKET_OPCODE_SENSOR_CONFIG);
+ //sensors_i2c(start_reg_array, std::size(start_reg_array), CAM_SENSOR_PACKET_OPCODE_SENSOR_STREAMON);
+ //sensors_i2c(stop_reg_array, std::size(stop_reg_array), CAM_SENSOR_PACKET_OPCODE_SENSOR_STREAMOFF);
// config csiphy
@@ -679,7 +685,7 @@ static void camera_open(CameraState *s) {
{
uint32_t cam_packet_handle = 0;
int size = sizeof(struct cam_packet)+sizeof(struct cam_cmd_buf_desc)*1;
- struct cam_packet *pkt = (struct cam_packet *)alloc_w_mmu_hdl(s->multi_cam_state->video0_fd, size, &cam_packet_handle);
+ struct cam_packet *pkt = (struct cam_packet *)alloc_w_mmu_hdl(multi_cam_state->video0_fd, size, &cam_packet_handle);
pkt->num_cmd_buf = 1;
pkt->kmd_cmd_buf_index = -1;
pkt->header.size = size;
@@ -688,7 +694,7 @@ static void camera_open(CameraState *s) {
buf_desc[0].size = buf_desc[0].length = sizeof(struct cam_csiphy_info);
buf_desc[0].type = CAM_CMD_BUF_GENERIC;
- struct cam_csiphy_info *csiphy_info = (struct cam_csiphy_info *)alloc_w_mmu_hdl(s->multi_cam_state->video0_fd, buf_desc[0].size, (uint32_t*)&buf_desc[0].mem_handle);
+ struct cam_csiphy_info *csiphy_info = (struct cam_csiphy_info *)alloc_w_mmu_hdl(multi_cam_state->video0_fd, buf_desc[0].size, (uint32_t*)&buf_desc[0].mem_handle);
csiphy_info->lane_mask = 0x1f;
csiphy_info->lane_assign = 0x3210;// skip clk. How is this 16 bit for 5 channels??
csiphy_info->csiphy_3phase = 0x0; // no 3 phase, only 2 conductors per lane
@@ -698,54 +704,51 @@ static void camera_open(CameraState *s) {
csiphy_info->settle_time = MIPI_SETTLE_CNT * 200000000ULL;
csiphy_info->data_rate = 48000000; // Calculated by camera_freqs.py
- int ret_ = device_config(s->csiphy_fd, s->session_handle, s->csiphy_dev_handle, cam_packet_handle);
+ int ret_ = device_config(csiphy_fd, session_handle, csiphy_dev_handle, cam_packet_handle);
assert(ret_ == 0);
munmap(csiphy_info, buf_desc[0].size);
- release_fd(s->multi_cam_state->video0_fd, buf_desc[0].mem_handle);
+ release_fd(multi_cam_state->video0_fd, buf_desc[0].mem_handle);
munmap(pkt, size);
- release_fd(s->multi_cam_state->video0_fd, cam_packet_handle);
+ release_fd(multi_cam_state->video0_fd, cam_packet_handle);
}
// link devices
LOG("-- Link devices");
struct cam_req_mgr_link_info req_mgr_link_info = {0};
- req_mgr_link_info.session_hdl = s->session_handle;
+ req_mgr_link_info.session_hdl = session_handle;
req_mgr_link_info.num_devices = 2;
- req_mgr_link_info.dev_hdls[0] = s->isp_dev_handle;
- req_mgr_link_info.dev_hdls[1] = s->sensor_dev_handle;
- ret = cam_control(s->multi_cam_state->video0_fd, CAM_REQ_MGR_LINK, &req_mgr_link_info, sizeof(req_mgr_link_info));
- s->link_handle = req_mgr_link_info.link_hdl;
- LOGD("link: %d hdl: 0x%X", ret, s->link_handle);
+ req_mgr_link_info.dev_hdls[0] = isp_dev_handle;
+ req_mgr_link_info.dev_hdls[1] = sensor_dev_handle;
+ ret = do_cam_control(multi_cam_state->video0_fd, CAM_REQ_MGR_LINK, &req_mgr_link_info, sizeof(req_mgr_link_info));
+ link_handle = req_mgr_link_info.link_hdl;
+ LOGD("link: %d hdl: 0x%X", ret, link_handle);
struct cam_req_mgr_link_control req_mgr_link_control = {0};
req_mgr_link_control.ops = CAM_REQ_MGR_LINK_ACTIVATE;
- req_mgr_link_control.session_hdl = s->session_handle;
+ req_mgr_link_control.session_hdl = session_handle;
req_mgr_link_control.num_links = 1;
- req_mgr_link_control.link_hdls[0] = s->link_handle;
- ret = cam_control(s->multi_cam_state->video0_fd, CAM_REQ_MGR_LINK_CONTROL, &req_mgr_link_control, sizeof(req_mgr_link_control));
+ req_mgr_link_control.link_hdls[0] = link_handle;
+ ret = do_cam_control(multi_cam_state->video0_fd, CAM_REQ_MGR_LINK_CONTROL, &req_mgr_link_control, sizeof(req_mgr_link_control));
LOGD("link control: %d", ret);
- ret = device_control(s->csiphy_fd, CAM_START_DEV, s->session_handle, s->csiphy_dev_handle);
+ ret = device_control(csiphy_fd, CAM_START_DEV, session_handle, csiphy_dev_handle);
LOGD("start csiphy: %d", ret);
- ret = device_control(s->multi_cam_state->isp_fd, CAM_START_DEV, s->session_handle, s->isp_dev_handle);
+ ret = device_control(multi_cam_state->isp_fd, CAM_START_DEV, session_handle, isp_dev_handle);
LOGD("start isp: %d", ret);
- ret = device_control(s->sensor_fd, CAM_START_DEV, s->session_handle, s->sensor_dev_handle);
+ ret = device_control(sensor_fd, CAM_START_DEV, session_handle, sensor_dev_handle);
LOGD("start sensor: %d", ret);
- enqueue_req_multi(s, 1, FRAME_BUF_COUNT, 0);
+ enqueue_req_multi(1, FRAME_BUF_COUNT, 0);
}
void cameras_init(VisionIpcServer *v, MultiCameraState *s, cl_device_id device_id, cl_context ctx) {
- camera_init(s, v, &s->driver_cam, CAMERA_ID_AR0231, 2, 20, device_id, ctx,
- VISION_STREAM_RGB_FRONT, VISION_STREAM_DRIVER);
+ s->driver_cam.camera_init(s, v, CAMERA_ID_AR0231, 2, 20, device_id, ctx, VISION_STREAM_RGB_DRIVER, VISION_STREAM_DRIVER);
printf("driver camera initted \n");
if (!env_only_driver) {
- camera_init(s, v, &s->road_cam, CAMERA_ID_AR0231, 1, 20, device_id, ctx,
- VISION_STREAM_RGB_BACK, VISION_STREAM_ROAD); // swap left/right
+ s->road_cam.camera_init(s, v, CAMERA_ID_AR0231, 1, 20, device_id, ctx, VISION_STREAM_RGB_ROAD, VISION_STREAM_ROAD); // swap left/right
printf("road camera initted \n");
- camera_init(s, v, &s->wide_road_cam, CAMERA_ID_AR0231, 0, 20, device_id, ctx,
- VISION_STREAM_RGB_WIDE, VISION_STREAM_WIDE_ROAD);
+ s->wide_road_cam.camera_init(s, v, CAMERA_ID_AR0231, 0, 20, device_id, ctx, VISION_STREAM_RGB_WIDE_ROAD, VISION_STREAM_WIDE_ROAD);
printf("wide road camera initted \n");
}
@@ -768,7 +771,7 @@ void cameras_open(MultiCameraState *s) {
LOGD("opened video1");
// looks like there's only one of these
- s->isp_fd = HANDLE_EINTR(open("/dev/v4l-subdev1", O_RDWR | O_NONBLOCK));
+ s->isp_fd = open_v4l_by_name_and_index("cam-isp");
assert(s->isp_fd >= 0);
LOGD("opened isp");
@@ -779,7 +782,7 @@ void cameras_open(MultiCameraState *s) {
query_cap_cmd.handle_type = 1;
query_cap_cmd.caps_handle = (uint64_t)&isp_query_cap_cmd;
query_cap_cmd.size = sizeof(isp_query_cap_cmd);
- ret = cam_control(s->isp_fd, CAM_QUERY_CAP, &query_cap_cmd, sizeof(query_cap_cmd));
+ ret = do_cam_control(s->isp_fd, CAM_QUERY_CAP, &query_cap_cmd, sizeof(query_cap_cmd));
assert(ret == 0);
LOGD("using MMU handle: %x", isp_query_cap_cmd.device_iommu.non_secure);
LOGD("using MMU handle: %x", isp_query_cap_cmd.cdm_iommu.non_secure);
@@ -794,74 +797,72 @@ void cameras_open(MultiCameraState *s) {
ret = HANDLE_EINTR(ioctl(s->video0_fd, VIDIOC_SUBSCRIBE_EVENT, &sub));
printf("req mgr subscribe: %d\n", ret);
- camera_open(&s->driver_cam);
+ s->driver_cam.camera_open();
printf("driver camera opened \n");
if (!env_only_driver) {
- camera_open(&s->road_cam);
+ s->road_cam.camera_open();
printf("road camera opened \n");
- camera_open(&s->wide_road_cam);
+ s->wide_road_cam.camera_open();
printf("wide road camera opened \n");
}
}
-static void camera_close(CameraState *s) {
+void CameraState::camera_close() {
int ret;
// stop devices
LOG("-- Stop devices");
- // ret = device_control(s->sensor_fd, CAM_STOP_DEV, s->session_handle, s->sensor_dev_handle);
+ // ret = device_control(sensor_fd, CAM_STOP_DEV, session_handle, sensor_dev_handle);
// LOGD("stop sensor: %d", ret);
- ret = device_control(s->multi_cam_state->isp_fd, CAM_STOP_DEV, s->session_handle, s->isp_dev_handle);
+ ret = device_control(multi_cam_state->isp_fd, CAM_STOP_DEV, session_handle, isp_dev_handle);
LOGD("stop isp: %d", ret);
- ret = device_control(s->csiphy_fd, CAM_STOP_DEV, s->session_handle, s->csiphy_dev_handle);
+ ret = device_control(csiphy_fd, CAM_STOP_DEV, session_handle, csiphy_dev_handle);
LOGD("stop csiphy: %d", ret);
// link control stop
LOG("-- Stop link control");
static struct cam_req_mgr_link_control req_mgr_link_control = {0};
req_mgr_link_control.ops = CAM_REQ_MGR_LINK_DEACTIVATE;
- req_mgr_link_control.session_hdl = s->session_handle;
+ req_mgr_link_control.session_hdl = session_handle;
req_mgr_link_control.num_links = 1;
- req_mgr_link_control.link_hdls[0] = s->link_handle;
- ret = cam_control(s->multi_cam_state->video0_fd, CAM_REQ_MGR_LINK_CONTROL, &req_mgr_link_control, sizeof(req_mgr_link_control));
+ req_mgr_link_control.link_hdls[0] = link_handle;
+ ret = do_cam_control(multi_cam_state->video0_fd, CAM_REQ_MGR_LINK_CONTROL, &req_mgr_link_control, sizeof(req_mgr_link_control));
LOGD("link control stop: %d", ret);
// unlink
LOG("-- Unlink");
static struct cam_req_mgr_unlink_info req_mgr_unlink_info = {0};
- req_mgr_unlink_info.session_hdl = s->session_handle;
- req_mgr_unlink_info.link_hdl = s->link_handle;
- ret = cam_control(s->multi_cam_state->video0_fd, CAM_REQ_MGR_UNLINK, &req_mgr_unlink_info, sizeof(req_mgr_unlink_info));
+ req_mgr_unlink_info.session_hdl = session_handle;
+ req_mgr_unlink_info.link_hdl = link_handle;
+ ret = do_cam_control(multi_cam_state->video0_fd, CAM_REQ_MGR_UNLINK, &req_mgr_unlink_info, sizeof(req_mgr_unlink_info));
LOGD("unlink: %d", ret);
// release devices
LOGD("-- Release devices");
- ret = device_control(s->sensor_fd, CAM_RELEASE_DEV, s->session_handle, s->sensor_dev_handle);
+ ret = device_control(sensor_fd, CAM_RELEASE_DEV, session_handle, sensor_dev_handle);
LOGD("release sensor: %d", ret);
- ret = device_control(s->multi_cam_state->isp_fd, CAM_RELEASE_DEV, s->session_handle, s->isp_dev_handle);
+ ret = device_control(multi_cam_state->isp_fd, CAM_RELEASE_DEV, session_handle, isp_dev_handle);
LOGD("release isp: %d", ret);
- ret = device_control(s->csiphy_fd, CAM_RELEASE_DEV, s->session_handle, s->csiphy_dev_handle);
+ ret = device_control(csiphy_fd, CAM_RELEASE_DEV, session_handle, csiphy_dev_handle);
LOGD("release csiphy: %d", ret);
// destroyed session
- struct cam_req_mgr_session_info session_info = {.session_hdl = s->session_handle};
- ret = cam_control(s->multi_cam_state->video0_fd, CAM_REQ_MGR_DESTROY_SESSION, &session_info, sizeof(session_info));
+ struct cam_req_mgr_session_info session_info = {.session_hdl = session_handle};
+ ret = do_cam_control(multi_cam_state->video0_fd, CAM_REQ_MGR_DESTROY_SESSION, &session_info, sizeof(session_info));
LOGD("destroyed session: %d", ret);
}
void cameras_close(MultiCameraState *s) {
- camera_close(&s->driver_cam);
+ s->driver_cam.camera_close();
if (!env_only_driver) {
- camera_close(&s->road_cam);
- camera_close(&s->wide_road_cam);
+ s->road_cam.camera_close();
+ s->wide_road_cam.camera_close();
}
delete s->sm;
delete s->pm;
}
-// ******************* just a helper *******************
-
-void handle_camera_event(CameraState *s, void *evdat) {
+void CameraState::handle_camera_event(void *evdat) {
struct cam_req_mgr_message *event_data = (struct cam_req_mgr_message *)evdat;
uint64_t timestamp = event_data->u.frame_msg.timestamp;
@@ -869,53 +870,53 @@ void handle_camera_event(CameraState *s, void *evdat) {
int real_id = event_data->u.frame_msg.request_id;
if (real_id != 0) { // next ready
- if (real_id == 1) {s->idx_offset = main_id;}
+ if (real_id == 1) {idx_offset = main_id;}
int buf_idx = (real_id - 1) % FRAME_BUF_COUNT;
// check for skipped frames
- if (main_id > s->frame_id_last + 1 && !s->skipped) {
+ if (main_id > frame_id_last + 1 && !skipped) {
// realign
- clear_req_queue(s->multi_cam_state->video0_fd, event_data->session_hdl, event_data->u.frame_msg.link_hdl);
- enqueue_req_multi(s, real_id + 1, FRAME_BUF_COUNT - 1, 0);
- s->skipped = true;
- } else if (main_id == s->frame_id_last + 1) {
- s->skipped = false;
+ clear_req_queue(multi_cam_state->video0_fd, event_data->session_hdl, event_data->u.frame_msg.link_hdl);
+ enqueue_req_multi(real_id + 1, FRAME_BUF_COUNT - 1, 0);
+ skipped = true;
+ } else if (main_id == frame_id_last + 1) {
+ skipped = false;
}
// check for dropped requests
- if (real_id > s->request_id_last + 1) {
- enqueue_req_multi(s, s->request_id_last + 1 + FRAME_BUF_COUNT, real_id - (s->request_id_last + 1), 0);
+ if (real_id > request_id_last + 1) {
+ enqueue_req_multi(request_id_last + 1 + FRAME_BUF_COUNT, real_id - (request_id_last + 1), 0);
}
// metas
- s->frame_id_last = main_id;
- s->request_id_last = real_id;
+ frame_id_last = main_id;
+ request_id_last = real_id;
- auto &meta_data = s->buf.camera_bufs_metadata[buf_idx];
- meta_data.frame_id = main_id - s->idx_offset;
+ auto &meta_data = buf.camera_bufs_metadata[buf_idx];
+ meta_data.frame_id = main_id - idx_offset;
meta_data.timestamp_sof = timestamp;
- s->exp_lock.lock();
- meta_data.gain = s->dc_gain_enabled ? s->analog_gain_frac * DC_GAIN : s->analog_gain_frac;
- meta_data.high_conversion_gain = s->dc_gain_enabled;
- meta_data.integ_lines = s->exposure_time;
- meta_data.measured_grey_fraction = s->measured_grey_fraction;
- meta_data.target_grey_fraction = s->target_grey_fraction;
- s->exp_lock.unlock();
+ exp_lock.lock();
+ meta_data.gain = dc_gain_enabled ? analog_gain_frac * DC_GAIN : analog_gain_frac;
+ meta_data.high_conversion_gain = dc_gain_enabled;
+ meta_data.integ_lines = exposure_time;
+ meta_data.measured_grey_fraction = measured_grey_fraction;
+ meta_data.target_grey_fraction = target_grey_fraction;
+ exp_lock.unlock();
// dispatch
- enqueue_req_multi(s, real_id + FRAME_BUF_COUNT, 1, 1);
+ enqueue_req_multi(real_id + FRAME_BUF_COUNT, 1, 1);
} else { // not ready
// reset after half second of no response
- if (main_id > s->frame_id_last + 10) {
- clear_req_queue(s->multi_cam_state->video0_fd, event_data->session_hdl, event_data->u.frame_msg.link_hdl);
- enqueue_req_multi(s, s->request_id_last + 1, FRAME_BUF_COUNT, 0);
- s->frame_id_last = main_id;
- s->skipped = true;
+ if (main_id > frame_id_last + 10) {
+ clear_req_queue(multi_cam_state->video0_fd, event_data->session_hdl, event_data->u.frame_msg.link_hdl);
+ enqueue_req_multi(request_id_last + 1, FRAME_BUF_COUNT, 0);
+ frame_id_last = main_id;
+ skipped = true;
}
}
}
-static void set_camera_exposure(CameraState *s, float grey_frac) {
+void CameraState::set_camera_exposure(float grey_frac) {
const float dt = 0.05;
const float ts_grey = 10.0;
@@ -929,15 +930,15 @@ static void set_camera_exposure(CameraState *s, float grey_frac) {
// Therefore we use the target EV from 3 frames ago, the grey fraction that was just measured was the result of that control action.
// TODO: Lower latency to 2 frames, by using the histogram outputed by the sensor we can do AE before the debayering is complete
- const float cur_ev = s->cur_ev[s->buf.cur_frame_data.frame_id % 3];
+ const float cur_ev_ = cur_ev[buf.cur_frame_data.frame_id % 3];
// Scale target grey between 0.1 and 0.4 depending on lighting conditions
- float new_target_grey = std::clamp(0.4 - 0.3 * log2(1.0 + cur_ev) / log2(6000.0), 0.1, 0.4);
- float target_grey = (1.0 - k_grey) * s->target_grey_fraction + k_grey * new_target_grey;
+ float new_target_grey = std::clamp(0.4 - 0.3 * log2(1.0 + cur_ev_) / log2(6000.0), 0.1, 0.4);
+ float target_grey = (1.0 - k_grey) * target_grey_fraction + k_grey * new_target_grey;
- float desired_ev = std::clamp(cur_ev * target_grey / grey_frac, s->min_ev, s->max_ev);
+ float desired_ev = std::clamp(cur_ev_ * target_grey / grey_frac, min_ev, max_ev);
float k = (1.0 - k_ev) / 3.0;
- desired_ev = (k * s->cur_ev[0]) + (k * s->cur_ev[1]) + (k * s->cur_ev[2]) + (k_ev * desired_ev);
+ desired_ev = (k * cur_ev[0]) + (k * cur_ev[1]) + (k * cur_ev[2]) + (k_ev * desired_ev);
float best_ev_score = 1e6;
int new_g = 0;
@@ -945,7 +946,7 @@ static void set_camera_exposure(CameraState *s, float grey_frac) {
// Hysteresis around high conversion gain
// We usually want this on since it results in lower noise, but turn off in very bright day scenes
- bool enable_dc_gain = s->dc_gain_enabled;
+ bool enable_dc_gain = dc_gain_enabled;
if (!enable_dc_gain && target_grey < 0.2) {
enable_dc_gain = true;
} else if (enable_dc_gain && target_grey > 0.3) {
@@ -954,14 +955,14 @@ static void set_camera_exposure(CameraState *s, float grey_frac) {
// Simple brute force optimizer to choose sensor parameters
// to reach desired EV
- for (int g = std::max((int)ANALOG_GAIN_MIN_IDX, s->gain_idx - 1); g <= std::min((int)ANALOG_GAIN_MAX_IDX, s->gain_idx + 1); g++) {
+ for (int g = std::max((int)ANALOG_GAIN_MIN_IDX, gain_idx - 1); g <= std::min((int)ANALOG_GAIN_MAX_IDX, gain_idx + 1); g++) {
float gain = sensor_analog_gains[g] * (enable_dc_gain ? DC_GAIN : 1);
// Compute optimal time for given gain
int t = std::clamp(int(std::round(desired_ev / gain)), EXPOSURE_TIME_MIN, EXPOSURE_TIME_MAX);
// Only go below recomended gain when absolutely necessary to not overexpose
- if (g < ANALOG_GAIN_REC_IDX && t > 20 && g < s->gain_idx) {
+ if (g < ANALOG_GAIN_REC_IDX && t > 20 && g < gain_idx) {
continue;
}
@@ -972,10 +973,10 @@ static void set_camera_exposure(CameraState *s, float grey_frac) {
float m = g > ANALOG_GAIN_REC_IDX ? 5.0 : 0.1;
score += std::abs(g - (int)ANALOG_GAIN_REC_IDX) * m;
- // LOGE("cam: %d - gain: %d, t: %d (%.2f), score %.2f, score + gain %.2f, %.3f, %.3f", s->camera_num, g, t, desired_ev / gain, score, score + std::abs(g - s->gain_idx) * (score + 1.0) / 10.0, desired_ev, s->min_ev);
+ // LOGE("cam: %d - gain: %d, t: %d (%.2f), score %.2f, score + gain %.2f, %.3f, %.3f", camera_num, g, t, desired_ev / gain, score, score + std::abs(g - gain_idx) * (score + 1.0) / 10.0, desired_ev, min_ev);
// Small penalty on changing gain
- score += std::abs(g - s->gain_idx) * (score + 1.0) / 10.0;
+ score += std::abs(g - gain_idx) * (score + 1.0) / 10.0;
if (score < best_ev_score) {
new_t = t;
@@ -984,42 +985,41 @@ static void set_camera_exposure(CameraState *s, float grey_frac) {
}
}
- s->exp_lock.lock();
+ exp_lock.lock();
- s->measured_grey_fraction = grey_frac;
- s->target_grey_fraction = target_grey;
+ measured_grey_fraction = grey_frac;
+ target_grey_fraction = target_grey;
- s->analog_gain_frac = sensor_analog_gains[new_g];
- s->gain_idx = new_g;
- s->exposure_time = new_t;
- s->dc_gain_enabled = enable_dc_gain;
+ analog_gain_frac = sensor_analog_gains[new_g];
+ gain_idx = new_g;
+ exposure_time = new_t;
+ dc_gain_enabled = enable_dc_gain;
- float gain = s->analog_gain_frac * (s->dc_gain_enabled ? DC_GAIN : 1.0);
- s->cur_ev[s->buf.cur_frame_data.frame_id % 3] = s->exposure_time * gain;
+ float gain = analog_gain_frac * (dc_gain_enabled ? DC_GAIN : 1.0);
+ cur_ev[buf.cur_frame_data.frame_id % 3] = exposure_time * gain;
- s->exp_lock.unlock();
+ exp_lock.unlock();
// Processing a frame takes right about 50ms, so we need to wait a few ms
// so we don't send i2c commands around the frame start.
- int ms = (nanos_since_boot() - s->buf.cur_frame_data.timestamp_sof) / 1000000;
+ int ms = (nanos_since_boot() - buf.cur_frame_data.timestamp_sof) / 1000000;
if (ms < 60) {
util::sleep_for(60 - ms);
}
- // LOGE("ae - camera %d, cur_t %.5f, sof %.5f, dt %.5f", s->camera_num, 1e-9 * nanos_since_boot(), 1e-9 * s->buf.cur_frame_data.timestamp_sof, 1e-9 * (nanos_since_boot() - s->buf.cur_frame_data.timestamp_sof));
+ // LOGE("ae - camera %d, cur_t %.5f, sof %.5f, dt %.5f", camera_num, 1e-9 * nanos_since_boot(), 1e-9 * buf.cur_frame_data.timestamp_sof, 1e-9 * (nanos_since_boot() - buf.cur_frame_data.timestamp_sof));
uint16_t analog_gain_reg = 0xFF00 | (new_g << 4) | new_g;
struct i2c_random_wr_payload exp_reg_array[] = {
{0x3366, analog_gain_reg},
- {0x3362, (uint16_t)(s->dc_gain_enabled ? 0x1 : 0x0)},
- {0x3012, (uint16_t)s->exposure_time},
+ {0x3362, (uint16_t)(dc_gain_enabled ? 0x1 : 0x0)},
+ {0x3012, (uint16_t)exposure_time},
};
- sensors_i2c(s, exp_reg_array, sizeof(exp_reg_array)/sizeof(struct i2c_random_wr_payload),
+ sensors_i2c(exp_reg_array, sizeof(exp_reg_array)/sizeof(struct i2c_random_wr_payload),
CAM_SENSOR_PACKET_OPCODE_SENSOR_CONFIG);
-
}
void camera_autoexposure(CameraState *s, float grey_frac) {
- set_camera_exposure(s, grey_frac);
+ s->set_camera_exposure(grey_frac);
}
// called by processing_thread
@@ -1053,11 +1053,10 @@ void cameras_run(MultiCameraState *s) {
// start devices
LOG("-- Starting devices");
- int start_reg_len = sizeof(start_reg_array) / sizeof(struct i2c_random_wr_payload);
- sensors_i2c(&s->driver_cam, start_reg_array, start_reg_len, CAM_SENSOR_PACKET_OPCODE_SENSOR_CONFIG);
+ s->driver_cam.sensors_start();
if (!env_only_driver) {
- sensors_i2c(&s->road_cam, start_reg_array, start_reg_len, CAM_SENSOR_PACKET_OPCODE_SENSOR_CONFIG);
- sensors_i2c(&s->wide_road_cam, start_reg_array, start_reg_len, CAM_SENSOR_PACKET_OPCODE_SENSOR_CONFIG);
+ s->road_cam.sensors_start();
+ s->wide_road_cam.sensors_start();
}
// poll events
@@ -1088,11 +1087,11 @@ void cameras_run(MultiCameraState *s) {
}
if (event_data->session_hdl == s->road_cam.session_handle) {
- handle_camera_event(&s->road_cam, event_data);
+ s->road_cam.handle_camera_event(event_data);
} else if (event_data->session_hdl == s->wide_road_cam.session_handle) {
- handle_camera_event(&s->wide_road_cam, event_data);
+ s->wide_road_cam.handle_camera_event(event_data);
} else if (event_data->session_hdl == s->driver_cam.session_handle) {
- handle_camera_event(&s->driver_cam, event_data);
+ s->driver_cam.handle_camera_event(event_data);
} else {
printf("Unknown vidioc event source\n");
assert(false);
diff --git a/selfdrive/camerad/cameras/camera_qcom2.h b/selfdrive/camerad/cameras/camera_qcom2.h
index f8ab2da8ae..d021ba256e 100644
--- a/selfdrive/camerad/cameras/camera_qcom2.h
+++ b/selfdrive/camerad/cameras/camera_qcom2.h
@@ -9,7 +9,8 @@
#define FRAME_BUF_COUNT 4
-typedef struct CameraState {
+class CameraState {
+public:
MultiCameraState *multi_cam_state;
CameraInfo ci;
@@ -31,6 +32,21 @@ typedef struct CameraState {
int camera_num;
+ void config_isp(int io_mem_handle, int fence, int request_id, int buf0_mem_handle, int buf0_offset);
+ void enqueue_req_multi(int start, int n, bool dp);
+ void enqueue_buffer(int i, bool dp);
+ void handle_camera_event(void *evdat);
+ void set_camera_exposure(float grey_frac);
+
+ void sensors_start();
+ void sensors_poke(int request_id);
+ void sensors_i2c(struct i2c_random_wr_payload* dat, int len, int op_code);
+ void sensors_init();
+
+ void camera_open();
+ void camera_init(MultiCameraState *multi_cam_state, VisionIpcServer * v, int camera_id, int camera_num, unsigned int fps, cl_device_id device_id, cl_context ctx, VisionStreamType rgb_type, VisionStreamType yuv_type);
+ void camera_close();
+
int32_t session_handle;
int32_t sensor_dev_handle;
int32_t isp_dev_handle;
@@ -48,7 +64,7 @@ typedef struct CameraState {
bool skipped;
CameraBuf buf;
-} CameraState;
+};
typedef struct MultiCameraState {
unique_fd video0_fd;
diff --git a/selfdrive/camerad/cameras/camera_replay.cc b/selfdrive/camerad/cameras/camera_replay.cc
index b5b2e6ad29..a9983fe23e 100644
--- a/selfdrive/camerad/cameras/camera_replay.cc
+++ b/selfdrive/camerad/cameras/camera_replay.cc
@@ -98,9 +98,9 @@ void process_road_camera(MultiCameraState *s, CameraState *c, int cnt) {
void cameras_init(VisionIpcServer *v, MultiCameraState *s, cl_device_id device_id, cl_context ctx) {
camera_init(v, &s->road_cam, CAMERA_ID_LGC920, 20, device_id, ctx,
- VISION_STREAM_RGB_BACK, VISION_STREAM_ROAD, get_url(road_camera_route, "fcamera", 0));
+ VISION_STREAM_RGB_ROAD, VISION_STREAM_ROAD, get_url(road_camera_route, "fcamera", 0));
// camera_init(v, &s->driver_cam, CAMERA_ID_LGC615, 10, device_id, ctx,
- // VISION_STREAM_RGB_FRONT, VISION_STREAM_DRIVER, get_url(driver_camera_route, "dcamera", 0));
+ // VISION_STREAM_RGB_DRIVER, VISION_STREAM_DRIVER, get_url(driver_camera_route, "dcamera", 0));
s->pm = new PubMaster({"roadCameraState", "driverCameraState", "thumbnail"});
}
diff --git a/selfdrive/camerad/cameras/camera_webcam.cc b/selfdrive/camerad/cameras/camera_webcam.cc
index 956f2dc88f..6001f9fd3b 100644
--- a/selfdrive/camerad/cameras/camera_webcam.cc
+++ b/selfdrive/camerad/cameras/camera_webcam.cc
@@ -141,9 +141,9 @@ void driver_camera_thread(CameraState *s) {
void cameras_init(VisionIpcServer *v, MultiCameraState *s, cl_device_id device_id, cl_context ctx) {
camera_init(v, &s->road_cam, CAMERA_ID_LGC920, 20, device_id, ctx,
- VISION_STREAM_RGB_BACK, VISION_STREAM_ROAD);
+ VISION_STREAM_RGB_ROAD, VISION_STREAM_ROAD);
camera_init(v, &s->driver_cam, CAMERA_ID_LGC615, 10, device_id, ctx,
- VISION_STREAM_RGB_FRONT, VISION_STREAM_DRIVER);
+ VISION_STREAM_RGB_DRIVER, VISION_STREAM_DRIVER);
s->pm = new PubMaster({"roadCameraState", "driverCameraState", "thumbnail"});
}
diff --git a/selfdrive/camerad/cameras/real_debayer.cl b/selfdrive/camerad/cameras/real_debayer.cl
index fe6a99f373..4553036ee3 100644
--- a/selfdrive/camerad/cameras/real_debayer.cl
+++ b/selfdrive/camerad/cameras/real_debayer.cl
@@ -40,12 +40,12 @@ half3 color_correct(half3 rgb) {
}
half val_from_10(const uchar * source, int gx, int gy) {
- // parse 10bit
- int start = gy * FRAME_STRIDE + (5 * (gx / 4));
- int offset = gx % 4;
- uint major = (uint)source[start + offset] << 2;
- uint minor = (source[start + 4] >> (2 * offset)) & 3;
- half pv = (half)(major + minor);
+ // parse 12bit
+ int start = gy * FRAME_STRIDE + (3 * (gx / 2));
+ int offset = gx % 2;
+ uint major = (uint)source[start + offset] << 4;
+ uint minor = (source[start + 2] >> (4 * offset)) & 0xf;
+ half pv = (half)((major + minor)/4);
// normalize
pv = max(0.0h, pv - black_level);
diff --git a/selfdrive/camerad/cameras/sensor2_i2c.h b/selfdrive/camerad/cameras/sensor2_i2c.h
index c3d8861a97..0f91503be0 100644
--- a/selfdrive/camerad/cameras/sensor2_i2c.h
+++ b/selfdrive/camerad/cameras/sensor2_i2c.h
@@ -9,7 +9,7 @@ struct i2c_random_wr_payload init_array_ar0231[] = {
{0x302C, 0x0001}, // VT_SYS_CLK_DIV
{0x302E, 0x0002}, // PRE_PLL_CLK_DIV
{0x3030, 0x0032}, // PLL_MULTIPLIER
- {0x3036, 0x000A}, // OP_WORD_CLK_DIV
+ {0x3036, 0x000C}, // OP_WORD_CLK_DIV
{0x3038, 0x0001}, // OP_SYS_CLK_DIV
// FORMAT
@@ -46,11 +46,11 @@ struct i2c_random_wr_payload init_array_ar0231[] = {
// Readout Settings
{0x31AE, 0x0204}, // SERIAL_FORMAT, 4-lane MIPI
- {0x31AC, 0x0C0A}, // DATA_FORMAT_BITS, 12 -> 10
- {0x3342, 0x122B}, // MIPI_F1_PDT_EDT
- {0x3346, 0x122B}, // MIPI_F2_PDT_EDT
- {0x334A, 0x122B}, // MIPI_F3_PDT_EDT
- {0x334E, 0x122B}, // MIPI_F4_PDT_EDT
+ {0x31AC, 0x0C0C}, // DATA_FORMAT_BITS, 12 -> 12
+ {0x3342, 0x122C}, // MIPI_F1_PDT_EDT
+ {0x3346, 0x122C}, // MIPI_F2_PDT_EDT
+ {0x334A, 0x122C}, // MIPI_F3_PDT_EDT
+ {0x334E, 0x122C}, // MIPI_F4_PDT_EDT
{0x3344, 0x0011}, // MIPI_F1_VDT_VC
{0x3348, 0x0111}, // MIPI_F2_VDT_VC
{0x334C, 0x0211}, // MIPI_F3_VDT_VC
diff --git a/selfdrive/camerad/snapshot/snapshot.py b/selfdrive/camerad/snapshot/snapshot.py
index 506064de3d..1ec7677d31 100755
--- a/selfdrive/camerad/snapshot/snapshot.py
+++ b/selfdrive/camerad/snapshot/snapshot.py
@@ -17,9 +17,9 @@ from selfdrive.manager.process_config import managed_processes
LM_THRESH = 120 # defined in selfdrive/camerad/imgproc/utils.h
VISION_STREAMS = {
- "roadCameraState": VisionStreamType.VISION_STREAM_RGB_BACK,
- "driverCameraState": VisionStreamType.VISION_STREAM_RGB_FRONT,
- "wideRoadCameraState": VisionStreamType.VISION_STREAM_RGB_WIDE,
+ "roadCameraState": VisionStreamType.VISION_STREAM_RGB_ROAD,
+ "driverCameraState": VisionStreamType.VISION_STREAM_RGB_DRIVER,
+ "wideRoadCameraState": VisionStreamType.VISION_STREAM_RGB_WIDE_ROAD,
}
diff --git a/selfdrive/car/chrysler/carstate.py b/selfdrive/car/chrysler/carstate.py
index 30a0bf6a3a..5f83bbde8b 100644
--- a/selfdrive/car/chrysler/carstate.py
+++ b/selfdrive/car/chrysler/carstate.py
@@ -1,7 +1,7 @@
from cereal import car
+from common.conversions import Conversions as CV
from opendbc.can.parser import CANParser
from opendbc.can.can_define import CANDefine
-from selfdrive.config import Conversions as CV
from selfdrive.car.interfaces import CarStateBase
from selfdrive.car.chrysler.values import DBC, STEER_THRESHOLD
@@ -58,7 +58,7 @@ class CarState(CarStateBase):
ret.steeringTorqueEps = cp.vl["EPS_STATUS"]["TORQUE_MOTOR"]
ret.steeringPressed = abs(ret.steeringTorque) > STEER_THRESHOLD
steer_state = cp.vl["EPS_STATUS"]["LKAS_STATE"]
- ret.steerError = steer_state == 4 or (steer_state == 0 and ret.vEgo > self.CP.minSteerSpeed)
+ ret.steerFaultPermanent = steer_state == 4 or (steer_state == 0 and ret.vEgo > self.CP.minSteerSpeed)
ret.genericToggle = bool(cp.vl["STEERING_LEVERS"]["HIGH_BEAM_FLASH"])
diff --git a/selfdrive/car/ford/carstate.py b/selfdrive/car/ford/carstate.py
index eba623f5ce..ff82e585b4 100644
--- a/selfdrive/car/ford/carstate.py
+++ b/selfdrive/car/ford/carstate.py
@@ -1,7 +1,7 @@
from cereal import car
-from opendbc.can.parser import CANParser
+from common.conversions import Conversions as CV
from common.numpy_fast import mean
-from selfdrive.config import Conversions as CV
+from opendbc.can.parser import CANParser
from selfdrive.car.interfaces import CarStateBase
from selfdrive.car.ford.values import DBC
@@ -23,7 +23,7 @@ class CarState(CarStateBase):
ret.standstill = not ret.vEgoRaw > 0.001
ret.steeringAngleDeg = cp.vl["Steering_Wheel_Data_CG1"]["SteWhlRelInit_An_Sns"]
ret.steeringPressed = not cp.vl["Lane_Keep_Assist_Status"]["LaHandsOff_B_Actl"]
- ret.steerError = cp.vl["Lane_Keep_Assist_Status"]["LaActDeny_B_Actl"] == 1
+ ret.steerFaultPermanent = cp.vl["Lane_Keep_Assist_Status"]["LaActDeny_B_Actl"] == 1
ret.cruiseState.speed = cp.vl["Cruise_Status"]["Set_Speed"] * CV.MPH_TO_MS
ret.cruiseState.enabled = not (cp.vl["Cruise_Status"]["Cruise_State"] in (0, 3))
ret.cruiseState.available = cp.vl["Cruise_Status"]["Cruise_State"] != 0
diff --git a/selfdrive/car/ford/interface.py b/selfdrive/car/ford/interface.py
index 0faaa3f669..5d89950816 100755
--- a/selfdrive/car/ford/interface.py
+++ b/selfdrive/car/ford/interface.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
from cereal import car
-from selfdrive.config import Conversions as CV
+from common.conversions import Conversions as CV
from selfdrive.car.ford.values import MAX_ANGLE
from selfdrive.car import STD_CARGO_KG, scale_rot_inertia, scale_tire_stiffness, gen_empty_fingerprint, get_safety_config
from selfdrive.car.interfaces import CarInterfaceBase
@@ -25,6 +25,8 @@ class CarInterface(CarInterfaceBase):
ret.steerRateCost = 1.0
ret.centerToFront = ret.wheelbase * 0.44
tire_stiffness_factor = 0.5328
+ # TODO: add minSteerSpeed
+ ret.minEnableSpeed = 12. * CV.MPH_TO_MS
# TODO: get actual value, for now starting with reasonable value for
# civic and scaling by mass and wheelbase
@@ -64,7 +66,7 @@ class CarInterface(CarInterfaceBase):
def apply(self, c):
ret = self.CC.update(c.enabled, self.CS, self.frame, c.actuators,
- c.hudControl.visualAlert, c.cruiseControl.cancel)
+ c.hudControl.visualAlert, c.cruiseControl.cancel)
self.frame += 1
return ret
diff --git a/selfdrive/car/ford/radar_interface.py b/selfdrive/car/ford/radar_interface.py
index 94eb8bb0cc..f8477951cd 100755
--- a/selfdrive/car/ford/radar_interface.py
+++ b/selfdrive/car/ford/radar_interface.py
@@ -1,8 +1,8 @@
#!/usr/bin/env python3
from cereal import car
+from common.conversions import Conversions as CV
from opendbc.can.parser import CANParser
from selfdrive.car.ford.values import DBC
-from selfdrive.config import Conversions as CV
from selfdrive.car.interfaces import RadarInterfaceBase
RADAR_MSGS = list(range(0x500, 0x540))
diff --git a/selfdrive/car/gm/carcontroller.py b/selfdrive/car/gm/carcontroller.py
index 7ad1e7cf88..11c2d367cb 100644
--- a/selfdrive/car/gm/carcontroller.py
+++ b/selfdrive/car/gm/carcontroller.py
@@ -1,11 +1,11 @@
from cereal import car
+from common.conversions import Conversions as CV
from common.realtime import DT_CTRL
from common.numpy_fast import interp
-from selfdrive.config import Conversions as CV
+from opendbc.can.packer import CANPacker
from selfdrive.car import apply_std_steer_torque_limits
from selfdrive.car.gm import gmcan
from selfdrive.car.gm.values import DBC, CanBus, CarControllerParams
-from opendbc.can.packer import CANPacker
VisualAlert = car.CarControl.HUDControl.VisualAlert
@@ -27,8 +27,7 @@ class CarController():
self.packer_obj = CANPacker(DBC[CP.carFingerprint]['radar'])
self.packer_ch = CANPacker(DBC[CP.carFingerprint]['chassis'])
- def update(self, c, enabled, CS, frame, actuators,
- hud_v_cruise, hud_show_lanes, hud_show_car, hud_alert):
+ def update(self, c, CS, frame, actuators, hud_v_cruise, hud_show_lanes, hud_show_car, hud_alert):
P = self.params
@@ -41,7 +40,7 @@ class CarController():
if CS.lka_steering_cmd_counter != self.lka_steering_cmd_counter_last:
self.lka_steering_cmd_counter_last = CS.lka_steering_cmd_counter
elif (frame % P.STEER_STEP) == 0:
- lkas_enabled = c.active and not (CS.out.steerWarning or CS.out.steerError) and CS.out.vEgo > P.MIN_STEER_SPEED
+ lkas_enabled = c.latActive and CS.out.vEgo > P.MIN_STEER_SPEED
if lkas_enabled:
new_steer = int(round(actuators.steer * P.STEER_MAX))
apply_steer = apply_std_steer_torque_limits(new_steer, self.apply_steer_last, CS.out.steeringTorque, P)
@@ -58,7 +57,7 @@ class CarController():
# Gas/regen and brakes - all at 25Hz
if (frame % 4) == 0:
- if not c.active:
+ if not c.longActive:
# Stock ECU sends max regen when not enabled.
self.apply_gas = P.MAX_ACC_REGEN
self.apply_brake = 0
@@ -68,15 +67,15 @@ class CarController():
idx = (frame // 4) % 4
- at_full_stop = enabled and CS.out.standstill
- near_stop = enabled and (CS.out.vEgo < P.NEAR_STOP_BRAKE_PHASE)
+ at_full_stop = c.longActive and CS.out.standstill
+ near_stop = c.longActive and (CS.out.vEgo < P.NEAR_STOP_BRAKE_PHASE)
can_sends.append(gmcan.create_friction_brake_command(self.packer_ch, CanBus.CHASSIS, self.apply_brake, idx, near_stop, at_full_stop))
- can_sends.append(gmcan.create_gas_regen_command(self.packer_pt, CanBus.POWERTRAIN, self.apply_gas, idx, enabled, at_full_stop))
+ can_sends.append(gmcan.create_gas_regen_command(self.packer_pt, CanBus.POWERTRAIN, self.apply_gas, idx, c.longActive, at_full_stop))
# Send dashboard UI commands (ACC status), 25hz
if (frame % 4) == 0:
send_fcw = hud_alert == VisualAlert.fcw
- can_sends.append(gmcan.create_acc_dashboard_command(self.packer_pt, CanBus.POWERTRAIN, enabled, hud_v_cruise * CV.MS_TO_KPH, hud_show_car, send_fcw))
+ can_sends.append(gmcan.create_acc_dashboard_command(self.packer_pt, CanBus.POWERTRAIN, c.longActive, hud_v_cruise * CV.MS_TO_KPH, hud_show_car, send_fcw))
# Radar needs to know current speed and yaw rate (50hz),
# and that ADAS is alive (10hz)
diff --git a/selfdrive/car/gm/carstate.py b/selfdrive/car/gm/carstate.py
index 4a6b75fa3f..b94fd0f2ab 100644
--- a/selfdrive/car/gm/carstate.py
+++ b/selfdrive/car/gm/carstate.py
@@ -45,8 +45,8 @@ class CarState(CarStateBase):
# 0 inactive, 1 active, 2 temporarily limited, 3 failed
self.lkas_status = pt_cp.vl["PSCMStatus"]["LKATorqueDeliveredStatus"]
- ret.steerWarning = self.lkas_status == 2
- ret.steerError = self.lkas_status == 3
+ ret.steerFaultTemporary = self.lkas_status == 2
+ ret.steerFaultPermanent = self.lkas_status == 3
# 1 - open, 0 - closed
ret.doorOpen = (pt_cp.vl["BCMDoorBeltStatus"]["FrontLeftDoor"] == 1 or
@@ -59,7 +59,7 @@ class CarState(CarStateBase):
ret.leftBlinker = pt_cp.vl["BCMTurnSignals"]["TurnSignals"] == 1
ret.rightBlinker = pt_cp.vl["BCMTurnSignals"]["TurnSignals"] == 2
- self.park_brake = pt_cp.vl["EPBStatus"]["EPBClosed"]
+ ret.parkingBrake = pt_cp.vl["EPBStatus"]["EPBClosed"] == 1
ret.cruiseState.available = pt_cp.vl["ECMEngineStatus"]["CruiseMainOn"] != 0
ret.espDisabled = pt_cp.vl["ESPStatus"]["TractionControlOn"] != 1
self.pcm_acc_status = pt_cp.vl["AcceleratorPedal2"]["CruiseState"]
diff --git a/selfdrive/car/gm/interface.py b/selfdrive/car/gm/interface.py
index d6a2d3cfee..0473abfc74 100755
--- a/selfdrive/car/gm/interface.py
+++ b/selfdrive/car/gm/interface.py
@@ -1,10 +1,11 @@
#!/usr/bin/env python3
from cereal import car
from math import fabs
-from selfdrive.config import Conversions as CV
+
+from common.conversions import Conversions as CV
+from selfdrive.car import STD_CARGO_KG, scale_rot_inertia, scale_tire_stiffness, gen_empty_fingerprint, get_safety_config
from selfdrive.car.gm.values import CAR, CruiseButtons, \
AccState, CarControllerParams
-from selfdrive.car import STD_CARGO_KG, scale_rot_inertia, scale_tire_stiffness, gen_empty_fingerprint, get_safety_config
from selfdrive.car.interfaces import CarInterfaceBase
ButtonType = car.CarState.ButtonEvent.Type
@@ -46,7 +47,7 @@ class CarInterface(CarInterfaceBase):
# These cars have been put into dashcam only due to both a lack of users and test coverage.
# These cars likely still work fine. Once a user confirms each car works and a test route is
- # added to selfdrive/test/test_routes, we can remove it from this list.
+ # added to selfdrive/car/tests/routes.py, we can remove it from this list.
ret.dashcamOnly = candidate in {CAR.CADILLAC_ATS, CAR.HOLDEN_ASTRA, CAR.MALIBU, CAR.BUICK_REGAL}
# Presence of a camera on the object bus is ok.
@@ -191,8 +192,6 @@ class CarInterface(CarInterfaceBase):
if ret.vEgo < self.CP.minEnableSpeed:
events.add(EventName.belowEngageSpeed)
- if self.CS.park_brake:
- events.add(EventName.parkBrake)
if ret.cruiseState.standstill:
events.add(EventName.resumeRequired)
if self.CS.pcm_acc_status == AccState.FAULTED:
@@ -222,12 +221,7 @@ class CarInterface(CarInterfaceBase):
if hud_v_cruise > 70:
hud_v_cruise = 0
- # For Openpilot, "enabled" includes pre-enable.
- # In GM, PCM faults out if ACC command overlaps user gas.
- enabled = c.enabled and not self.CS.out.gasPressed
-
- ret = self.CC.update(c, enabled, self.CS, self.frame,
- c.actuators,
+ ret = self.CC.update(c, self.CS, self.frame, c.actuators,
hud_v_cruise, hud_control.lanesVisible,
hud_control.leadVisible, hud_control.visualAlert)
diff --git a/selfdrive/car/gm/radar_interface.py b/selfdrive/car/gm/radar_interface.py
index 66fac54748..6904e6f899 100755
--- a/selfdrive/car/gm/radar_interface.py
+++ b/selfdrive/car/gm/radar_interface.py
@@ -1,9 +1,9 @@
#!/usr/bin/env python3
import math
from cereal import car
+from common.conversions import Conversions as CV
from opendbc.can.parser import CANParser
from selfdrive.car.gm.values import DBC, CAR, CanBus
-from selfdrive.config import Conversions as CV
from selfdrive.car.interfaces import RadarInterfaceBase
RADAR_HEADER_MSG = 1120
diff --git a/selfdrive/car/honda/carcontroller.py b/selfdrive/car/honda/carcontroller.py
index 49581799a7..bf5456bc4b 100644
--- a/selfdrive/car/honda/carcontroller.py
+++ b/selfdrive/car/honda/carcontroller.py
@@ -112,12 +112,12 @@ class CarController():
self.params = CarControllerParams(CP)
- def update(self, enabled, active, CS, frame, actuators, pcm_cancel_cmd,
+ def update(self, c, CS, frame, actuators, pcm_cancel_cmd,
hud_v_cruise, hud_show_lanes, hud_show_car, hud_alert):
P = self.params
- if active:
+ if c.longActive:
accel = actuators.accel
gas, brake = compute_gas_brake(actuators.accel, CS.out.vEgo, CS.CP.carFingerprint)
else:
@@ -136,7 +136,7 @@ class CarController():
else:
hud_lanes = 0
- if enabled:
+ if c.enabled:
if hud_show_car:
hud_car = 2
else:
@@ -152,8 +152,6 @@ class CarController():
# steer torque is converted back to CAN reference (positive when steering right)
apply_steer = int(interp(-actuators.steer * P.STEER_MAX, P.STEER_LOOKUP_BP, P.STEER_LOOKUP_V))
- lkas_active = active and not CS.steer_not_allowed
-
# Send CAN commands.
can_sends = []
@@ -165,7 +163,7 @@ class CarController():
# Send steering command.
idx = frame % 4
can_sends.append(hondacan.create_steering_control(self.packer, apply_steer,
- lkas_active, CS.CP.carFingerprint, idx, CS.CP.openpilotLongitudinalControl))
+ c.latActive, CS.CP.carFingerprint, idx, CS.CP.openpilotLongitudinalControl))
stopping = actuators.longControlState == LongCtrlState.stopping
@@ -217,7 +215,7 @@ class CarController():
if CS.CP.carFingerprint in HONDA_BOSCH:
self.accel = clip(accel, P.BOSCH_ACCEL_MIN, P.BOSCH_ACCEL_MAX)
self.gas = interp(accel, P.BOSCH_GAS_LOOKUP_BP, P.BOSCH_GAS_LOOKUP_V)
- can_sends.extend(hondacan.create_acc_commands(self.packer, enabled, active, accel, self.gas, idx, stopping, CS.CP.carFingerprint))
+ can_sends.extend(hondacan.create_acc_commands(self.packer, c.enabled, c.longActive, accel, self.gas, idx, stopping, CS.CP.carFingerprint))
else:
apply_brake = clip(self.brake_last - wind_brake, 0.0, 1.0)
apply_brake = int(clip(apply_brake * P.NIDEC_BRAKE_MAX, 0, P.NIDEC_BRAKE_MAX - 1))
@@ -236,7 +234,7 @@ class CarController():
# This prevents unexpected pedal range rescaling
# Sending non-zero gas when OP is not enabled will cause the PCM not to respond to throttle as expected
# when you do enable.
- if active:
+ if c.longActive:
self.gas = clip(gas_mult * (gas - brake + wind_brake*3/4), 0., 1.)
else:
self.gas = 0.0
diff --git a/selfdrive/car/honda/carstate.py b/selfdrive/car/honda/carstate.py
index 0a56a02b94..fc262ba42c 100644
--- a/selfdrive/car/honda/carstate.py
+++ b/selfdrive/car/honda/carstate.py
@@ -1,9 +1,10 @@
-from cereal import car
from collections import defaultdict
+
+from cereal import car
+from common.conversions import Conversions as CV
from common.numpy_fast import interp
from opendbc.can.can_define import CANDefine
from opendbc.can.parser import CANParser
-from selfdrive.config import Conversions as CV
from selfdrive.car.interfaces import CarStateBase
from selfdrive.car.honda.values import CAR, DBC, STEER_THRESHOLD, HONDA_BOSCH, HONDA_NIDEC_ALT_SCM_MESSAGES, HONDA_BOSCH_ALT_BRAKE_SIGNAL
@@ -197,11 +198,10 @@ class CarState(CarStateBase):
ret.seatbeltUnlatched = bool(cp.vl["SEATBELT_STATUS"]["SEATBELT_DRIVER_LAMP"] or not cp.vl["SEATBELT_STATUS"]["SEATBELT_DRIVER_LATCHED"])
steer_status = self.steer_status_values[cp.vl["STEER_STATUS"]["STEER_STATUS"]]
- ret.steerError = steer_status not in ("NORMAL", "NO_TORQUE_ALERT_1", "NO_TORQUE_ALERT_2", "LOW_SPEED_LOCKOUT", "TMP_FAULT")
- # NO_TORQUE_ALERT_2 can be caused by bump OR steering nudge from driver
- self.steer_not_allowed = steer_status not in ("NORMAL", "NO_TORQUE_ALERT_2")
+ ret.steerFaultPermanent = steer_status not in ("NORMAL", "NO_TORQUE_ALERT_1", "NO_TORQUE_ALERT_2", "LOW_SPEED_LOCKOUT", "TMP_FAULT")
# LOW_SPEED_LOCKOUT is not worth a warning
- ret.steerWarning = steer_status not in ("NORMAL", "LOW_SPEED_LOCKOUT", "NO_TORQUE_ALERT_2")
+ # NO_TORQUE_ALERT_2 can be caused by bump or steering nudge from driver
+ ret.steerFaultTemporary = steer_status not in ("NORMAL", "LOW_SPEED_LOCKOUT", "NO_TORQUE_ALERT_2")
if self.CP.openpilotLongitudinalControl:
self.brake_error = cp.vl["STANDSTILL"]["BRAKE_ERROR_1"] or cp.vl["STANDSTILL"]["BRAKE_ERROR_2"]
@@ -230,11 +230,10 @@ class CarState(CarStateBase):
250, cp.vl["SCM_FEEDBACK"]["LEFT_BLINKER"], cp.vl["SCM_FEEDBACK"]["RIGHT_BLINKER"])
ret.brakeHoldActive = cp.vl["VSA_STATUS"]["BRAKE_HOLD_ACTIVE"] == 1
+ # TODO: set for all cars
if self.CP.carFingerprint in (CAR.CIVIC, CAR.ODYSSEY, CAR.ODYSSEY_CHN, CAR.CRV_5G, CAR.ACCORD, CAR.ACCORDH, CAR.CIVIC_BOSCH,
CAR.CIVIC_BOSCH_DIESEL, CAR.CRV_HYBRID, CAR.INSIGHT, CAR.ACURA_RDX_3G, CAR.HONDA_E):
- self.park_brake = cp.vl["EPB_STATUS"]["EPB_STATE"] != 0
- else:
- self.park_brake = 0 # TODO
+ ret.parkingBrake = cp.vl["EPB_STATUS"]["EPB_STATE"] != 0
gear = int(cp.vl[self.gearbox_msg]["GEAR_SHIFTER"])
ret.gearShifter = self.parse_gear_shifter(self.shifter_values.get(gear, None))
diff --git a/selfdrive/car/honda/hondacan.py b/selfdrive/car/honda/hondacan.py
index db7104cd4f..513babf3d1 100644
--- a/selfdrive/car/honda/hondacan.py
+++ b/selfdrive/car/honda/hondacan.py
@@ -1,5 +1,5 @@
+from common.conversions import Conversions as CV
from selfdrive.car.honda.values import HondaFlags, HONDA_BOSCH, CAR, CarControllerParams
-from selfdrive.config import Conversions as CV
# CAN bus layout with relay
# 0 = ACC-CAN - radar side
diff --git a/selfdrive/car/honda/interface.py b/selfdrive/car/honda/interface.py
index 94e4305909..040587be6f 100755
--- a/selfdrive/car/honda/interface.py
+++ b/selfdrive/car/honda/interface.py
@@ -1,13 +1,13 @@
#!/usr/bin/env python3
from cereal import car
from panda import Panda
+from common.conversions import Conversions as CV
from common.numpy_fast import interp
from common.params import Params
from selfdrive.car.honda.values import CarControllerParams, CruiseButtons, HondaFlags, CAR, HONDA_BOSCH, HONDA_NIDEC_ALT_SCM_MESSAGES, HONDA_BOSCH_ALT_BRAKE_SIGNAL
from selfdrive.car import STD_CARGO_KG, CivicParams, scale_rot_inertia, scale_tire_stiffness, gen_empty_fingerprint, get_safety_config
from selfdrive.car.interfaces import CarInterfaceBase
from selfdrive.car.disable_ecu import disable_ecu
-from selfdrive.config import Conversions as CV
ButtonType = car.CarState.ButtonEvent.Type
@@ -380,8 +380,6 @@ class CarInterface(CarInterfaceBase):
events = self.create_common_events(ret, pcm_enable=False)
if self.CS.brake_error:
events.add(EventName.brakeUnavailable)
- if self.CS.park_brake:
- events.add(EventName.parkBrake)
if self.CP.pcmCruise and ret.vEgo < self.CP.minEnableSpeed:
events.add(EventName.belowEngageSpeed)
@@ -427,11 +425,9 @@ class CarInterface(CarInterfaceBase):
else:
hud_v_cruise = 255
- ret = self.CC.update(c.enabled, c.active, self.CS, self.frame,
- c.actuators,
- c.cruiseControl.cancel,
- hud_v_cruise,
- hud_control.lanesVisible,
+ ret = self.CC.update(c, self.CS, self.frame,
+ c.actuators, c.cruiseControl.cancel,
+ hud_v_cruise, hud_control.lanesVisible,
hud_show_car=hud_control.leadVisible,
hud_alert=hud_control.visualAlert)
diff --git a/selfdrive/car/hyundai/carcontroller.py b/selfdrive/car/hyundai/carcontroller.py
index f7c43bd6e3..6b2cbd422d 100644
--- a/selfdrive/car/hyundai/carcontroller.py
+++ b/selfdrive/car/hyundai/carcontroller.py
@@ -1,7 +1,7 @@
from cereal import car
from common.realtime import DT_CTRL
from common.numpy_fast import clip, interp
-from selfdrive.config import Conversions as CV
+from common.conversions import Conversions as CV
from selfdrive.car import apply_std_steer_torque_limits
from selfdrive.car.hyundai.hyundaican import create_lkas11, create_clu11, create_lfahda_mfc, create_acc_commands, create_acc_opt, create_frt_radar_opt
from selfdrive.car.hyundai.values import Buttons, CarControllerParams, CAR
@@ -46,23 +46,20 @@ class CarController():
self.last_resume_frame = 0
self.accel = 0
- def update(self, c, enabled, CS, frame, actuators, pcm_cancel_cmd, visual_alert, hud_speed,
+ def update(self, c, CS, frame, actuators, pcm_cancel_cmd, visual_alert, hud_speed,
left_lane, right_lane, left_lane_depart, right_lane_depart):
# Steering Torque
new_steer = int(round(actuators.steer * self.p.STEER_MAX))
apply_steer = apply_std_steer_torque_limits(new_steer, self.apply_steer_last, CS.out.steeringTorque, self.p)
self.steer_rate_limited = new_steer != apply_steer
- # disable when temp fault is active, or below LKA minimum speed
- lkas_active = c.active and not CS.out.steerWarning and CS.out.vEgo >= CS.CP.minSteerSpeed
-
- if not lkas_active:
+ if not c.latActive:
apply_steer = 0
self.apply_steer_last = apply_steer
sys_warning, sys_state, left_lane_warning, right_lane_warning = \
- process_hud_alert(enabled, self.car_fingerprint, visual_alert,
+ process_hud_alert(c.enabled, self.car_fingerprint, visual_alert,
left_lane, right_lane, left_lane_depart, right_lane_depart)
can_sends = []
@@ -72,8 +69,8 @@ class CarController():
if (frame % 100) == 0:
can_sends.append([0x7D0, 0, b"\x02\x3E\x80\x00\x00\x00\x00\x00", 0])
- can_sends.append(create_lkas11(self.packer, frame, self.car_fingerprint, apply_steer, lkas_active,
- CS.lkas11, sys_warning, sys_state, enabled,
+ can_sends.append(create_lkas11(self.packer, frame, self.car_fingerprint, apply_steer, c.latActive,
+ CS.lkas11, sys_warning, sys_state, c.enabled,
left_lane, right_lane,
left_lane_warning, right_lane_warning))
@@ -89,7 +86,7 @@ class CarController():
if frame % 2 == 0 and CS.CP.openpilotLongitudinalControl:
lead_visible = False
- accel = actuators.accel if c.active else 0
+ accel = actuators.accel if c.longActive else 0
jerk = clip(2.0 * (accel - CS.out.aEgo), -12.7, 12.7)
@@ -100,7 +97,7 @@ class CarController():
stopping = (actuators.longControlState == LongCtrlState.stopping)
set_speed_in_units = hud_speed * (CV.MS_TO_MPH if CS.clu11["CF_Clu_SPEED_UNIT"] == 1 else CV.MS_TO_KPH)
- can_sends.extend(create_acc_commands(self.packer, enabled, accel, jerk, int(frame / 2), lead_visible, set_speed_in_units, stopping))
+ can_sends.extend(create_acc_commands(self.packer, c.enabled, accel, jerk, int(frame / 2), lead_visible, set_speed_in_units, stopping))
self.accel = accel
# 20 Hz LFA MFA message
@@ -108,7 +105,7 @@ class CarController():
CAR.IONIQ_EV_2020, CAR.IONIQ_PHEV, CAR.KIA_CEED, CAR.KIA_SELTOS, CAR.KONA_EV,
CAR.ELANTRA_2021, CAR.ELANTRA_HEV_2021, CAR.SONATA_HYBRID, CAR.KONA_HEV, CAR.SANTA_FE_2022,
CAR.KIA_K5_2021, CAR.IONIQ_HEV_2022, CAR.SANTA_FE_HEV_2022, CAR.GENESIS_G70_2020, CAR.SANTA_FE_PHEV_2022):
- can_sends.append(create_lfahda_mfc(self.packer, enabled))
+ can_sends.append(create_lfahda_mfc(self.packer, c.enabled))
# 5 Hz ACC options
if frame % 20 == 0 and CS.CP.openpilotLongitudinalControl:
diff --git a/selfdrive/car/hyundai/carstate.py b/selfdrive/car/hyundai/carstate.py
index bdd49e2067..b47fed75df 100644
--- a/selfdrive/car/hyundai/carstate.py
+++ b/selfdrive/car/hyundai/carstate.py
@@ -1,10 +1,10 @@
import copy
from cereal import car
-from selfdrive.car.hyundai.values import DBC, STEER_THRESHOLD, FEATURES, EV_CAR, HYBRID_CAR
-from selfdrive.car.interfaces import CarStateBase
+from common.conversions import Conversions as CV
from opendbc.can.parser import CANParser
from opendbc.can.can_define import CANDefine
-from selfdrive.config import Conversions as CV
+from selfdrive.car.hyundai.values import DBC, STEER_THRESHOLD, FEATURES, EV_CAR, HYBRID_CAR
+from selfdrive.car.interfaces import CarStateBase
class CarState(CarStateBase):
@@ -47,7 +47,7 @@ class CarState(CarStateBase):
ret.steeringTorque = cp.vl["MDPS12"]["CR_Mdps_StrColTq"]
ret.steeringTorqueEps = cp.vl["MDPS12"]["CR_Mdps_OutTq"]
ret.steeringPressed = abs(ret.steeringTorque) > STEER_THRESHOLD
- ret.steerWarning = cp.vl["MDPS12"]["CF_Mdps_ToiUnavail"] != 0 or cp.vl["MDPS12"]["CF_Mdps_ToiFlt"] != 0
+ ret.steerFaultTemporary = cp.vl["MDPS12"]["CF_Mdps_ToiUnavail"] != 0 or cp.vl["MDPS12"]["CF_Mdps_ToiFlt"] != 0
# cruise state
if self.CP.openpilotLongitudinalControl:
@@ -70,6 +70,7 @@ class CarState(CarStateBase):
ret.brake = 0
ret.brakePressed = cp.vl["TCS13"]["DriverBraking"] != 0
ret.brakeHoldActive = cp.vl["TCS15"]["AVH_LAMP"] == 2 # 0 OFF, 1 ERROR, 2 ACTIVE, 3 READY
+ ret.parkingBrake = cp.vl["TCS13"]["PBRAKE_ACT"] == 1
if self.CP.carFingerprint in (HYBRID_CAR | EV_CAR):
if self.CP.carFingerprint in HYBRID_CAR:
@@ -109,7 +110,6 @@ class CarState(CarStateBase):
# save the entire LKAS11 and CLU11
self.lkas11 = copy.copy(cp_cam.vl["LKAS11"])
self.clu11 = copy.copy(cp.vl["CLU11"])
- self.park_brake = cp.vl["TCS13"]["PBRAKE_ACT"] == 1
self.steer_state = cp.vl["MDPS12"]["CF_Mdps_ToiActive"] # 0 NOT ACTIVE, 1 ACTIVE
self.brake_error = cp.vl["TCS13"]["ACCEnable"] != 0 # 0 ACC CONTROL ENABLED, 1-3 ACC CONTROL DISABLED
self.prev_cruise_buttons = self.cruise_buttons
diff --git a/selfdrive/car/hyundai/interface.py b/selfdrive/car/hyundai/interface.py
index 379e6937ae..5d75be0aa4 100644
--- a/selfdrive/car/hyundai/interface.py
+++ b/selfdrive/car/hyundai/interface.py
@@ -2,7 +2,7 @@
from cereal import car
from panda import Panda
from common.params import Params
-from selfdrive.config import Conversions as CV
+from common.conversions import Conversions as CV
from selfdrive.car.hyundai.values import CAR, EV_CAR, HYBRID_CAR, LEGACY_SAFETY_MODE_CAR, Buttons, CarControllerParams
from selfdrive.car.hyundai.radar_interface import RADAR_START_ADDR
from selfdrive.car import STD_CARGO_KG, scale_rot_inertia, scale_tire_stiffness, gen_empty_fingerprint, get_safety_config
@@ -32,7 +32,7 @@ class CarInterface(CarInterfaceBase):
# These cars have been put into dashcam only due to both a lack of users and test coverage.
# These cars likely still work fine. Once a user confirms each car works and a test route is
- # added to selfdrive/test/test_routes, we can remove it from this list.
+ # added to selfdrive/car/tests/routes.py, we can remove it from this list.
ret.dashcamOnly = candidate in {CAR.KIA_OPTIMA_H, CAR.ELANTRA_GT_I30}
ret.steerActuatorDelay = 0.1 # Default delay
@@ -302,8 +302,6 @@ class CarInterface(CarInterfaceBase):
if self.CS.brake_error:
events.add(EventName.brakeUnavailable)
- if self.CS.park_brake:
- events.add(EventName.parkBrake)
if self.CS.CP.openpilotLongitudinalControl:
buttonEvents = []
@@ -352,8 +350,8 @@ class CarInterface(CarInterfaceBase):
def apply(self, c):
hud_control = c.hudControl
- ret = self.CC.update(c, c.enabled, self.CS, self.frame, c.actuators,
- c.cruiseControl.cancel, hud_control.visualAlert, hud_control.setSpeed, hud_control.leftLaneVisible,
- hud_control.rightLaneVisible, hud_control.leftLaneDepart, hud_control.rightLaneDepart)
+ ret = self.CC.update(c, self.CS, self.frame, c.actuators, c.cruiseControl.cancel, hud_control.visualAlert,
+ hud_control.setSpeed, hud_control.leftLaneVisible, hud_control.rightLaneVisible,
+ hud_control.leftLaneDepart, hud_control.rightLaneDepart)
self.frame += 1
return ret
diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py
index e689a57f48..78a0ead909 100644
--- a/selfdrive/car/hyundai/values.py
+++ b/selfdrive/car/hyundai/values.py
@@ -11,8 +11,8 @@ class CarControllerParams:
# To determine the limit for your car, find the maximum value that the stock LKAS will request.
# If the max stock LKAS request is <384, add your car to this list.
if CP.carFingerprint in (CAR.GENESIS_G80, CAR.GENESIS_G90, CAR.ELANTRA, CAR.HYUNDAI_GENESIS, CAR.ELANTRA_GT_I30, CAR.IONIQ,
- CAR.IONIQ_EV_LTD, CAR.IONIQ_PHEV, CAR.SANTA_FE_PHEV_2022, CAR.SONATA_LF, CAR.KIA_FORTE, CAR.KIA_NIRO_HEV,
- CAR.KIA_NIRO_HEV_2021, CAR.KIA_OPTIMA_H, CAR.KIA_OPTIMA, CAR.KIA_SORENTO, CAR.KIA_STINGER):
+ CAR.IONIQ_EV_LTD, CAR.SANTA_FE_PHEV_2022, CAR.SONATA_LF, CAR.KIA_FORTE, CAR.KIA_NIRO_HEV,
+ CAR.KIA_OPTIMA_H, CAR.KIA_OPTIMA, CAR.KIA_SORENTO, CAR.KIA_STINGER):
self.STEER_MAX = 255
else:
self.STEER_MAX = 384
@@ -184,21 +184,27 @@ FW_VERSIONS = {
(Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\000AEhe SCC FHCUP 1.00 1.02 99110-G2100 ',
b'\xf1\x00AEhe SCC F-CUP 1.00 1.00 99110-G2200 ',
+ b'\xf1\x00AEhe SCC F-CUP 1.00 1.00 99110-G2600 ',
],
(Ecu.eps, 0x7d4, None): [
b'\xf1\000AE MDPS C 1.00 1.01 56310/G2510 4APHC101',
b'\xf1\x00AE MDPS C 1.00 1.01 56310/G2560 4APHC101',
+ b'\xf1\x00AE MDPS C 1.00 1.01 56310G2510\x00 4APHC101',
],
(Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\000AEP MFC AT USA LHD 1.00 1.01 95740-G2600 190819',
b'\xf1\x00AEP MFC AT EUR RHD 1.00 1.01 95740-G2600 190819',
+ b'\xf1\x00AEP MFC AT USA LHD 1.00 1.00 95740-G2700 201027',
],
(Ecu.engine, 0x7e0, None): [
b'\xf1\x816H6F6051\x00\x00\x00\x00\x00\x00\x00\x00',
+ b'\xf1\x816H6G6051\x00\x00\x00\x00\x00\x00\x00\x00',
],
(Ecu.transmission, 0x7e1, None): [
b'\xf1\x816U3J9051\000\000\xf1\0006U3H1_C2\000\0006U3J9051\000\000PAE0G16NL0\x82zT\xd2',
b'\xf1\x816U3J8051\x00\x00\xf1\x006U3H1_C2\x00\x006U3J8051\x00\x00PAETG16UL0\x00\x00\x00\x00',
+ b'\xf1\x816U3J9051\x00\x00\xf1\x006U3H1_C2\x00\x006U3J9051\x00\x00PAE0G16NL2\xad\xeb\xabt',
+ b'\xf1\x816U3J9051\x00\x00\xf1\x006U3H1_C2\x00\x006U3J9051\x00\x00PAE0G16NL2\x00\x00\x00\x00',
],
},
CAR.IONIQ_EV_2020: {
@@ -460,6 +466,7 @@ FW_VERSIONS = {
(Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00TM__ SCC F-CUP 1.00 1.00 99110-S1500 ',
b'\xf1\x8799110S1500\xf1\x00TM__ SCC F-CUP 1.00 1.00 99110-S1500 ',
+ b'\xf1\x8799110S1500\xf1\x00TM__ SCC FHCUP 1.00 1.00 99110-S1500 ',
],
(Ecu.esp, 0x7d1, None): [
b'\xf1\x00TM ESC \x02 101 \x08\x04 58910-S2GA0',
@@ -467,11 +474,14 @@ FW_VERSIONS = {
b'\xf1\x8758910-S2DA0\xf1\x00TM ESC \x03 101 \x08\x02 58910-S2DA0',
b'\xf1\x8758910-S2GA0\xf1\x00TM ESC \x02 101 \x08\x04 58910-S2GA0',
b'\xf1\x8758910-S1DA0\xf1\x00TM ESC \x1e 102 \x08\x08 58910-S1DA0',
+ b'\xf1\x8758910-S2GA0\xf1\x00TM ESC \x04 102!\x04\x05 58910-S2GA0',
],
(Ecu.engine, 0x7e0, None): [
+ b'\xf1\x82TACVN5GMI3XXXH0A',
b'\xf1\x82TMBZN5TMD3XXXG2E',
b'\xf1\x82TACVN5GSI3XXXH0A',
b'\xf1\x82TMCFD5MMCXXXXG0A',
+ b'\xf1\x870\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x82TMDWN5TMD3TXXJ1A',
],
(Ecu.eps, 0x7d4, None): [
b'\xf1\x00TM MDPS C 1.00 1.02 56370-S2AA0 0B19',
@@ -481,12 +491,15 @@ FW_VERSIONS = {
b'\xf1\x00TMA MFC AT MEX LHD 1.00 1.01 99211-S2500 210205',
b'\xf1\x00TMA MFC AT USA LHD 1.00 1.00 99211-S2500 200720',
b'\xf1\x00TM MFC AT EUR LHD 1.00 1.03 99211-S1500 210224',
+ b'\xf1\x00TMA MFC AT USA LHD 1.00 1.01 99211-S2500 210205',
],
(Ecu.transmission, 0x7e1, None): [
+ b'\xf1\x87SDMXCA9087684GN1VfvgUUeVwwgwwwwwffffU?\xfb\xff\x97\x88\x7f\xff+\xa4\xf1\x89HT6WAD00A1\xf1\x82STM4G25NH1\x00\x00\x00\x00\x00\x00',
b'\xf1\x00T02601BL T02730A1 VTMPT25XXX730NS2\xa6\x06\x88\xf7',
b'\xf1\x87SDMXCA8653204GN1EVugEUuWwwwwww\x87wwwwwv/\xfb\xff\xa8\x88\x9f\xff\xa5\x9c\xf1\x89HT6WAD00A1\xf1\x82STM4G25NH1\x00\x00\x00\x00\x00\x00',
b'\xf1\x87954A02N250\x00\x00\x00\x00\x00\xf1\x81T02730A1 \xf1\x00T02601BL T02730A1 VTMPT25XXX730NS2\xa6\x06\x88\xf7',
b'\xf1\x87KMMYBU034207SB72x\x89\x88\x98h\x88\x98\x89\x87fhvvfWf33_\xff\x87\xff\x8f\xfa\x81\xe5\xf1\x89HT6TAF00A1\xf1\x82STM0M25GS1\x00\x00\x00\x00\x00\x00',
+ b'\xf1\x87954A02N250\x00\x00\x00\x00\x00\xf1\x81T02730A1 \xf1\x00T02601BL T02730A1 VTMPT25XXX730NS2\xa6',
],
},
CAR.SANTA_FE_HEV_2022: {
@@ -855,6 +868,7 @@ FW_VERSIONS = {
],
(Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00DEH MFC AT USA LHD 1.00 1.07 99211-G5000 201221',
+ b'\xf1\x00DEH MFC AT USA LHD 1.00 1.00 99211-G5500 210428',
],
(Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00DEhe SCC FHCUP 1.00 1.00 99110-G5600 ',
@@ -905,6 +919,7 @@ FW_VERSIONS = {
b'\xf1\x00CN7_ SCC F-CUP 1.00 1.01 99110-AA000 ',
b'\xf1\x00CN7_ SCC FHCUP 1.00 1.01 99110-AA000 ',
b'\xf1\x8799110AA000\xf1\x00CN7_ SCC FHCUP 1.00 1.01 99110-AA000 ',
+ b'\xf1\x8799110AA000\xf1\x00CN7_ SCC F-CUP 1.00 1.01 99110-AA000 ',
],
(Ecu.eps, 0x7d4, None): [
b'\xf1\x87\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x00CN7 MDPS C 1.00 1.06 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 4CNDC106',
@@ -927,7 +942,8 @@ FW_VERSIONS = {
b'\xf1\x87CXMQFM2135005JB2E\xb9\x89\x98W\xa9y\x97h\xa9\x98\x99wxvwh\x87\177\xffx\xff\xff\xff,,\xf1\x89HT6VA640A1\xf1\x82CCN0N20NS5\x00\x00\x00\x00\x00\x00',
b'\xf1\x87CXMQFM1916035JB2\x88vvgg\x87Wuwgev\xa9\x98\x88\x98h\x99\x9f\xffh\xff\xff\xff\xa5\xee\xf1\x89HT6VA640A1\xf1\x82CCN0N20NS5\x00\x00\x00\x00\x00\x00',
b'\xf1\x87CXLQF40189012JL2f\x88\x86\x88\x88vUex\xb8\x88\x88\x88\x87\x88\x89fh?\xffz\xff\xff\xff\x08z\xf1\x89HT6VA640A1\xf1\x82CCN0N20NS5\x00\x00\x00\x00\x00\x00',
- b'\xf1\x87CXMQFM2728305JB2E\x97\x87xw\x87vwgw\x84x\x88\x88w\x89EI\xbf\xff{\xff\xff\xff\xe6\x0e\xf1\x89HT6VA640A1\xf1\x82CCN0N20NS5\x00\x00\x00\x00\x00\x00'
+ b'\xf1\x87CXMQFM2728305JB2E\x97\x87xw\x87vwgw\x84x\x88\x88w\x89EI\xbf\xff{\xff\xff\xff\xe6\x0e\xf1\x89HT6VA640A1\xf1\x82CCN0N20NS5\x00\x00\x00\x00\x00\x00',
+ b'\xf1\x87CXMQFM3806705JB2\x89\x87wwx\x88g\x86\x99\x87\x86xwwv\x88yv\x7f\xffz\xff\xff\xffV\x15\xf1\x89HT6VA640A1\xf1\x82CCN0N20NS5\x00\x00\x00\x00\x00\x00',
],
(Ecu.engine, 0x7e0, None): [
b'\xf1\x82CNCWD0AMFCXCSFFA',
diff --git a/selfdrive/car/interfaces.py b/selfdrive/car/interfaces.py
index b19eae8730..0116c1668d 100644
--- a/selfdrive/car/interfaces.py
+++ b/selfdrive/car/interfaces.py
@@ -7,7 +7,7 @@ from cereal import car
from common.kalman.simple_kalman import KF1D
from common.realtime import DT_CTRL
from selfdrive.car import gen_empty_fingerprint
-from selfdrive.config import Conversions as CV
+from common.conversions import Conversions as CV
from selfdrive.controls.lib.drive_helpers import V_CRUISE_MAX
from selfdrive.controls.lib.events import Events
from selfdrive.controls.lib.vehicle_model import VehicleModel
@@ -90,7 +90,7 @@ class CarInterfaceBase(ABC):
ret.stopAccel = -2.0
ret.stoppingDecelRate = 0.8 # brake_travel/s while trying to stop
ret.vEgoStopping = 0.5
- ret.vEgoStarting = 0.5 # needs to be >= vEgoStopping to avoid state transition oscillation
+ ret.vEgoStarting = 0.5
ret.stoppingControl = True
ret.longitudinalTuning.deadzoneBP = [0.]
ret.longitudinalTuning.deadzoneV = [0.]
@@ -141,11 +141,13 @@ class CarInterfaceBase(ABC):
events.add(EventName.wrongCruiseMode)
if cs_out.brakeHoldActive and self.CP.openpilotLongitudinalControl:
events.add(EventName.brakeHold)
+ if cs_out.parkingBrake:
+ events.add(EventName.parkBrake)
# Handle permanent and temporary steering faults
self.steering_unpressed = 0 if cs_out.steeringPressed else self.steering_unpressed + 1
- if cs_out.steerWarning:
+ if cs_out.steerFaultTemporary:
# if the user overrode recently, show a less harsh alert
if self.silent_steer_warning or cs_out.standstill or self.steering_unpressed < int(1.5 / DT_CTRL):
self.silent_steer_warning = True
@@ -154,7 +156,7 @@ class CarInterfaceBase(ABC):
events.add(EventName.steerTempUnavailable)
else:
self.silent_steer_warning = False
- if cs_out.steerError:
+ if cs_out.steerFaultPermanent:
events.add(EventName.steerUnavailable)
# Disable on rising edge of gas or brake. Also disable on brake when speed > 0.
diff --git a/selfdrive/car/mazda/carcontroller.py b/selfdrive/car/mazda/carcontroller.py
index 60bb620377..5f3d41ae34 100644
--- a/selfdrive/car/mazda/carcontroller.py
+++ b/selfdrive/car/mazda/carcontroller.py
@@ -19,7 +19,7 @@ class CarController():
apply_steer = 0
self.steer_rate_limited = False
- if c.active:
+ if c.latActive:
# calculate steer and also set limits due to driver torque
new_steer = int(round(c.actuators.steer * CarControllerParams.STEER_MAX))
apply_steer = apply_std_steer_torque_limits(new_steer, self.apply_steer_last,
@@ -32,7 +32,7 @@ class CarController():
# TODO: improve the resume trigger logic by looking at actual radar data
can_sends.append(mazdacan.create_button_cmd(self.packer, CS.CP.carFingerprint, CS.crz_btns_counter, Buttons.RESUME))
- if c.cruiseControl.cancel or (CS.out.cruiseState.enabled and not c.enabled):
+ if c.cruiseControl.cancel:
# If brake is pressed, let us wait >70ms before trying to disable crz to avoid
# a race condition with the stock system, where the second cancel from openpilot
# will disable the crz 'main on'. crz ctrl msg runs at 50hz. 70ms allows us to
diff --git a/selfdrive/car/mazda/carstate.py b/selfdrive/car/mazda/carstate.py
index feb1147549..fa15f2453c 100644
--- a/selfdrive/car/mazda/carstate.py
+++ b/selfdrive/car/mazda/carstate.py
@@ -1,5 +1,5 @@
from cereal import car
-from selfdrive.config import Conversions as CV
+from common.conversions import Conversions as CV
from opendbc.can.can_define import CANDefine
from opendbc.can.parser import CANParser
from selfdrive.car.interfaces import CarStateBase
@@ -88,7 +88,7 @@ class CarState(CarStateBase):
# Check if LKAS is disabled due to lack of driver torque when all other states indicate
# it should be enabled (steer lockout). Don't warn until we actually get lkas active
# and lose it again, i.e, after initial lkas activation
- ret.steerWarning = self.lkas_allowed_speed and lkas_blocked
+ ret.steerFaultTemporary = self.lkas_allowed_speed and lkas_blocked
self.acc_active_last = ret.cruiseState.enabled
@@ -98,7 +98,7 @@ class CarState(CarStateBase):
self.lkas_disabled = cp_cam.vl["CAM_LANEINFO"]["LANE_LINES"] == 0
self.cam_lkas = cp_cam.vl["CAM_LKAS"]
self.cam_laneinfo = cp_cam.vl["CAM_LANEINFO"]
- ret.steerError = cp_cam.vl["CAM_LKAS"]["ERR_BIT_1"] == 1
+ ret.steerFaultPermanent = cp_cam.vl["CAM_LKAS"]["ERR_BIT_1"] == 1
return ret
diff --git a/selfdrive/car/mazda/interface.py b/selfdrive/car/mazda/interface.py
index fb8edd6f42..c910d7e148 100755
--- a/selfdrive/car/mazda/interface.py
+++ b/selfdrive/car/mazda/interface.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
from cereal import car
-from selfdrive.config import Conversions as CV
+from common.conversions import Conversions as CV
from selfdrive.car.mazda.values import CAR, LKAS_LIMITS
from selfdrive.car import STD_CARGO_KG, scale_rot_inertia, scale_tire_stiffness, gen_empty_fingerprint, get_safety_config
from selfdrive.car.interfaces import CarInterfaceBase
diff --git a/selfdrive/car/mock/interface.py b/selfdrive/car/mock/interface.py
index b2e315a5f9..d7fcad0748 100755
--- a/selfdrive/car/mock/interface.py
+++ b/selfdrive/car/mock/interface.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
import math
from cereal import car
-from selfdrive.config import Conversions as CV
+from common.conversions import Conversions as CV
from selfdrive.swaglog import cloudlog
import cereal.messaging as messaging
from selfdrive.car import gen_empty_fingerprint, get_safety_config
diff --git a/selfdrive/car/nissan/carcontroller.py b/selfdrive/car/nissan/carcontroller.py
index 8b30c11249..15cd44be92 100644
--- a/selfdrive/car/nissan/carcontroller.py
+++ b/selfdrive/car/nissan/carcontroller.py
@@ -18,20 +18,19 @@ class CarController():
self.packer = CANPacker(dbc_name)
- def update(self, c, enabled, CS, frame, actuators, cruise_cancel, hud_alert,
+ def update(self, c, CS, frame, actuators, cruise_cancel, hud_alert,
left_line, right_line, left_lane_depart, right_lane_depart):
can_sends = []
### STEER ###
- acc_active = CS.out.cruiseState.enabled
lkas_hud_msg = CS.lkas_hud_msg
lkas_hud_info_msg = CS.lkas_hud_info_msg
apply_angle = actuators.steeringAngleDeg
steer_hud_alert = 1 if hud_alert in (VisualAlert.steerRequired, VisualAlert.ldw) else 0
- if c.active:
+ if c.latActive:
# # windup slower
if self.last_angle * apply_angle > 0. and abs(apply_angle) > abs(self.last_angle):
angle_rate_lim = interp(CS.out.vEgo, CarControllerParams.ANGLE_DELTA_BP, CarControllerParams.ANGLE_DELTA_V)
@@ -58,10 +57,6 @@ class CarController():
self.last_angle = apply_angle
- if not enabled and acc_active:
- # send acc cancel cmd if drive is disabled but pcm is still on, or if the system can't be activated
- cruise_cancel = 1
-
if self.CP.carFingerprint in (CAR.ROGUE, CAR.XTRAIL, CAR.ALTIMA) and cruise_cancel:
can_sends.append(nissancan.create_acc_cancel_cmd(self.packer, self.car_fingerprint, CS.cruise_throttle_msg, frame))
@@ -73,12 +68,12 @@ class CarController():
can_sends.append(nissancan.create_cancel_msg(self.packer, CS.cancel_msg, cruise_cancel))
can_sends.append(nissancan.create_steering_control(
- self.packer, apply_angle, frame, enabled, self.lkas_max_torque))
+ self.packer, apply_angle, frame, c.enabled, self.lkas_max_torque))
if lkas_hud_msg and lkas_hud_info_msg:
if frame % 2 == 0:
can_sends.append(nissancan.create_lkas_hud_msg(
- self.packer, lkas_hud_msg, enabled, left_line, right_line, left_lane_depart, right_lane_depart))
+ self.packer, lkas_hud_msg, c.enabled, left_line, right_line, left_lane_depart, right_lane_depart))
if frame % 50 == 0:
can_sends.append(nissancan.create_lkas_hud_info_msg(
diff --git a/selfdrive/car/nissan/carstate.py b/selfdrive/car/nissan/carstate.py
index 6b030e9b45..3c5d7dc24b 100644
--- a/selfdrive/car/nissan/carstate.py
+++ b/selfdrive/car/nissan/carstate.py
@@ -3,7 +3,7 @@ from collections import deque
from cereal import car
from opendbc.can.can_define import CANDefine
from selfdrive.car.interfaces import CarStateBase
-from selfdrive.config import Conversions as CV
+from common.conversions import Conversions as CV
from opendbc.can.parser import CANParser
from selfdrive.car.nissan.values import CAR, DBC, CarControllerParams
diff --git a/selfdrive/car/nissan/interface.py b/selfdrive/car/nissan/interface.py
index c32fb13780..63b4dad7fd 100644
--- a/selfdrive/car/nissan/interface.py
+++ b/selfdrive/car/nissan/interface.py
@@ -79,7 +79,7 @@ class CarInterface(CarInterfaceBase):
def apply(self, c):
hud_control = c.hudControl
- ret = self.CC.update(c, c.enabled, self.CS, self.frame, c.actuators,
+ ret = self.CC.update(c, self.CS, self.frame, c.actuators,
c.cruiseControl.cancel, hud_control.visualAlert,
hud_control.leftLaneVisible, hud_control.rightLaneVisible,
hud_control.leftLaneDepart, hud_control.rightLaneDepart)
diff --git a/selfdrive/car/subaru/carcontroller.py b/selfdrive/car/subaru/carcontroller.py
index afc91f4755..fd439356e9 100644
--- a/selfdrive/car/subaru/carcontroller.py
+++ b/selfdrive/car/subaru/carcontroller.py
@@ -15,7 +15,7 @@ class CarController():
self.p = CarControllerParams(CP)
self.packer = CANPacker(DBC[CP.carFingerprint]['pt'])
- def update(self, c, enabled, CS, frame, actuators, pcm_cancel_cmd, visual_alert, left_line, right_line, left_lane_depart, right_lane_depart):
+ def update(self, c, CS, frame, actuators, pcm_cancel_cmd, visual_alert, left_line, right_line, left_lane_depart, right_lane_depart):
can_sends = []
@@ -30,7 +30,7 @@ class CarController():
apply_steer = apply_std_steer_torque_limits(new_steer, self.apply_steer_last, CS.out.steeringTorque, self.p)
self.steer_rate_limited = new_steer != apply_steer
- if not c.active:
+ if not c.latActive:
apply_steer = 0
if CS.CP.carFingerprint in PREGLOBAL_CARS:
@@ -69,7 +69,7 @@ class CarController():
self.es_distance_cnt = CS.es_distance_msg["Counter"]
if self.es_lkas_cnt != CS.es_lkas_msg["Counter"]:
- can_sends.append(subarucan.create_es_lkas(self.packer, CS.es_lkas_msg, enabled, visual_alert, left_line, right_line, left_lane_depart, right_lane_depart))
+ can_sends.append(subarucan.create_es_lkas(self.packer, CS.es_lkas_msg, c.enabled, visual_alert, left_line, right_line, left_lane_depart, right_lane_depart))
self.es_lkas_cnt = CS.es_lkas_msg["Counter"]
new_actuators = actuators.copy()
diff --git a/selfdrive/car/subaru/carstate.py b/selfdrive/car/subaru/carstate.py
index 1eefb18584..45ea66fb27 100644
--- a/selfdrive/car/subaru/carstate.py
+++ b/selfdrive/car/subaru/carstate.py
@@ -1,7 +1,7 @@
import copy
from cereal import car
from opendbc.can.can_define import CANDefine
-from selfdrive.config import Conversions as CV
+from common.conversions import Conversions as CV
from selfdrive.car.interfaces import CarStateBase
from opendbc.can.parser import CANParser
from selfdrive.car.subaru.values import DBC, STEER_THRESHOLD, CAR, PREGLOBAL_CARS
@@ -62,13 +62,13 @@ class CarState(CarStateBase):
cp.vl["BodyInfo"]["DOOR_OPEN_RL"],
cp.vl["BodyInfo"]["DOOR_OPEN_FR"],
cp.vl["BodyInfo"]["DOOR_OPEN_FL"]])
- ret.steerError = cp.vl["Steering_Torque"]["Steer_Error_1"] == 1
+ ret.steerFaultPermanent = cp.vl["Steering_Torque"]["Steer_Error_1"] == 1
if self.car_fingerprint in PREGLOBAL_CARS:
self.cruise_button = cp_cam.vl["ES_Distance"]["Cruise_Button"]
self.ready = not cp_cam.vl["ES_DashStatus"]["Not_Ready_Startup"]
else:
- ret.steerWarning = cp.vl["Steering_Torque"]["Steer_Warning"] == 1
+ ret.steerFaultTemporary = cp.vl["Steering_Torque"]["Steer_Warning"] == 1
ret.cruiseState.nonAdaptive = cp_cam.vl["ES_DashStatus"]["Conventional_Cruise"] == 1
self.es_lkas_msg = copy.copy(cp_cam.vl["ES_LKAS_State"])
self.es_distance_msg = copy.copy(cp_cam.vl["ES_Distance"])
diff --git a/selfdrive/car/subaru/interface.py b/selfdrive/car/subaru/interface.py
index 8c6d188643..fdd077ac49 100644
--- a/selfdrive/car/subaru/interface.py
+++ b/selfdrive/car/subaru/interface.py
@@ -123,7 +123,7 @@ class CarInterface(CarInterfaceBase):
def apply(self, c):
hud_control = c.hudControl
- ret = self.CC.update(c, c.enabled, self.CS, self.frame, c.actuators,
+ ret = self.CC.update(c, self.CS, self.frame, c.actuators,
c.cruiseControl.cancel, hud_control.visualAlert,
hud_control.leftLaneVisible, hud_control.rightLaneVisible, hud_control.leftLaneDepart, hud_control.rightLaneDepart)
self.frame += 1
diff --git a/selfdrive/car/subaru/values.py b/selfdrive/car/subaru/values.py
index 9bd3d009f8..ee11485291 100644
--- a/selfdrive/car/subaru/values.py
+++ b/selfdrive/car/subaru/values.py
@@ -74,12 +74,14 @@ FW_VERSIONS = {
b'\x7a\x94\x3f\x90\x00',
b'\xa2 \x185\x00',
b'\xa2 \x193\x00',
+ b'\xa2 \x194\x00',
b'z\x94.\x90\x00',
b'z\x94\b\x90\x01',
b'\xa2 \x19`\x00',
b'z\x94\f\x90\001',
b'z\x9c\x19\x80\x01',
b'z\x94\x08\x90\x00',
+ b'z\x84\x19\x90\x00',
],
(Ecu.eps, 0x746, None): [
b'\x7a\xc0\x0c\x00',
diff --git a/selfdrive/car/tesla/carcontroller.py b/selfdrive/car/tesla/carcontroller.py
index 03f09f2407..d5a5bb8629 100644
--- a/selfdrive/car/tesla/carcontroller.py
+++ b/selfdrive/car/tesla/carcontroller.py
@@ -12,12 +12,12 @@ class CarController():
self.pt_packer = CANPacker(DBC[CP.carFingerprint]['pt'])
self.tesla_can = TeslaCAN(self.packer, self.pt_packer)
- def update(self, c, enabled, CS, frame, actuators, cruise_cancel):
+ def update(self, c, CS, frame, actuators, cruise_cancel):
can_sends = []
# Temp disable steering on a hands_on_fault, and allow for user override
hands_on_fault = (CS.steer_warning == "EAC_ERROR_HANDS_ON" and CS.hands_on_level >= 3)
- lkas_enabled = c.active and (not hands_on_fault)
+ lkas_enabled = c.latActive and (not hands_on_fault)
if lkas_enabled:
apply_angle = actuators.steeringAngleDeg
@@ -50,10 +50,6 @@ class CarController():
if hands_on_fault:
cruise_cancel = True
- # Cancel when openpilot is not enabled anymore
- if not enabled and bool(CS.out.cruiseState.enabled):
- cruise_cancel = True
-
if ((frame % 10) == 0 and cruise_cancel):
# Spam every possible counter value, otherwise it might not be accepted
for counter in range(16):
diff --git a/selfdrive/car/tesla/carstate.py b/selfdrive/car/tesla/carstate.py
index 51ae43ad1b..42a7983505 100644
--- a/selfdrive/car/tesla/carstate.py
+++ b/selfdrive/car/tesla/carstate.py
@@ -1,10 +1,10 @@
import copy
from cereal import car
+from common.conversions import Conversions as CV
from selfdrive.car.tesla.values import DBC, CANBUS, GEAR_MAP, DOORS, BUTTONS
from selfdrive.car.interfaces import CarStateBase
from opendbc.can.parser import CANParser
from opendbc.can.can_define import CANDefine
-from selfdrive.config import Conversions as CV
class CarState(CarStateBase):
def __init__(self, CP):
@@ -43,8 +43,8 @@ class CarState(CarStateBase):
ret.steeringRateDeg = -cp.vl["STW_ANGLHP_STAT"]["StW_AnglHP_Spd"] # This is from a different angle sensor, and at different rate
ret.steeringTorque = -cp.vl["EPAS_sysStatus"]["EPAS_torsionBarTorque"]
ret.steeringPressed = (self.hands_on_level > 0)
- ret.steerError = steer_status == "EAC_FAULT"
- ret.steerWarning = self.steer_warning != "EAC_ERROR_IDLE"
+ ret.steerFaultPermanent = steer_status == "EAC_FAULT"
+ ret.steerFaultTemporary = self.steer_warning != "EAC_ERROR_IDLE"
# Cruise state
cruise_state = self.can_define.dv["DI_state"]["DI_cruiseState"].get(int(cp.vl["DI_state"]["DI_cruiseState"]), None)
diff --git a/selfdrive/car/tesla/interface.py b/selfdrive/car/tesla/interface.py
index 746cd356ea..3bd1a0efca 100755
--- a/selfdrive/car/tesla/interface.py
+++ b/selfdrive/car/tesla/interface.py
@@ -71,6 +71,6 @@ class CarInterface(CarInterfaceBase):
return self.CS.out
def apply(self, c):
- ret = self.CC.update(c, c.enabled, self.CS, self.frame, c.actuators, c.cruiseControl.cancel)
+ ret = self.CC.update(c, self.CS, self.frame, c.actuators, c.cruiseControl.cancel)
self.frame += 1
return ret
diff --git a/selfdrive/car/tesla/teslacan.py b/selfdrive/car/tesla/teslacan.py
index 1301802860..d48cd284d9 100644
--- a/selfdrive/car/tesla/teslacan.py
+++ b/selfdrive/car/tesla/teslacan.py
@@ -1,6 +1,6 @@
import copy
import crcmod
-from selfdrive.config import Conversions as CV
+from common.conversions import Conversions as CV
from selfdrive.car.tesla.values import CANBUS, CarControllerParams
diff --git a/selfdrive/test/test_routes.py b/selfdrive/car/tests/routes.py
similarity index 99%
rename from selfdrive/test/test_routes.py
rename to selfdrive/car/tests/routes.py
index 02bcd36b19..1980a7f0ed 100644
--- a/selfdrive/test/test_routes.py
+++ b/selfdrive/car/tests/routes.py
@@ -69,7 +69,7 @@ routes = [
TestRoute("6fe86b4e410e4c37|2020-07-22--16-27-13", HYUNDAI.HYUNDAI_GENESIS),
TestRoute("70c5bec28ec8e345|2020-08-08--12-22-23", HYUNDAI.GENESIS_G70),
TestRoute("6b301bf83f10aa90|2020-11-22--16-45-07", HYUNDAI.GENESIS_G80),
- TestRoute("38bfd238edecbcd7|2018-08-29--22-02-15", HYUNDAI.SANTA_FE),
+ TestRoute("4dbd55df87507948|2022-03-01--09-45-38", HYUNDAI.SANTA_FE),
TestRoute("bf43d9df2b660eb0|2021-09-23--14-16-37", HYUNDAI.SANTA_FE_2022),
TestRoute("37398f32561a23ad|2021-11-18--00-11-35", HYUNDAI.SANTA_FE_HEV_2022),
TestRoute("656ac0d830792fcc|2021-12-28--14-45-56", HYUNDAI.SANTA_FE_PHEV_2022),
diff --git a/selfdrive/car/tests/test_car_interfaces.py b/selfdrive/car/tests/test_car_interfaces.py
index 930619ee67..2f4984c3d9 100755
--- a/selfdrive/car/tests/test_car_interfaces.py
+++ b/selfdrive/car/tests/test_car_interfaces.py
@@ -12,7 +12,6 @@ class TestCarInterfaces(unittest.TestCase):
@parameterized.expand([(car,) for car in all_known_cars()])
def test_car_interfaces(self, car_name):
- print(car_name)
if car_name in FINGERPRINTS:
fingerprint = FINGERPRINTS[car_name][0]
else:
diff --git a/selfdrive/test/test_fingerprints.py b/selfdrive/car/tests/test_fingerprints.py
similarity index 100%
rename from selfdrive/test/test_fingerprints.py
rename to selfdrive/car/tests/test_fingerprints.py
diff --git a/selfdrive/test/test_models.py b/selfdrive/car/tests/test_models.py
similarity index 97%
rename from selfdrive/test/test_models.py
rename to selfdrive/car/tests/test_models.py
index 3be0f96b37..09d17462e6 100755
--- a/selfdrive/test/test_models.py
+++ b/selfdrive/car/tests/test_models.py
@@ -17,7 +17,7 @@ from selfdrive.car.gm.values import CAR as GM
from selfdrive.car.honda.values import CAR as HONDA, HONDA_BOSCH
from selfdrive.car.hyundai.values import CAR as HYUNDAI
from selfdrive.car.toyota.values import CAR as TOYOTA
-from selfdrive.test.test_routes import routes, non_tested_cars
+from selfdrive.car.tests.routes import routes, non_tested_cars
from selfdrive.test.openpilotci import get_url
from tools.lib.logreader import LogReader
@@ -29,11 +29,6 @@ PandaType = log.PandaState.PandaType
NUM_JOBS = int(os.environ.get("NUM_JOBS", "1"))
JOB_ID = int(os.environ.get("JOB_ID", "0"))
-# TODO: get updated routes for these cars
-ignore_can_valid = [
- HYUNDAI.SANTA_FE,
-]
-
ignore_addr_checks_valid = [
GM.BUICK_REGAL,
HYUNDAI.GENESIS_G70_2020,
@@ -135,8 +130,7 @@ class TestCarModel(unittest.TestCase):
if i > 200:
can_invalid_cnt += not CS.canValid
- if self.car_model not in ignore_can_valid:
- self.assertLess(can_invalid_cnt, 50)
+ self.assertLess(can_invalid_cnt, 50)
def test_radar_interface(self):
os.environ['NO_RADAR_SLEEP'] = "1"
diff --git a/selfdrive/car/toyota/carcontroller.py b/selfdrive/car/toyota/carcontroller.py
index 87ba0055f0..5ec69488d5 100644
--- a/selfdrive/car/toyota/carcontroller.py
+++ b/selfdrive/car/toyota/carcontroller.py
@@ -22,11 +22,11 @@ class CarController():
self.gas = 0
self.accel = 0
- def update(self, enabled, active, CS, frame, actuators, pcm_cancel_cmd, hud_alert,
+ def update(self, c, CS, frame, actuators, pcm_cancel_cmd, hud_alert,
left_line, right_line, lead, left_lane_depart, right_lane_depart):
# gas and brake
- if CS.CP.enableGasInterceptor and active:
+ if CS.CP.enableGasInterceptor and c.longActive:
MAX_INTERCEPTOR_GAS = 0.5
# RAV4 has very sensitive gas pedal
if CS.CP.carFingerprint in (CAR.RAV4, CAR.RAV4H, CAR.HIGHLANDER, CAR.HIGHLANDERH):
@@ -49,7 +49,7 @@ class CarController():
self.steer_rate_limited = new_steer != apply_steer
# Cut steering while we're in a known fault state (2s)
- if not active or CS.steer_state in (9, 25):
+ if not c.latActive or CS.steer_state in (9, 25):
apply_steer = 0
apply_steer_req = 0
else:
@@ -57,7 +57,7 @@ class CarController():
# TODO: probably can delete this. CS.pcm_acc_status uses a different signal
# than CS.cruiseState.enabled. confirm they're not meaningfully different
- if not enabled and CS.pcm_acc_status:
+ if not c.enabled and CS.pcm_acc_status:
pcm_cancel_cmd = 1
# on entering standstill, send standstill request
@@ -122,7 +122,7 @@ class CarController():
send_ui = True
if (frame % 100 == 0 or send_ui):
- can_sends.append(create_ui_command(self.packer, steer_alert, pcm_cancel_cmd, left_line, right_line, left_lane_depart, right_lane_depart, enabled))
+ can_sends.append(create_ui_command(self.packer, steer_alert, pcm_cancel_cmd, left_line, right_line, left_lane_depart, right_lane_depart, c.enabled))
if frame % 100 == 0 and CS.CP.enableDsu:
can_sends.append(create_fcw_command(self.packer, fcw_alert))
diff --git a/selfdrive/car/toyota/carstate.py b/selfdrive/car/toyota/carstate.py
index d73460ef32..a951955505 100644
--- a/selfdrive/car/toyota/carstate.py
+++ b/selfdrive/car/toyota/carstate.py
@@ -1,11 +1,11 @@
from cereal import car
+from common.conversions import Conversions as CV
from common.numpy_fast import mean
from common.filter_simple import FirstOrderFilter
from common.realtime import DT_CTRL
from opendbc.can.can_define import CANDefine
-from selfdrive.car.interfaces import CarStateBase
from opendbc.can.parser import CANParser
-from selfdrive.config import Conversions as CV
+from selfdrive.car.interfaces import CarStateBase
from selfdrive.car.toyota.values import ToyotaFlags, CAR, DBC, STEER_THRESHOLD, NO_STOP_TIMER_CAR, TSS2_CAR, EPS_SCALE
@@ -19,7 +19,6 @@ class CarState(CarStateBase):
# On cars with cp.vl["STEER_TORQUE_SENSOR"]["STEER_ANGLE"]
# the signal is zeroed to where the steering angle is at start.
# Need to apply an offset as soon as the steering angle measurements are both received
- self.needs_angle_offset = True
self.accurate_steer_angle_seen = False
self.angle_offset = FirstOrderFilter(None, 60.0, DT_CTRL, initialized=False)
@@ -32,6 +31,7 @@ class CarState(CarStateBase):
ret.doorOpen = any([cp.vl["BODY_CONTROL_STATE"]["DOOR_OPEN_FL"], cp.vl["BODY_CONTROL_STATE"]["DOOR_OPEN_FR"],
cp.vl["BODY_CONTROL_STATE"]["DOOR_OPEN_RL"], cp.vl["BODY_CONTROL_STATE"]["DOOR_OPEN_RR"]])
ret.seatbeltUnlatched = cp.vl["BODY_CONTROL_STATE"]["SEATBELT_DRIVER_UNLATCHED"] != 0
+ ret.parkingBrake = cp.vl["BODY_CONTROL_STATE"]["PARKING_BRAKE"] == 1
ret.brakePressed = cp.vl["BRAKE_MODULE"]["BRAKE_PRESSED"] != 0
ret.brakeHoldActive = cp.vl["ESP_CONTROL"]["BRAKE_HOLD_ACTIVE"] == 1
@@ -58,8 +58,8 @@ class CarState(CarStateBase):
ret.steeringAngleDeg = cp.vl["STEER_ANGLE_SENSOR"]["STEER_ANGLE"] + cp.vl["STEER_ANGLE_SENSOR"]["STEER_FRACTION"]
torque_sensor_angle_deg = cp.vl["STEER_TORQUE_SENSOR"]["STEER_ANGLE"]
- # Some newer models have a more accurate angle measurement in the TORQUE_SENSOR message. Use if non-zero
- if abs(torque_sensor_angle_deg) > 1e-3:
+ # On some cars, the angle measurement is non-zero while initializing
+ if abs(torque_sensor_angle_deg) > 1e-3 and not bool(cp.vl["STEER_TORQUE_SENSOR"]["STEER_ANGLE_INITIALIZING"]):
self.accurate_steer_angle_seen = True
if self.accurate_steer_angle_seen:
@@ -82,7 +82,7 @@ class CarState(CarStateBase):
ret.steeringTorqueEps = cp.vl["STEER_TORQUE_SENSOR"]["STEER_TORQUE_EPS"] * self.eps_torque_scale
# we could use the override bit from dbc, but it's triggered at too high torque values
ret.steeringPressed = abs(ret.steeringTorque) > STEER_THRESHOLD
- ret.steerWarning = cp.vl["EPS_STATUS"]["LKA_STATE"] not in (1, 5)
+ ret.steerFaultTemporary = cp.vl["EPS_STATUS"]["LKA_STATE"] not in (1, 5)
if self.CP.carFingerprint in (CAR.LEXUS_IS, CAR.LEXUS_RC):
ret.cruiseState.available = cp.vl["DSU_CRUISE"]["MAIN_ON"] != 0
@@ -141,6 +141,7 @@ class CarState(CarStateBase):
("DOOR_OPEN_RL", "BODY_CONTROL_STATE"),
("DOOR_OPEN_RR", "BODY_CONTROL_STATE"),
("SEATBELT_DRIVER_UNLATCHED", "BODY_CONTROL_STATE"),
+ ("PARKING_BRAKE", "BODY_CONTROL_STATE"),
("TC_DISABLED", "ESP_CONTROL"),
("BRAKE_HOLD_ACTIVE", "ESP_CONTROL"),
("STEER_FRACTION", "STEER_ANGLE_SENSOR"),
@@ -151,6 +152,7 @@ class CarState(CarStateBase):
("STEER_TORQUE_DRIVER", "STEER_TORQUE_SENSOR"),
("STEER_TORQUE_EPS", "STEER_TORQUE_SENSOR"),
("STEER_ANGLE", "STEER_TORQUE_SENSOR"),
+ ("STEER_ANGLE_INITIALIZING", "STEER_TORQUE_SENSOR"),
("TURN_SIGNALS", "BLINKERS_STATE"),
("LKA_STATE", "EPS_STATUS"),
("AUTO_HIGH_BEAM", "LIGHT_STALK"),
diff --git a/selfdrive/car/toyota/interface.py b/selfdrive/car/toyota/interface.py
index be9d7fd587..4ac13d3d97 100644
--- a/selfdrive/car/toyota/interface.py
+++ b/selfdrive/car/toyota/interface.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
from cereal import car
-from selfdrive.config import Conversions as CV
+from common.conversions import Conversions as CV
from selfdrive.car.toyota.tunes import LatTunes, LongTunes, set_long_tune, set_lat_tune
from selfdrive.car.toyota.values import Ecu, CAR, ToyotaFlags, TSS2_CAR, NO_DSU_CAR, MIN_ACC_SPEED, EPS_SCALE, EV_HYBRID_CAR, CarControllerParams
from selfdrive.car import STD_CARGO_KG, scale_rot_inertia, scale_tire_stiffness, gen_empty_fingerprint, get_safety_config
@@ -103,6 +103,9 @@ class CarInterface(CarInterfaceBase):
set_lat_tune(ret.lateralTuning, LatTunes.PID_G)
elif candidate in (CAR.AVALON, CAR.AVALON_2019, CAR.AVALONH_2019, CAR.AVALON_TSS2):
+ # starting from 2019, all Avalon variants have stop and go
+ # https://engage.toyota.com/static/images/toyota_safety_sense/TSS_Applicability_Chart.pdf
+ stop_and_go = candidate != CAR.AVALON
ret.wheelbase = 2.82
ret.steerRatio = 14.8 # Found at https://pressroom.toyota.com/releases/2016+avalon+product+specs.download
tire_stiffness_factor = 0.7983
@@ -270,7 +273,7 @@ class CarInterface(CarInterfaceBase):
# to be called @ 100hz
def apply(self, c):
hud_control = c.hudControl
- ret = self.CC.update(c.enabled, c.active, self.CS, self.frame,
+ ret = self.CC.update(c, self.CS, self.frame,
c.actuators, c.cruiseControl.cancel,
hud_control.visualAlert, hud_control.leftLaneVisible,
hud_control.rightLaneVisible, hud_control.leadVisible,
diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py
index b8a6ae7e0d..acf3f42c38 100644
--- a/selfdrive/car/toyota/values.py
+++ b/selfdrive/car/toyota/values.py
@@ -2,8 +2,8 @@ from collections import defaultdict
from enum import IntFlag
from cereal import car
+from common.conversions import Conversions as CV
from selfdrive.car import dbc_dict
-from selfdrive.config import Conversions as CV
Ecu = car.CarParams.Ecu
MIN_ACC_SPEED = 19. * CV.MPH_TO_MS
@@ -30,7 +30,7 @@ class CAR:
AVALON = "TOYOTA AVALON 2016"
AVALON_2019 = "TOYOTA AVALON 2019"
AVALONH_2019 = "TOYOTA AVALON HYBRID 2019"
- AVALON_TSS2 = "TOYOTA AVALON 2022"
+ AVALON_TSS2 = "TOYOTA AVALON 2022" # TSS 2.5
CAMRY = "TOYOTA CAMRY 2018"
CAMRYH = "TOYOTA CAMRY HYBRID 2018"
CAMRY_TSS2 = "TOYOTA CAMRY 2021" # TSS 2.5
@@ -1388,6 +1388,7 @@ FW_VERSIONS = {
(Ecu.engine, 0x700, None): [
b'\x018966378B2100\x00\x00\x00\x00',
b'\x018966378G3000\x00\x00\x00\x00',
+ b'\x018966378B3000\x00\x00\x00\x00'
],
(Ecu.esp, 0x7b0, None): [
b'\x01F152678221\x00\x00\x00\x00\x00\x00',
@@ -1397,6 +1398,7 @@ FW_VERSIONS = {
],
(Ecu.fwdRadar, 0x750, 0xf): [
b"\x018821F3301400\x00\x00\x00\x00",
+ b'\x018821F3301200\x00\x00\x00\x00',
],
(Ecu.fwdCamera, 0x750, 0x6d): [
b'\x028646F78030A0\x00\x00\x00\x008646G2601200\x00\x00\x00\x00',
diff --git a/selfdrive/car/volkswagen/carcontroller.py b/selfdrive/car/volkswagen/carcontroller.py
index f85a81a538..5726c98285 100644
--- a/selfdrive/car/volkswagen/carcontroller.py
+++ b/selfdrive/car/volkswagen/carcontroller.py
@@ -21,7 +21,7 @@ class CarController():
self.steer_rate_limited = False
- def update(self, c, enabled, CS, frame, ext_bus, actuators, visual_alert, left_lane_visible, right_lane_visible, left_lane_depart, right_lane_depart):
+ def update(self, c, CS, frame, ext_bus, actuators, visual_alert, left_lane_visible, right_lane_visible, left_lane_depart, right_lane_depart):
""" Controls thread """
can_sends = []
@@ -39,7 +39,7 @@ class CarController():
# torque value. Do that anytime we happen to have 0 torque, or failing that,
# when exceeding ~1/3 the 360 second timer.
- if c.active and CS.out.vEgo > CS.CP.minSteerSpeed and not (CS.out.standstill or CS.out.steerError or CS.out.steerWarning):
+ if c.latActive:
new_steer = int(round(actuators.steer * P.STEER_MAX))
apply_steer = apply_std_steer_torque_limits(new_steer, self.apply_steer_last, CS.out.steeringTorque, P)
self.steer_rate_limited = new_steer != apply_steer
@@ -77,7 +77,7 @@ class CarController():
else:
hud_alert = MQB_LDW_MESSAGES["none"]
- can_sends.append(volkswagencan.create_mqb_hud_control(self.packer_pt, CANBUS.pt, enabled,
+ can_sends.append(volkswagencan.create_mqb_hud_control(self.packer_pt, CANBUS.pt, c.enabled,
CS.out.steeringPressed, hud_alert, left_lane_visible,
right_lane_visible, CS.ldw_stock_values,
left_lane_depart, right_lane_depart))
@@ -88,11 +88,11 @@ class CarController():
if CS.CP.pcmCruise:
if frame > self.graMsgStartFramePrev + P.GRA_VBP_STEP:
- if not enabled and CS.out.cruiseState.enabled:
+ if c.cruiseControl.cancel:
# Cancel ACC if it's engaged with OP disengaged.
self.graButtonStatesToSend = BUTTON_STATES.copy()
self.graButtonStatesToSend["cancel"] = True
- elif enabled and CS.esp_hold_confirmation:
+ elif c.enabled and CS.esp_hold_confirmation:
# Blip the Resume button if we're engaged at standstill.
# FIXME: This is a naive implementation, improve with visiond or radar input.
self.graButtonStatesToSend = BUTTON_STATES.copy()
diff --git a/selfdrive/car/volkswagen/carstate.py b/selfdrive/car/volkswagen/carstate.py
index 1fe8b56b90..858b5e1440 100644
--- a/selfdrive/car/volkswagen/carstate.py
+++ b/selfdrive/car/volkswagen/carstate.py
@@ -1,6 +1,6 @@
import numpy as np
from cereal import car
-from selfdrive.config import Conversions as CV
+from common.conversions import Conversions as CV
from selfdrive.car.interfaces import CarStateBase
from opendbc.can.parser import CANParser
from opendbc.can.can_define import CANDefine
@@ -41,14 +41,15 @@ class CarState(CarStateBase):
# Verify EPS readiness to accept steering commands
hca_status = self.hca_status_values.get(pt_cp.vl["LH_EPS_03"]["EPS_HCA_Status"])
- ret.steerError = hca_status in ("DISABLED", "FAULT")
- ret.steerWarning = hca_status in ("INITIALIZING", "REJECTED")
+ ret.steerFaultPermanent = hca_status in ("DISABLED", "FAULT")
+ ret.steerFaultTemporary = hca_status in ("INITIALIZING", "REJECTED")
# Update gas, brakes, and gearshift.
ret.gas = pt_cp.vl["Motor_20"]["MO_Fahrpedalrohwert_01"] / 100.0
ret.gasPressed = ret.gas > 0
ret.brake = pt_cp.vl["ESP_05"]["ESP_Bremsdruck"] / 250.0 # FIXME: this is pressure in Bar, not sure what OP expects
ret.brakePressed = bool(pt_cp.vl["ESP_05"]["ESP_Fahrer_bremst"])
+ ret.parkingBrake = bool(pt_cp.vl["Kombi_01"]["KBI_Handbremse"]) # FIXME: need to include an EPB check as well
self.esp_hold_confirmation = pt_cp.vl["ESP_21"]["ESP_Haltebestaetigung"]
# Update gear and/or clutch position data.
@@ -140,7 +141,6 @@ class CarState(CarStateBase):
self.graMsgBusCounter = pt_cp.vl["GRA_ACC_01"]["COUNTER"]
# Additional safety checks performed in CarInterface.
- self.parkingBrakeSet = bool(pt_cp.vl["Kombi_01"]["KBI_Handbremse"]) # FIXME: need to include an EPB check as well
ret.espDisabled = pt_cp.vl["ESP_21"]["ESP_Tastung_passiv"] != 0
return ret
diff --git a/selfdrive/car/volkswagen/interface.py b/selfdrive/car/volkswagen/interface.py
index 961cfed7fe..f96f1bae5a 100644
--- a/selfdrive/car/volkswagen/interface.py
+++ b/selfdrive/car/volkswagen/interface.py
@@ -186,8 +186,6 @@ class CarInterface(CarInterfaceBase):
events = self.create_common_events(ret, extra_gears=[GearShifter.eco, GearShifter.sport, GearShifter.manumatic])
# Vehicle health and operation safety checks
- if self.CS.parkingBrakeSet:
- events.add(EventName.parkBrake)
if self.CS.tsk_status in (6, 7):
events.add(EventName.accFaulted)
@@ -211,7 +209,7 @@ class CarInterface(CarInterfaceBase):
def apply(self, c):
hud_control = c.hudControl
- ret = self.CC.update(c, c.enabled, self.CS, self.frame, self.ext_bus, c.actuators,
+ ret = self.CC.update(c, self.CS, self.frame, self.ext_bus, c.actuators,
hud_control.visualAlert,
hud_control.leftLaneVisible,
hud_control.rightLaneVisible,
diff --git a/selfdrive/car/volkswagen/values.py b/selfdrive/car/volkswagen/values.py
index 241338c2c5..935407fca8 100755
--- a/selfdrive/car/volkswagen/values.py
+++ b/selfdrive/car/volkswagen/values.py
@@ -301,6 +301,7 @@ FW_VERSIONS = {
(Ecu.engine, 0x7e0, None): [
b'\xf1\x8704E906024AK\xf1\x899937',
b'\xf1\x8704E906024AS\xf1\x899912',
+ b'\xf1\x8704E906024BC\xf1\x899971',
b'\xf1\x8704E906024B \xf1\x895594',
b'\xf1\x8704E906024C \xf1\x899970',
b'\xf1\x8704E906024L \xf1\x895595',
@@ -311,6 +312,7 @@ FW_VERSIONS = {
(Ecu.transmission, 0x7e1, None): [
b'\xf1\x8709G927158BQ\xf1\x893545',
b'\xf1\x8709S927158BS\xf1\x893642',
+ b'\xf1\x8709S927158BS\xf1\x893694',
b'\xf1\x8709S927158R \xf1\x893552',
b'\xf1\x8709S927158R \xf1\x893587',
b'\xf1\x870GC300020N \xf1\x892803',
@@ -426,9 +428,11 @@ FW_VERSIONS = {
b'\xf1\x8704L906027G \xf1\x899893',
b'\xf1\x875N0906259 \xf1\x890002',
b'\xf1\x8783A907115B \xf1\x890005',
+ b'\xf1\x8783A907115G \xf1\x890001',
],
(Ecu.transmission, 0x7e1, None): [
b'\xf1\x8709G927158DT\xf1\x893698',
+ b'\xf1\x8709G927158GD\xf1\x893820',
b'\xf1\x870DL300011N \xf1\x892001',
b'\xf1\x870DL300011N \xf1\x892012',
b'\xf1\x870DL300013A \xf1\x893005',
@@ -439,6 +443,7 @@ FW_VERSIONS = {
b'\xf1\x875Q0959655BM\xf1\x890403\xf1\x82\02316143231313500314641011750179333423100',
b'\xf1\x875Q0959655BT\xf1\x890403\xf1\x82\02312110031333300314240583752379333423100',
b'\xf1\x875Q0959655BT\xf1\x890403\xf1\x82\02331310031333336313140013950399333423100',
+ b'\xf1\x875Q0959655CB\xf1\x890421\xf1\x82\x1316143231313500314647021750179333613100',
],
(Ecu.eps, 0x712, None): [
b'\xf1\x875Q0909143M \xf1\x892041\xf1\x820529A6060603',
@@ -450,6 +455,7 @@ FW_VERSIONS = {
b'\xf1\x872Q0907572J \xf1\x890156',
b'\xf1\x872Q0907572Q \xf1\x890342',
b'\xf1\x872Q0907572R \xf1\x890372',
+ b'\xf1\x872Q0907572T \xf1\x890383',
],
},
CAR.TOURAN_MK2: {
@@ -516,6 +522,7 @@ FW_VERSIONS = {
b'\xf1\x875G0906259L \xf1\x890002',
b'\xf1\x875G0906259Q \xf1\x890002',
b'\xf1\x878V0906259F \xf1\x890002',
+ b'\xf1\x878V0906259K \xf1\x890001',
b'\xf1\x878V0906264B \xf1\x890003',
b'\xf1\x878V0907115B \xf1\x890007',
],
@@ -525,6 +532,7 @@ FW_VERSIONS = {
b'\xf1\x870D9300012 \xf1\x894912',
b'\xf1\x870D9300013B \xf1\x894931',
b'\xf1\x870D9300041N \xf1\x894512',
+ b'\xf1\x870D9300043T \xf1\x899699',
b'\xf1\x870DD300046A \xf1\x891602',
b'\xf1\x870DD300046F \xf1\x891602',
b'\xf1\x870DD300046G \xf1\x891601',
@@ -542,6 +550,7 @@ FW_VERSIONS = {
],
(Ecu.eps, 0x712, None): [
b'\xf1\x873Q0909144H \xf1\x895061\xf1\x82\00566G0HA14A1',
+ b'\xf1\x873Q0909144K \xf1\x895072\xf1\x82\x0571G0HA16A1',
b'\xf1\x875Q0909144AB\xf1\x891082\xf1\x82\00521G0G809A1',
b'\xf1\x875Q0909144P \xf1\x891043\xf1\x82\00503G00303A0',
b'\xf1\x875Q0909144P \xf1\x891043\xf1\x82\00503G00803A0',
@@ -705,11 +714,13 @@ FW_VERSIONS = {
(Ecu.engine, 0x7e0, None): [
b'\xf1\x8704E906016ER\xf1\x895823',
b'\xf1\x8704E906027HD\xf1\x893742',
+ b'\xf1\x8704E906027MH\xf1\x894786',
b'\xf1\x8704L906021DT\xf1\x898127',
b'\xf1\x8704L906026BS\xf1\x891541',
b'\xf1\x875G0906259C \xf1\x890002',
],
(Ecu.transmission, 0x7e1, None): [
+ b'\xf1\x870CW300041L \xf1\x891601',
b'\xf1\x870CW300041N \xf1\x891605',
b'\xf1\x870CW300043B \xf1\x891601',
b'\xf1\x870D9300041C \xf1\x894936',
@@ -722,11 +733,13 @@ FW_VERSIONS = {
b'\xf1\x873Q0959655AS\xf1\x890200\xf1\x82\r11120011100010022212110200',
b'\xf1\x873Q0959655BH\xf1\x890703\xf1\x82\0163221003221002105755331052100',
b'\xf1\x873Q0959655CN\xf1\x890720\xf1\x82\x0e3221003221002105755331052100',
+ b'\xf1\x875QD959655 \xf1\x890388\xf1\x82\x111101000011110006110411111111119111',
],
(Ecu.eps, 0x712, None): [
b'\xf1\x873Q0909144J \xf1\x895063\xf1\x82\00566A01513A1',
b'\xf1\x875Q0909144AA\xf1\x891081\xf1\x82\00521T00403A1',
b'\xf1\x875Q0909144AB\xf1\x891082\xf1\x82\x0521T00403A1',
+ b'\xf1\x875QD909144E \xf1\x891081\xf1\x82\x0521T00503A1',
b'\xf1\x875Q0909144R \xf1\x891061\xf1\x82\x0516A00604A1',
],
(Ecu.fwdRadar, 0x757, None): [
@@ -734,6 +747,7 @@ FW_VERSIONS = {
b'\xf1\x875Q0907572F \xf1\x890400\xf1\x82\00101',
b'\xf1\x875Q0907572J \xf1\x890654',
b'\xf1\x875Q0907572P \xf1\x890682',
+ b'\xf1\x875Q0907572R \xf1\x890771',
],
},
CAR.SKODA_SCALA_MK1: {
diff --git a/selfdrive/common/params.cc b/selfdrive/common/params.cc
index 675a45fd7f..25062b4975 100644
--- a/selfdrive/common/params.cc
+++ b/selfdrive/common/params.cc
@@ -91,7 +91,6 @@ std::unordered_map keys = {
{"CarParams", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON},
{"CarParamsCache", CLEAR_ON_MANAGER_START},
{"CarVin", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON},
- {"CellularUnmetered", PERSISTENT},
{"CompletedTrainingVersion", PERSISTENT},
{"ControlsReady", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON},
{"CurrentRoute", CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON},
diff --git a/selfdrive/config.py b/selfdrive/config.py
deleted file mode 100644
index 511f6126c4..0000000000
--- a/selfdrive/config.py
+++ /dev/null
@@ -1,29 +0,0 @@
-import numpy as np
-
-class Conversions:
- #Speed
- MPH_TO_KPH = 1.609344
- KPH_TO_MPH = 1. / MPH_TO_KPH
- MS_TO_KPH = 3.6
- KPH_TO_MS = 1. / MS_TO_KPH
- MS_TO_MPH = MS_TO_KPH * KPH_TO_MPH
- MPH_TO_MS = MPH_TO_KPH * KPH_TO_MS
- MS_TO_KNOTS = 1.9438
- KNOTS_TO_MS = 1. / MS_TO_KNOTS
- #Angle
- DEG_TO_RAD = np.pi / 180.
- RAD_TO_DEG = 1. / DEG_TO_RAD
- #Mass
- LB_TO_KG = 0.453592
-
-
-RADAR_TO_CENTER = 2.7 # (deprecated) RADAR is ~ 2.7m ahead from center of car
-RADAR_TO_CAMERA = 1.52 # RADAR is ~ 1.5m ahead from center of mesh frame
-
-class UIParams:
- lidar_x, lidar_y, lidar_zoom = 384, 960, 6
- lidar_car_x, lidar_car_y = lidar_x / 2., lidar_y / 1.1
- car_hwidth = 1.7272 / 2 * lidar_zoom
- car_front = 2.6924 * lidar_zoom
- car_back = 1.8796 * lidar_zoom
- car_color = 110
diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py
index 1a34d31311..fcb1a4974a 100755
--- a/selfdrive/controls/controlsd.py
+++ b/selfdrive/controls/controlsd.py
@@ -9,7 +9,7 @@ from common.realtime import sec_since_boot, config_realtime_process, Priority, R
from common.profiler import Profiler
from common.params import Params, put_nonblocking
import cereal.messaging as messaging
-from selfdrive.config import Conversions as CV
+from common.conversions import Conversions as CV
from selfdrive.swaglog import cloudlog
from selfdrive.boardd.boardd import can_list_to_can_capnp
from selfdrive.car.car_helpers import get_car, get_startup_event, get_one_can
@@ -298,7 +298,7 @@ class Controls:
self.events.add(EventName.cruiseMismatch)
# Check for FCW
- stock_long_is_braking = self.enabled and not self.CP.openpilotLongitudinalControl and CS.aEgo < -1.5
+ stock_long_is_braking = self.enabled and not self.CP.openpilotLongitudinalControl and CS.aEgo < -1.25
model_fcw = self.sm['modelV2'].meta.hardBrakePredicted and not CS.brakePressed and not stock_long_is_braking
planner_fcw = self.sm['longitudinalPlan'].fcw and self.enabled
if planner_fcw or model_fcw:
@@ -455,10 +455,11 @@ class Controls:
else:
self.state = State.enabled
self.current_alert_types.append(ET.ENABLE)
- self.v_cruise_kph = initialize_v_cruise(CS.vEgo, CS.buttonEvents, self.v_cruise_kph_last)
+ if not self.CP.pcmCruise:
+ self.v_cruise_kph = initialize_v_cruise(CS.vEgo, CS.buttonEvents, self.v_cruise_kph_last)
# Check if actuators are enabled
- self.active = self.state == State.enabled or self.state == State.softDisabling
+ self.active = self.state in (State.enabled, State.softDisabling)
if self.active:
self.current_alert_types.append(ET.WARNING)
@@ -466,7 +467,7 @@ class Controls:
self.enabled = self.active or self.state == State.preEnabled
def state_control(self, CS):
- """Given the state, this function returns an actuators packet"""
+ """Given the state, this function returns a CarControl packet"""
# Update VehicleModel
params = self.sm['liveParameters']
@@ -477,7 +478,14 @@ class Controls:
lat_plan = self.sm['lateralPlan']
long_plan = self.sm['longitudinalPlan']
- actuators = car.CarControl.Actuators.new_message()
+ CC = car.CarControl.new_message()
+ CC.enabled = self.enabled
+ # Check which actuators can be enabled
+ CC.latActive = self.active and not CS.steerFaultTemporary and not CS.steerFaultPermanent and \
+ CS.vEgo > self.CP.minSteerSpeed and not CS.standstill
+ CC.longActive = self.active
+
+ actuators = CC.actuators
actuators.longControlState = self.LoC.long_control_state
if CS.leftBlinker or CS.rightBlinker:
@@ -485,37 +493,40 @@ class Controls:
# State specific actions
- if not self.active:
+ if not CC.latActive:
self.LaC.reset()
+ if not CC.longActive:
self.LoC.reset(v_pid=CS.vEgo)
if not self.joystick_mode:
# accel PID loop
pid_accel_limits = self.CI.get_pid_accel_limits(self.CP, CS.vEgo, self.v_cruise_kph * CV.KPH_TO_MS)
t_since_plan = (self.sm.frame - self.sm.rcv_frame['longitudinalPlan']) * DT_CTRL
- actuators.accel = self.LoC.update(self.active, CS, self.CP, long_plan, pid_accel_limits, t_since_plan)
+ actuators.accel = self.LoC.update(CC.longActive, CS, self.CP, long_plan, pid_accel_limits, t_since_plan)
# Steering PID loop and lateral MPC
- lat_active = self.active and not CS.steerWarning and not CS.steerError and CS.vEgo > self.CP.minSteerSpeed
desired_curvature, desired_curvature_rate = get_lag_adjusted_curvature(self.CP, CS.vEgo,
lat_plan.psis,
lat_plan.curvatures,
lat_plan.curvatureRates)
- actuators.steer, actuators.steeringAngleDeg, lac_log = self.LaC.update(lat_active, CS, self.CP, self.VM, params, self.last_actuators,
- desired_curvature, desired_curvature_rate)
+ actuators.steer, actuators.steeringAngleDeg, lac_log = self.LaC.update(CC.latActive, CS, self.CP, self.VM,
+ params, self.last_actuators, desired_curvature,
+ desired_curvature_rate)
else:
lac_log = log.ControlsState.LateralDebugState.new_message()
- if self.sm.rcv_frame['testJoystick'] > 0 and self.active:
- actuators.accel = 4.0*clip(self.sm['testJoystick'].axes[0], -1, 1)
+ if self.sm.rcv_frame['testJoystick'] > 0:
+ if CC.longActive:
+ actuators.accel = 4.0*clip(self.sm['testJoystick'].axes[0], -1, 1)
- steer = clip(self.sm['testJoystick'].axes[1], -1, 1)
- # max angle is 45 for angle-based cars
- actuators.steer, actuators.steeringAngleDeg = steer, steer * 45.
+ if CC.latActive:
+ steer = clip(self.sm['testJoystick'].axes[1], -1, 1)
+ # max angle is 45 for angle-based cars
+ actuators.steer, actuators.steeringAngleDeg = steer, steer * 45.
- lac_log.active = True
+ lac_log.active = self.active
lac_log.steeringAngleDeg = CS.steeringAngleDeg
- lac_log.output = steer
- lac_log.saturated = abs(steer) >= 0.9
+ lac_log.output = actuators.steer
+ lac_log.saturated = abs(actuators.steer) >= 0.9
# Send a "steering required alert" if saturation count has reached the limit
if lac_log.active and lac_log.saturated and not CS.steeringPressed:
@@ -539,7 +550,7 @@ class Controls:
cloudlog.error(f"actuators.{p} not finite {actuators.to_dict()}")
setattr(actuators, p, 0.0)
- return actuators, lac_log
+ return CC, lac_log
def update_button_timers(self, buttonEvents):
# increment timer for buttons still pressed
@@ -551,14 +562,9 @@ class Controls:
if b.type.raw in self.button_timers:
self.button_timers[b.type.raw] = 1 if b.pressed else 0
- def publish_logs(self, CS, start_time, actuators, lac_log):
+ def publish_logs(self, CS, start_time, CC, lac_log):
"""Send actuators and hud commands to the car, send controlsstate and MPC logging"""
- CC = car.CarControl.new_message()
- CC.enabled = self.enabled
- CC.active = self.active
- CC.actuators = actuators
-
orientation_value = self.sm['liveLocationKalman'].orientationNED.value
if len(orientation_value) > 2:
CC.roll = orientation_value[0]
@@ -579,7 +585,7 @@ class Controls:
recent_blinker = (self.sm.frame - self.last_blinker_frame) * DT_CTRL < 5.0 # 5s blinker cooldown
ldw_allowed = self.is_ldw_enabled and CS.vEgo > LDW_MIN_SPEED and not recent_blinker \
- and not self.active and self.sm['liveCalibration'].calStatus == Calibration.CALIBRATED
+ and not CC.latActive and self.sm['liveCalibration'].calStatus == Calibration.CALIBRATED
model_v2 = self.sm['modelV2']
desire_prediction = model_v2.meta.desirePrediction
@@ -718,12 +724,12 @@ class Controls:
self.prof.checkpoint("State transition")
# Compute actuators (runs PID loops and lateral MPC)
- actuators, lac_log = self.state_control(CS)
+ CC, lac_log = self.state_control(CS)
self.prof.checkpoint("State Control")
# Publish data
- self.publish_logs(CS, start_time, actuators, lac_log)
+ self.publish_logs(CS, start_time, CC, lac_log)
self.prof.checkpoint("Sent")
self.update_button_timers(CS.buttonEvents)
diff --git a/selfdrive/controls/lib/desire_helper.py b/selfdrive/controls/lib/desire_helper.py
index c34d143a5a..978c386530 100644
--- a/selfdrive/controls/lib/desire_helper.py
+++ b/selfdrive/controls/lib/desire_helper.py
@@ -1,6 +1,6 @@
from cereal import log
+from common.conversions import Conversions as CV
from common.realtime import DT_MDL
-from selfdrive.config import Conversions as CV
LaneChangeState = log.LateralPlan.LaneChangeState
LaneChangeDirection = log.LateralPlan.LaneChangeDirection
diff --git a/selfdrive/controls/lib/drive_helpers.py b/selfdrive/controls/lib/drive_helpers.py
index 01d7600345..f34467081b 100644
--- a/selfdrive/controls/lib/drive_helpers.py
+++ b/selfdrive/controls/lib/drive_helpers.py
@@ -2,7 +2,7 @@ import math
from cereal import car
from common.numpy_fast import clip, interp
from common.realtime import DT_MDL
-from selfdrive.config import Conversions as CV
+from common.conversions import Conversions as CV
from selfdrive.modeld.constants import T_IDXS
# WARNING: this value was determined based on the model's training distribution,
@@ -54,7 +54,7 @@ def update_v_cruise(v_cruise_kph, buttonEvents, button_timers, enabled, metric):
long_press = False
button_type = None
- v_cruise_delta = 1 if metric else 1.6
+ v_cruise_delta = 1. if metric else CV.MPH_TO_KPH
for b in buttonEvents:
if b.type.raw in button_timers and not b.pressed:
@@ -91,9 +91,9 @@ def initialize_v_cruise(v_ego, buttonEvents, v_cruise_last):
def get_lag_adjusted_curvature(CP, v_ego, psis, curvatures, curvature_rates):
if len(psis) != CONTROL_N:
- psis = [0.0 for i in range(CONTROL_N)]
- curvatures = [0.0 for i in range(CONTROL_N)]
- curvature_rates = [0.0 for i in range(CONTROL_N)]
+ psis = [0.0]*CONTROL_N
+ curvatures = [0.0]*CONTROL_N
+ curvature_rates = [0.0]*CONTROL_N
# TODO this needs more thought, use .2s extra for now to estimate other delays
delay = CP.steerActuatorDelay + .2
diff --git a/selfdrive/controls/lib/events.py b/selfdrive/controls/lib/events.py
index 931932cc0d..e04ec262de 100644
--- a/selfdrive/controls/lib/events.py
+++ b/selfdrive/controls/lib/events.py
@@ -4,8 +4,8 @@ from typing import Dict, Union, Callable, List, Optional
from cereal import log, car
import cereal.messaging as messaging
+from common.conversions import Conversions as CV
from common.realtime import DT_CTRL
-from selfdrive.config import Conversions as CV
from selfdrive.locationd.calibrationd import MIN_SPEED_FILTER
from selfdrive.version import get_short_branch
diff --git a/selfdrive/controls/lib/lateral_mpc_lib/SConscript b/selfdrive/controls/lib/lateral_mpc_lib/SConscript
index f402e6e15e..64eada95c1 100644
--- a/selfdrive/controls/lib/lateral_mpc_lib/SConscript
+++ b/selfdrive/controls/lib/lateral_mpc_lib/SConscript
@@ -43,11 +43,19 @@ generated_files = [
f'{gen}/lat_cost/lat_cost_y_0_fun.h',
] + build_files
+acados_dir = '#third_party/acados'
+source_list = ['lat_mpc.py',
+ f'{acados_dir}/include/acados_c/ocp_nlp_interface.h',
+ f'{acados_dir}/aarch64/lib/libacados.so',
+ f'{acados_dir}/x86_64/lib/libacados.so',
+ f'{acados_dir}/larch64/lib/libacados.so',
+]
+
lenv = env.Clone()
lenv.Clean(generated_files, Dir(gen))
lenv.Command(generated_files,
- ["lat_mpc.py"],
+ source_list,
f"cd {Dir('.').abspath} && python3 lat_mpc.py")
lenv["CFLAGS"].append("-DACADOS_WITH_QPOASES")
diff --git a/selfdrive/controls/lib/lateral_mpc_lib/lat_mpc.py b/selfdrive/controls/lib/lateral_mpc_lib/lat_mpc.py
index e4a73bf97d..a1037f040b 100755
--- a/selfdrive/controls/lib/lateral_mpc_lib/lat_mpc.py
+++ b/selfdrive/controls/lib/lateral_mpc_lib/lat_mpc.py
@@ -11,18 +11,19 @@ from selfdrive.modeld.constants import T_IDXS
if __name__ == '__main__': # generating code
from pyextra.acados_template import AcadosModel, AcadosOcp, AcadosOcpSolver
else:
- # from pyextra.acados_template import AcadosOcpSolverFast
- from selfdrive.controls.lib.lateral_mpc_lib.c_generated_code.acados_ocp_solver_pyx import AcadosOcpSolverFast # pylint: disable=no-name-in-module, import-error
+ from selfdrive.controls.lib.lateral_mpc_lib.c_generated_code.acados_ocp_solver_pyx import AcadosOcpSolverCython # pylint: disable=no-name-in-module, import-error
LAT_MPC_DIR = os.path.dirname(os.path.abspath(__file__))
EXPORT_DIR = os.path.join(LAT_MPC_DIR, "c_generated_code")
-JSON_FILE = "acados_ocp_lat.json"
+JSON_FILE = os.path.join(LAT_MPC_DIR, "acados_ocp_lat.json")
X_DIM = 4
P_DIM = 2
+MODEL_NAME = 'lat'
+ACADOS_SOLVER_TYPE = 'SQP_RTI'
def gen_lat_model():
model = AcadosModel()
- model.name = 'lat'
+ model.name = MODEL_NAME
# set up states & controls
x_ego = SX.sym('x_ego')
@@ -58,7 +59,7 @@ def gen_lat_model():
return model
-def gen_lat_mpc_solver():
+def gen_lat_ocp():
ocp = AcadosOcp()
ocp.model = gen_lat_model()
@@ -103,7 +104,7 @@ def gen_lat_mpc_solver():
ocp.solver_options.qp_solver = 'PARTIAL_CONDENSING_HPIPM'
ocp.solver_options.hessian_approx = 'GAUSS_NEWTON'
ocp.solver_options.integrator_type = 'ERK'
- ocp.solver_options.nlp_solver_type = 'SQP_RTI'
+ ocp.solver_options.nlp_solver_type = ACADOS_SOLVER_TYPE
ocp.solver_options.qp_solver_iter_max = 1
ocp.solver_options.qp_solver_cond_N = 1
@@ -117,7 +118,7 @@ def gen_lat_mpc_solver():
class LateralMpc():
def __init__(self, x0=np.zeros(X_DIM)):
- self.solver = AcadosOcpSolverFast('lat', N, EXPORT_DIR)
+ self.solver = AcadosOcpSolverCython(MODEL_NAME, ACADOS_SOLVER_TYPE, N)
self.reset(x0)
def reset(self, x0=np.zeros(X_DIM)):
@@ -173,5 +174,6 @@ class LateralMpc():
if __name__ == "__main__":
- ocp = gen_lat_mpc_solver()
- AcadosOcpSolver.generate(ocp, json_file=JSON_FILE, build=False)
+ ocp = gen_lat_ocp()
+ AcadosOcpSolver.generate(ocp, json_file=JSON_FILE)
+ # AcadosOcpSolver.build(ocp.code_export_directory, with_cython=True)
diff --git a/selfdrive/controls/lib/longcontrol.py b/selfdrive/controls/lib/longcontrol.py
index 3ba50fd0cf..21682d8263 100644
--- a/selfdrive/controls/lib/longcontrol.py
+++ b/selfdrive/controls/lib/longcontrol.py
@@ -12,14 +12,15 @@ ACCEL_MIN_ISO = -3.5 # m/s^2
ACCEL_MAX_ISO = 2.0 # m/s^2
-def long_control_state_trans(CP, active, long_control_state, v_ego, v_target_future,
- brake_pressed, cruise_standstill):
+def long_control_state_trans(CP, active, long_control_state, v_ego, v_target,
+ v_target_future, brake_pressed, cruise_standstill):
"""Update longitudinal control state machine"""
+ accelerating = v_target_future > v_target
stopping_condition = (v_ego < 2.0 and cruise_standstill) or \
(v_ego < CP.vEgoStopping and
- (v_target_future < CP.vEgoStopping or brake_pressed))
+ ((v_target_future < CP.vEgoStopping and not accelerating) or brake_pressed))
- starting_condition = v_target_future > CP.vEgoStarting and not cruise_standstill
+ starting_condition = v_target_future > CP.vEgoStarting and accelerating and not cruise_standstill
if not active:
long_control_state = LongCtrlState.off
@@ -83,7 +84,7 @@ class LongControl():
# Update state machine
output_accel = self.last_output_accel
self.long_control_state = long_control_state_trans(CP, active, self.long_control_state, CS.vEgo,
- v_target_future, CS.brakePressed,
+ v_target, v_target_future, CS.brakePressed,
CS.cruiseState.standstill)
if self.long_control_state == LongCtrlState.off or CS.gasPressed:
diff --git a/selfdrive/controls/lib/longitudinal_mpc_lib/SConscript b/selfdrive/controls/lib/longitudinal_mpc_lib/SConscript
index 4c43985d1f..cd764114c4 100644
--- a/selfdrive/controls/lib/longitudinal_mpc_lib/SConscript
+++ b/selfdrive/controls/lib/longitudinal_mpc_lib/SConscript
@@ -28,8 +28,6 @@ casadi_cost_0 = [
casadi_constraints = [
f'{gen}/long_constraints/long_constr_h_fun.c',
f'{gen}/long_constraints/long_constr_h_fun_jac_uxt_zt.c',
- f'{gen}/long_constraints/long_constr_h_e_fun.c',
- f'{gen}/long_constraints/long_constr_h_e_fun_jac_uxt_zt.c',
]
build_files = [f'{gen}/acados_solver_long.c'] + casadi_model + casadi_cost_y + casadi_cost_e + \
@@ -47,17 +45,24 @@ generated_files = [
f'{gen}/long_model/long_model.h',
f'{gen}/long_constraints/long_h_constraint.h',
- f'{gen}/long_constraints/long_h_e_constraint.h',
f'{gen}/long_cost/long_cost_y_fun.h',
f'{gen}/long_cost/long_cost_y_e_fun.h',
f'{gen}/long_cost/long_cost_y_0_fun.h',
] + build_files
+acados_dir = '#third_party/acados'
+source_list = ['long_mpc.py',
+ f'{acados_dir}/include/acados_c/ocp_nlp_interface.h',
+ f'{acados_dir}/aarch64/lib/libacados.so',
+ f'{acados_dir}/x86_64/lib/libacados.so',
+ f'{acados_dir}/larch64/lib/libacados.so',
+]
+
lenv = env.Clone()
lenv.Clean(generated_files, Dir(gen))
lenv.Command(generated_files,
- ["long_mpc.py"],
+ source_list,
f"cd {Dir('.').abspath} && python3 long_mpc.py")
lenv["CFLAGS"].append("-DACADOS_WITH_QPOASES")
diff --git a/selfdrive/controls/lib/longitudinal_mpc_lib/long_mpc.py b/selfdrive/controls/lib/longitudinal_mpc_lib/long_mpc.py
index f9f9c31bb4..69bf081ee3 100644
--- a/selfdrive/controls/lib/longitudinal_mpc_lib/long_mpc.py
+++ b/selfdrive/controls/lib/longitudinal_mpc_lib/long_mpc.py
@@ -11,20 +11,20 @@ from selfdrive.controls.lib.radar_helpers import _LEAD_ACCEL_TAU
if __name__ == '__main__': # generating code
from pyextra.acados_template import AcadosModel, AcadosOcp, AcadosOcpSolver
else:
- # from pyextra.acados_template import AcadosOcpSolver as AcadosOcpSolverFast
- from selfdrive.controls.lib.longitudinal_mpc_lib.c_generated_code.acados_ocp_solver_pyx import AcadosOcpSolverFast # pylint: disable=no-name-in-module, import-error
+ from selfdrive.controls.lib.longitudinal_mpc_lib.c_generated_code.acados_ocp_solver_pyx import AcadosOcpSolverCython # pylint: disable=no-name-in-module, import-error
from casadi import SX, vertcat
+MODEL_NAME = 'long'
LONG_MPC_DIR = os.path.dirname(os.path.abspath(__file__))
EXPORT_DIR = os.path.join(LONG_MPC_DIR, "c_generated_code")
-JSON_FILE = "acados_ocp_long.json"
+JSON_FILE = os.path.join(LONG_MPC_DIR, "acados_ocp_long.json")
SOURCES = ['lead0', 'lead1', 'cruise']
X_DIM = 3
U_DIM = 1
-PARAM_DIM= 4
+PARAM_DIM = 4
COST_E_DIM = 5
COST_DIM = COST_E_DIM + 1
CONSTR_DIM = 4
@@ -34,17 +34,18 @@ X_EGO_COST = 0.
V_EGO_COST = 0.
A_EGO_COST = 0.
J_EGO_COST = 5.0
-A_CHANGE_COST = .5
+A_CHANGE_COST = 200.
DANGER_ZONE_COST = 100.
CRASH_DISTANCE = .5
LIMIT_COST = 1e6
+ACADOS_SOLVER_TYPE = 'SQP_RTI'
# Fewer timestamps don't hurt performance and lead to
# much better convergence of the MPC with low iterations
N = 12
MAX_T = 10.0
-T_IDXS_LST = [index_function(idx, max_val=MAX_T, max_idx=N+1) for idx in range(N+1)]
+T_IDXS_LST = [index_function(idx, max_val=MAX_T, max_idx=N) for idx in range(N+1)]
T_IDXS = np.array(T_IDXS_LST)
T_DIFFS = np.diff(T_IDXS, prepend=[0.])
@@ -65,7 +66,7 @@ def desired_follow_distance(v_ego, v_lead):
def gen_long_model():
model = AcadosModel()
- model.name = 'long'
+ model.name = MODEL_NAME
# set up states & controls
x_ego = SX.sym('x_ego')
@@ -97,7 +98,7 @@ def gen_long_model():
return model
-def gen_long_mpc_solver():
+def gen_long_ocp():
ocp = AcadosOcp()
ocp.model = gen_long_model()
@@ -136,7 +137,7 @@ def gen_long_mpc_solver():
x_ego,
v_ego,
a_ego,
- 20*(a_ego - prev_a),
+ a_ego - prev_a,
j_ego]
ocp.model.cost_y_expr = vertcat(*costs)
ocp.model.cost_y_expr_e = vertcat(*costs[:-1])
@@ -149,7 +150,6 @@ def gen_long_mpc_solver():
(a_max - a_ego),
((x_obstacle - x_ego) - (3/4) * (desired_dist_comfort)) / (v_ego + 10.))
ocp.model.con_h_expr = constraints
- ocp.model.con_h_expr_e = vertcat(np.zeros(CONSTR_DIM))
x0 = np.zeros(X_DIM)
ocp.constraints.x0 = x0
@@ -163,9 +163,7 @@ def gen_long_mpc_solver():
ocp.cost.zu = cost_weights
ocp.constraints.lh = np.zeros(CONSTR_DIM)
- ocp.constraints.lh_e = np.zeros(CONSTR_DIM)
ocp.constraints.uh = 1e4*np.ones(CONSTR_DIM)
- ocp.constraints.uh_e = 1e4*np.ones(CONSTR_DIM)
ocp.constraints.idxsh = np.arange(CONSTR_DIM)
# The HPIPM solver can give decent solutions even when it is stopped early
@@ -175,12 +173,13 @@ def gen_long_mpc_solver():
ocp.solver_options.qp_solver = 'PARTIAL_CONDENSING_HPIPM'
ocp.solver_options.hessian_approx = 'GAUSS_NEWTON'
ocp.solver_options.integrator_type = 'ERK'
- ocp.solver_options.nlp_solver_type = 'SQP_RTI'
- ocp.solver_options.qp_solver_cond_N = N//4
+ ocp.solver_options.nlp_solver_type = ACADOS_SOLVER_TYPE
+ ocp.solver_options.qp_solver_cond_N = 1
# More iterations take too much time and less lead to inaccurate convergence in
# some situations. Ideally we would run just 1 iteration to ensure fixed runtime.
ocp.solver_options.qp_solver_iter_max = 10
+ ocp.solver_options.qp_tol = 1e-3
# set prediction horizon
ocp.solver_options.tf = Tf
@@ -197,7 +196,7 @@ class LongitudinalMpc:
self.source = SOURCES[2]
def reset(self):
- self.solver = AcadosOcpSolverFast('long', N, EXPORT_DIR)
+ self.solver = AcadosOcpSolverCython(MODEL_NAME, ACADOS_SOLVER_TYPE, N)
self.v_solution = np.zeros(N+1)
self.a_solution = np.zeros(N+1)
self.prev_a = np.array(self.a_solution)
@@ -215,7 +214,11 @@ class LongitudinalMpc:
self.status = False
self.crash_cnt = 0.0
self.solution_status = 0
+ # timers
self.solve_time = 0.0
+ self.time_qp_solution = 0.0
+ self.time_linearization = 0.0
+ self.time_integrator = 0.0
self.x0 = np.zeros(X_DIM)
self.set_weights()
@@ -232,6 +235,7 @@ class LongitudinalMpc:
a_change_cost = A_CHANGE_COST if prev_accel_constraint else 0
W = np.asfortranarray(np.diag([X_EGO_OBSTACLE_COST, X_EGO_COST, V_EGO_COST, A_EGO_COST, a_change_cost, J_EGO_COST]))
for i in range(N):
+ # reduce the cost on (a-a_prev) later in the horizon.
W[4,4] = a_change_cost * np.interp(T_IDXS[i], [0.0, 1.0, 2.0], [1.0, 1.0, 0.0])
self.solver.cost_set(i, 'W', W)
# Setting the slice without the copy make the array not contiguous,
@@ -257,14 +261,12 @@ class LongitudinalMpc:
self.solver.cost_set(i, 'Zl', Zl)
def set_cur_state(self, v, a):
- if abs(self.x0[1] - v) > 2.:
- self.x0[1] = v
- self.x0[2] = a
+ v_prev = self.x0[1]
+ self.x0[1] = v
+ self.x0[2] = a
+ if abs(v_prev - v) > 2.: # probably only helps if v < v_prev
for i in range(0, N+1):
self.solver.set(i, 'x', self.x0)
- else:
- self.x0[1] = v
- self.x0[2] = a
@staticmethod
def extrapolate_lead(x_lead, v_lead, a_lead, a_lead_tau):
@@ -355,9 +357,17 @@ class LongitudinalMpc:
self.solver.constraints_set(0, "lbx", self.x0)
self.solver.constraints_set(0, "ubx", self.x0)
- t = sec_since_boot()
self.solution_status = self.solver.solve()
- self.solve_time = sec_since_boot() - t
+ self.solve_time = float(self.solver.get_stats('time_tot')[0])
+ self.time_qp_solution = float(self.solver.get_stats('time_qp')[0])
+ self.time_linearization = float(self.solver.get_stats('time_lin')[0])
+ self.time_integrator = float(self.solver.get_stats('time_sim')[0])
+
+ # qp_iter = self.solver.get_stats('statistics')[-1][-1] # SQP_RTI specific
+ # print(f"long_mpc timings: tot {self.solve_time:.2e}, qp {self.time_qp_solution:.2e}, lin {self.time_linearization:.2e}, integrator {self.time_integrator:.2e}, qp_iter {qp_iter}")
+ # res = self.solver.get_residuals()
+ # print(f"long_mpc residuals: {res[0]:.2e}, {res[1]:.2e}, {res[2]:.2e}, {res[3]:.2e}")
+ # self.solver.print_statistics()
for i in range(N+1):
self.x_sol[i] = self.solver.get(i, 'x')
@@ -370,6 +380,7 @@ class LongitudinalMpc:
self.prev_a = np.interp(T_IDXS + 0.05, T_IDXS, self.a_solution)
+ t = sec_since_boot()
if self.solution_status != 0:
if t > self.last_cloudlog_t + 5.0:
self.last_cloudlog_t = t
@@ -378,5 +389,6 @@ class LongitudinalMpc:
if __name__ == "__main__":
- ocp = gen_long_mpc_solver()
- AcadosOcpSolver.generate(ocp, json_file=JSON_FILE, build=False)
+ ocp = gen_long_ocp()
+ AcadosOcpSolver.generate(ocp, json_file=JSON_FILE)
+ # AcadosOcpSolver.build(ocp.code_export_directory, with_cython=True)
diff --git a/selfdrive/controls/lib/longitudinal_planner.py b/selfdrive/controls/lib/longitudinal_planner.py
index 865442f735..fd76142366 100755
--- a/selfdrive/controls/lib/longitudinal_planner.py
+++ b/selfdrive/controls/lib/longitudinal_planner.py
@@ -4,10 +4,10 @@ import numpy as np
from common.numpy_fast import interp
import cereal.messaging as messaging
+from common.conversions import Conversions as CV
from common.filter_simple import FirstOrderFilter
from common.realtime import DT_MDL
from selfdrive.modeld.constants import T_IDXS
-from selfdrive.config import Conversions as CV
from selfdrive.controls.lib.longcontrol import LongCtrlState
from selfdrive.controls.lib.longitudinal_mpc_lib.long_mpc import LongitudinalMpc
from selfdrive.controls.lib.longitudinal_mpc_lib.long_mpc import T_IDXS as T_IDXS_MPC
@@ -55,6 +55,7 @@ class Planner:
self.v_desired_trajectory = np.zeros(CONTROL_N)
self.a_desired_trajectory = np.zeros(CONTROL_N)
self.j_desired_trajectory = np.zeros(CONTROL_N)
+ self.solverExecutionTime = 0.0
def update(self, sm):
v_ego = sm['carState'].vEgo
diff --git a/selfdrive/controls/lib/radar_helpers.py b/selfdrive/controls/lib/radar_helpers.py
index 4f87fdf09b..85699866b0 100644
--- a/selfdrive/controls/lib/radar_helpers.py
+++ b/selfdrive/controls/lib/radar_helpers.py
@@ -1,6 +1,5 @@
from common.numpy_fast import mean
from common.kalman.simple_kalman import KF1D
-from selfdrive.config import RADAR_TO_CAMERA
# the longer lead decels, the more likely it will keep decelerating
@@ -13,6 +12,8 @@ SPEED, ACCEL = 0, 1 # Kalman filter states enum
# stationary qualification parameters
v_ego_stationary = 4. # no stationary object flag below this speed
+RADAR_TO_CENTER = 2.7 # (deprecated) RADAR is ~ 2.7m ahead from center of car
+RADAR_TO_CAMERA = 1.52 # RADAR is ~ 1.5m ahead from center of mesh frame
class Track():
def __init__(self, v_lead, kalman_params):
diff --git a/selfdrive/controls/radard.py b/selfdrive/controls/radard.py
index 65f8480c7c..ddba0920b8 100755
--- a/selfdrive/controls/radard.py
+++ b/selfdrive/controls/radard.py
@@ -8,9 +8,8 @@ from cereal import car
from common.numpy_fast import interp
from common.params import Params
from common.realtime import Ratekeeper, Priority, config_realtime_process
-from selfdrive.config import RADAR_TO_CAMERA
from selfdrive.controls.lib.cluster.fastcluster_py import cluster_points_centroid
-from selfdrive.controls.lib.radar_helpers import Cluster, Track
+from selfdrive.controls.lib.radar_helpers import Cluster, Track, RADAR_TO_CAMERA
from selfdrive.swaglog import cloudlog
from selfdrive.hardware import TICI
diff --git a/selfdrive/controls/tests/test_following_distance.py b/selfdrive/controls/tests/test_following_distance.py
index a0110a4dab..ebe4776739 100644
--- a/selfdrive/controls/tests/test_following_distance.py
+++ b/selfdrive/controls/tests/test_following_distance.py
@@ -21,7 +21,7 @@ def run_following_distance_simulation(v_lead, t_end=100.0):
class TestFollowingDistance(unittest.TestCase):
- def test_following_distanc(self):
+ def test_following_distance(self):
for speed in np.arange(0, 40, 5):
print(f'Testing {speed} m/s')
v_lead = float(speed)
diff --git a/selfdrive/debug/can_print_changes.py b/selfdrive/debug/can_print_changes.py
index 4fa775ac17..b883fbc23f 100755
--- a/selfdrive/debug/can_print_changes.py
+++ b/selfdrive/debug/can_print_changes.py
@@ -1,46 +1,103 @@
#!/usr/bin/env python3
+import argparse
import binascii
-import sys
+import time
from collections import defaultdict
import cereal.messaging as messaging
-from common.realtime import sec_since_boot
+from selfdrive.debug.can_table import can_table
+from tools.lib.logreader import logreader_from_route_or_segment
+RED = '\033[91m'
+CLEAR = '\033[0m'
+
+def update(msgs, bus, dat, low_to_high, high_to_low, quiet=False):
+ for x in msgs:
+ if x.which() != 'can':
+ continue
+
+ for y in x.can:
+ if y.src == bus:
+ dat[y.address] = y.dat
+
+ i = int.from_bytes(y.dat, byteorder='big')
+ l_h = low_to_high[y.address]
+ h_l = high_to_low[y.address]
+
+ change = None
+ if (i | l_h) != l_h:
+ low_to_high[y.address] = i | l_h
+ change = "+"
+
+ if (~i | h_l) != h_l:
+ high_to_low[y.address] = ~i | h_l
+ change = "-"
+
+ if change and not quiet:
+ print(f"{time.monotonic():.2f}\t{hex(y.address)} ({y.address})\t{change}{binascii.hexlify(y.dat)}")
-def can_printer(bus=0):
- """Collects messages and prints when a new bit transition is observed.
- This is very useful to find signals based on user triggered actions, such as blinkers and seatbelt.
- Leave the script running until no new transitions are seen, then perform the action."""
- logcan = messaging.sub_sock('can')
+def can_printer(bus=0, init_msgs=None, new_msgs=None, table=False):
+ logcan = messaging.sub_sock('can', timeout=10)
+
+ dat = defaultdict(int)
low_to_high = defaultdict(int)
high_to_low = defaultdict(int)
- while 1:
- can_recv = messaging.drain_sock(logcan, wait_for_one=True)
- for x in can_recv:
- for y in x.can:
- if y.src == bus:
- i = int.from_bytes(y.dat, byteorder='big')
+ if init_msgs is not None:
+ update(init_msgs, bus, dat, low_to_high, high_to_low, quiet=True)
- l_h = low_to_high[y.address]
- h_l = high_to_low[y.address]
+ low_to_high_init = low_to_high.copy()
+ high_to_low_init = high_to_low.copy()
- change = None
- if (i | l_h) != l_h:
- low_to_high[y.address] = i | l_h
- change = "+"
+ if new_msgs is not None:
+ update(new_msgs, bus, dat, low_to_high, high_to_low)
+ else:
+ # Live mode
+ try:
+ while 1:
+ can_recv = messaging.drain_sock(logcan)
+ update(can_recv, bus, dat, low_to_high, high_to_low)
+ time.sleep(0.02)
+ except KeyboardInterrupt:
+ pass
- if (~i | h_l) != h_l:
- high_to_low[y.address] = ~i | h_l
- change = "-"
+ print("\n\n")
+ tables = ""
+ for addr in sorted(dat.keys()):
+ init = low_to_high_init[addr] & high_to_low_init[addr]
+ now = low_to_high[addr] & high_to_low[addr]
+ d = now & ~init
+ if d == 0:
+ continue
+ b = d.to_bytes(len(dat[addr]), byteorder='big')
- if change:
- print(f"{sec_since_boot():.2f}\t{hex(y.address)} ({y.address})\t{change}{binascii.hexlify(y.dat)}")
+ byts = ''.join([(c if c == '0' else f'{RED}{c}{CLEAR}') for c in str(binascii.hexlify(b))[2:-1]])
+ header = f"{hex(addr).ljust(6)}({str(addr).ljust(4)})"
+ print(header, byts)
+ tables += f"{header}\n"
+ tables += can_table(b) + "\n\n"
+ if table:
+ print(tables)
if __name__ == "__main__":
- if len(sys.argv) > 1:
- can_printer(int(sys.argv[1]))
- else:
- can_printer()
+ desc = """Collects messages and prints when a new bit transition is observed.
+ This is very useful to find signals based on user triggered actions, such as blinkers and seatbelt.
+ Leave the script running until no new transitions are seen, then perform the action."""
+ parser = argparse.ArgumentParser(description=desc,
+ formatter_class=argparse.ArgumentDefaultsHelpFormatter)
+ parser.add_argument("--bus", type=int, help="CAN bus to print out", default=0)
+ parser.add_argument("--table", action="store_true", help="Print a cabana-like table")
+ parser.add_argument("init", type=str, nargs='?', help="Route or segment to initialize with")
+ parser.add_argument("comp", type=str, nargs='?', help="Route or segment to compare against init")
+
+ args = parser.parse_args()
+
+ init_lr, new_lr = None, None
+ if args.init:
+ init_lr = logreader_from_route_or_segment(args.init)
+ if args.comp:
+ new_lr = logreader_from_route_or_segment(args.comp)
+
+ can_printer(args.bus, init_msgs=init_lr, new_msgs=new_lr, table=args.table)
diff --git a/selfdrive/debug/can_table.py b/selfdrive/debug/can_table.py
index 1569849053..e8cd084a32 100755
--- a/selfdrive/debug/can_table.py
+++ b/selfdrive/debug/can_table.py
@@ -5,6 +5,19 @@ import pandas as pd # pylint: disable=import-error
import cereal.messaging as messaging
+def can_table(dat):
+ rows = []
+ for b in dat:
+ r = list(bin(b).lstrip('0b').zfill(8))
+ r += [hex(b)]
+ rows.append(r)
+
+ df = pd.DataFrame(data=rows)
+ df.columns = [str(n) for n in range(7, -1, -1)] + [' ']
+ table = df.to_markdown(tablefmt='grid')
+ return table
+
+
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Cabana-like table of bits for your terminal",
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
@@ -28,12 +41,5 @@ if __name__ == "__main__":
if latest is None:
continue
- rows = []
- for b in latest.dat:
- r = list(bin(b).lstrip('0b').zfill(8))
- r += [hex(b)]
- rows.append(r)
-
- df = pd.DataFrame(data=rows)
- table = df.to_markdown(tablefmt='grid')
+ table = can_table(latest.dat)
print(f"\n\n{hex(addr)} ({addr}) on bus {args.bus}\n{table}")
diff --git a/selfdrive/hardware/base.py b/selfdrive/hardware/base.py
index b551138ce3..20258b85d0 100644
--- a/selfdrive/hardware/base.py
+++ b/selfdrive/hardware/base.py
@@ -2,7 +2,11 @@ from abc import abstractmethod, ABC
from collections import namedtuple
from typing import Dict
+from cereal import log
+
ThermalConfig = namedtuple('ThermalConfig', ['cpu', 'gpu', 'mem', 'bat', 'ambient', 'pmic'])
+NetworkType = log.DeviceState.NetworkType
+
class HardwareBase(ABC):
@staticmethod
@@ -67,6 +71,9 @@ class HardwareBase(ABC):
def get_network_strength(self, network_type):
pass
+ def get_network_metered(self, network_type) -> bool:
+ return network_type not in (NetworkType.none, NetworkType.wifi, NetworkType.ethernet)
+
@staticmethod
def set_bandwidth_limit(upload_speed_kbps: int, download_speed_kbps: int) -> None:
pass
diff --git a/selfdrive/hardware/eon/hardware.py b/selfdrive/hardware/eon/hardware.py
index 4ab9f81fcf..dcc29d5919 100644
--- a/selfdrive/hardware/eon/hardware.py
+++ b/selfdrive/hardware/eon/hardware.py
@@ -380,7 +380,9 @@ class Android(HardwareBase):
os.system('LD_LIBRARY_PATH="" svc power shutdown')
def get_thermal_config(self):
- return ThermalConfig(cpu=((5, 7, 10, 12), 10), gpu=((16,), 10), mem=(2, 10), bat=(29, 1000), ambient=(25, 1), pmic=((22,), 1000))
+ # the thermal sensors on the 820 don't have meaningful names
+ return ThermalConfig(cpu=((5, 7, 10, 12), 10), gpu=((16,), 10), mem=(2, 10),
+ bat=("battery", 1000), ambient=("pa_therm0", 1), pmic=(("pm8994_tz",), 1000))
def set_screen_brightness(self, percentage):
with open("/sys/class/leds/lcd-backlight/brightness", "w") as f:
diff --git a/selfdrive/hardware/tici/hardware.py b/selfdrive/hardware/tici/hardware.py
index 41ae316d3c..7a0d5204c1 100644
--- a/selfdrive/hardware/tici/hardware.py
+++ b/selfdrive/hardware/tici/hardware.py
@@ -13,6 +13,7 @@ from selfdrive.hardware.tici.amplifier import Amplifier
NM = 'org.freedesktop.NetworkManager'
NM_CON_ACT = NM + '.Connection.Active'
+NM_DEV = NM + '.Device'
NM_DEV_WL = NM + '.Device.Wireless'
NM_AP = NM + '.AccessPoint'
DBUS_PROPS = 'org.freedesktop.DBus.Properties'
@@ -37,6 +38,13 @@ class MM_MODEM_STATE(IntEnum):
CONNECTING = 10
CONNECTED = 11
+class NMMetered(IntEnum):
+ NM_METERED_UNKNOWN = 0
+ NM_METERED_YES = 1
+ NM_METERED_NO = 2
+ NM_METERED_GUESS_YES = 3
+ NM_METERED_GUESS_NO = 4
+
TIMEOUT = 0.1
NetworkType = log.DeviceState.NetworkType
@@ -91,11 +99,10 @@ class Tici(HardwareBase):
primary_connection = self.nm.Get(NM, 'PrimaryConnection', dbus_interface=DBUS_PROPS, timeout=TIMEOUT)
primary_connection = self.bus.get_object(NM, primary_connection)
primary_type = primary_connection.Get(NM_CON_ACT, 'Type', dbus_interface=DBUS_PROPS, timeout=TIMEOUT)
- primary_id = primary_connection.Get(NM_CON_ACT, 'Id', dbus_interface=DBUS_PROPS, timeout=TIMEOUT)
if primary_type == '802-3-ethernet':
return NetworkType.ethernet
- elif primary_type == '802-11-wireless' and primary_id != 'Hotspot':
+ elif primary_type == '802-11-wireless':
return NetworkType.wifi
else:
active_connections = self.nm.Get(NM, 'ActiveConnections', dbus_interface=DBUS_PROPS, timeout=TIMEOUT)
@@ -218,6 +225,27 @@ class Tici(HardwareBase):
return network_strength
+ def get_network_metered(self, network_type) -> bool:
+ try:
+ primary_connection = self.nm.Get(NM, 'PrimaryConnection', dbus_interface=DBUS_PROPS, timeout=TIMEOUT)
+ primary_connection = self.bus.get_object(NM, primary_connection)
+ primary_devices = primary_connection.Get(NM_CON_ACT, 'Devices', dbus_interface=DBUS_PROPS, timeout=TIMEOUT)
+
+ for dev in primary_devices:
+ dev_obj = self.bus.get_object(NM, str(dev))
+ metered_prop = dev_obj.Get(NM_DEV, 'Metered', dbus_interface=DBUS_PROPS, timeout=TIMEOUT)
+
+ if network_type == NetworkType.wifi:
+ if metered_prop in [NMMetered.NM_METERED_YES, NMMetered.NM_METERED_GUESS_YES]:
+ return True
+ elif network_type in [NetworkType.cell2G, NetworkType.cell3G, NetworkType.cell4G, NetworkType.cell5G]:
+ if metered_prop == NMMetered.NM_METERED_NO:
+ return False
+ except Exception:
+ pass
+
+ return super().get_network_metered(network_type)
+
@staticmethod
def set_bandwidth_limit(upload_speed_kbps: int, download_speed_kbps: int) -> None:
upload_speed_kbps = int(upload_speed_kbps) # Ensure integer value
@@ -334,7 +362,13 @@ class Tici(HardwareBase):
os.system("sudo poweroff")
def get_thermal_config(self):
- return ThermalConfig(cpu=((1, 2, 3, 4, 5, 6, 7, 8), 1000), gpu=((48,49), 1000), mem=(15, 1000), bat=(None, 1), ambient=(65, 1000), pmic=((35, 36), 1000))
+ return ThermalConfig(cpu=(["cpu%d-silver-usr" % i for i in range(4)] +
+ ["cpu%d-gold-usr" % i for i in range(4)], 1000),
+ gpu=(("gpu0-usr", "gpu1-usr"), 1000),
+ mem=("ddr-usr", 1000),
+ bat=(None, 1),
+ ambient=("xo-therm-adc", 1000),
+ pmic=(("pm8998_tz", "pm8005_tz"), 1000))
def set_screen_brightness(self, percentage):
try:
diff --git a/selfdrive/locationd/calibrationd.py b/selfdrive/locationd/calibrationd.py
index ae314e38c4..c8c3912528 100755
--- a/selfdrive/locationd/calibrationd.py
+++ b/selfdrive/locationd/calibrationd.py
@@ -13,12 +13,12 @@ from typing import NoReturn
from cereal import log
import cereal.messaging as messaging
+from common.conversions import Conversions as CV
from common.params import Params, put_nonblocking
from common.realtime import set_realtime_priority
from common.transformations.model import model_height
from common.transformations.camera import get_view_frame_from_road_frame
from common.transformations.orientation import rot_from_euler, euler_from_rot
-from selfdrive.config import Conversions as CV
from selfdrive.hardware import TICI
from selfdrive.swaglog import cloudlog
diff --git a/selfdrive/locationd/locationd.cc b/selfdrive/locationd/locationd.cc
index b723878e9d..5cec492d67 100755
--- a/selfdrive/locationd/locationd.cc
+++ b/selfdrive/locationd/locationd.cc
@@ -262,7 +262,6 @@ void Localizer::input_fake_gps_observations(double current_time) {
void Localizer::handle_gps(double current_time, const cereal::GpsLocationData::Reader& log) {
// ignore the message if the fix is invalid
-
bool gps_invalid_flag = (log.getFlags() % 2 == 0);
bool gps_unreasonable = (Vector2d(log.getAccuracy(), log.getVerticalAccuracy()).norm() >= SANE_GPS_UNCERTAINTY);
bool gps_accuracy_insane = ((log.getVerticalAccuracy() <= 0) || (log.getSpeedAccuracy() <= 0) || (log.getBearingAccuracyDeg() <= 0));
@@ -462,9 +461,9 @@ kj::ArrayPtr Localizer::get_message_bytes(MessageBuilder& msg_build
{
cereal::Event::Builder evt = msg_builder.initEvent();
evt.setLogMonoTime(logMonoTime);
+ evt.setValid(inputsOK);
cereal::LiveLocationKalman::Builder liveLoc = evt.initLiveLocationKalman();
this->build_live_location(liveLoc);
- liveLoc.setInputsOK(inputsOK);
liveLoc.setSensorsOK(sensorsOK);
liveLoc.setGpsOK(gpsOK);
return msg_builder.toBytes();
@@ -497,14 +496,19 @@ int Localizer::locationd_thread() {
PubMaster pm({ "liveLocationKalman" });
SubMaster sm(service_list, nullptr, { "gpsLocationExternal" });
+ uint64_t cnt = 0;
+
while (!do_exit) {
sm.update();
- for (const char* service : service_list) {
- if (sm.updated(service) && sm.valid(service)) {
- const cereal::Event::Reader log = sm[service];
- this->handle_msg(log);
+ if (sm.allAliveAndValid()){
+ for (const char* service : service_list) {
+ if (sm.updated(service)){
+ const cereal::Event::Reader log = sm[service];
+ this->handle_msg(log);
+ }
}
}
+
if (sm.updated("cameraOdometry")) {
uint64_t logMonoTime = sm["cameraOdometry"].getLogMonoTime();
@@ -516,7 +520,7 @@ int Localizer::locationd_thread() {
kj::ArrayPtr bytes = this->get_message_bytes(msg_builder, logMonoTime, inputsOK, sensorsOK, gpsOK);
pm.send("liveLocationKalman", bytes.begin(), bytes.size());
- if (sm.frame % 1200 == 0 && gpsOK) { // once a minute
+ if (cnt % 1200 == 0 && gpsOK) { // once a minute
VectorXd posGeo = this->get_position_geodetic();
std::string lastGPSPosJSON = util::string_format(
"{\"latitude\": %.15f, \"longitude\": %.15f, \"altitude\": %.15f}", posGeo(0), posGeo(1), posGeo(2));
@@ -525,6 +529,7 @@ int Localizer::locationd_thread() {
Params().put("LastGPSPosition", gpsjson);
}, lastGPSPosJSON).detach();
}
+ cnt++;
}
}
return 0;
diff --git a/selfdrive/locationd/paramsd.py b/selfdrive/locationd/paramsd.py
index 0efb4d04be..44ffccdf1a 100755
--- a/selfdrive/locationd/paramsd.py
+++ b/selfdrive/locationd/paramsd.py
@@ -62,7 +62,7 @@ class ParamsLearner:
yaw_rate_valid = yaw_rate_valid and abs(yaw_rate) < 1 # rad/s
if self.active:
- if msg.inputsOK and msg.posenetOK:
+ if msg.posenetOK:
if yaw_rate_valid:
self.kf.predict_and_observe(t,
@@ -160,10 +160,11 @@ def main(sm=None, pm=None):
while True:
sm.update()
- for which in sorted(sm.updated.keys(), key=lambda x: sm.logMonoTime[x]):
- if sm.updated[which]:
- t = sm.logMonoTime[which] * 1e-9
- learner.handle_log(t, which, sm[which])
+ if sm.all_alive_and_valid():
+ for which in sorted(sm.updated.keys(), key=lambda x: sm.logMonoTime[x]):
+ if sm.updated[which]:
+ t = sm.logMonoTime[which] * 1e-9
+ learner.handle_log(t, which, sm[which])
if sm.updated['liveLocationKalman']:
x = learner.kf.x
@@ -198,6 +199,8 @@ def main(sm=None, pm=None):
liveParameters.angleOffsetAverageStd = float(P[States.ANGLE_OFFSET])
liveParameters.angleOffsetFastStd = float(P[States.ANGLE_OFFSET_FAST])
+ msg.valid = sm.all_alive_and_valid()
+
if sm.frame % 1200 == 0: # once a minute
params = {
'carFingerprint': CP.carFingerprint,
diff --git a/selfdrive/locationd/test/test_locationd.py b/selfdrive/locationd/test/test_locationd.py
index 76f82efc10..515bd59431 100755
--- a/selfdrive/locationd/test/test_locationd.py
+++ b/selfdrive/locationd/test/test_locationd.py
@@ -4,10 +4,12 @@ import json
import random
import unittest
import time
+import capnp
from cffi import FFI
from cereal import log
import cereal.messaging as messaging
+from cereal.services import service_list
from common.params import Params
from selfdrive.manager.process_config import managed_processes
@@ -103,13 +105,15 @@ void localizer_handle_msg_bytes(Localizer_t localizer, const char *data, size_t
ret = self.localizer_get_msg()
self.assertFalse(ret.liveLocationKalman.posenetOK)
+
class TestLocationdProc(unittest.TestCase):
MAX_WAITS = 1000
+ LLD_MSGS = {'gpsLocationExternal', 'cameraOdometry', 'carState', 'sensorEvents', 'liveCalibration'}
def setUp(self):
random.seed(123489234)
- self.pm = messaging.PubMaster({'gpsLocationExternal', 'cameraOdometry'})
+ self.pm = messaging.PubMaster(self.LLD_MSGS)
managed_processes['locationd'].prepare()
managed_processes['locationd'].start()
@@ -127,43 +131,53 @@ class TestLocationdProc(unittest.TestCase):
waits_left -= 1
time.sleep(0.0001)
- def test_params_gps(self):
- # first reset params
- Params().put('LastGPSPosition', json.dumps({"latitude": 0.0, "longitude": 0.0, "altitude": 0.0}))
-
- lat = 30 + (random.random() * 10.0)
- lon = -70 + (random.random() * 10.0)
- alt = 5 + (random.random() * 10.0)
+ def get_fake_msg(self, name, t):
+ try:
+ msg = messaging.new_message(name)
+ except capnp.lib.capnp.KjException:
+ msg = messaging.new_message(name, 0)
- for _ in range(1000): # because of kalman filter, send often
- msg = messaging.new_message('gpsLocationExternal')
- msg.logMonoTime = 0
+ if name == "gpsLocationExternal":
msg.gpsLocationExternal.flags = 1
msg.gpsLocationExternal.verticalAccuracy = 1.0
msg.gpsLocationExternal.speedAccuracy = 1.0
msg.gpsLocationExternal.bearingAccuracyDeg = 1.0
msg.gpsLocationExternal.vNED = [0.0, 0.0, 0.0]
- msg.gpsLocationExternal.latitude = lat
- msg.gpsLocationExternal.longitude = lon
- msg.gpsLocationExternal.altitude = alt
- self.send_msg(msg)
-
- for _ in range(250): # params is only written so often
- msg = messaging.new_message('cameraOdometry')
- msg.logMonoTime = 0
+ msg.gpsLocationExternal.latitude = self.lat
+ msg.gpsLocationExternal.longitude = self.lon
+ msg.gpsLocationExternal.altitude = self.alt
+ elif name == 'cameraOdometry':
msg.cameraOdometry.rot = [0.0, 0.0, 0.0]
msg.cameraOdometry.rotStd = [0.0, 0.0, 0.0]
msg.cameraOdometry.trans = [0.0, 0.0, 0.0]
msg.cameraOdometry.transStd = [0.0, 0.0, 0.0]
- self.send_msg(msg)
+ msg.logMonoTime = t
+ return msg
+ def test_params_gps(self):
+ # first reset params
+ Params().delete('LastGPSPosition')
+
+ self.lat = 30 + (random.random() * 10.0)
+ self.lon = -70 + (random.random() * 10.0)
+ self.alt = 5 + (random.random() * 10.0)
+ self.fake_duration = 90 # secs
+ # get fake messages at the correct frequency, listed in services.py
+ fake_msgs = []
+ for sec in range(self.fake_duration):
+ for name in self.LLD_MSGS:
+ for j in range(int(service_list[name].frequency)):
+ fake_msgs.append(self.get_fake_msg(name, int((sec + j / service_list[name].frequency) * 1e9)))
+
+ for fake_msg in sorted(fake_msgs, key=lambda x: x.logMonoTime):
+ self.send_msg(fake_msg)
time.sleep(1) # wait for async params write
lastGPS = json.loads(Params().get('LastGPSPosition'))
- self.assertAlmostEqual(lastGPS['latitude'], lat, places=3)
- self.assertAlmostEqual(lastGPS['longitude'], lon, places=3)
- self.assertAlmostEqual(lastGPS['altitude'], alt, places=3)
+ self.assertAlmostEqual(lastGPS['latitude'], self.lat, places=3)
+ self.assertAlmostEqual(lastGPS['longitude'], self.lon, places=3)
+ self.assertAlmostEqual(lastGPS['altitude'], self.alt, places=3)
if __name__ == "__main__":
diff --git a/selfdrive/loggerd/uploader.py b/selfdrive/loggerd/uploader.py
index afdc5a6ed1..4dd982a02b 100644
--- a/selfdrive/loggerd/uploader.py
+++ b/selfdrive/loggerd/uploader.py
@@ -165,14 +165,14 @@ class Uploader():
return self.last_resp
- def upload(self, key, fn, network_type):
+ def upload(self, key, fn, network_type, metered):
try:
sz = os.path.getsize(fn)
except OSError:
cloudlog.exception("upload: getsize failed")
return False
- cloudlog.event("upload_start", key=key, fn=fn, sz=sz, network_type=network_type)
+ cloudlog.event("upload_start", key=key, fn=fn, sz=sz, network_type=network_type, metered=metered)
if sz == 0:
try:
@@ -195,10 +195,10 @@ class Uploader():
self.last_time = time.monotonic() - start_time
self.last_speed = (sz / 1e6) / self.last_time
success = True
- cloudlog.event("upload_success" if stat.status_code != 412 else "upload_ignored", key=key, fn=fn, sz=sz, network_type=network_type)
+ cloudlog.event("upload_success" if stat.status_code != 412 else "upload_ignored", key=key, fn=fn, sz=sz, network_type=network_type, metered=metered)
else:
success = False
- cloudlog.event("upload_failed", stat=stat, exc=self.last_exc, key=key, fn=fn, sz=sz, network_type=network_type)
+ cloudlog.event("upload_failed", stat=stat, exc=self.last_exc, key=key, fn=fn, sz=sz, network_type=network_type, metered=metered)
return success
@@ -247,7 +247,7 @@ def uploader_fn(exit_event):
key, fn = d
- success = uploader.upload(key, fn, sm['deviceState'].networkType.raw)
+ success = uploader.upload(key, fn, sm['deviceState'].networkType.raw, sm['deviceState'].networkMetered)
if success:
backoff = 0.1
elif allow_sleep:
@@ -257,6 +257,7 @@ def uploader_fn(exit_event):
pm.send("uploaderState", uploader.get_msg())
+
def main():
uploader_fn(threading.Event())
diff --git a/selfdrive/manager/process_config.py b/selfdrive/manager/process_config.py
index c017e48fab..bc88154c2c 100644
--- a/selfdrive/manager/process_config.py
+++ b/selfdrive/manager/process_config.py
@@ -27,7 +27,7 @@ procs = [
PythonProcess("deleter", "selfdrive.loggerd.deleter", persistent=True),
PythonProcess("dmonitoringd", "selfdrive.monitoring.dmonitoringd", enabled=(not PC or WEBCAM), driverview=True),
PythonProcess("logmessaged", "selfdrive.logmessaged", persistent=True),
- PythonProcess("pandad", "selfdrive.pandad", persistent=True),
+ PythonProcess("pandad", "selfdrive.boardd.pandad", persistent=True),
PythonProcess("paramsd", "selfdrive.locationd.paramsd"),
PythonProcess("plannerd", "selfdrive.controls.plannerd"),
PythonProcess("radard", "selfdrive.controls.radard"),
diff --git a/selfdrive/modeld/SConscript b/selfdrive/modeld/SConscript
index 9066a653fa..20d3fb8acc 100644
--- a/selfdrive/modeld/SConscript
+++ b/selfdrive/modeld/SConscript
@@ -31,9 +31,6 @@ thneed_src = [
use_thneed = not GetOption('no_thneed')
-use_extra = True # arch == "larch64"
-lenv['CXXFLAGS'].append('-DUSE_EXTRA=true' if use_extra else '-DUSE_EXTRA=false')
-
if arch == "aarch64" or arch == "larch64":
libs += ['gsl', 'CB']
libs += ['gnustl_shared'] if arch == "aarch64" else ['pthread', 'dl']
@@ -68,16 +65,24 @@ common_model = lenv.Object(common_src)
# build thneed model
if use_thneed and arch in ("aarch64", "larch64"):
- fn = "../../models/big_supercombo" if use_extra else "../../models/supercombo"
+ fn = File("#models/supercombo").abspath
compiler = lenv.Program('thneed/compile', ["thneed/compile.cc"]+common_model, LIBS=libs)
- cmd = f"cd {Dir('.').abspath} && {compiler[0].abspath} {fn}.dlc {fn}.thneed --binary"
+ cmd = f"cd {Dir('.').abspath} && {compiler[0].abspath} {fn}.dlc {fn}_badweights.thneed --binary"
lib_paths = ':'.join(Dir(p).abspath for p in lenv["LIBPATH"])
kernel_path = os.path.join(Dir('.').abspath, "thneed", "kernels")
cenv = Environment(ENV={'LD_LIBRARY_PATH': f"{lib_paths}:{lenv['ENV']['LD_LIBRARY_PATH']}", 'KERNEL_PATH': kernel_path})
kernels = [os.path.join(kernel_path, x) for x in os.listdir(kernel_path) if x.endswith(".cl")]
- cenv.Command(fn + ".thneed", [fn + ".dlc", kernels, compiler], cmd)
+ cenv.Command(fn + "_badweights.thneed", [fn + ".dlc", kernels, compiler], cmd)
+
+ from selfdrive.modeld.thneed.weights_fixup import weights_fixup
+ def weights_fixup_action(target, source, env):
+ weights_fixup(target[0].abspath, source[0].abspath, source[1].abspath)
+
+ env = Environment(BUILDERS = {'WeightFixup' : Builder(action = weights_fixup_action)})
+ env.WeightFixup(target=fn + ".thneed", source=[fn+"_badweights.thneed", fn+".dlc"])
+
lenv.Program('_dmonitoringmodeld', [
"dmonitoringmodeld.cc",
diff --git a/selfdrive/modeld/modeld.cc b/selfdrive/modeld/modeld.cc
index 697e31a7b7..2714370106 100644
--- a/selfdrive/modeld/modeld.cc
+++ b/selfdrive/modeld/modeld.cc
@@ -51,7 +51,12 @@ mat3 update_calibration(Eigen::Matrix &extrinsics, bool wide_camera
return matmul3(yuv_transform, transform);
}
-void run_model(ModelState &model, VisionIpcClient &vipc_client_main, VisionIpcClient &vipc_client_extra, bool main_wide_camera, bool use_extra, bool use_extra_client) {
+static uint64_t get_ts(const VisionIpcBufExtra &extra) {
+ return Hardware::TICI() ? extra.timestamp_sof : extra.timestamp_eof;
+}
+
+
+void run_model(ModelState &model, VisionIpcClient &vipc_client_main, VisionIpcClient &vipc_client_extra, bool main_wide_camera, bool use_extra_client) {
// messaging
PubMaster pm({"modelV2", "cameraOdometry"});
SubMaster sm({"lateralPlan", "roadCameraState", "liveCalibration"});
@@ -74,18 +79,9 @@ void run_model(ModelState &model, VisionIpcClient &vipc_client_main, VisionIpcCl
VisionIpcBufExtra meta_extra = {0};
while (!do_exit) {
- // TODO: change sync logic to use timestamp start of frame in case camerad skips a frame
- // log frame id in model packet
-
// Keep receiving frames until we are at least 1 frame ahead of previous extra frame
- while (meta_main.frame_id <= meta_extra.frame_id) {
+ while (get_ts(meta_main) < get_ts(meta_extra) + 25000000ULL) {
buf_main = vipc_client_main.recv(&meta_main);
- if (meta_main.frame_id <= meta_extra.frame_id) {
- LOGE("main camera behind! main: %d (%.5f), extra: %d (%.5f)",
- meta_main.frame_id, double(meta_main.timestamp_sof) / 1e9,
- meta_extra.frame_id, double(meta_extra.timestamp_sof) / 1e9);
- }
-
if (buf_main == nullptr) break;
}
@@ -98,20 +94,14 @@ void run_model(ModelState &model, VisionIpcClient &vipc_client_main, VisionIpcCl
// Keep receiving extra frames until frame id matches main camera
do {
buf_extra = vipc_client_extra.recv(&meta_extra);
-
- if (meta_main.frame_id > meta_extra.frame_id) {
- LOGE("extra camera behind! main: %d (%.5f), extra: %d (%.5f)",
- meta_main.frame_id, double(meta_main.timestamp_sof) / 1e9,
- meta_extra.frame_id, double(meta_extra.timestamp_sof) / 1e9);
- }
- } while (buf_extra != nullptr && meta_main.frame_id > meta_extra.frame_id);
+ } while (buf_extra != nullptr && get_ts(meta_main) > get_ts(meta_extra) + 25000000ULL);
if (buf_extra == nullptr) {
LOGE("vipc_client_extra no frame");
continue;
}
- if (meta_main.frame_id != meta_extra.frame_id || std::abs((int64_t)meta_main.timestamp_sof - (int64_t)meta_extra.timestamp_sof) > 10000000ULL) {
+ if (std::abs((int64_t)meta_main.timestamp_sof - (int64_t)meta_extra.timestamp_sof) > 10000000ULL) {
LOGE("frames out of sync! main: %d (%.5f), extra: %d (%.5f)",
meta_main.frame_id, double(meta_main.timestamp_sof) / 1e9,
meta_extra.frame_id, double(meta_extra.timestamp_sof) / 1e9);
@@ -134,9 +124,7 @@ void run_model(ModelState &model, VisionIpcClient &vipc_client_main, VisionIpcCl
}
model_transform_main = update_calibration(extrinsic_matrix_eigen, main_wide_camera, false);
- if (use_extra) {
- model_transform_extra = update_calibration(extrinsic_matrix_eigen, Hardware::TICI(), true);
- }
+ model_transform_extra = update_calibration(extrinsic_matrix_eigen, Hardware::TICI(), true);
live_calib_seen = true;
}
@@ -161,7 +149,7 @@ void run_model(ModelState &model, VisionIpcClient &vipc_client_main, VisionIpcCl
float frame_drop_ratio = frames_dropped / (1 + frames_dropped);
- model_publish(pm, meta_main.frame_id, frame_id, frame_drop_ratio, *model_output, meta_main.timestamp_eof, model_execution_time,
+ model_publish(pm, meta_main.frame_id, meta_extra.frame_id, frame_id, frame_drop_ratio, *model_output, meta_main.timestamp_eof, model_execution_time,
kj::ArrayPtr(model.output.data(), model.output.size()), live_calib_seen);
posenet_publish(pm, meta_main.frame_id, vipc_dropped_frames, *model_output, meta_main.timestamp_eof, live_calib_seen);
@@ -181,8 +169,7 @@ int main(int argc, char **argv) {
}
bool main_wide_camera = Hardware::TICI() ? Params().getBool("EnableWideCamera") : false;
- bool use_extra = USE_EXTRA;
- bool use_extra_client = Hardware::TICI() && use_extra && !main_wide_camera;
+ bool use_extra_client = Hardware::TICI() && !main_wide_camera;
// cl init
cl_device_id device_id = cl_get_device_id(CL_DEVICE_TYPE_DEFAULT);
@@ -190,7 +177,7 @@ int main(int argc, char **argv) {
// init the models
ModelState model;
- model_init(&model, device_id, context, use_extra);
+ model_init(&model, device_id, context);
LOGW("models loaded, modeld starting");
VisionIpcClient vipc_client_main = VisionIpcClient("camerad", main_wide_camera ? VISION_STREAM_WIDE_ROAD : VISION_STREAM_ROAD, true, device_id, context);
@@ -215,7 +202,7 @@ int main(int argc, char **argv) {
LOGW("connected extra cam with buffer size: %d (%d x %d)", wb->len, wb->width, wb->height);
}
- run_model(model, vipc_client_main, vipc_client_extra, main_wide_camera, use_extra, use_extra_client);
+ run_model(model, vipc_client_main, vipc_client_extra, main_wide_camera, use_extra_client);
}
model_free(&model);
diff --git a/selfdrive/modeld/models/driving.cc b/selfdrive/modeld/models/driving.cc
index e42f2c0f46..18ab82223b 100644
--- a/selfdrive/modeld/models/driving.cc
+++ b/selfdrive/modeld/models/driving.cc
@@ -26,20 +26,18 @@ constexpr const kj::ArrayPtr to_kj_array_ptr(const std::array
return kj::ArrayPtr(arr.data(), arr.size());
}
-void model_init(ModelState* s, cl_device_id device_id, cl_context context, bool use_extra) {
+void model_init(ModelState* s, cl_device_id device_id, cl_context context) {
s->frame = new ModelFrame(device_id, context);
s->wide_frame = new ModelFrame(device_id, context);
#ifdef USE_THNEED
- s->m = std::make_unique(use_extra ? "../../models/big_supercombo.thneed" : "../../models/supercombo.thneed",
- &s->output[0], NET_OUTPUT_SIZE, USE_GPU_RUNTIME, use_extra);
+ s->m = std::make_unique("../../models/supercombo.thneed",
#elif USE_ONNX_MODEL
- s->m = std::make_unique(use_extra ? "../../models/big_supercombo.onnx" : "../../models/supercombo.onnx",
- &s->output[0], NET_OUTPUT_SIZE, USE_GPU_RUNTIME, use_extra);
+ s->m = std::make_unique("../../models/supercombo.onnx",
#else
- s->m = std::make_unique(use_extra ? "../../models/big_supercombo.dlc" : "../../models/supercombo.dlc",
- &s->output[0], NET_OUTPUT_SIZE, USE_GPU_RUNTIME, use_extra);
+ s->m = std::make_unique("../../models/supercombo.dlc",
#endif
+ &s->output[0], NET_OUTPUT_SIZE, USE_GPU_RUNTIME, true);
#ifdef TEMPORAL
s->m->addRecurrent(&s->output[OUTPUT_SIZE], TEMPORAL_SIZE);
@@ -316,13 +314,14 @@ void fill_model(cereal::ModelDataV2::Builder &framed, const ModelOutput &net_out
}
}
-void model_publish(PubMaster &pm, uint32_t vipc_frame_id, uint32_t frame_id, float frame_drop,
+void model_publish(PubMaster &pm, uint32_t vipc_frame_id, uint32_t vipc_frame_id_extra, uint32_t frame_id, float frame_drop,
const ModelOutput &net_outputs, uint64_t timestamp_eof,
float model_execution_time, kj::ArrayPtr raw_pred, const bool valid) {
const uint32_t frame_age = (frame_id > vipc_frame_id) ? (frame_id - vipc_frame_id) : 0;
MessageBuilder msg;
auto framed = msg.initEvent(valid).initModelV2();
framed.setFrameId(vipc_frame_id);
+ framed.setFrameIdExtra(vipc_frame_id_extra);
framed.setFrameAge(frame_age);
framed.setFrameDropPerc(frame_drop * 100);
framed.setTimestampEof(timestamp_eof);
diff --git a/selfdrive/modeld/models/driving.h b/selfdrive/modeld/models/driving.h
index eead06575f..f83cb86939 100644
--- a/selfdrive/modeld/models/driving.h
+++ b/selfdrive/modeld/models/driving.h
@@ -266,11 +266,11 @@ struct ModelState {
#endif
};
-void model_init(ModelState* s, cl_device_id device_id, cl_context context, bool use_extra);
+void model_init(ModelState* s, cl_device_id device_id, cl_context context);
ModelOutput *model_eval_frame(ModelState* s, VisionBuf* buf, VisionBuf* buf_wide,
const mat3 &transform, const mat3 &transform_wide, float *desire_in);
void model_free(ModelState* s);
-void model_publish(PubMaster &pm, uint32_t vipc_frame_id, uint32_t frame_id, float frame_drop,
+void model_publish(PubMaster &pm, uint32_t vipc_frame_id, uint32_t vipc_frame_id_extra, uint32_t frame_id, float frame_drop,
const ModelOutput &net_outputs, uint64_t timestamp_eof,
float model_execution_time, kj::ArrayPtr raw_pred, const bool valid);
void posenet_publish(PubMaster &pm, uint32_t vipc_frame_id, uint32_t vipc_dropped_frames,
diff --git a/selfdrive/modeld/runners/thneedmodel.cc b/selfdrive/modeld/runners/thneedmodel.cc
index a85b2ac022..edc091bda9 100644
--- a/selfdrive/modeld/runners/thneedmodel.cc
+++ b/selfdrive/modeld/runners/thneedmodel.cc
@@ -47,7 +47,7 @@ void* ThneedModel::getExtraBuf() {
void ThneedModel::execute() {
if (!recorded) {
- thneed->record = THNEED_RECORD;
+ thneed->record = true;
if (use_extra) {
float *inputs[5] = {recurrent, trafficConvention, desire, extra, input};
thneed->copy_inputs(inputs);
diff --git a/selfdrive/modeld/thneed/__init__.py b/selfdrive/modeld/thneed/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/selfdrive/modeld/thneed/compile.cc b/selfdrive/modeld/thneed/compile.cc
index 8e031b9ab6..c22156d2c9 100644
--- a/selfdrive/modeld/thneed/compile.cc
+++ b/selfdrive/modeld/thneed/compile.cc
@@ -13,7 +13,7 @@ int main(int argc, char* argv[]) {
#define OUTPUT_SIZE 0x10000
float *output = (float*)calloc(OUTPUT_SIZE, sizeof(float));
- SNPEModel mdl(argv[1], output, 0, USE_GPU_RUNTIME, USE_EXTRA);
+ SNPEModel mdl(argv[1], output, 0, USE_GPU_RUNTIME, true);
float state[TEMPORAL_SIZE] = {0};
float desire[DESIRE_LEN] = {0};
@@ -25,9 +25,7 @@ int main(int argc, char* argv[]) {
mdl.addDesire(desire, DESIRE_LEN);
mdl.addTrafficConvention(traffic_convention, TRAFFIC_CONVENTION_LEN);
mdl.addImage(input, 0);
- if (USE_EXTRA) {
- mdl.addExtra(extra, 0);
- }
+ mdl.addExtra(extra, 0);
// first run
printf("************** execute 1 **************\n");
@@ -37,6 +35,14 @@ int main(int argc, char* argv[]) {
// save model
bool save_binaries = (argc > 3) && (strcmp(argv[3], "--binary") == 0);
mdl.thneed->save(argv[2], save_binaries);
+
+ // test model
+ auto thneed = new Thneed(true);
+ thneed->record = false;
+ thneed->load(argv[2]);
+ thneed->clexec();
+ thneed->find_inputs_outputs();
+
return 0;
}
diff --git a/selfdrive/modeld/thneed/kernels/convolution_horizontal_reduced_reads.cl b/selfdrive/modeld/thneed/kernels/convolution_horizontal_reduced_reads.cl
index bc8add79aa..fcea88ce90 100644
--- a/selfdrive/modeld/thneed/kernels/convolution_horizontal_reduced_reads.cl
+++ b/selfdrive/modeld/thneed/kernels/convolution_horizontal_reduced_reads.cl
@@ -1,4 +1,3 @@
#define SUPPORT_DILATION
__kernel void convolution_horizontal_reduced_reads(
-#include "convolution_.cl"
diff --git a/selfdrive/modeld/thneed/kernels/convolution_horizontal_reduced_reads_1x1.cl b/selfdrive/modeld/thneed/kernels/convolution_horizontal_reduced_reads_1x1.cl
index 75a090ca22..0d15d80581 100644
--- a/selfdrive/modeld/thneed/kernels/convolution_horizontal_reduced_reads_1x1.cl
+++ b/selfdrive/modeld/thneed/kernels/convolution_horizontal_reduced_reads_1x1.cl
@@ -2,4 +2,3 @@
#define SUPPORT_ACCUMULATION
__kernel void convolution_horizontal_reduced_reads_1x1(
-#include "convolution_.cl"
diff --git a/selfdrive/modeld/thneed/kernels/convolution_horizontal_reduced_reads_5_outputs.cl b/selfdrive/modeld/thneed/kernels/convolution_horizontal_reduced_reads_5_outputs.cl
index 980e7d1f67..69421fc2a9 100644
--- a/selfdrive/modeld/thneed/kernels/convolution_horizontal_reduced_reads_5_outputs.cl
+++ b/selfdrive/modeld/thneed/kernels/convolution_horizontal_reduced_reads_5_outputs.cl
@@ -1,4 +1,3 @@
#define NUM_OUTPUTS 5
__kernel void convolution_horizontal_reduced_reads_5_outputs(
-#include "convolution_.cl"
diff --git a/selfdrive/modeld/thneed/kernels/convolution_horizontal_reduced_reads_depthwise.cl b/selfdrive/modeld/thneed/kernels/convolution_horizontal_reduced_reads_depthwise.cl
index 80be0da924..50e39941d4 100644
--- a/selfdrive/modeld/thneed/kernels/convolution_horizontal_reduced_reads_depthwise.cl
+++ b/selfdrive/modeld/thneed/kernels/convolution_horizontal_reduced_reads_depthwise.cl
@@ -2,4 +2,3 @@
#define SUPPORT_DILATION
__kernel void convolution_horizontal_reduced_reads_depthwise(
-#include "convolution_.cl"
diff --git a/selfdrive/modeld/thneed/kernels/convolution_horizontal_reduced_reads_depthwise_stride_1.cl b/selfdrive/modeld/thneed/kernels/convolution_horizontal_reduced_reads_depthwise_stride_1.cl
index 3d651c229b..b347cb6c71 100644
--- a/selfdrive/modeld/thneed/kernels/convolution_horizontal_reduced_reads_depthwise_stride_1.cl
+++ b/selfdrive/modeld/thneed/kernels/convolution_horizontal_reduced_reads_depthwise_stride_1.cl
@@ -1,4 +1,3 @@
#define DEPTHWISE
__kernel void convolution_horizontal_reduced_reads_depthwise_stride_1(
-#include "convolution_.cl"
diff --git a/selfdrive/modeld/thneed/lib.py b/selfdrive/modeld/thneed/lib.py
new file mode 100644
index 0000000000..dccdfb10ac
--- /dev/null
+++ b/selfdrive/modeld/thneed/lib.py
@@ -0,0 +1,31 @@
+import struct, json
+
+def load_thneed(fn):
+ with open(fn, "rb") as f:
+ json_len = struct.unpack("I", f.read(4))[0]
+ jdat = json.loads(f.read(json_len).decode('latin_1'))
+ weights = f.read()
+ ptr = 0
+ for o in jdat['objects']:
+ if o['needs_load']:
+ nptr = ptr + o['size']
+ o['data'] = weights[ptr:nptr]
+ ptr = nptr
+ for o in jdat['binaries']:
+ nptr = ptr + o['length']
+ o['data'] = weights[ptr:nptr]
+ ptr = nptr
+ return jdat
+
+def save_thneed(jdat, fn):
+ new_weights = []
+ for o in jdat['objects'] + jdat['binaries']:
+ if 'data' in o:
+ new_weights.append(o['data'])
+ del o['data']
+ new_weights = b''.join(new_weights)
+ with open(fn, "wb") as f:
+ j = json.dumps(jdat, ensure_ascii=False).encode('latin_1')
+ f.write(struct.pack("I", len(j)))
+ f.write(j)
+ f.write(new_weights)
diff --git a/selfdrive/modeld/thneed/optimizer.cc b/selfdrive/modeld/thneed/optimizer.cc
index 3c7c41873d..b516b5fa50 100644
--- a/selfdrive/modeld/thneed/optimizer.cc
+++ b/selfdrive/modeld/thneed/optimizer.cc
@@ -4,6 +4,9 @@
#include
#include "thneed.h"
+#include "selfdrive/common/util.h"
+#include "selfdrive/common/clutil.h"
+
extern map g_program_source;
static int is_same_size_image(cl_mem a, cl_mem b) {
@@ -63,6 +66,14 @@ static cl_mem make_image_like(cl_context context, cl_mem val) {
int Thneed::optimize() {
const char *kernel_path = getenv("KERNEL_PATH");
if (!kernel_path) { kernel_path = "/data/openpilot/selfdrive/modeld/thneed/kernels"; printf("no KERNEL_PATH set, defaulting to %s\n", kernel_path); }
+
+ string convolution_;
+ {
+ char fn[0x100];
+ snprintf(fn, sizeof(fn), "%s/%s.cl", kernel_path, "convolution_");
+ convolution_ = util::read_file(fn);
+ }
+
// load custom kernels
map g_programs;
for (auto &k : kq) {
@@ -70,33 +81,17 @@ int Thneed::optimize() {
if (g_programs.find(k->name) == g_programs.end()) {
char fn[0x100];
snprintf(fn, sizeof(fn), "%s/%s.cl", kernel_path, k->name.c_str());
- FILE *g = fopen(fn, "rb");
- if (g != NULL) {
- char *src[0x10000];
- const char *srcs[1]; srcs[0] = (const char *)src;
- memset(src, 0, sizeof(src));
- size_t length = fread(src, 1, sizeof(src), g);
- fclose(g);
-
- printf("building kernel %s\n", k->name.c_str());
- k->program = clCreateProgramWithSource(context, 1, srcs, &length, NULL);
- char options[0x100];
- snprintf(options, sizeof(options)-1, "-I %s", kernel_path);
- int err = clBuildProgram(k->program, 1, &device_id, options, NULL, NULL);
-
- if (err != 0) {
- printf("got err %d\n", err);
- size_t err_length;
- char buffer[2048];
- clGetProgramBuildInfo(k->program, device_id, CL_PROGRAM_BUILD_LOG, sizeof(buffer), buffer, &err_length);
- buffer[err_length] = '\0';
- printf("%s\n", buffer);
+ if (util::file_exists(fn)) {
+ string kernel_src = util::read_file(fn);
+ if (k->name.rfind("convolution_", 0) == 0) {
+ kernel_src += convolution_;
}
- assert(err == 0);
+ printf("building kernel %s with len %lu\n", k->name.c_str(), kernel_src.length());
+ k->program = cl_program_from_source(context, device_id, kernel_src);
// save in cache
g_programs[k->name] = k->program;
- g_program_source[k->program] = string((char *)src, length);
+ g_program_source[k->program] = kernel_src;
} else {
g_programs[k->name] = NULL;
}
diff --git a/selfdrive/modeld/thneed/serialize.cc b/selfdrive/modeld/thneed/serialize.cc
index cd5584553b..89b761b9d2 100644
--- a/selfdrive/modeld/thneed/serialize.cc
+++ b/selfdrive/modeld/thneed/serialize.cc
@@ -63,14 +63,14 @@ void Thneed::load(const char *filename) {
map g_programs;
for (const auto &[name, source] : jdat["programs"].object_items()) {
- if (record & THNEED_DEBUG) printf("building %s with size %zu\n", name.c_str(), source.string_value().size());
+ if (debug >= 1) printf("building %s with size %zu\n", name.c_str(), source.string_value().size());
g_programs[name] = cl_program_from_source(context, device_id, source.string_value());
}
for (auto &obj : jdat["binaries"].array_items()) {
string name = obj["name"].string_value();
size_t length = obj["length"].int_value();
- if (record & THNEED_DEBUG) printf("binary %s with size %zu\n", name.c_str(), length);
+ if (debug >= 1) printf("binary %s with size %zu\n", name.c_str(), length);
g_programs[name] = cl_program_from_binary(context, device_id, (const uint8_t*)&buf[ptr], length);
ptr += length;
}
diff --git a/selfdrive/modeld/thneed/thneed.cc b/selfdrive/modeld/thneed/thneed.cc
index 31bfa3e2f3..e2dc9b72f2 100644
--- a/selfdrive/modeld/thneed/thneed.cc
+++ b/selfdrive/modeld/thneed/thneed.cc
@@ -55,12 +55,12 @@ int ioctl(int filedes, unsigned long request, void *argp) {
if (thneed != NULL) {
if (request == IOCTL_KGSL_GPU_COMMAND) {
struct kgsl_gpu_command *cmd = (struct kgsl_gpu_command *)argp;
- if (thneed->record & THNEED_RECORD) {
+ if (thneed->record) {
thneed->timestamp = cmd->timestamp;
thneed->context_id = cmd->context_id;
thneed->cmds.push_back(unique_ptr(new CachedCommand(thneed, cmd)));
}
- if (thneed->record & THNEED_DEBUG) {
+ if (thneed->debug >= 1) {
printf("IOCTL_KGSL_GPU_COMMAND(%2zu): flags: 0x%lx context_id: %u timestamp: %u numcmds: %d numobjs: %d\n",
thneed->cmds.size(),
cmd->flags,
@@ -70,7 +70,7 @@ int ioctl(int filedes, unsigned long request, void *argp) {
struct kgsl_gpuobj_sync *cmd = (struct kgsl_gpuobj_sync *)argp;
struct kgsl_gpuobj_sync_obj *objs = (struct kgsl_gpuobj_sync_obj *)(cmd->objs);
- if (thneed->record & THNEED_DEBUG) {
+ if (thneed->debug >= 2) {
printf("IOCTL_KGSL_GPUOBJ_SYNC count:%d ", cmd->count);
for (int i = 0; i < cmd->count; i++) {
printf(" -- offset:0x%lx len:0x%lx id:%d op:%d ", objs[i].offset, objs[i].length, objs[i].id, objs[i].op);
@@ -78,21 +78,21 @@ int ioctl(int filedes, unsigned long request, void *argp) {
printf("\n");
}
- if (thneed->record & THNEED_RECORD) {
+ if (thneed->record) {
thneed->cmds.push_back(unique_ptr(new
CachedSync(thneed, string((char *)objs, sizeof(struct kgsl_gpuobj_sync_obj)*cmd->count))));
}
} else if (request == IOCTL_KGSL_DEVICE_WAITTIMESTAMP_CTXTID) {
struct kgsl_device_waittimestamp_ctxtid *cmd = (struct kgsl_device_waittimestamp_ctxtid *)argp;
- if (thneed->record & THNEED_DEBUG) {
+ if (thneed->debug >= 1) {
printf("IOCTL_KGSL_DEVICE_WAITTIMESTAMP_CTXTID: context_id: %d timestamp: %d timeout: %d\n",
cmd->context_id, cmd->timestamp, cmd->timeout);
}
} else if (request == IOCTL_KGSL_SETPROPERTY) {
- if (thneed->record & THNEED_DEBUG) {
+ if (thneed->debug >= 1) {
struct kgsl_device_getproperty *prop = (struct kgsl_device_getproperty *)argp;
printf("IOCTL_KGSL_SETPROPERTY: 0x%x sizebytes:%zu\n", prop->type, prop->sizebytes);
- if (thneed->record & THNEED_VERBOSE_DEBUG) {
+ if (thneed->debug >= 2) {
hexdump((uint8_t *)prop->value, prop->sizebytes);
if (prop->type == KGSL_PROP_PWR_CONSTRAINT) {
struct kgsl_device_constraint *constraint = (struct kgsl_device_constraint *)prop->value;
@@ -105,7 +105,7 @@ int ioctl(int filedes, unsigned long request, void *argp) {
} else if (request == IOCTL_KGSL_GPUOBJ_ALLOC || request == IOCTL_KGSL_GPUOBJ_FREE) {
// this happens
} else {
- if (thneed->record & THNEED_DEBUG) {
+ if (thneed->debug >= 1) {
printf("other ioctl %lx\n", request);
}
}
@@ -197,9 +197,9 @@ void CachedCommand::exec() {
cache.timestamp = ++thneed->timestamp;
int ret = ioctl(thneed->fd, IOCTL_KGSL_GPU_COMMAND, &cache);
- if (thneed->record & THNEED_DEBUG) printf("CachedCommand::exec got %d\n", ret);
+ if (thneed->debug >= 1) printf("CachedCommand::exec got %d\n", ret);
- if (thneed->record & THNEED_VERBOSE_DEBUG) {
+ if (thneed->debug >= 2) {
for (auto &it : kq) {
it->debug_print(false);
}
@@ -220,9 +220,11 @@ Thneed::Thneed(bool do_clinit) {
assert(g_fd != -1);
fd = g_fd;
ram = make_unique(0x80000, fd);
- record = THNEED_RECORD;
+ record = true;
timestamp = -1;
g_thneed = this;
+ char *thneed_debug_env = getenv("THNEED_DEBUG");
+ debug = (thneed_debug_env != NULL) ? atoi(thneed_debug_env) : 0;
}
void Thneed::stop() {
@@ -261,7 +263,7 @@ void Thneed::find_inputs_outputs() {
void Thneed::copy_inputs(float **finputs) {
//cl_int ret;
for (int idx = 0; idx < inputs.size(); ++idx) {
- if (record & THNEED_DEBUG) printf("copying %lu -- %p -> %p\n", input_sizes[idx], finputs[idx], inputs[idx]);
+ if (debug >= 1) printf("copying %lu -- %p -> %p\n", input_sizes[idx], finputs[idx], inputs[idx]);
if (finputs[idx] != NULL) memcpy(inputs[idx], finputs[idx], input_sizes[idx]);
}
}
@@ -270,7 +272,7 @@ void Thneed::copy_output(float *foutput) {
if (output != NULL) {
size_t sz;
clGetMemObjectInfo(output, CL_MEM_SIZE, sizeof(sz), &sz, NULL);
- if (record & THNEED_DEBUG) printf("copying %lu for output %p -> %p\n", sz, output, foutput);
+ if (debug >= 1) printf("copying %lu for output %p -> %p\n", sz, output, foutput);
clEnqueueReadBuffer(command_queue, output, CL_TRUE, 0, sz, foutput, 0, NULL, NULL);
} else {
printf("CAUTION: model output is NULL, does it have no outputs?\n");
@@ -287,12 +289,12 @@ void Thneed::wait() {
int wret = ioctl(fd, IOCTL_KGSL_DEVICE_WAITTIMESTAMP_CTXTID, &wait);
uint64_t te = nanos_since_boot();
- if (record & THNEED_DEBUG) printf("wait %d after %lu us\n", wret, (te-tb)/1000);
+ if (debug >= 1) printf("wait %d after %lu us\n", wret, (te-tb)/1000);
}
void Thneed::execute(float **finputs, float *foutput, bool slow) {
uint64_t tb, te;
- if (record & THNEED_DEBUG) tb = nanos_since_boot();
+ if (debug >= 1) tb = nanos_since_boot();
// ****** copy inputs
copy_inputs(finputs);
@@ -319,7 +321,7 @@ void Thneed::execute(float **finputs, float *foutput, bool slow) {
int i = 0;
for (auto &it : cmds) {
++i;
- if (record & THNEED_DEBUG) printf("run %2d @ %7lu us: ", i, (nanos_since_boot()-tb)/1000);
+ if (debug >= 1) printf("run %2d @ %7lu us: ", i, (nanos_since_boot()-tb)/1000);
it->exec();
if ((i == cmds.size()) || slow) wait();
}
@@ -335,7 +337,7 @@ void Thneed::execute(float **finputs, float *foutput, bool slow) {
ret = ioctl(fd, IOCTL_KGSL_SETPROPERTY, &prop);
assert(ret == 0);
- if (record & THNEED_DEBUG) {
+ if (debug >= 1) {
te = nanos_since_boot();
printf("model exec in %lu us\n", (te-tb)/1000);
}
@@ -353,7 +355,7 @@ void Thneed::clinit() {
cl_int Thneed::clexec() {
printf("Thneed::clexec: running %lu queued kernels\n", kq.size());
for (auto &k : kq) {
- if (record & THNEED_RECORD) ckq.push_back(k);
+ if (record) ckq.push_back(k);
cl_int ret = k->exec();
assert(ret == CL_SUCCESS);
}
@@ -391,7 +393,7 @@ cl_int thneed_clEnqueueNDRangeKernel(cl_command_queue command_queue,
assert(event_wait_list == NULL);
cl_int ret = 0;
- if (thneed != NULL && thneed->record & THNEED_RECORD) {
+ if (thneed != NULL && thneed->record) {
if (thneed->context == NULL) {
thneed->command_queue = command_queue;
clGetKernelInfo(kernel, CL_KERNEL_CONTEXT, sizeof(thneed->context), &thneed->context, NULL);
@@ -413,7 +415,7 @@ cl_int thneed_clEnqueueNDRangeKernel(cl_command_queue command_queue,
cl_int thneed_clFinish(cl_command_queue command_queue) {
Thneed *thneed = g_thneed;
- if (thneed != NULL && thneed->record & THNEED_RECORD) {
+ if (thneed != NULL && thneed->record) {
#ifdef RUN_OPTIMIZER
thneed->optimize();
#endif
@@ -520,8 +522,8 @@ cl_int CLQueuedKernel::exec() {
}
}
- if (thneed->record & THNEED_DEBUG) {
- debug_print(thneed->record & THNEED_VERBOSE_DEBUG);
+ if (thneed->debug >= 1) {
+ debug_print(thneed->debug >= 2);
}
return clEnqueueNDRangeKernel(thneed->command_queue,
diff --git a/selfdrive/modeld/thneed/thneed.h b/selfdrive/modeld/thneed/thneed.h
index 1197e4c5ed..b09d32b0ef 100644
--- a/selfdrive/modeld/thneed/thneed.h
+++ b/selfdrive/modeld/thneed/thneed.h
@@ -14,10 +14,6 @@
#include "selfdrive/modeld/thneed/include/msm_kgsl.h"
-#define THNEED_RECORD 1
-#define THNEED_DEBUG 2
-#define THNEED_VERBOSE_DEBUG 4
-
using namespace std;
namespace json11 {
@@ -110,7 +106,8 @@ class Thneed {
int context_id;
// protected?
- int record;
+ bool record;
+ int debug;
int timestamp;
unique_ptr ram;
vector > cmds;
diff --git a/selfdrive/modeld/thneed/weights_fixup.py b/selfdrive/modeld/thneed/weights_fixup.py
new file mode 100755
index 0000000000..47875a9ee0
--- /dev/null
+++ b/selfdrive/modeld/thneed/weights_fixup.py
@@ -0,0 +1,145 @@
+#!/usr/bin/env python3
+import os
+import struct
+import zipfile
+import numpy as np
+from tqdm import tqdm
+
+from common.basedir import BASEDIR
+from selfdrive.modeld.thneed.lib import load_thneed, save_thneed
+
+# this is junk code, but it doesn't have deps
+def load_dlc_weights(fn):
+ archive = zipfile.ZipFile(fn, 'r')
+ dlc_params = archive.read("model.params")
+
+ def extract(rdat):
+ idx = rdat.find(b"\x00\x00\x00\x09\x04\x00\x00\x00")
+ rdat = rdat[idx+8:]
+ ll = struct.unpack("I", rdat[0:4])[0]
+ buf = np.frombuffer(rdat[4:4+ll*4], dtype=np.float32)
+ rdat = rdat[4+ll*4:]
+ dims = struct.unpack("I", rdat[0:4])[0]
+ buf = buf.reshape(struct.unpack("I"*dims, rdat[4:4+dims*4]))
+ if len(buf.shape) == 4:
+ buf = np.transpose(buf, (3,2,0,1))
+ return buf
+
+ def parse(tdat):
+ ll = struct.unpack("I", tdat[0:4])[0] + 4
+ return (None, [extract(tdat[0:]), extract(tdat[ll:])])
+
+ ptr = 0x20
+ def r4():
+ nonlocal ptr
+ ret = struct.unpack("I", dlc_params[ptr:ptr+4])[0]
+ ptr += 4
+ return ret
+ ranges = []
+ cnt = r4()
+ for _ in range(cnt):
+ o = r4() + ptr
+ # the header is 0xC
+ plen, is_4, is_2 = struct.unpack("III", dlc_params[o:o+0xC])
+ assert is_4 == 4 and is_2 == 2
+ ranges.append((o+0xC, o+plen+0xC))
+ ranges = sorted(ranges, reverse=True)
+
+ return [parse(dlc_params[s:e]) for s,e in ranges]
+
+# this won't run on device without onnx
+def load_onnx_weights(fn):
+ import onnx
+ from onnx import numpy_helper
+
+ model = onnx.load(fn)
+ graph = model.graph # pylint: disable=maybe-no-member
+ init = {x.name:x for x in graph.initializer}
+
+ onnx_layers = []
+ for node in graph.node:
+ #print(node.name, node.op_type, node.input, node.output)
+ vals = []
+ for inp in node.input:
+ if inp in init:
+ vals.append(numpy_helper.to_array(init[inp]))
+ if len(vals) > 0:
+ onnx_layers.append((node.name, vals))
+ return onnx_layers
+
+def weights_fixup(target, source_thneed, dlc):
+ #onnx_layers = load_onnx_weights(os.path.join(BASEDIR, "models/supercombo.onnx"))
+ onnx_layers = load_dlc_weights(dlc)
+ jdat = load_thneed(source_thneed)
+
+ bufs = {}
+ for o in jdat['objects']:
+ bufs[o['id']] = o
+
+ thneed_layers = []
+ for k in jdat['kernels']:
+ #print(k['name'])
+ vals = []
+ for a in k['args']:
+ if a in bufs:
+ o = bufs[a]
+ if o['needs_load'] or ('buffer_id' in o and bufs[o['buffer_id']]['needs_load']):
+ #print(" ", o['arg_type'])
+ vals.append(o)
+ if len(vals) > 0:
+ thneed_layers.append((k['name'], vals))
+
+ assert len(thneed_layers) == len(onnx_layers)
+
+ # fix up weights
+ for tl, ol in tqdm(zip(thneed_layers, onnx_layers), total=len(thneed_layers)):
+ #print(tl[0], ol[0])
+ assert len(tl[1]) == len(ol[1])
+ for o, onnx_weight in zip(tl[1], ol[1]):
+ if o['arg_type'] == "image2d_t":
+ obuf = bufs[o['buffer_id']]
+ saved_weights = np.frombuffer(obuf['data'], dtype=np.float16).reshape(o['height'], o['row_pitch']//2)
+
+ if len(onnx_weight.shape) == 4:
+ # convolution
+ oc,ic,ch,cw = onnx_weight.shape
+
+ if 'depthwise' in tl[0]:
+ assert ic == 1
+ weights = np.transpose(onnx_weight.reshape(oc//4,4,ch,cw), (0,2,3,1)).reshape(o['height'], o['width']*4)
+ else:
+ weights = np.transpose(onnx_weight.reshape(oc//4,4,ic//4,4,ch,cw), (0,4,2,5,1,3)).reshape(o['height'], o['width']*4)
+ else:
+ # fc_Wtx
+ weights = onnx_weight
+
+ new_weights = np.zeros((o['height'], o['row_pitch']//2), dtype=np.float32)
+ new_weights[:, :weights.shape[1]] = weights
+
+ # weights shouldn't be too far off
+ err = np.mean((saved_weights.astype(np.float32) - new_weights)**2)
+ assert err < 1e-3
+ rerr = np.mean(np.abs((saved_weights.astype(np.float32) - new_weights)/(new_weights+1e-12)))
+ assert rerr < 0.5
+
+ # fix should improve things
+ fixed_err = np.mean((new_weights.astype(np.float16).astype(np.float32) - new_weights)**2)
+ assert (err/fixed_err) >= 1
+
+ #print(" ", o['size'], onnx_weight.shape, o['row_pitch'], o['width'], o['height'], "err %.2fx better" % (err/fixed_err))
+
+ obuf['data'] = new_weights.astype(np.float16).tobytes()
+
+ elif o['arg_type'] == "float*":
+ # unconverted floats are correct
+ new_weights = np.zeros(o['size']//4, dtype=np.float32)
+ new_weights[:onnx_weight.shape[0]] = onnx_weight
+ assert new_weights.tobytes() == o['data']
+ #print(" ", o['size'], onnx_weight.shape)
+
+ save_thneed(jdat, target)
+
+if __name__ == "__main__":
+ weights_fixup(os.path.join(BASEDIR, "models/supercombo_fixed.thneed"),
+ os.path.join(BASEDIR, "models/supercombo.thneed"),
+ os.path.join(BASEDIR, "models/supercombo.dlc"))
diff --git a/selfdrive/monitoring/driver_monitor.py b/selfdrive/monitoring/driver_monitor.py
index efb00ecb77..2e317aefbd 100644
--- a/selfdrive/monitoring/driver_monitor.py
+++ b/selfdrive/monitoring/driver_monitor.py
@@ -18,8 +18,9 @@ EventName = car.CarEvent.EventName
class DRIVER_MONITOR_SETTINGS():
def __init__(self, TICI=TICI, DT_DMON=DT_DMON):
self._DT_DMON = DT_DMON
- self._AWARENESS_TIME = 35. # passive wheeltouch total timeout
- self._AWARENESS_PRE_TIME_TILL_TERMINAL = 12.
+ # ref (page15-16): https://eur-lex.europa.eu/legal-content/EN/TXT/PDF/?uri=CELEX:42018X1947&rid=2
+ self._AWARENESS_TIME = 30. # passive wheeltouch total timeout
+ self._AWARENESS_PRE_TIME_TILL_TERMINAL = 15.
self._AWARENESS_PROMPT_TIME_TILL_TERMINAL = 6.
self._DISTRACTED_TIME = 11. # active monitoring total timeout
self._DISTRACTED_PRE_TIME_TILL_TERMINAL = 8.
diff --git a/selfdrive/test/longitudinal_maneuvers/test_longitudinal.py b/selfdrive/test/longitudinal_maneuvers/test_longitudinal.py
index 60aaeb724d..698877dd3a 100755
--- a/selfdrive/test/longitudinal_maneuvers/test_longitudinal.py
+++ b/selfdrive/test/longitudinal_maneuvers/test_longitudinal.py
@@ -9,7 +9,7 @@ from selfdrive.test.longitudinal_maneuvers.maneuver import Maneuver
# TODO: make new FCW tests
maneuvers = [
Maneuver(
- 'approach stopped car at 20m/s',
+ 'approach stopped car at 20m/s, initial distance: 120m',
duration=20.,
initial_speed=25.,
lead_relevancy=True,
@@ -18,7 +18,7 @@ maneuvers = [
breakpoints=[0., 1.],
),
Maneuver(
- 'approach stopped car at 20m/s',
+ 'approach stopped car at 20m/s, initial distance 90m',
duration=20.,
initial_speed=20.,
lead_relevancy=True,
@@ -65,7 +65,7 @@ maneuvers = [
breakpoints=[2., 2.01, 8.8],
),
Maneuver(
- "approach stopped car at 20m/s",
+ "approach stopped car at 20m/s, with prob_lead_values",
duration=30.,
initial_speed=20.,
lead_relevancy=True,
diff --git a/selfdrive/test/process_replay/model_replay_ref_commit b/selfdrive/test/process_replay/model_replay_ref_commit
index d210251c09..a875d709c2 100644
--- a/selfdrive/test/process_replay/model_replay_ref_commit
+++ b/selfdrive/test/process_replay/model_replay_ref_commit
@@ -1 +1 @@
-19720e79b1c5136a882efd689651d9044e2e2007
+710313545a2b5e0899c6ee0b99ecd9d322cfecb7
diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit
index 9982949b20..3226b8614b 100644
--- a/selfdrive/test/process_replay/ref_commit
+++ b/selfdrive/test/process_replay/ref_commit
@@ -1 +1 @@
-67c8f283858998b75ac28879e1350a589a968e5d
\ No newline at end of file
+37aa2e3afedc8364d2bbecc5f1b7ed4efec52e30
\ No newline at end of file
diff --git a/selfdrive/test/process_replay/regen.py b/selfdrive/test/process_replay/regen.py
index 16ee5e9a28..e2493d048f 100755
--- a/selfdrive/test/process_replay/regen.py
+++ b/selfdrive/test/process_replay/regen.py
@@ -159,7 +159,7 @@ def replay_cameras(lr, frs):
args=(s, stream, dt, vs, frames, size)))
# hack to make UI work
- vs.create_buffers(VisionStreamType.VISION_STREAM_RGB_BACK, 4, True, eon_f_frame_size[0], eon_f_frame_size[1])
+ vs.create_buffers(VisionStreamType.VISION_STREAM_RGB_ROAD, 4, True, eon_f_frame_size[0], eon_f_frame_size[1])
vs.start_listener()
return vs, p
diff --git a/selfdrive/test/setup_device_ci.sh b/selfdrive/test/setup_device_ci.sh
index 260a1b4487..f2f76299f2 100755
--- a/selfdrive/test/setup_device_ci.sh
+++ b/selfdrive/test/setup_device_ci.sh
@@ -20,28 +20,47 @@ fi
umount /data/safe_staging/merged/ || true
sudo umount /data/safe_staging/merged/ || true
+export KEYS_PARAM_PATH="/data/params/d/GithubSshKeys"
if [ -f "/EON" ]; then
+ export KEYS_PATH="/data/data/com.termux/files/home/setup_keys"
+ export CONTINUE_PATH="/data/data/com.termux/files/continue.sh"
+
+ if ! grep -F "$KEYS_PATH" /usr/etc/ssh/sshd_config; then
+ echo "setting up keys"
+ mount -o rw,remount /system
+ sed -i "s,$KEYS_PARAM_PATH,$KEYS_PATH," /usr/etc/ssh/sshd_config
+ mount -o ro,remount /system
+ fi
+
+ # these can get pretty big
rm -rf /data/core
rm -rf /data/neoupdate
rm -rf /data/safe_staging
-fi
+else
+ export KEYS_PATH="/usr/comma/setup_keys"
+ export CONTINUE_PATH="/data/continue.sh"
-export KEYS_PATH="/usr/comma/setup_keys"
-export CONTINUE_PATH="/data/continue.sh"
-if [ -f "/EON" ]; then
- export KEYS_PATH="/data/data/com.termux/files/home/setup_keys"
- export CONTINUE_PATH="/data/data/com.termux/files/continue.sh"
+ if ! grep -F "$KEYS_PATH" /etc/ssh/sshd_config; then
+ echo "setting up keys"
+ sudo mount -o rw,remount /
+ sudo systemctl enable ssh
+ sudo sed -i "s,$KEYS_PARAM_PATH,$KEYS_PATH," /etc/ssh/sshd_config
+ sudo mount -o ro,remount /
+ fi
fi
+
tee $CONTINUE_PATH << EOF
#!/usr/bin/bash
-PARAMS_ROOT="/data/params/d"
-
while true; do
- mkdir -p \$PARAMS_ROOT
- cp $KEYS_PATH \$PARAMS_ROOT/GithubSshKeys
- echo -n 1 > \$PARAMS_ROOT/SshEnabled
- sleep 1m
+ if [ -f /EON ]; then
+ setprop persist.neos.ssh 1
+ else
+ if ! sudo systemctl is-active -q ssh; then
+ sudo systemctl start ssh
+ fi
+ fi
+ sleep 10s
done
sleep infinity
diff --git a/selfdrive/test/test_onroad.py b/selfdrive/test/test_onroad.py
index a49f93e37d..80a381d3fc 100755
--- a/selfdrive/test/test_onroad.py
+++ b/selfdrive/test/test_onroad.py
@@ -216,8 +216,9 @@ class TestOnroad(unittest.TestCase):
ts = [getattr(getattr(m, s), "solverExecutionTime") for m in self.lr if m.which() == s]
self.assertLess(min(ts), instant_max, f"high '{s}' execution time: {min(ts)}")
self.assertLess(np.mean(ts), avg_max, f"high avg '{s}' execution time: {np.mean(ts)}")
- result += f"'{s}' execution time: {min(ts)}\n"
- result += f"'{s}' avg execution time: {np.mean(ts)}\n"
+ result += f"'{s}' execution time: min {min(ts):.5f}s\n"
+ result += f"'{s}' execution time: max {max(ts):.5f}s\n"
+ result += f"'{s}' execution time: mean {np.mean(ts):.5f}s\n"
result += "------------------------------------------------\n"
print(result)
@@ -237,8 +238,8 @@ class TestOnroad(unittest.TestCase):
ts = [getattr(getattr(m, s), "modelExecutionTime") for m in self.lr if m.which() == s]
self.assertLess(min(ts), instant_max, f"high '{s}' execution time: {min(ts)}")
self.assertLess(np.mean(ts), avg_max, f"high avg '{s}' execution time: {np.mean(ts)}")
- result += f"'{s}' execution time: {min(ts)}\n"
- result += f"'{s}' avg execution time: {np.mean(ts)}\n"
+ result += f"'{s}' execution time: min {min(ts):.5f}s\n"
+ result += f"'{s}' execution time: mean {np.mean(ts):.5f}s\n"
result += "------------------------------------------------\n"
print(result)
diff --git a/selfdrive/test/update_ci_routes.py b/selfdrive/test/update_ci_routes.py
index 3a392b4b36..fe6d815ebf 100755
--- a/selfdrive/test/update_ci_routes.py
+++ b/selfdrive/test/update_ci_routes.py
@@ -3,7 +3,7 @@ import sys
import subprocess
from azure.storage.blob import BlockBlobService # pylint: disable=import-error
-from selfdrive.test.test_routes import routes as test_car_models_routes
+from selfdrive.car.tests.routes import routes as test_car_models_routes
from selfdrive.test.process_replay.test_processes import original_segments as replay_segments
from xx.chffr.lib import azureutil # pylint: disable=import-error
from xx.chffr.lib.storage import _DATA_ACCOUNT_PRODUCTION, _DATA_ACCOUNT_CI, _DATA_BUCKET_PRODUCTION # pylint: disable=import-error
diff --git a/selfdrive/thermald/fan_controller.py b/selfdrive/thermald/fan_controller.py
new file mode 100644
index 0000000000..2fe52d0cb8
--- /dev/null
+++ b/selfdrive/thermald/fan_controller.py
@@ -0,0 +1,103 @@
+#!/usr/bin/env python3
+
+import os
+from smbus2 import SMBus
+from abc import ABC, abstractmethod
+from common.realtime import DT_TRML
+from common.numpy_fast import interp
+from selfdrive.swaglog import cloudlog
+from selfdrive.controls.lib.pid import PIController
+
+class BaseFanController(ABC):
+ @abstractmethod
+ def update(self, max_cpu_temp: float, ignition: bool) -> int:
+ pass
+
+
+class EonFanController(BaseFanController):
+ # Temp thresholds to control fan speed - high hysteresis
+ TEMP_THRS_H = [50., 65., 80., 10000]
+ # Temp thresholds to control fan speed - low hysteresis
+ TEMP_THRS_L = [42.5, 57.5, 72.5, 10000]
+ # Fan speed options
+ FAN_SPEEDS = [0, 16384, 32768, 65535]
+
+ def __init__(self) -> None:
+ super().__init__()
+ cloudlog.info("Setting up EON fan handler")
+
+ self.fan_speed = -1
+ self.setup_eon_fan()
+
+ def setup_eon_fan(self) -> None:
+ os.system("echo 2 > /sys/module/dwc3_msm/parameters/otg_switch")
+
+ def set_eon_fan(self, speed: int) -> None:
+ if self.fan_speed != speed:
+ # FIXME: this is such an ugly hack to get the right index
+ val = speed // 16384
+
+ bus = SMBus(7, force=True)
+ try:
+ i = [0x1, 0x3 | 0, 0x3 | 0x08, 0x3 | 0x10][val]
+ bus.write_i2c_block_data(0x3d, 0, [i])
+ except OSError:
+ # tusb320
+ if val == 0:
+ bus.write_i2c_block_data(0x67, 0xa, [0])
+ else:
+ bus.write_i2c_block_data(0x67, 0xa, [0x20])
+ bus.write_i2c_block_data(0x67, 0x8, [(val - 1) << 6])
+ bus.close()
+ self.fan_speed = speed
+
+ def update(self, max_cpu_temp: float, ignition: bool) -> int:
+ new_speed_h = next(speed for speed, temp_h in zip(self.FAN_SPEEDS, self.TEMP_THRS_H) if temp_h > max_cpu_temp)
+ new_speed_l = next(speed for speed, temp_l in zip(self.FAN_SPEEDS, self.TEMP_THRS_L) if temp_l > max_cpu_temp)
+
+ if new_speed_h > self.fan_speed:
+ self.set_eon_fan(new_speed_h)
+ elif new_speed_l < self.fan_speed:
+ self.set_eon_fan(new_speed_l)
+
+ return self.fan_speed
+
+
+class UnoFanController(BaseFanController):
+ def __init__(self) -> None:
+ super().__init__()
+ cloudlog.info("Setting up UNO fan handler")
+
+ def update(self, max_cpu_temp: float, ignition: bool) -> int:
+ new_speed = int(interp(max_cpu_temp, [40.0, 80.0], [0, 80]))
+
+ if not ignition:
+ new_speed = min(30, new_speed)
+
+ return new_speed
+
+
+class TiciFanController(BaseFanController):
+ def __init__(self) -> None:
+ super().__init__()
+ cloudlog.info("Setting up TICI fan handler")
+
+ self.last_ignition = False
+ self.controller = PIController(k_p=0, k_i=2e-3, k_f=1, neg_limit=-80, pos_limit=0, rate=(1 / DT_TRML))
+
+ def update(self, max_cpu_temp: float, ignition: bool) -> int:
+ self.controller.neg_limit = -(80 if ignition else 30)
+ self.controller.pos_limit = -(30 if ignition else 0)
+
+ if ignition != self.last_ignition:
+ self.controller.reset()
+
+ fan_pwr_out = -int(self.controller.update(
+ setpoint=75,
+ measurement=max_cpu_temp,
+ feedforward=interp(max_cpu_temp, [60.0, 100.0], [0, -80])
+ ))
+
+ self.last_ignition = ignition
+ return fan_pwr_out
+
diff --git a/selfdrive/thermald/tests/test_fan_controller.py b/selfdrive/thermald/tests/test_fan_controller.py
new file mode 100755
index 0000000000..8865b1f98b
--- /dev/null
+++ b/selfdrive/thermald/tests/test_fan_controller.py
@@ -0,0 +1,58 @@
+#!/usr/bin/env python3
+import unittest
+from unittest.mock import Mock, MagicMock, patch
+from parameterized import parameterized
+
+with patch("smbus2.SMBus", new=MagicMock()):
+ from selfdrive.thermald.fan_controller import EonFanController, UnoFanController, TiciFanController
+
+ALL_CONTROLLERS = [(EonFanController, ), (UnoFanController,), (TiciFanController,)]
+GEN2_CONTROLLERS = [(UnoFanController,), (TiciFanController,)]
+
+def patched_controller(controller_class):
+ with patch("os.system", new=Mock()):
+ return controller_class()
+
+class TestFanController(unittest.TestCase):
+ def wind_up(self, controller, ignition=True):
+ for _ in range(1000):
+ controller.update(max_cpu_temp=100, ignition=ignition)
+
+ def wind_down(self, controller, ignition=False):
+ for _ in range(1000):
+ controller.update(max_cpu_temp=10, ignition=ignition)
+
+ @parameterized.expand(ALL_CONTROLLERS)
+ def test_hot_onroad(self, controller_class):
+ controller = patched_controller(controller_class)
+ self.wind_up(controller)
+ self.assertGreaterEqual(controller.update(max_cpu_temp=100, ignition=True), 70)
+
+ @parameterized.expand(GEN2_CONTROLLERS)
+ def test_offroad_limits(self, controller_class):
+ controller = patched_controller(controller_class)
+ self.wind_up(controller)
+ self.assertLessEqual(controller.update(max_cpu_temp=100, ignition=False), 30)
+
+ @parameterized.expand(ALL_CONTROLLERS)
+ def test_no_fan_wear(self, controller_class):
+ controller = patched_controller(controller_class)
+ self.wind_down(controller)
+ self.assertEqual(controller.update(max_cpu_temp=10, ignition=False), 0)
+
+ @parameterized.expand(GEN2_CONTROLLERS)
+ def test_limited(self, controller_class):
+ controller = patched_controller(controller_class)
+ self.wind_up(controller, ignition=True)
+ self.assertGreaterEqual(controller.update(max_cpu_temp=100, ignition=True), 80)
+
+ @parameterized.expand(ALL_CONTROLLERS)
+ def test_windup_speed(self, controller_class):
+ controller = patched_controller(controller_class)
+ self.wind_down(controller, ignition=True)
+ for _ in range(10):
+ controller.update(max_cpu_temp=90, ignition=True)
+ self.assertGreaterEqual(controller.update(max_cpu_temp=90, ignition=True), 60)
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/selfdrive/thermald/thermald.py b/selfdrive/thermald/thermald.py
index 113ffaa04c..1f62738ed7 100755
--- a/selfdrive/thermald/thermald.py
+++ b/selfdrive/thermald/thermald.py
@@ -9,22 +9,20 @@ from pathlib import Path
from typing import Dict, Optional, Tuple
import psutil
-from smbus2 import SMBus
import cereal.messaging as messaging
from cereal import log
from common.dict_helpers import strip_deprecated_keys
from common.filter_simple import FirstOrderFilter
-from common.numpy_fast import interp
from common.params import Params
from common.realtime import DT_TRML, sec_since_boot
from selfdrive.controls.lib.alertmanager import set_offroad_alert
-from selfdrive.controls.lib.pid import PIController
from selfdrive.hardware import EON, HARDWARE, PC, TICI
from selfdrive.loggerd.config import get_available_percent
from selfdrive.statsd import statlog
from selfdrive.swaglog import cloudlog
from selfdrive.thermald.power_monitoring import PowerMonitoring
+from selfdrive.thermald.fan_controller import EonFanController, UnoFanController, TiciFanController
from selfdrive.version import terms_version, training_version
ThermalStatus = log.DeviceState.ThermalStatus
@@ -36,7 +34,7 @@ DISCONNECT_TIMEOUT = 5. # wait 5 seconds before going offroad after disconnect
PANDA_STATES_TIMEOUT = int(1000 * 2.5 * DT_TRML) # 2.5x the expected pandaState frequency
ThermalBand = namedtuple("ThermalBand", ['min_temp', 'max_temp'])
-HardwareState = namedtuple("HardwareState", ['network_type', 'network_strength', 'network_info', 'nvme_temps', 'modem_temps'])
+HardwareState = namedtuple("HardwareState", ['network_type', 'network_metered', 'network_strength', 'network_info', 'nvme_temps', 'modem_temps'])
# List of thermal bands. We will stay within this region as long as we are within the bounds.
# When exiting the bounds, we'll jump to the lower or higher band. Bands are ordered in the dict.
@@ -52,10 +50,25 @@ OFFROAD_DANGER_TEMP = 79.5 if TICI else 70.0
prev_offroad_states: Dict[str, Tuple[bool, Optional[str]]] = {}
+tz_by_type: Optional[Dict[str, int]] = None
+def populate_tz_by_type():
+ global tz_by_type
+ tz_by_type = {}
+ for n in os.listdir("/sys/devices/virtual/thermal"):
+ if not n.startswith("thermal_zone"):
+ continue
+ with open(os.path.join("/sys/devices/virtual/thermal", n, "type")) as f:
+ tz_by_type[f.read().strip()] = int(n.lstrip("thermal_zone"))
+
def read_tz(x):
if x is None:
return 0
+ if isinstance(x, str):
+ if tz_by_type is None:
+ populate_tz_by_type()
+ x = tz_by_type[x]
+
try:
with open(f"/sys/devices/virtual/thermal/thermal_zone{x}/temp") as f:
return int(f.read())
@@ -73,83 +86,6 @@ def read_thermal(thermal_config):
return dat
-def setup_eon_fan():
- os.system("echo 2 > /sys/module/dwc3_msm/parameters/otg_switch")
-
-
-last_eon_fan_val = None
-def set_eon_fan(val):
- global last_eon_fan_val
-
- if last_eon_fan_val is None or last_eon_fan_val != val:
- bus = SMBus(7, force=True)
- try:
- i = [0x1, 0x3 | 0, 0x3 | 0x08, 0x3 | 0x10][val]
- bus.write_i2c_block_data(0x3d, 0, [i])
- except OSError:
- # tusb320
- if val == 0:
- bus.write_i2c_block_data(0x67, 0xa, [0])
- else:
- bus.write_i2c_block_data(0x67, 0xa, [0x20])
- bus.write_i2c_block_data(0x67, 0x8, [(val - 1) << 6])
- bus.close()
- last_eon_fan_val = val
-
-
-# temp thresholds to control fan speed - high hysteresis
-_TEMP_THRS_H = [50., 65., 80., 10000]
-# temp thresholds to control fan speed - low hysteresis
-_TEMP_THRS_L = [42.5, 57.5, 72.5, 10000]
-# fan speed options
-_FAN_SPEEDS = [0, 16384, 32768, 65535]
-
-
-def handle_fan_eon(controller, max_cpu_temp, fan_speed, ignition):
- new_speed_h = next(speed for speed, temp_h in zip(_FAN_SPEEDS, _TEMP_THRS_H) if temp_h > max_cpu_temp)
- new_speed_l = next(speed for speed, temp_l in zip(_FAN_SPEEDS, _TEMP_THRS_L) if temp_l > max_cpu_temp)
-
- if new_speed_h > fan_speed:
- # update speed if using the high thresholds results in fan speed increment
- fan_speed = new_speed_h
- elif new_speed_l < fan_speed:
- # update speed if using the low thresholds results in fan speed decrement
- fan_speed = new_speed_l
-
- set_eon_fan(fan_speed // 16384)
-
- return fan_speed
-
-
-def handle_fan_uno(controller, max_cpu_temp, fan_speed, ignition):
- new_speed = int(interp(max_cpu_temp, [40.0, 80.0], [0, 80]))
-
- if not ignition:
- new_speed = min(30, new_speed)
-
- return new_speed
-
-
-last_ignition = False
-def handle_fan_tici(controller, max_cpu_temp, fan_speed, ignition):
- global last_ignition
-
- controller.neg_limit = -(80 if ignition else 30)
- controller.pos_limit = -(30 if ignition else 0)
-
- if ignition != last_ignition:
- controller.reset()
-
- fan_pwr_out = -int(controller.update(
- setpoint=75,
- measurement=max_cpu_temp,
- feedforward=interp(max_cpu_temp, [60.0, 100.0], [0, -80])
- ))
-
- last_ignition = ignition
- return fan_pwr_out
-
-
def set_offroad_alert_if_changed(offroad_alert: str, show_alert: bool, extra_text: Optional[str]=None):
if prev_offroad_states.get(offroad_alert, None) == (show_alert, extra_text):
return
@@ -161,19 +97,24 @@ def hw_state_thread(end_event, hw_queue):
"""Handles non critical hardware state, and sends over queue"""
count = 0
registered_count = 0
+ prev_hw_state = None
while not end_event.is_set():
# these are expensive calls. update every 10s
if (count % int(10. / DT_TRML)) == 0:
try:
network_type = HARDWARE.get_network_type()
+ modem_temps = HARDWARE.get_modem_temperatures()
+ if len(modem_temps) == 0 and prev_hw_state is not None:
+ modem_temps = prev_hw_state.modem_temps
hw_state = HardwareState(
network_type=network_type,
+ network_metered=HARDWARE.get_network_metered(network_type),
network_strength=HARDWARE.get_network_strength(network_type),
network_info=HARDWARE.get_network_info(),
nvme_temps=HARDWARE.get_nvme_temperatures(),
- modem_temps=HARDWARE.get_modem_temperatures(),
+ modem_temps=modem_temps,
)
try:
@@ -191,8 +132,9 @@ def hw_state_thread(end_event, hw_queue):
os.system("nmcli conn up lte")
registered_count = 0
+ prev_hw_state = hw_state
except Exception:
- cloudlog.exception("Error getting network status")
+ cloudlog.exception("Error getting hardware state")
count += 1
time.sleep(DT_TRML)
@@ -202,7 +144,6 @@ def thermald_thread(end_event, hw_queue):
pm = messaging.PubMaster(['deviceState'])
sm = messaging.SubMaster(["peripheralState", "gpsLocationExternal", "controlsState", "pandaStates"], poll=["pandaStates"])
- fan_speed = 0
count = 0
onroad_conditions: Dict[str, bool] = {
@@ -219,6 +160,7 @@ def thermald_thread(end_event, hw_queue):
last_hw_state = HardwareState(
network_type=NetworkType.none,
+ network_metered=False,
network_strength=NetworkStrength.unknown,
network_info=None,
nvme_temps=[],
@@ -229,7 +171,6 @@ def thermald_thread(end_event, hw_queue):
temp_filter = FirstOrderFilter(0., TEMP_TAU, DT_TRML)
should_start_prev = False
in_car = False
- handle_fan = None
is_uno = False
engaged_prev = False
@@ -239,8 +180,7 @@ def thermald_thread(end_event, hw_queue):
HARDWARE.initialize_hardware()
thermal_config = HARDWARE.get_thermal_config()
- # TODO: use PI controller for UNO
- controller = PIController(k_p=0, k_i=2e-3, neg_limit=-80, pos_limit=0, rate=(1 / DT_TRML))
+ fan_controller = None
while not end_event.is_set():
sm.update(PANDA_STATES_TIMEOUT)
@@ -261,19 +201,15 @@ def thermald_thread(end_event, hw_queue):
usb_power = peripheralState.usbPowerMode != log.PeripheralState.UsbPowerMode.client
# Setup fan handler on first connect to panda
- if handle_fan is None and peripheralState.pandaType != log.PandaState.PandaType.unknown:
+ if fan_controller is None and peripheralState.pandaType != log.PandaState.PandaType.unknown:
is_uno = peripheralState.pandaType == log.PandaState.PandaType.uno
if TICI:
- cloudlog.info("Setting up TICI fan handler")
- handle_fan = handle_fan_tici
+ fan_controller = TiciFanController()
elif is_uno or PC:
- cloudlog.info("Setting up UNO fan handler")
- handle_fan = handle_fan_uno
+ fan_controller = UnoFanController()
else:
- cloudlog.info("Setting up EON fan handler")
- setup_eon_fan()
- handle_fan = handle_fan_eon
+ fan_controller = EonFanController()
try:
last_hw_state = hw_queue.get_nowait()
@@ -286,6 +222,7 @@ def thermald_thread(end_event, hw_queue):
msg.deviceState.gpuUsagePercent = int(round(HARDWARE.get_gpu_usage_percent()))
msg.deviceState.networkType = last_hw_state.network_type
+ msg.deviceState.networkMetered = last_hw_state.network_metered
msg.deviceState.networkStrength = last_hw_state.network_strength
if last_hw_state.network_info is not None:
msg.deviceState.networkInfo = last_hw_state.network_info
@@ -303,9 +240,8 @@ def thermald_thread(end_event, hw_queue):
max(max(msg.deviceState.cpuTempC), msg.deviceState.memoryTempC, max(msg.deviceState.gpuTempC))
)
- if handle_fan is not None:
- fan_speed = handle_fan(controller, max_comp_temp, fan_speed, onroad_conditions["ignition"])
- msg.deviceState.fanSpeedPercentDesired = fan_speed
+ if fan_controller is not None:
+ msg.deviceState.fanSpeedPercentDesired = fan_controller.update(max_comp_temp, onroad_conditions["ignition"])
is_offroad_for_5_min = (started_ts is None) and ((not started_seen) or (off_ts is None) or (sec_since_boot() - off_ts > 60 * 5))
if is_offroad_for_5_min and max_comp_temp > OFFROAD_DANGER_TEMP:
diff --git a/selfdrive/ui/installer/installer.cc b/selfdrive/ui/installer/installer.cc
index 6ee6e99e09..5366a0eac6 100644
--- a/selfdrive/ui/installer/installer.cc
+++ b/selfdrive/ui/installer/installer.cc
@@ -221,7 +221,7 @@ void Installer::cloneFinished(int exitCode, QProcess::ExitStatus exitStatus) {
}
int main(int argc, char *argv[]) {
- initApp();
+ initApp(argc, argv);
QApplication a(argc, argv);
Installer installer;
setMainWindow(&installer);
diff --git a/selfdrive/ui/main.cc b/selfdrive/ui/main.cc
index 3d2411b9c6..8477bc8966 100644
--- a/selfdrive/ui/main.cc
+++ b/selfdrive/ui/main.cc
@@ -12,7 +12,7 @@ int main(int argc, char *argv[]) {
setpriority(PRIO_PROCESS, 0, -20);
qInstallMessageHandler(swagLogMessageHandler);
- initApp();
+ initApp(argc, argv);
if (Hardware::EON()) {
QSslConfiguration ssl = QSslConfiguration::defaultConfiguration();
diff --git a/selfdrive/ui/qt/offroad/driverview.cc b/selfdrive/ui/qt/offroad/driverview.cc
index 3ab5b999b2..c17d2e2573 100644
--- a/selfdrive/ui/qt/offroad/driverview.cc
+++ b/selfdrive/ui/qt/offroad/driverview.cc
@@ -12,7 +12,7 @@ DriverViewWindow::DriverViewWindow(QWidget* parent) : QWidget(parent) {
layout = new QStackedLayout(this);
layout->setStackingMode(QStackedLayout::StackAll);
- cameraView = new CameraViewWidget("camerad", VISION_STREAM_RGB_FRONT, true, this);
+ cameraView = new CameraViewWidget("camerad", VISION_STREAM_RGB_DRIVER, true, this);
layout->addWidget(cameraView);
scene = new DriverViewScene(this);
diff --git a/selfdrive/ui/qt/onroad.cc b/selfdrive/ui/qt/onroad.cc
index 44dde85817..e8d871aae1 100644
--- a/selfdrive/ui/qt/onroad.cc
+++ b/selfdrive/ui/qt/onroad.cc
@@ -20,7 +20,7 @@ OnroadWindow::OnroadWindow(QWidget *parent) : QWidget(parent) {
QStackedLayout *road_view_layout = new QStackedLayout;
road_view_layout->setStackingMode(QStackedLayout::StackAll);
- nvg = new NvgWindow(VISION_STREAM_RGB_BACK, this);
+ nvg = new NvgWindow(VISION_STREAM_RGB_ROAD, this);
road_view_layout->addWidget(nvg);
hud = new OnroadHud(this);
road_view_layout->addWidget(hud);
@@ -97,7 +97,7 @@ void OnroadWindow::offroadTransition(bool offroad) {
// update stream type
bool wide_cam = Hardware::TICI() && Params().getBool("EnableWideCamera");
- nvg->setStreamType(wide_cam ? VISION_STREAM_RGB_WIDE : VISION_STREAM_RGB_BACK);
+ nvg->setStreamType(wide_cam ? VISION_STREAM_RGB_WIDE_ROAD : VISION_STREAM_RGB_ROAD);
}
void OnroadWindow::paintEvent(QPaintEvent *event) {
@@ -222,7 +222,7 @@ void OnroadHud::paintEvent(QPaintEvent *event) {
configFont(p, "Open Sans", 48, "Regular");
drawText(p, rc.center().x(), 118, "MAX", is_cruise_set ? 200 : 100);
if (is_cruise_set) {
- configFont(p, "Open Sans", 88, is_cruise_set ? "Bold" : "SemiBold");
+ configFont(p, "Open Sans", 88, "Bold");
drawText(p, rc.center().x(), 212, maxSpeed, 255);
} else {
configFont(p, "Open Sans", 80, "SemiBold");
@@ -314,8 +314,8 @@ void NvgWindow::drawLaneLines(QPainter &painter, const UIScene &scene) {
}
// paint path
QLinearGradient bg(0, height(), 0, height() / 4);
- bg.setColorAt(0, scene.end_to_end ? redColor() : QColor(255, 255, 255));
- bg.setColorAt(1, scene.end_to_end ? redColor(0) : QColor(255, 255, 255, 0));
+ bg.setColorAt(0, scene.end_to_end ? redColor() : whiteColor());
+ bg.setColorAt(1, scene.end_to_end ? redColor(0) : whiteColor(0));
painter.setBrush(bg);
painter.drawPolygon(scene.track_vertices.v, scene.track_vertices.cnt);
}
diff --git a/selfdrive/ui/qt/onroad.h b/selfdrive/ui/qt/onroad.h
index 05811c5060..61da7698c1 100644
--- a/selfdrive/ui/qt/onroad.h
+++ b/selfdrive/ui/qt/onroad.h
@@ -76,6 +76,7 @@ protected:
void drawLaneLines(QPainter &painter, const UIScene &scene);
void drawLead(QPainter &painter, const cereal::ModelDataV2::LeadDataV3::Reader &lead_data, const QPointF &vd);
inline QColor redColor(int alpha = 255) { return QColor(201, 34, 49, alpha); }
+ inline QColor whiteColor(int alpha = 255) { return QColor(255, 255, 255, alpha); }
double prev_draw_t = 0;
};
diff --git a/selfdrive/ui/qt/setup/updater.cc b/selfdrive/ui/qt/setup/updater.cc
index dfa63fca11..6345d80db8 100644
--- a/selfdrive/ui/qt/setup/updater.cc
+++ b/selfdrive/ui/qt/setup/updater.cc
@@ -190,7 +190,7 @@ bool Updater::eventFilter(QObject *obj, QEvent *event) {
}
int main(int argc, char *argv[]) {
- initApp();
+ initApp(argc, argv);
QApplication a(argc, argv);
Updater updater(argv[1], argv[2]);
setMainWindow(&updater);
diff --git a/selfdrive/ui/qt/spinner.cc b/selfdrive/ui/qt/spinner.cc
index b9868f6035..e0b263227b 100644
--- a/selfdrive/ui/qt/spinner.cc
+++ b/selfdrive/ui/qt/spinner.cc
@@ -111,7 +111,7 @@ void Spinner::update(int n) {
}
int main(int argc, char *argv[]) {
- initApp();
+ initApp(argc, argv);
QApplication a(argc, argv);
Spinner spinner;
setMainWindow(&spinner);
diff --git a/selfdrive/ui/qt/text.cc b/selfdrive/ui/qt/text.cc
index cb69cc082b..04fda35483 100644
--- a/selfdrive/ui/qt/text.cc
+++ b/selfdrive/ui/qt/text.cc
@@ -11,7 +11,7 @@
#include "selfdrive/ui/qt/widgets/scrollview.h"
int main(int argc, char *argv[]) {
- initApp();
+ initApp(argc, argv);
QApplication a(argc, argv);
QWidget window;
setMainWindow(&window);
diff --git a/selfdrive/ui/qt/util.cc b/selfdrive/ui/qt/util.cc
index 16d5c174b5..967b7d15d1 100644
--- a/selfdrive/ui/qt/util.cc
+++ b/selfdrive/ui/qt/util.cc
@@ -89,9 +89,18 @@ void setQtSurfaceFormat() {
QSurfaceFormat::setDefaultFormat(fmt);
}
-void initApp() {
+void initApp(int argc, char *argv[]) {
Hardware::set_display_power(true);
Hardware::set_brightness(65);
+
+#ifdef __APPLE__
+ {
+ // Get the devicePixelRatio, and scale accordingly to maintain 1:1 rendering
+ QApplication tmp(argc, argv);
+ qputenv("QT_SCALE_FACTOR", QString::number(1.0 / tmp.devicePixelRatio() ).toLocal8Bit());
+ }
+#endif
+
setQtSurfaceFormat();
if (Hardware::EON()) {
QApplication::setAttribute(Qt::AA_ShareOpenGLContexts);
diff --git a/selfdrive/ui/qt/util.h b/selfdrive/ui/qt/util.h
index 1b9461fabf..813777710a 100644
--- a/selfdrive/ui/qt/util.h
+++ b/selfdrive/ui/qt/util.h
@@ -19,6 +19,6 @@ void clearLayout(QLayout* layout);
void setQtSurfaceFormat();
QString timeAgo(const QDateTime &date);
void swagLogMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg);
-void initApp();
+void initApp(int argc, char *argv[]);
QWidget* topWidget (QWidget* widget);
QPixmap loadPixmap(const QString &fileName, const QSize &size = {}, Qt::AspectRatioMode aspectRatioMode = Qt::KeepAspectRatio);
diff --git a/selfdrive/ui/qt/widgets/cameraview.cc b/selfdrive/ui/qt/widgets/cameraview.cc
index fbd425b025..ed40094f73 100644
--- a/selfdrive/ui/qt/widgets/cameraview.cc
+++ b/selfdrive/ui/qt/widgets/cameraview.cc
@@ -123,7 +123,7 @@ void CameraViewWidget::initializeGL() {
GLint frame_pos_loc = program->attributeLocation("aPosition");
GLint frame_texcoord_loc = program->attributeLocation("aTexCoord");
- auto [x1, x2, y1, y2] = stream_type == VISION_STREAM_RGB_FRONT ? std::tuple(0.f, 1.f, 1.f, 0.f) : std::tuple(1.f, 0.f, 1.f, 0.f);
+ auto [x1, x2, y1, y2] = stream_type == VISION_STREAM_RGB_DRIVER ? std::tuple(0.f, 1.f, 1.f, 0.f) : std::tuple(1.f, 0.f, 1.f, 0.f);
const uint8_t frame_indicies[] = {0, 1, 2, 0, 2, 3};
const float frame_coords[4][4] = {
{-1.0, -1.0, x2, y1}, // bl
@@ -171,12 +171,12 @@ void CameraViewWidget::hideEvent(QHideEvent *event) {
void CameraViewWidget::updateFrameMat(int w, int h) {
if (zoomed_view) {
- if (stream_type == VISION_STREAM_RGB_FRONT) {
+ if (stream_type == VISION_STREAM_RGB_DRIVER) {
frame_mat = matmul(device_transform, get_driver_view_transform(w, h, stream_width, stream_height));
} else {
- auto intrinsic_matrix = stream_type == VISION_STREAM_RGB_WIDE ? ecam_intrinsic_matrix : fcam_intrinsic_matrix;
+ auto intrinsic_matrix = stream_type == VISION_STREAM_RGB_WIDE_ROAD ? ecam_intrinsic_matrix : fcam_intrinsic_matrix;
float zoom = ZOOM / intrinsic_matrix.v[0];
- if (stream_type == VISION_STREAM_RGB_WIDE) {
+ if (stream_type == VISION_STREAM_RGB_WIDE_ROAD) {
zoom *= 0.5;
}
float zx = zoom * 2 * intrinsic_matrix.v[2] / width();
diff --git a/selfdrive/ui/replay/camera.h b/selfdrive/ui/replay/camera.h
index 340a120e8c..9d72094d4c 100644
--- a/selfdrive/ui/replay/camera.h
+++ b/selfdrive/ui/replay/camera.h
@@ -32,9 +32,9 @@ protected:
void cameraThread(Camera &cam);
Camera cameras_[MAX_CAMERAS] = {
- {.type = RoadCam, .rgb_type = VISION_STREAM_RGB_BACK, .yuv_type = VISION_STREAM_ROAD},
- {.type = DriverCam, .rgb_type = VISION_STREAM_RGB_FRONT, .yuv_type = VISION_STREAM_DRIVER},
- {.type = WideRoadCam, .rgb_type = VISION_STREAM_RGB_WIDE, .yuv_type = VISION_STREAM_WIDE_ROAD},
+ {.type = RoadCam, .rgb_type = VISION_STREAM_RGB_ROAD, .yuv_type = VISION_STREAM_ROAD},
+ {.type = DriverCam, .rgb_type = VISION_STREAM_RGB_DRIVER, .yuv_type = VISION_STREAM_DRIVER},
+ {.type = WideRoadCam, .rgb_type = VISION_STREAM_RGB_WIDE_ROAD, .yuv_type = VISION_STREAM_WIDE_ROAD},
};
std::atomic publishing_ = 0;
std::unique_ptr vipc_server_;
diff --git a/selfdrive/ui/watch3.cc b/selfdrive/ui/watch3.cc
index aeabfe110e..74c00fe18e 100644
--- a/selfdrive/ui/watch3.cc
+++ b/selfdrive/ui/watch3.cc
@@ -6,7 +6,7 @@
#include "selfdrive/ui/qt/widgets/cameraview.h"
int main(int argc, char *argv[]) {
- setQtSurfaceFormat();
+ initApp(argc, argv);
QApplication a(argc, argv);
QWidget w;
@@ -20,14 +20,14 @@ int main(int argc, char *argv[]) {
QHBoxLayout *hlayout = new QHBoxLayout();
layout->addLayout(hlayout);
hlayout->addWidget(new CameraViewWidget("navd", VISION_STREAM_RGB_MAP, false));
- hlayout->addWidget(new CameraViewWidget("camerad", VISION_STREAM_RGB_BACK, false));
+ hlayout->addWidget(new CameraViewWidget("camerad", VISION_STREAM_RGB_ROAD, false));
}
{
QHBoxLayout *hlayout = new QHBoxLayout();
layout->addLayout(hlayout);
- hlayout->addWidget(new CameraViewWidget("camerad", VISION_STREAM_RGB_FRONT, false));
- hlayout->addWidget(new CameraViewWidget("camerad", VISION_STREAM_RGB_WIDE, false));
+ hlayout->addWidget(new CameraViewWidget("camerad", VISION_STREAM_RGB_DRIVER, false));
+ hlayout->addWidget(new CameraViewWidget("camerad", VISION_STREAM_RGB_WIDE_ROAD, false));
}
return a.exec();
diff --git a/third_party/acados/aarch64/lib/libacados.so b/third_party/acados/aarch64/lib/libacados.so
index fe961d8c50..640de2c2ac 100755
Binary files a/third_party/acados/aarch64/lib/libacados.so and b/third_party/acados/aarch64/lib/libacados.so differ
diff --git a/third_party/acados/aarch64/lib/libblasfeo.so b/third_party/acados/aarch64/lib/libblasfeo.so
index a59f3f79f8..fae141e9fc 100755
Binary files a/third_party/acados/aarch64/lib/libblasfeo.so and b/third_party/acados/aarch64/lib/libblasfeo.so differ
diff --git a/third_party/acados/build.sh b/third_party/acados/build.sh
index 9216032e98..96aa23419b 100755
--- a/third_party/acados/build.sh
+++ b/third_party/acados/build.sh
@@ -13,19 +13,19 @@ elif [ -f /EON ]; then
fi
if [ ! -d acados_repo/ ]; then
- #git clone https://github.com/acados/acados.git $DIR/acados
- git clone https://github.com/commaai/acados.git $DIR/acados_repo
+ git clone https://github.com/acados/acados.git $DIR/acados_repo
+ # git clone https://github.com/commaai/acados.git $DIR/acados_repo
fi
cd acados_repo
git fetch
-git checkout 79e9e3e76f2751198858adf382c97837833ad31f
+git checkout 105e06df87f06ea02df4af825867c946b31defdd
git submodule update --recursive --init
# build
mkdir -p build
cd build
cmake -DACADOS_WITH_QPOASES=ON -UBLASFEO_TARGET -DBLASFEO_TARGET=$BLAS_TARGET ..
-make -j4 install
+make -j20 install
INSTALL_DIR="$DIR/$ARCHNAME"
rm -rf $INSTALL_DIR
@@ -33,8 +33,10 @@ mkdir -p $INSTALL_DIR
rm $DIR/acados_repo/lib/*.json
+rm -rf $DIR/include
cp -r $DIR/acados_repo/include $DIR
cp -r $DIR/acados_repo/lib $INSTALL_DIR
+rm -rf $DIR/../../pyextra/acados_template
cp -r $DIR/acados_repo/interfaces/acados_template/acados_template $DIR/../../pyextra
#pip3 install -e $DIR/acados/interfaces/acados_template
diff --git a/third_party/acados/include/acados/ocp_nlp/ocp_nlp_common.h b/third_party/acados/include/acados/ocp_nlp/ocp_nlp_common.h
index 64939b9ed1..4a7f19a07e 100644
--- a/third_party/acados/include/acados/ocp_nlp/ocp_nlp_common.h
+++ b/third_party/acados/include/acados/ocp_nlp/ocp_nlp_common.h
@@ -234,11 +234,7 @@ typedef struct ocp_nlp_out
// NOTE: the inequalities are internally organized in the following order:
// [ lbu lbx lg lh lphi ubu ubx ug uh uphi; lsbu lsbx lsg lsh lsphi usbu usbx usg ush usphi]
-
- int sqp_iter;
- int qp_iter;
double inf_norm_res;
- double total_time;
void *raw_memory; // Pointer to allocated memory, to be used for freeing
@@ -274,11 +270,16 @@ typedef struct ocp_nlp_opts
double levenberg_marquardt; // LM factor to be added to the hessian before regularization
int reuse_workspace;
int num_threads;
+ int print_level;
// TODO: move to separate struct?
ocp_nlp_globalization_t globalization;
+ int full_step_dual;
+ int line_search_use_sufficient_descent;
+ int globalization_use_SOC;
double alpha_min;
double alpha_reduction;
+ double eps_sufficient_descent;
} ocp_nlp_opts;
//
@@ -316,6 +317,8 @@ typedef struct ocp_nlp_res
acados_size_t ocp_nlp_res_calculate_size(ocp_nlp_dims *dims);
//
ocp_nlp_res *ocp_nlp_res_assign(ocp_nlp_dims *dims, void *raw_memory);
+//
+void ocp_nlp_res_get_inf_norm(ocp_nlp_res *res, double *out);
/************************************************
* memory
@@ -351,7 +354,7 @@ typedef struct ocp_nlp_memory
bool *set_sim_guess; // indicate if there is new explicitly provided guess for integration variables
struct blasfeo_dvec *sim_guess;
- int *sqp_iter; // pointer to iteration number
+ int *sqp_iter; // pointer to iteration number
} ocp_nlp_memory;
@@ -375,8 +378,12 @@ typedef struct ocp_nlp_workspace
void **cost; // cost_workspace
void **constraints; // constraints_workspace
- ocp_nlp_out *tmp_nlp_out;
- ocp_nlp_out *weight_merit_fun;
+ // for globalization: -> move to module?!
+ ocp_nlp_out *tmp_nlp_out;
+ ocp_nlp_out *weight_merit_fun;
+ struct blasfeo_dvec tmp_nxu;
+ struct blasfeo_dvec tmp_ni;
+ struct blasfeo_dvec dxnext_dy;
} ocp_nlp_workspace;
@@ -392,6 +399,8 @@ ocp_nlp_workspace *ocp_nlp_workspace_assign(ocp_nlp_config *config, ocp_nlp_dims
* function
************************************************/
+void ocp_nlp_alias_memory_to_submodules(ocp_nlp_config *config, ocp_nlp_dims *dims, ocp_nlp_in *in,
+ ocp_nlp_out *out, ocp_nlp_opts *opts, ocp_nlp_memory *mem, ocp_nlp_workspace *work);
//
void ocp_nlp_initialize_qp(ocp_nlp_config *config, ocp_nlp_dims *dims, ocp_nlp_in *in,
ocp_nlp_out *out, ocp_nlp_opts *opts, ocp_nlp_memory *mem, ocp_nlp_workspace *work);
@@ -409,7 +418,8 @@ void ocp_nlp_update_variables_sqp(ocp_nlp_config *config, ocp_nlp_dims *dims, oc
ocp_nlp_out *out, ocp_nlp_opts *opts, ocp_nlp_memory *mem, ocp_nlp_workspace *work, double alpha);
//
double ocp_nlp_line_search(ocp_nlp_config *config, ocp_nlp_dims *dims, ocp_nlp_in *in,
- ocp_nlp_out *out, ocp_nlp_opts *opts, ocp_nlp_memory *mem, ocp_nlp_workspace *work);
+ ocp_nlp_out *out, ocp_nlp_opts *opts, ocp_nlp_memory *mem, ocp_nlp_workspace *work,
+ int check_early_termination);
//
double ocp_nlp_evaluate_merit_fun(ocp_nlp_config *config, ocp_nlp_dims *dims, ocp_nlp_in *in,
ocp_nlp_out *out, ocp_nlp_opts *opts, ocp_nlp_memory *mem, ocp_nlp_workspace *work);
diff --git a/third_party/acados/include/acados/ocp_nlp/ocp_nlp_dynamics_common.h b/third_party/acados/include/acados/ocp_nlp/ocp_nlp_dynamics_common.h
index 45dac20a25..f2128a8574 100644
--- a/third_party/acados/include/acados/ocp_nlp/ocp_nlp_dynamics_common.h
+++ b/third_party/acados/include/acados/ocp_nlp/ocp_nlp_dynamics_common.h
@@ -84,6 +84,7 @@ typedef struct
/* memory */
acados_size_t (*memory_calculate_size)(void *config, void *dims, void *opts);
void *(*memory_assign)(void *config, void *dims, void *opts, void *raw_memory);
+ // get shooting node gap x_next(x_n, u_n) - x_{n+1}
struct blasfeo_dvec *(*memory_get_fun_ptr)(void *memory_);
struct blasfeo_dvec *(*memory_get_adj_ptr)(void *memory_);
void (*memory_set_ux_ptr)(struct blasfeo_dvec *ux, void *memory_);
diff --git a/third_party/acados/include/acados/ocp_nlp/ocp_nlp_reg_noreg.h b/third_party/acados/include/acados/ocp_nlp/ocp_nlp_reg_noreg.h
index 8d2b6ecc13..c085e00d5d 100644
--- a/third_party/acados/include/acados/ocp_nlp/ocp_nlp_reg_noreg.h
+++ b/third_party/acados/include/acados/ocp_nlp/ocp_nlp_reg_noreg.h
@@ -65,11 +65,6 @@ extern "C" {
* options
************************************************/
-typedef struct
-{
- int dummy;
-} ocp_nlp_reg_noreg_opts;
-
//
acados_size_t ocp_nlp_reg_noreg_opts_calculate_size(void);
//
@@ -84,12 +79,6 @@ void ocp_nlp_reg_noreg_opts_set(void *config_, ocp_nlp_reg_dims *dims, void *opt
/************************************************
* memory
************************************************/
-
-typedef struct
-{
- int dummy;
-} ocp_nlp_reg_noreg_memory;
-
//
acados_size_t ocp_nlp_reg_noreg_memory_calculate_size(void *config, ocp_nlp_reg_dims *dims, void *opts);
//
diff --git a/third_party/acados/include/acados/ocp_nlp/ocp_nlp_sqp.h b/third_party/acados/include/acados/ocp_nlp/ocp_nlp_sqp.h
index 81a4afd030..5e4fc810d9 100644
--- a/third_party/acados/include/acados/ocp_nlp/ocp_nlp_sqp.h
+++ b/third_party/acados/include/acados/ocp_nlp/ocp_nlp_sqp.h
@@ -68,7 +68,6 @@ typedef struct
int qp_warm_start; // qp_warm_start in all but the first sqp iterations
bool warm_start_first_qp; // to set qp_warm_start in first iteration
int rti_phase; // only phase 0 at the moment
- int print_level; // verbosity
int initialize_t_slacks; // 0-false or 1-true
} ocp_nlp_sqp_opts;
@@ -107,6 +106,7 @@ typedef struct
double time_sim;
double time_sim_la;
double time_sim_ad;
+ double time_solution_sensitivities;
// statistics
double *stat;
diff --git a/third_party/acados/include/acados/ocp_nlp/ocp_nlp_sqp_rti.h b/third_party/acados/include/acados/ocp_nlp/ocp_nlp_sqp_rti.h
index 6f16594d2b..af22c06a17 100644
--- a/third_party/acados/include/acados/ocp_nlp/ocp_nlp_sqp_rti.h
+++ b/third_party/acados/include/acados/ocp_nlp/ocp_nlp_sqp_rti.h
@@ -64,7 +64,6 @@ typedef struct
int qp_warm_start; // NOTE: this is not actually setting the warm_start! Just for compatibility with sqp.
bool warm_start_first_qp; // to set qp_warm_start in first iteration
int rti_phase; // phase of RTI. Possible values 1 (preparation), 2 (feedback) 0 (both)
- int print_level; // verbosity
} ocp_nlp_sqp_rti_opts;
@@ -100,6 +99,7 @@ typedef struct
double time_reg;
double time_tot;
double time_glob;
+ double time_solution_sensitivities;
// statistics
double *stat;
diff --git a/third_party/acados/include/acados/utils/print.h b/third_party/acados/include/acados/utils/print.h
index 2993447dbd..f8568afb26 100644
--- a/third_party/acados/include/acados/utils/print.h
+++ b/third_party/acados/include/acados/utils/print.h
@@ -69,28 +69,32 @@ void ocp_nlp_out_print(ocp_nlp_dims *dims, ocp_nlp_out *nlp_out);
void ocp_nlp_res_print(ocp_nlp_dims *dims, ocp_nlp_res *nlp_res);
// ocp qp
+// TODO: move printing routines below that print qp structures to HPIPM!
void print_ocp_qp_dims(ocp_qp_dims *dims);
// void print_dense_qp_dims(dense_qp_dims *dims);
void print_ocp_qp_in(ocp_qp_in *qp_in);
+void print_ocp_qp_in_to_file(FILE *file, ocp_qp_in *qp_in);
+
void print_ocp_qp_out(ocp_qp_out *qp_out);
+void print_ocp_qp_out_to_file(FILE *file, ocp_qp_out *qp_out);
+
+void print_ocp_qp_res(ocp_qp_res *qp_res);
+
+void print_dense_qp_in(dense_qp_in *qp_in);
// void print_ocp_qp_in_to_string(char string_out[], ocp_qp_in *qp_in);
// void print_ocp_qp_out_to_string(char string_out[], ocp_qp_out *qp_out);
-void print_ocp_qp_res(ocp_qp_res *qp_res);
-
// void print_colmaj_ocp_qp_in(colmaj_ocp_qp_in *qp);
// void print_colmaj_ocp_qp_in_to_file(colmaj_ocp_qp_in *qp);
// void print_colmaj_ocp_qp_out(char *filename, colmaj_ocp_qp_in *qp, colmaj_ocp_qp_out *out);
-void print_dense_qp_in(dense_qp_in *qp_in);
-
void print_qp_info(qp_info *info);
// void acados_warning(char warning_string[]);
diff --git a/third_party/acados/include/acados_c/ocp_nlp_interface.h b/third_party/acados/include/acados_c/ocp_nlp_interface.h
index b6b893024b..0ec82a437a 100644
--- a/third_party/acados/include/acados_c/ocp_nlp_interface.h
+++ b/third_party/acados/include/acados_c/ocp_nlp_interface.h
@@ -107,13 +107,13 @@ typedef enum
/// Structure to store the configuration of a non-linear program
-typedef struct ocp_nlp_plan
+typedef struct ocp_nlp_plan_t
{
/// QP solver configuration.
- ocp_qp_solver_plan ocp_qp_solver_plan;
+ ocp_qp_solver_plan_t ocp_qp_solver_plan;
/// Simulation solver configuration for each stage.
- sim_solver_plan *sim_solver_plan;
+ sim_solver_plan_t *sim_solver_plan;
/// Nlp solver type.
ocp_nlp_solver_t nlp_solver;
@@ -133,7 +133,7 @@ typedef struct ocp_nlp_plan
/// Horizon length.
int N;
-} ocp_nlp_plan;
+} ocp_nlp_plan_t;
/// Structure to store the state/configuration for the non-linear programming solver
@@ -151,7 +151,7 @@ typedef struct ocp_nlp_solver
/// default/invalid state.
///
/// \param N Horizon length
-ocp_nlp_plan *ocp_nlp_plan_create(int N);
+ocp_nlp_plan_t *ocp_nlp_plan_create(int N);
/// Destructor for plan struct, frees memory.
///
@@ -162,7 +162,7 @@ void ocp_nlp_plan_destroy(void* plan_);
/// Constructs an nlp configuration struct from a plan.
///
/// \param plan The plan (user nlp configuration).
-ocp_nlp_config *ocp_nlp_config_create(ocp_nlp_plan plan);
+ocp_nlp_config *ocp_nlp_config_create(ocp_nlp_plan_t plan);
/// Desctructor of the nlp configuration.
///
@@ -372,6 +372,14 @@ void ocp_nlp_eval_cost(ocp_nlp_solver *solver, ocp_nlp_in *nlp_in, ocp_nlp_out *
//
void ocp_nlp_eval_residuals(ocp_nlp_solver *solver, ocp_nlp_in *nlp_in, ocp_nlp_out *nlp_out);
+/// Computes the residuals.
+///
+/// \param solver The solver struct.
+/// \param nlp_in The inputs struct.
+/// \param nlp_out The output struct.
+void ocp_nlp_eval_residuals(ocp_nlp_solver *solver, ocp_nlp_in *nlp_in, ocp_nlp_out *nlp_out);
+
+
//
void ocp_nlp_eval_param_sens(ocp_nlp_solver *solver, char *field, int stage, int index, ocp_nlp_out *sens_nlp_out);
diff --git a/third_party/acados/include/acados_c/ocp_qp_interface.h b/third_party/acados/include/acados_c/ocp_qp_interface.h
index a567ebeb35..2582f142da 100644
--- a/third_party/acados/include/acados_c/ocp_qp_interface.h
+++ b/third_party/acados/include/acados_c/ocp_qp_interface.h
@@ -105,7 +105,7 @@ typedef enum {
typedef struct
{
ocp_qp_solver_t qp_solver;
-} ocp_qp_solver_plan;
+} ocp_qp_solver_plan_t;
/// Linear ocp configuration.
@@ -127,7 +127,7 @@ void ocp_qp_xcond_solver_config_initialize_from_plan(
/// Constructs a qp solver config and Initializes with default values.
///
/// \param plan The qp solver plan struct.
-ocp_qp_xcond_solver_config *ocp_qp_xcond_solver_config_create(ocp_qp_solver_plan plan);
+ocp_qp_xcond_solver_config *ocp_qp_xcond_solver_config_create(ocp_qp_solver_plan_t plan);
/// Destructor for config struct, frees memory.
///
diff --git a/third_party/acados/include/acados_c/sim_interface.h b/third_party/acados/include/acados_c/sim_interface.h
index cc47b62ed4..92969e8017 100644
--- a/third_party/acados/include/acados_c/sim_interface.h
+++ b/third_party/acados/include/acados_c/sim_interface.h
@@ -57,7 +57,7 @@ typedef enum
typedef struct
{
sim_solver_t sim_solver;
-} sim_solver_plan;
+} sim_solver_plan_t;
@@ -74,7 +74,7 @@ typedef struct
/* config */
//
-sim_config *sim_config_create(sim_solver_plan plan);
+sim_config *sim_config_create(sim_solver_plan_t plan);
//
void sim_config_destroy(void *config);
diff --git a/third_party/acados/include/blasfeo/include/blasfeo_d_aux.h b/third_party/acados/include/blasfeo/include/blasfeo_d_aux.h
index 7a9415a59d..d4d805c3e4 100644
--- a/third_party/acados/include/blasfeo/include/blasfeo_d_aux.h
+++ b/third_party/acados/include/blasfeo/include/blasfeo_d_aux.h
@@ -185,9 +185,14 @@ void blasfeo_dveccp(int m, struct blasfeo_dvec *sx, int xi, struct blasfeo_dvec
void blasfeo_dvecsc(int m, double alpha, struct blasfeo_dvec *sx, int xi);
// y <= alpha*x
void blasfeo_dveccpsc(int m, double alpha, struct blasfeo_dvec *sx, int xi, struct blasfeo_dvec *sy, int yi);
+// z[idx] += alpha * x
void blasfeo_dvecad_sp(int m, double alpha, struct blasfeo_dvec *sx, int xi, int *idx, struct blasfeo_dvec *sz, int zi);
+// z[idx] <= alpha * x
void blasfeo_dvecin_sp(int m, double alpha, struct blasfeo_dvec *sx, int xi, int *idx, struct blasfeo_dvec *sz, int zi);
-void blasfeo_dvecex_sp(int m, double alpha, int *idx, struct blasfeo_dvec *sx, int x, struct blasfeo_dvec *sz, int zi);
+// z <= alpha * x[idx]
+void blasfeo_dvecex_sp(int m, double alpha, int *idx, struct blasfeo_dvec *sx, int xi, struct blasfeo_dvec *sz, int zi);
+// z += alpha * x[idx]
+void blasfeo_dvecexad_sp(int m, double alpha, int *idx, struct blasfeo_dvec *sx, int xi, struct blasfeo_dvec *sz, int zi);
void blasfeo_dveccl(int m,
struct blasfeo_dvec *sxm, int xim, struct blasfeo_dvec *sx, int xi,
diff --git a/third_party/acados/include/blasfeo/include/blasfeo_d_aux_ref.h b/third_party/acados/include/blasfeo/include/blasfeo_d_aux_ref.h
index 448234044a..1e007fa89e 100644
--- a/third_party/acados/include/blasfeo/include/blasfeo_d_aux_ref.h
+++ b/third_party/acados/include/blasfeo/include/blasfeo_d_aux_ref.h
@@ -182,6 +182,8 @@ void blasfeo_ref_dveccpsc(int m, double alpha, struct blasfeo_dvec *sx, int xi,
void blasfeo_ref_dvecad_sp(int m, double alpha, struct blasfeo_dvec *sx, int xi, int *idx, struct blasfeo_dvec *sz, int zi);
void blasfeo_ref_dvecin_sp(int m, double alpha, struct blasfeo_dvec *sx, int xi, int *idx, struct blasfeo_dvec *sz, int zi);
void blasfeo_ref_dvecex_sp(int m, double alpha, int *idx, struct blasfeo_dvec *sx, int x, struct blasfeo_dvec *sz, int zi);
+// z += alpha * x[idx]
+void blasfeo_ref_dvecexad_sp(int m, double alpha, int *idx, struct blasfeo_dvec *sx, int xi, struct blasfeo_dvec *sz, int zi);
void blasfeo_ref_dveccl(int m,
struct blasfeo_dvec *sxm, int xim, struct blasfeo_dvec *sx, int xi,
diff --git a/third_party/acados/include/blasfeo/include/blasfeo_s_aux.h b/third_party/acados/include/blasfeo/include/blasfeo_s_aux.h
index 539268849c..f43f5e83ce 100644
--- a/third_party/acados/include/blasfeo/include/blasfeo_s_aux.h
+++ b/third_party/acados/include/blasfeo/include/blasfeo_s_aux.h
@@ -127,6 +127,8 @@ float blasfeo_svecex1(struct blasfeo_svec *sx, int xi);
void blasfeo_svecad_sp(int m, float alpha, struct blasfeo_svec *sx, int xi, int *idx, struct blasfeo_svec *sz, int zi);
void blasfeo_svecin_sp(int m, float alpha, struct blasfeo_svec *sx, int xi, int *idx, struct blasfeo_svec *sz, int zi);
void blasfeo_svecex_sp(int m, float alpha, int *idx, struct blasfeo_svec *sx, int x, struct blasfeo_svec *sz, int zi);
+// z += alpha * x[idx]
+void blasfeo_svecexad_sp(int m, double alpha, int *idx, struct blasfeo_svec *sx, int xi, struct blasfeo_svec *sz, int zi);
void blasfeo_sveccl(int m, struct blasfeo_svec *sxm, int xim, struct blasfeo_svec *sx, int xi, struct blasfeo_svec *sxp, int xip, struct blasfeo_svec *sz, int zi);
void blasfeo_sveccl_mask(int m, struct blasfeo_svec *sxm, int xim, struct blasfeo_svec *sx, int xi, struct blasfeo_svec *sxp, int xip, struct blasfeo_svec *sz, int zi, struct blasfeo_svec *sm, int mi);
void blasfeo_svecze(int m, struct blasfeo_svec *sm, int mi, struct blasfeo_svec *sv, int vi, struct blasfeo_svec *se, int ei);
diff --git a/third_party/acados/include/blasfeo/include/blasfeo_s_aux_ref.h b/third_party/acados/include/blasfeo/include/blasfeo_s_aux_ref.h
index f6e16a9577..998e1d8999 100644
--- a/third_party/acados/include/blasfeo/include/blasfeo_s_aux_ref.h
+++ b/third_party/acados/include/blasfeo/include/blasfeo_s_aux_ref.h
@@ -128,6 +128,8 @@ float blasfeo_ref_svecex1(struct blasfeo_svec *sx, int xi);
void blasfeo_ref_svecad_sp(int m, float alpha, struct blasfeo_svec *sx, int xi, int *idx, struct blasfeo_svec *sz, int zi);
void blasfeo_ref_svecin_sp(int m, float alpha, struct blasfeo_svec *sx, int xi, int *idx, struct blasfeo_svec *sz, int zi);
void blasfeo_ref_svecex_sp(int m, float alpha, int *idx, struct blasfeo_svec *sx, int x, struct blasfeo_svec *sz, int zi);
+// z += alpha * x[idx]
+void blasfeo_ref_svecexad_sp(int m, double alpha, int *idx, struct blasfeo_svec *sx, int xi, struct blasfeo_svec *sz, int zi);
void blasfeo_ref_sveccl(int m, struct blasfeo_svec *sxm, int xim, struct blasfeo_svec *sx, int xi, struct blasfeo_svec *sxp, int xip, struct blasfeo_svec *sz, int zi);
void blasfeo_ref_sveccl_mask(int m, struct blasfeo_svec *sxm, int xim, struct blasfeo_svec *sx, int xi, struct blasfeo_svec *sxp, int xip, struct blasfeo_svec *sz, int zi, struct blasfeo_svec *sm, int mi);
void blasfeo_ref_svecze(int m, struct blasfeo_svec *sm, int mi, struct blasfeo_svec *sv, int vi, struct blasfeo_svec *se, int ei);
diff --git a/third_party/acados/larch64/lib/libacados.so b/third_party/acados/larch64/lib/libacados.so
index 1f2b1f5c0b..c9448d9632 100644
Binary files a/third_party/acados/larch64/lib/libacados.so and b/third_party/acados/larch64/lib/libacados.so differ
diff --git a/third_party/acados/larch64/lib/libblasfeo.so b/third_party/acados/larch64/lib/libblasfeo.so
index 790282fa19..583769e982 100644
Binary files a/third_party/acados/larch64/lib/libblasfeo.so and b/third_party/acados/larch64/lib/libblasfeo.so differ
diff --git a/third_party/acados/x86_64/lib/libacados.so b/third_party/acados/x86_64/lib/libacados.so
index 00a5e2371a..5c3203b553 100644
Binary files a/third_party/acados/x86_64/lib/libacados.so and b/third_party/acados/x86_64/lib/libacados.so differ
diff --git a/third_party/acados/x86_64/lib/libblasfeo.so b/third_party/acados/x86_64/lib/libblasfeo.so
index 5a8399287a..262cf9f12a 100644
Binary files a/third_party/acados/x86_64/lib/libblasfeo.so and b/third_party/acados/x86_64/lib/libblasfeo.so differ
diff --git a/third_party/acados/x86_64/lib/libhpipm.so b/third_party/acados/x86_64/lib/libhpipm.so
index f52091d931..48421183fd 100644
Binary files a/third_party/acados/x86_64/lib/libhpipm.so and b/third_party/acados/x86_64/lib/libhpipm.so differ
diff --git a/third_party/acados/x86_64/lib/libqpOASES_e.so.3.1 b/third_party/acados/x86_64/lib/libqpOASES_e.so.3.1
index 6b553554fd..6aa7b4f8b5 100644
Binary files a/third_party/acados/x86_64/lib/libqpOASES_e.so.3.1 and b/third_party/acados/x86_64/lib/libqpOASES_e.so.3.1 differ
diff --git a/third_party/acados/x86_64/t_renderer b/third_party/acados/x86_64/t_renderer
index 181ef9c3d2..5e7871bf8a 100755
Binary files a/third_party/acados/x86_64/t_renderer and b/third_party/acados/x86_64/t_renderer differ
diff --git a/tools/camerastream/receive.py b/tools/camerastream/receive.py
new file mode 100755
index 0000000000..6f8d67c78f
--- /dev/null
+++ b/tools/camerastream/receive.py
@@ -0,0 +1,44 @@
+#!/usr/bin/env python
+import os
+import sys
+import numpy as np
+os.environ['ZMQ'] = '1'
+
+from common.window import Window
+import cereal.messaging as messaging
+
+# start camerad with 'SEND_ROAD=1 SEND_DRIVER=1 SEND_WIDE_ROAD=1 XMIN=771 XMAX=1156 YMIN=483 YMAX=724 ./camerad'
+# also start bridge
+# then run this "./receive.py "
+
+if "FULL" in os.environ:
+ SCALE = 2
+ XMIN, XMAX = 0, 1927
+ YMIN, YMAX = 0, 1207
+else:
+ SCALE = 1
+ XMIN = 771
+ XMAX = 1156
+ YMIN = 483
+ YMAX = 724
+H, W = ((YMAX-YMIN+1)//SCALE, (XMAX-XMIN+1)//SCALE)
+
+if __name__ == '__main__':
+ cameras = ['roadCameraState', 'wideRoadCameraState', 'driverCameraState']
+ if "CAM" in os.environ:
+ cam = int(os.environ['CAM'])
+ cameras = cameras[cam:cam+1]
+ sm = messaging.SubMaster(cameras, addr=sys.argv[1])
+ win = Window(W*len(cameras), H)
+ bdat = np.zeros((H, W*len(cameras), 3), dtype=np.uint8)
+
+ while 1:
+ sm.update()
+ for i,k in enumerate(cameras):
+ if sm.updated[k]:
+ #print("update", k)
+ bgr_raw = sm[k].image
+ dat = np.frombuffer(bgr_raw, dtype=np.uint8).reshape(H, W, 3)[:, :, [2,1,0]]
+ bdat[:, W*i:W*(i+1)] = dat
+ win.draw(bdat)
+
diff --git a/tools/lib/README.md b/tools/lib/README.md
index c681809eae..241232eae2 100644
--- a/tools/lib/README.md
+++ b/tools/lib/README.md
@@ -31,3 +31,21 @@ for msg in lr:
if msg.which() == "carState":
print(msg.carState.steeringAngleDeg)
```
+
+### MultiLogIterator
+
+`MultiLogIterator` is similar to `LogReader`, but reads multiple logs.
+
+```python
+from tools.lib.route import Route
+from tools.lib.logreader import MultiLogIterator
+
+# setup a MultiLogIterator to read all the logs in the route
+r = Route("4cf7a6ad03080c90|2021-09-29--13-46-36")
+lr = MultiLogIterator(r.log_paths())
+
+# print all the steering angles values from all the logs in the route
+for msg in lr:
+ if msg.which() == "carState":
+ print(msg.carState.steeringAngleDeg)
+```
diff --git a/tools/lib/logreader.py b/tools/lib/logreader.py
index c8d506b4b3..5597a5ffda 100755
--- a/tools/lib/logreader.py
+++ b/tools/lib/logreader.py
@@ -5,8 +5,9 @@ import bz2
import urllib.parse
import capnp
-from tools.lib.filereader import FileReader
from cereal import log as capnp_log
+from tools.lib.filereader import FileReader
+from tools.lib.route import Route, SegmentName
# this is an iterator itself, and uses private variables from LogReader
class MultiLogIterator:
@@ -99,6 +100,16 @@ class LogReader:
else:
yield ent
+
+def logreader_from_route_or_segment(r):
+ sn = SegmentName(r, allow_route_name=True)
+ route = Route(sn.route_name.canonical_name)
+ if sn.segment_num < 0:
+ return MultiLogIterator(route.log_paths())
+ else:
+ return LogReader(route.log_paths()[sn.segment_num])
+
+
if __name__ == "__main__":
import codecs
# capnproto <= 0.8.0 throws errors converting byte data to string
diff --git a/tools/mac_setup.sh b/tools/mac_setup.sh
index 9140cc4335..b85981dc04 100755
--- a/tools/mac_setup.sh
+++ b/tools/mac_setup.sh
@@ -30,6 +30,7 @@ fi
# TODO: remove protobuf,protobuf-c,swig when casadi can be pip installed
brew bundle --file=- <<-EOS
+brew "catch2"
brew "cmake"
brew "cppcheck"
brew "git-lfs"
diff --git a/tools/plotjuggler/README.md b/tools/plotjuggler/README.md
index 2e79aecbca..cd3b358e31 100644
--- a/tools/plotjuggler/README.md
+++ b/tools/plotjuggler/README.md
@@ -12,8 +12,7 @@ Once you've cloned and are in openpilot, this command will download PlotJuggler
```
$ ./juggle.py -h
-usage: juggle.py [-h] [--demo] [--qlog] [--can] [--stream] [--layout [LAYOUT]] [--install]
- [route_or_segment_name] [segment_count]
+usage: juggle.py [-h] [--demo] [--qlog] [--can] [--stream] [--layout [LAYOUT]] [--install] [--dbc DBC] [route_or_segment_name] [segment_count]
A helper to run PlotJuggler on openpilot routes
@@ -23,13 +22,15 @@ positional arguments:
segment_count The number of segments to plot (default: None)
optional arguments:
- -h, --help show this help message and exit
- --demo Use the demo route instead of providing one (default: False)
- --qlog Use qlogs (default: False)
- --can Parse CAN data (default: False)
- --stream Start PlotJuggler in streaming mode (default: False)
- --layout [LAYOUT] Run PlotJuggler with a pre-defined layout (default: None)
- --install Install or update PlotJuggler + plugins (default: False)
+ -h, --help show this help message and exit
+ --demo Use the demo route instead of providing one (default: False)
+ --qlog Use qlogs (default: False)
+ --can Parse CAN data (default: False)
+ --stream Start PlotJuggler in streaming mode (default: False)
+ --layout [LAYOUT] Run PlotJuggler with a pre-defined layout (default: None)
+ --install Install or update PlotJuggler + plugins (default: False)
+ --dbc DBC Set the DBC name to load for parsing CAN data. If not set, the DBC will be
+ automatically inferred from the logs. (default: None)
```
Examples using route name:
diff --git a/tools/plotjuggler/juggle.py b/tools/plotjuggler/juggle.py
index af69bd7c8b..6f7be73490 100755
--- a/tools/plotjuggler/juggle.py
+++ b/tools/plotjuggler/juggle.py
@@ -75,7 +75,7 @@ def start_juggler(fn=None, dbc=None, layout=None):
subprocess.call(cmd, shell=True, env=env, cwd=juggle_dir)
-def juggle_route(route_or_segment_name, segment_count, qlog, can, layout):
+def juggle_route(route_or_segment_name, segment_count, qlog, can, layout, dbc=None):
segment_start = 0
if 'cabana' in route_or_segment_name:
query = parse_qs(urlparse(route_or_segment_name).query)
@@ -113,14 +113,14 @@ def juggle_route(route_or_segment_name, segment_count, qlog, can, layout):
all_data = [d for d in all_data if d.which() not in ['can', 'sendcan']]
# Infer DBC name from logs
- dbc = None
- for cp in [m for m in all_data if m.which() == 'carParams']:
- try:
- DBC = __import__(f"selfdrive.car.{cp.carParams.carName}.values", fromlist=['DBC']).DBC
- dbc = DBC[cp.carParams.carFingerprint]['pt']
- except Exception:
- pass
- break
+ if dbc is None:
+ for cp in [m for m in all_data if m.which() == 'carParams']:
+ try:
+ DBC = __import__(f"selfdrive.car.{cp.carParams.carName}.values", fromlist=['DBC']).DBC
+ dbc = DBC[cp.carParams.carFingerprint]['pt']
+ except Exception:
+ pass
+ break
with tempfile.NamedTemporaryFile(suffix='.rlog', dir=juggle_dir) as tmp:
save_log(tmp.name, all_data, compress=False)
@@ -138,6 +138,7 @@ if __name__ == "__main__":
parser.add_argument("--stream", action="store_true", help="Start PlotJuggler in streaming mode")
parser.add_argument("--layout", nargs='?', help="Run PlotJuggler with a pre-defined layout")
parser.add_argument("--install", action="store_true", help="Install or update PlotJuggler + plugins")
+ parser.add_argument("--dbc", help="Set the DBC name to load for parsing CAN data. If not set, the DBC will be automatically inferred from the logs.")
parser.add_argument("route_or_segment_name", nargs='?', help="The route or segment name to plot (cabana share URL accepted)")
parser.add_argument("segment_count", type=int, nargs='?', help="The number of segments to plot")
@@ -158,4 +159,4 @@ if __name__ == "__main__":
start_juggler(layout=args.layout)
else:
route_or_segment_name = DEMO_ROUTE if args.demo else args.route_or_segment_name.strip()
- juggle_route(route_or_segment_name, args.segment_count, args.qlog, args.can, args.layout)
+ juggle_route(route_or_segment_name, args.segment_count, args.qlog, args.can, args.layout, args.dbc)
diff --git a/tools/replay/lib/ui_helpers.py b/tools/replay/lib/ui_helpers.py
index 33a1e77e05..d66fe79306 100644
--- a/tools/replay/lib/ui_helpers.py
+++ b/tools/replay/lib/ui_helpers.py
@@ -10,8 +10,7 @@ from matplotlib.backends.backend_agg import FigureCanvasAgg
from common.transformations.camera import (eon_f_frame_size, eon_f_focal_length,
tici_f_frame_size, tici_f_focal_length,
get_view_frame_from_calib_frame)
-from selfdrive.config import UIParams as UP
-from selfdrive.config import RADAR_TO_CAMERA
+from selfdrive.controls.lib.radar_helpers import RADAR_TO_CAMERA
RED = (255, 0, 0)
@@ -24,6 +23,15 @@ WHITE = (255, 255, 255)
_FULL_FRAME_SIZE = {
}
+class UIParams:
+ lidar_x, lidar_y, lidar_zoom = 384, 960, 6
+ lidar_car_x, lidar_car_y = lidar_x / 2., lidar_y / 1.1
+ car_hwidth = 1.7272 / 2 * lidar_zoom
+ car_front = 2.6924 * lidar_zoom
+ car_back = 1.8796 * lidar_zoom
+ car_color = 110
+UP = UIParams
+
_BB_TO_FULL_FRAME = {}
_CALIB_BB_TO_FULL = {}
_FULL_FRAME_TO_BB = {}
diff --git a/tools/replay/ui.py b/tools/replay/ui.py
index b39377ffdc..729d4cd0d8 100755
--- a/tools/replay/ui.py
+++ b/tools/replay/ui.py
@@ -10,8 +10,7 @@ import pygame # pylint: disable=import-error
import cereal.messaging as messaging
from common.numpy_fast import clip
from common.basedir import BASEDIR
-from selfdrive.config import UIParams as UP
-from tools.replay.lib.ui_helpers import (_BB_TO_FULL_FRAME,
+from tools.replay.lib.ui_helpers import (_BB_TO_FULL_FRAME, UP,
_INTRINSICS, BLACK, GREEN,
YELLOW, Calibration,
get_blank_lid_overlay, init_plots,
@@ -100,7 +99,7 @@ def ui_thread(addr):
draw_plots = init_plots(plot_arr, name_to_arr_idx, plot_xlims, plot_ylims, plot_names, plot_colors, plot_styles)
- vipc_client = VisionIpcClient("camerad", VisionStreamType.VISION_STREAM_RGB_BACK, True)
+ vipc_client = VisionIpcClient("camerad", VisionStreamType.VISION_STREAM_RGB_ROAD, True)
while 1:
list(pygame.event.get())
diff --git a/tools/sim/bridge.py b/tools/sim/bridge.py
index 2e19faefcd..ae6483fd28 100755
--- a/tools/sim/bridge.py
+++ b/tools/sim/bridge.py
@@ -67,7 +67,7 @@ class Camerad:
self.vipc_server = VisionIpcServer("camerad")
# TODO: remove RGB buffers once the last RGB vipc subscriber is removed
- self.vipc_server.create_buffers(VisionStreamType.VISION_STREAM_RGB_BACK, 4, True, W, H)
+ self.vipc_server.create_buffers(VisionStreamType.VISION_STREAM_RGB_ROAD, 4, True, W, H)
self.vipc_server.create_buffers(VisionStreamType.VISION_STREAM_ROAD, 40, False, W, H)
self.vipc_server.start_listener()
@@ -97,7 +97,7 @@ class Camerad:
eof = self.frame_id * 0.05
# TODO: remove RGB send once the last RGB vipc subscriber is removed
- self.vipc_server.send(VisionStreamType.VISION_STREAM_RGB_BACK, img.tobytes(), self.frame_id, eof, eof)
+ self.vipc_server.send(VisionStreamType.VISION_STREAM_RGB_ROAD, img.tobytes(), self.frame_id, eof, eof)
self.vipc_server.send(VisionStreamType.VISION_STREAM_ROAD, yuv.data.tobytes(), self.frame_id, eof, eof)
dat = messaging.new_message('roadCameraState')
diff --git a/update_requirements.sh b/update_requirements.sh
index ac9472dca2..94b14496f1 100755
--- a/update_requirements.sh
+++ b/update_requirements.sh
@@ -1,5 +1,4 @@
#!/bin/bash
-
set -e
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
@@ -45,10 +44,11 @@ echo "pip packages install..."
pipenv install --dev --deploy --clear
pyenv rehash
-if [ -f "$DIR/.pre-commit-config.yaml" ]; then
- echo "precommit install ..."
- $RUN pre-commit install
- [ -d "./xx" ] && (cd xx && $RUN pre-commit install)
- [ -d "./notebooks" ] && (cd notebooks && $RUN pre-commit install)
- echo "pre-commit hooks installed"
-fi
+echo "pre-commit hooks install..."
+shopt -s nullglob
+for f in .pre-commit-config.yaml */.pre-commit-config.yaml; do
+ cd $DIR/$(dirname $f)
+ if [ -e ".git" ]; then
+ $RUN pre-commit install
+ fi
+done