diff --git a/.gitignore b/.gitignore index b4385e16d..5fc18bb07 100644 --- a/.gitignore +++ b/.gitignore @@ -42,7 +42,6 @@ selfdrive/logcatd/logcatd selfdrive/mapd/default_speeds_by_region.json selfdrive/proclogd/proclogd selfdrive/ui/_ui -selfdrive/ui/_soundd selfdrive/test/longitudinal_maneuvers/out selfdrive/visiond/visiond selfdrive/loggerd/loggerd @@ -78,3 +77,7 @@ selfdrive/modeld/thneed/compile models/*.thneed *.bz2 + +build/ + +!**/.gitkeep diff --git a/Jenkinsfile b/Jenkinsfile index d41a1f904..bcdb7c99f 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -37,7 +37,7 @@ EOF""" def phone_steps(String device_type, steps) { lock(resource: "", label: device_type, inversePrecedence: true, variable: 'device_ip', quantity: 1) { - timeout(time: 150, unit: 'MINUTES') { + timeout(time: 60, unit: 'MINUTES') { phone(device_ip, "git checkout", readFile("selfdrive/test/setup_device_ci.sh"),) steps.each { item -> phone(device_ip, item[0], item[1]) @@ -53,7 +53,7 @@ pipeline { SOURCE_DIR = "/data/openpilot_source/" } options { - timeout(time: 3, unit: 'HOURS') + timeout(time: 4, unit: 'HOURS') } stages { @@ -145,10 +145,10 @@ pipeline { stages { stage('parallel tests') { parallel { - stage('Devel Tests') { + stage('C2: build') { steps { phone_steps("eon-build", [ - ["build devel", "cd $SOURCE_DIR/release && EXTRA_FILES='tools/' ./build_devel.sh"], + ["build master-ci", "cd $SOURCE_DIR/release && EXTRA_FILES='tools/' ./build_devel.sh"], ["build openpilot", "cd selfdrive/manager && ./build.py"], ["test manager", "python selfdrive/manager/test/test_manager.py"], ["onroad tests", "cd selfdrive/test/ && ./test_onroad.py"], @@ -157,7 +157,7 @@ pipeline { } } - stage('Replay Tests') { + stage('C2: replay') { steps { phone_steps("eon2", [ ["build", "cd selfdrive/manager && ./build.py"], @@ -166,7 +166,7 @@ pipeline { } } - stage('HW + Unit Tests') { + stage('C2: HW + Unit Tests') { steps { phone_steps("eon", [ ["build", "cd selfdrive/manager && ./build.py"], @@ -201,29 +201,33 @@ pipeline { } */ - stage('tici Build') { + stage('C3: build') { environment { R3_PUSH = "${env.BRANCH_NAME == 'master' ? '1' : ' '}" } steps { phone_steps("tici", [ - ["build", "cd selfdrive/manager && ./build.py"], + ["build master-ci", "cd $SOURCE_DIR/release && EXTRA_FILES='tools/' ./build_devel.sh"], + ["build openpilot", "cd selfdrive/manager && ./build.py"], + ["test manager", "python selfdrive/manager/test/test_manager.py"], ["onroad tests", "cd selfdrive/test/ && ./test_onroad.py"], + ["test car interfaces", "cd selfdrive/car/tests/ && ./test_car_interfaces.py"], ]) } } - stage('Unit Tests (tici)') { + stage('C3: HW + Unit Tests') { steps { phone_steps("tici2", [ ["build", "cd selfdrive/manager && ./build.py"], + ["test boardd loopback", "python selfdrive/boardd/tests/test_boardd_loopback.py"], ["test loggerd", "python selfdrive/loggerd/tests/test_loggerd.py"], ["test encoder", "LD_LIBRARY_PATH=/usr/local/lib python selfdrive/loggerd/tests/test_encoder.py"], ]) } } - stage('EON camerad') { + stage('C2: camerad') { steps { phone_steps("eon-party", [ ["build", "cd selfdrive/manager && ./build.py"], @@ -233,7 +237,7 @@ pipeline { } } - stage('tici camerad') { + stage('C3: camerad') { steps { phone_steps("tici-party", [ ["build", "cd selfdrive/manager && ./build.py"], diff --git a/README.md b/README.md index abe87a72f..b9a58f6a1 100755 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ Table of Contents What is openpilot? ------ -[openpilot](http://github.com/commaai/openpilot) is an open source driver assistance system. Currently, openpilot performs the functions of Adaptive Cruise Control (ACC), Automated Lane Centering (ALC), Forward Collision Warning (FCW) and Lane Departure Warning (LDW) for a growing variety of [supported car makes, models and model years](docs/CARS.md). In addition, while openpilot is engaged, a camera based Driver Monitoring (DM) feature alerts distracted and asleep drivers. See more about [the vehicle integration and limitations here](docs/INTEGRATION.md). +[openpilot](http://github.com/commaai/openpilot) is an open source driver assistance system. Currently, openpilot performs the functions of Adaptive Cruise Control (ACC), Automated Lane Centering (ALC), Forward Collision Warning (FCW) and Lane Departure Warning (LDW) for a growing variety of [supported car makes, models and model years](docs/CARS.md). In addition, while openpilot is engaged, a camera based Driver Monitoring (DM) feature alerts distracted and asleep drivers. See more about [the vehicle integration](docs/INTEGRATION.md) and [limitations](docs/LIMITATIONS.md). @@ -61,6 +61,8 @@ Community and Contributing openpilot is developed by [comma](https://comma.ai/) and by users like you. We welcome both pull requests and issues on [GitHub](http://github.com/commaai/openpilot). Bug fixes and new car ports are encouraged. Check out [the contributing docs](docs/CONTRIBUTING.md). +Documentation related to openpilot development can be found on [docs.comma.ai](https://docs.comma.ai). Information about running openpilot (e.g. FAQ, fingerprinting, troubleshooting, custom forks, community hardware) should go on the [wiki](https://github.com/commaai/openpilot/wiki). + You can add support for your car by following guides we have written for [Brand](https://blog.comma.ai/how-to-write-a-car-port-for-openpilot/) and [Model](https://blog.comma.ai/openpilot-port-guide-for-toyota-models/) ports. Generally, a car with adaptive cruise control and lane keep assist is a good candidate. [Join our Discord](https://discord.comma.ai) to discuss car ports: most car makes have a dedicated channel. Want to get paid to work on openpilot? [comma is hiring](https://comma.ai/jobs/). diff --git a/RELEASES.md b/RELEASES.md index 64f0814e2..12a90fba6 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,17 @@ +Version 0.8.11 (2021-11-29) +======================== + * Support for CAN FD on the red panda + * Support for an external panda on the comma three + * Navigation: Show more detailed instructions when approaching maneuver + * Fixed occasional steering faults on GM cars thanks to jyoung8607! + * Nissan ECU firmware fingerprinting thanks to robin-reckmann, martinl, and razem-io! + * Cadillac Escalade ESV 2016 support thanks to Gibby! + * Genesis G70 2020 support thanks to tecandrew! + * Hyundai Santa Fe Hybrid 2022 support thanks to sunnyhaibin! + * Mazda CX-9 2021 support thanks to Jacar! + * Volkswagen Polo 2020 support thanks to jyoung8607! + * Volkswagen T-Roc 2021 support thanks to jyoung8607! + Version 0.8.10 (2021-11-01) ======================== * New driving model diff --git a/SConstruct b/SConstruct index 18c8d2f12..67acd3eac 100644 --- a/SConstruct +++ b/SConstruct @@ -13,9 +13,9 @@ AddOption('--test', action='store_true', help='build test files') -AddOption('--setup', +AddOption('--extras', action='store_true', - help='build setup and installer files') + help='build misc extras, like setup and installer files') AddOption('--kaitai', action='store_true', @@ -68,6 +68,7 @@ lenv = { "PYTHONPATH": Dir("#").abspath + ":" + Dir("#pyextra/").abspath, "ACADOS_SOURCE_DIR": Dir("#third_party/acados/acados").abspath, + "ACADOS_PYTHON_INTERFACE_PATH": Dir("#pyextra/acados_template").abspath, "TERA_PATH": Dir("#").abspath + f"/third_party/acados/{arch}/t_renderer", } @@ -181,12 +182,14 @@ env = Environment( "-O2", "-Wunused", "-Werror", + "-Wshadow", "-Wno-unknown-warning-option", "-Wno-deprecated-register", "-Wno-register", "-Wno-inconsistent-missing-override", "-Wno-c99-designator", "-Wno-reorder-init-list", + "-Wno-error=unused-but-set-variable", ] + cflags + ccflags, CPPPATH=cpppath + [ @@ -267,7 +270,7 @@ def abspath(x): py_include = sysconfig.get_paths()['include'] envCython = env.Clone() envCython["CPPPATH"] += [py_include, np.get_include()] -envCython["CCFLAGS"] += ["-Wno-#warnings", "-Wno-deprecated-declarations"] +envCython["CCFLAGS"] += ["-Wno-#warnings", "-Wno-shadow", "-Wno-deprecated-declarations"] envCython["LIBS"] = [] if arch == "Darwin": @@ -429,6 +432,9 @@ SConscript(['selfdrive/ui/SConscript']) if arch != "Darwin": SConscript(['selfdrive/logcatd/SConscript']) +if GetOption('test'): + SConscript('panda/tests/safety/SConscript') + external_sconscript = GetOption('external_sconscript') if external_sconscript: SConscript([external_sconscript]) diff --git a/cereal/car.capnp b/cereal/car.capnp index d78acb28e..ce81c7eaf 100644 --- a/cereal/car.capnp +++ b/cereal/car.capnp @@ -104,6 +104,7 @@ struct CarEvent @0x9b1657f34caf3ad3 { wideRoadCameraError @102; localizerMalfunction @103; highCpuUsage @105; + cruiseMismatch @106; driverMonitorLowAccDEPRECATED @68; radarCanErrorDEPRECATED @15; @@ -150,6 +151,7 @@ struct CarState { # brake pedal, 0.0-1.0 brake @5 :Float32; # this is user pedal only brakePressed @6 :Bool; # this is user pedal only + brakeHoldActive @38 :Bool; # steering wheel steeringAngleDeg @7 :Float32; @@ -289,6 +291,8 @@ struct CarControl { active @7 :Bool; actuators @6 :Actuators; + roll @8 :Float32; + pitch @9 :Float32; cruiseControl @4 :CruiseControl; hudControl @5 :HUDControl; @@ -350,11 +354,11 @@ struct CarControl { chimeEngage @1; chimeDisengage @2; chimeError @3; - chimeWarning1 @4; - chimeWarning2 @5; - chimeWarningRepeat @6; + chimeWarning1 @4; # unused + chimeWarningRepeat @5; + chimeWarningRepeatInfinite @6; chimePrompt @7; - chimeWarning2Repeat @8; + chimeWarning2RepeatInfinite @8; } } diff --git a/cereal/log.capnp b/cereal/log.capnp index 8c6245ab5..92ec6429d 100644 --- a/cereal/log.capnp +++ b/cereal/log.capnp @@ -307,6 +307,7 @@ struct DeviceState @0xa4d8b5af2aa492eb { chargingDisabled @18 :Bool; offroadPowerUsageUwh @23 :UInt32; carBatteryCapacityUwh @25 :UInt32; + powerDrawW @40 :Float32; # device thermals cpuTempC @26 :List(Float32); @@ -315,11 +316,18 @@ struct DeviceState @0xa4d8b5af2aa492eb { ambientTempC @30 :Float32; nvmeTempC @35 :List(Float32); modemTempC @36 :List(Float32); + pmicTempC @39 :List(Float32); + thermalZones @38 :List(ThermalZone); thermalStatus @14 :ThermalStatus; fanSpeedPercentDesired @10 :UInt16; screenBrightnessPercent @37 :Int8; + struct ThermalZone { + name @0 :Text; + temp @1 :Float32; + } + enum ThermalStatus { green @0; yellow @1; @@ -685,6 +693,7 @@ struct ModelDataV2 { orientation @5 :XYZTData; velocity @6 :XYZTData; orientationRate @7 :XYZTData; + acceleration @19 :XYZTData; # prediction lanelines and road edges laneLines @8 :List(XYZTData); @@ -1285,6 +1294,7 @@ struct DriverMonitoringState @0xb83cda094a1da284 { struct Boot { wallTimeNanos @0 :UInt64; pstore @4 :Map(Text, Data); + commands @5 :Map(Text, Data); launchLog @3 :Text; lastKmsgDEPRECATED @1 :Data; @@ -1372,6 +1382,44 @@ struct UploaderState { lastFilename @6 :Text; } +struct NavInstruction { + maneuverPrimaryText @0 :Text; + maneuverSecondaryText @1 :Text; + maneuverDistance @2 :Float32; # m + maneuverType @3 :Text; # TODO: Make Enum + maneuverModifier @4 :Text; # TODO: Make Enum + + distanceRemaining @5 :Float32; # m + timeRemaining @6 :Float32; # s + timeRemainingTypical @7 :Float32; # s + + lanes @8 :List(Lane); + showFull @9 :Bool; + + struct Lane { + directions @0 :List(Direction); + active @1 :Bool; + activeDirection @2 :Direction; + } + + enum Direction { + none @0; + left @1; + right @2; + straight @3; + } + +} + +struct NavRoute { + coordinates @0 :List(Coordinate); + + struct Coordinate { + latitude @0 :Float32; + longitude @1 :Float32; + } +} + struct Event { logMonoTime @0 :UInt64; # nanoseconds valid @67 :Bool = true; @@ -1429,6 +1477,9 @@ struct Event { deviceState @6 :DeviceState; logMessage @18 :Text; + # navigation + navInstruction @82 :NavInstruction; + navRoute @83 :NavRoute; # *********** debug *********** testJoystick @52 :Joystick; diff --git a/cereal/services.py b/cereal/services.py index 4cf10a344..7b9287780 100755 --- a/cereal/services.py +++ b/cereal/services.py @@ -62,6 +62,8 @@ services = { "modelV2": (True, 20., 40), "managerState": (True, 2., 1), "uploaderState": (True, 0., 1), + "navInstruction": (True, 0.), + "navRoute": (True, 0.), # debug "testJoystick": (False, 0.), diff --git a/cereal/visionipc/visionbuf.cc b/cereal/visionipc/visionbuf.cc index 39c521913..e94a8bbc0 100644 --- a/cereal/visionipc/visionbuf.cc +++ b/cereal/visionipc/visionbuf.cc @@ -22,19 +22,28 @@ void visionbuf_compute_aligned_width_and_height(int width, int height, int *alig #endif } -void VisionBuf::init_rgb(size_t width, size_t height, size_t stride) { +void VisionBuf::init_rgb(size_t init_width, size_t init_height, size_t init_stride) { this->rgb = true; - this->width = width; - this->height = height; - this->stride = stride; + this->width = init_width; + this->height = init_height; + this->stride = init_stride; } -void VisionBuf::init_yuv(size_t width, size_t height){ +void VisionBuf::init_yuv(size_t init_width, size_t init_height){ this->rgb = false; - this->width = width; - this->height = height; + this->width = init_width; + this->height = init_height; this->y = (uint8_t *)this->addr; - this->u = this->y + (width * height); - this->v = this->u + (width / 2 * height / 2); + this->u = this->y + (this->width * this->height); + this->v = this->u + (this->width / 2 * this->height / 2); +} + + +uint64_t VisionBuf::get_frame_id() { + return *frame_id; +} + +void VisionBuf::set_frame_id(uint64_t id) { + *frame_id = id; } diff --git a/cereal/visionipc/visionbuf.h b/cereal/visionipc/visionbuf.h index 165a3dbdd..418cbacb9 100644 --- a/cereal/visionipc/visionbuf.h +++ b/cereal/visionipc/visionbuf.h @@ -18,6 +18,7 @@ enum VisionStreamType { VISION_STREAM_YUV_BACK, VISION_STREAM_YUV_FRONT, VISION_STREAM_YUV_WIDE, + VISION_STREAM_RGB_MAP, VISION_STREAM_MAX, }; @@ -26,6 +27,7 @@ class VisionBuf { size_t len = 0; size_t mmap_len = 0; void * addr = nullptr; + uint64_t *frame_id; int fd = 0; bool rgb = false; @@ -57,6 +59,9 @@ class VisionBuf { void init_yuv(size_t width, size_t height); int sync(int dir); int free(); + + void set_frame_id(uint64_t id); + uint64_t get_frame_id(); }; void visionbuf_compute_aligned_width_and_height(int width, int height, int *aligned_w, int *aligned_h); diff --git a/cereal/visionipc/visionbuf_cl.cc b/cereal/visionipc/visionbuf_cl.cc index c203c944c..0286d28fd 100644 --- a/cereal/visionipc/visionbuf_cl.cc +++ b/cereal/visionipc/visionbuf_cl.cc @@ -32,14 +32,11 @@ static void *malloc_with_fd(size_t len, int *fd) { return addr; } -void VisionBuf::allocate(size_t len) { - int fd; - void *addr = malloc_with_fd(len, &fd); - - this->len = len; - this->mmap_len = len; - this->addr = addr; - this->fd = fd; +void VisionBuf::allocate(size_t length) { + this->len = length; + this->mmap_len = this->len; + this->addr = malloc_with_fd(this->len, &this->fd); + this->frame_id = (uint64_t*)((uint8_t*)this->addr + this->len); } void VisionBuf::init_cl(cl_device_id device_id, cl_context ctx){ @@ -57,6 +54,8 @@ void VisionBuf::import(){ assert(this->fd >= 0); this->addr = mmap(NULL, this->mmap_len, PROT_READ | PROT_WRITE, MAP_SHARED, this->fd, 0); assert(this->addr != MAP_FAILED); + + this->frame_id = (uint64_t*)((uint8_t*)this->addr + this->len); } diff --git a/cereal/visionipc/visionbuf_ion.cc b/cereal/visionipc/visionbuf_ion.cc index c367304e9..c66b668c6 100644 --- a/cereal/visionipc/visionbuf_ion.cc +++ b/cereal/visionipc/visionbuf_ion.cc @@ -47,13 +47,13 @@ static void ion_init() { } } -void VisionBuf::allocate(size_t len) { +void VisionBuf::allocate(size_t length) { int err; ion_init(); struct ion_allocation_data ion_alloc = {0}; - ion_alloc.len = len + PADDING_CL; + ion_alloc.len = length + PADDING_CL + sizeof(uint64_t); ion_alloc.align = 4096; ion_alloc.heap_id_mask = 1 << ION_IOMMU_HEAP_ID; ion_alloc.flags = ION_FLAG_CACHED; @@ -66,18 +66,19 @@ void VisionBuf::allocate(size_t len) { err = HANDLE_EINTR(ioctl(ion_fd, ION_IOC_SHARE, &ion_fd_data)); assert(err == 0); - void *addr = mmap(NULL, ion_alloc.len, - PROT_READ | PROT_WRITE, - MAP_SHARED, ion_fd_data.fd, 0); - assert(addr != MAP_FAILED); + void *mmap_addr = mmap(NULL, ion_alloc.len, + PROT_READ | PROT_WRITE, + MAP_SHARED, ion_fd_data.fd, 0); + assert(mmap_addr != MAP_FAILED); - memset(addr, 0, ion_alloc.len); + memset(mmap_addr, 0, ion_alloc.len); - this->len = len; + this->len = length; this->mmap_len = ion_alloc.len; - this->addr = addr; + this->addr = mmap_addr; this->handle = ion_alloc.handle; this->fd = ion_fd_data.fd; + this->frame_id = (uint64_t*)((uint8_t*)this->addr + this->len + PADDING_CL); } void VisionBuf::import(){ @@ -95,6 +96,8 @@ void VisionBuf::import(){ this->handle = fd_data.handle; this->addr = mmap(NULL, this->mmap_len, PROT_READ | PROT_WRITE, MAP_SHARED, this->fd, 0); assert(this->addr != MAP_FAILED); + + this->frame_id = (uint64_t*)((uint8_t*)this->addr + this->len + PADDING_CL); } void VisionBuf::init_cl(cl_device_id device_id, cl_context ctx) { diff --git a/cereal/visionipc/visionipc_server.cc b/cereal/visionipc/visionipc_server.cc index fdacd7843..e15c1aee4 100644 --- a/cereal/visionipc/visionipc_server.cc +++ b/cereal/visionipc/visionipc_server.cc @@ -45,7 +45,6 @@ void VisionIpcServer::create_buffers(VisionStreamType type, size_t num_buffers, size = width * height * 3 / 2; } - // Create map + alloc requested buffers for (size_t i = 0; i < num_buffers; i++){ VisionBuf* buf = new VisionBuf(); diff --git a/cereal/visionipc/visionipc_tests.cc b/cereal/visionipc/visionipc_tests.cc index c2cd43da2..a68bda0b8 100644 --- a/cereal/visionipc/visionipc_tests.cc +++ b/cereal/visionipc/visionipc_tests.cc @@ -68,6 +68,7 @@ TEST_CASE("Send single buffer"){ VisionIpcBufExtra extra = {0}; extra.frame_id = 1337; + buf->set_frame_id(extra.frame_id); server.send(buf, &extra); @@ -76,6 +77,7 @@ TEST_CASE("Send single buffer"){ REQUIRE(recv_buf != nullptr); REQUIRE(*(uint64_t*)recv_buf->addr == 1234); REQUIRE(extra_recv.frame_id == extra.frame_id); + REQUIRE(recv_buf->get_frame_id() == extra.frame_id); } diff --git a/common/markdown.py b/common/markdown.py new file mode 100755 index 000000000..30c5bc2c0 --- /dev/null +++ b/common/markdown.py @@ -0,0 +1,48 @@ +from typing import List + +HTML_REPLACEMENTS = [ + (r'&', r'&'), + (r'"', r'"'), +] + + +def parse_markdown(text: str, tab_length: int = 2) -> str: + lines = text.split("\n") + output: List[str] = [] + list_level = 0 + + def end_outstanding_lists(level: int, end_level: int) -> int: + while level > end_level: + level -= 1 + output.append("") + if level > 0: + output.append("") + return end_level + + for i, line in enumerate(lines): + if i + 1 < len(lines) and lines[i + 1].startswith("==="): # heading + output.append(f"

{line}

") + elif line.startswith("==="): + pass + elif line.lstrip().startswith("* "): # list + line_level = 1 + line.count(" " * tab_length, 0, line.index("*")) + if list_level >= line_level: + list_level = end_outstanding_lists(list_level, line_level) + else: + list_level += 1 + if list_level > 1: + output[-1] = output[-1].replace("", "") + output.append("