diff --git a/README.md b/README.md
index 519abc75ad7fbc..20dcf47e85a2c0 100644
--- a/README.md
+++ b/README.md
@@ -13,13 +13,14 @@ Here's how to flash back to v9 NEOS if you want to downgrade (it's not that bad)
NOTICE: Due to feedback I have turned on OTA updates. You will receive updates automatically (after rebooting 2X) on your Eon so you don't have to reclone or git pull any longer to receive new features *MADE BETWEEN COMMA RELEASES*. The reason why I separate the branches by release is because some releases can sometimes cause issues. Features that I or others add, will continue to be updated when you are on the most current release. If you DO NOT want OTA updates then create a file called "/data/no_ota_updates" and it will not perform OTA updates as long as that file exists.
+GM Users: Execute the script, `selfdrive/car/lock_safety_model.py gm` from the root directory of this Openpilot installation. This sets the Panda safety mode to `gm` (from the default of `noOutput`), allowing OP to control the vehicle. Otherwise a "Steering Temporarily Unavailable" error is thrown when attempting to enagage OP.
I will attempt to detail the changes in each of the branches here:
kegman - this is the default branch which does not include Gernby's resonant feed forward steering (i.e. it's comma's default steering)
-kegman-noAEB - this branch disables the Honda Nidec AEB passthrough introduced in 0.6.4 as it gives problems and unexpectedly brakes on tight curves and oncoming traffic.
+kegman-plusBoschGasPress - this branch gives Honda Bosch users the ability to press the gas without disengaging OP for more "stock ACC"-like behaviour. Remember to manually flash panda after checking out. cd /data/openpilot/panda/board && pkill -f boardd && make - then reboot.
kegman-stockUI - for 0.6 some people were having trouble with devUI so I separated the branches out.
@@ -39,15 +40,28 @@ I will attempt to detail the changes in each of the branches here:
List of changes and tweaks (latest changes at the top):
+- New! Adjustable stopping distance, one, two, and three bar distance intervals: BE CAREFUL WITH THESE OPTIONAL SETTINGS IN kegman.json! Add ONE_BAR_DISTANCE, TWO_BAR_DISTANCE, THREE_BAR_DISTANCE, FOUR_BAR_DISTANCE values in kegman.json to change the following distance interval. Add STOPPING_DISTANCE to change the distance between you and the lead car at a stop. If these values do not exist in kegman.json, they just assume default values of 0.9, 1.3, 1.8, 2.3, and 2 respectively. Thanks to @joeljacobs for adding the optional distance intervals.
+
+- New! Disable Auto Emergency Braking (Nidec Hondas): Since 0.6.4 Comma passes through the AEB signal. This causes unexpected emergency braking on 2 lane highways with oncoming traffic and is unsafe. I have disabled this. Ensure that you reflash you Panda if you get AEBs: cd /data/openpilot/panda/board && pkill -f boardd && make - after a successful flash, reboot.
+
- New! Toyota support: Thanks to @j4z for adding distance interval support with his Arduino solution and also helping to debug the kegman.json issues to make Kegman fork work with Toyotas!
- New! Added highway speed braking profile tweaks. Note that 1barHwy, 2barHwy and 3barHwy are DELTAS. For example if One bar distance is 0.9 seconds, 1barHwy of 0.3 will add 3 seconds to the distance during braking making you brake harder.
- New! Added kF feedforward param to live tuner.
-- New! Enable / Disable Model based Slowdowns on turns: On tight turns, the model will slow down the car so that you can make the turn. Some like this, some people don't. Set slowOnCurve = "1" to enable slowdowns on curves, or "0" (default) to disable.
+- New! Enable / Disable Model based Slowdowns on turns: On tight turns, the model will slow down the car so that you can make the turn. Some like this, some people don't. Set slowOnCurve = "1" to enable slowdowns on curves, or "0" (default) to disable.
+
+- New! Live long tuning for city speeds < 19.44 m/s (43.5 mph, 70 km/h): Execute cd /data/openpilot && ./tune.sh to access live tuner on your mobile device while driving.
-- New! Live long tuning for city speeds < 19.44 m/s : Execute cd /data/openpilot && ./tune.sh to access live tuner on your mobile device while driving.
+Instructions for tuning steering with live tuner:
+- Kp too high = the car overshoots and undershoots center
+- Kp too low = the car doesn't turn enough
+- Ki - dampens the overshoot / undershoot of Kp and allows the car to be centered faster, allowing for a higher Kp value
+- Ki too high = it gets to center without oscillations, but it takes too long to center. If you hit a bump or give the wheel a quick nudge, it should oscillate 3 - 5 times before coming to steady-state. If the wheel oscillates forever (critically damped), then your Kp or Ki or both are too high.
+- SteerRatio - too high, and the car ping pongs on straights and turns, too low, and the car doesn't turn enough on curves. If you're on a turn and the wheel is oversteering and then correcting, steerRatio is too high, and it's fighting with Kp and Ki (which you don't want) - although in the past I've been able to have an oscillating oversteering tune which could do tighter turns, but the turns werent pleasant.
+- Kf - lower this if your car oscillates and you've done everything else. It can be lowered to 0
+- All of these parameters interact with each other so finding the balance is a bit experimental
Be careful and ready to take over at any time when doing this!!! The "distance" in s is the target distance the car will try to maintain. The default distancces are 0.9s, 1.3s, 1.8s for 1,2 and 3 bar intervals. I manipulate this value to pass to the MPC to scale the behavior which leads to harder braking or sooner braking or softer braking. Essentially when you are approaching a car, the distance changes depending on your approach speed. When the lead car pulls away, the distance returns to whatever your bar setting is
@@ -69,19 +83,10 @@ Example:
Everything inbetween -0.25 m/s and 3 m/s is interpolated, which adjusts the distance smoothly as you slow down depending on the lead car approach relative speed.
-
-- (Not functional in 0.6.x yet) Toggle Comma's live tuning: Comma live tunes things like alignment, steerRatio etc. But sometimes it doesn't converge to the right value and throws lane centering off during turns. This allows you to use /data/openpilot/.tune.sh to toggle the auto-tune to off when the car feels right so that it doesn't tune the car any further than necessary.
-
- Highway speed braking profiles: Added highway braking profiles so that you won't follow so closely at speeds > 70 kph. This affects kegman-0.5.8-gold, kegman-0.5.11, kegman-plusGernbySteering-0.5.11, kegman-0.12, kegman-0.13-stockUI, kegman-0.6 kegman-plusGernbySteering-0.6 branches only.
- Live tuner for Kp and Ki: Tune your Kp and Ki values live using your cell phone by SSHing into the Eon and executing cd /data/openpilot && ./tune.sh
-- Kill services if plugged in and Eon batt < kegman.json --> battPercOff Shutting down of the Eon never worked on Nidec vehicles because the Panda always supplies power. When Eon senses power it just starts up again. So I have mitigated the power drain by about 40% when it is discharging in the car. Reminder that the Eon continues to charge cycling between battChargeMax and battChargeMin in the /data/kegman.json file. If the car battery falls below carVoltageMinEonShutdown in the /data/kegman.json file WHILE CHARGING THE EON then charging is disabled. As charging is disabled, the Eon battery will continue to drain until it reaches battPercOff (again in /data/kegman.json) at which point it will shut down services to conserve power. This will not prevent the Eon from discharging completely but will cut the drainage by about 40%, buying you some more time before it goes dead. If the Eon is in this "Power Saving" mode you will need to reboot the Eon by pressing on the power button and touching somewhere near the center of the screen (note that the screen will note work). Also note that if you unplug the Eon and the battery is below battPercOff it will shutdown. If you reboot the Eon while unplugged, it will give you 3 minutes until it shuts down again unless it is plugged in during this time. If you unplugged the Eon and forgot to turn it off, it will shutdown when the battery falls below battPercOff. Hopefully this mitigates the "dead Eon" syndrome that occurs when people have trouble powering their device back up after the battery is completely drained.
-
-For Bosch vehicles, the Eon will just simply shutdown as usual when battery falls below battPercOff. Killing of services only occurs for Nidecs.
-
-
-
- Add @pjlao307's Dashcam Recording: Sometimes you just want to record a wicked OP run on a twisty highway to show your friends. Sometimes you want to record a big flashing red error and complain about it and show your friends. This does a screen video capture of the Eon screen and stores the files in /sdcard/videos on your Eon when the REC button is pressed. Thanks to @pjlao307 and @theantihero for submitting the PR.
- Stop logging when space hits 18% free space: Thanks to @emmertex for this easy fix to stop the Eon from filling up while driving when free space is low.
@@ -89,9 +94,7 @@ For Bosch vehicles, the Eon will just simply shutdown as usual when battery fall
- Added primitive tuning script: To invoke live tuning: (a) turn on tethering on your Eon, (b) install JuiceSSH or similar and connect your cellphone to the wifi of the Eon using 192.168.43.1 and import the Comma private key, (c) in JuiceSSH in the SSH session on the Eon issue cd /data/openpilot command, then ./tune.sh. The text UI will be shown. (d) turn "tuneGernby" to a "1" (e) start driving and change the values to tune your steering. It is best to have a cell phone mount in your car. Note: It takes 3 seconds for any changes to take effect.
- Replaced dev UI with @perpetuoviator dev UI with brake light icon by @berno22 - Thank you both! NOTE: There are lots of conveniences in this UI. When the car is on, you have to press the top left corner to get to the Settings screen. If you tap the lower right corner you can see the tmux session. The brake light icon doesn't work properly with some cars (needs a fingerprint tweak I believe. The wifi IP address and upload speed is printed on the screen. The brake icon is so that you can see if OP is causing the brake lights to turn on and off and pissing the guy or gal off behind you. NOTE: For GM vehicles, the brake icon indicates use of the friction brakes on the vehicle instead of the brake lights themselves.
-UI touch controls:
-[Acess "EON Settings" by touching the top left hand corner (left side of the Speed Limit sign)]
-[Acess "TmuxLog" by touching the bottom right hand corner]
+
- Added moar JSON parameters:
@@ -181,5 +184,3 @@ Enjoy everyone.
NOTE: If you have upgraded at any time to v0.5.10, v0.6.x and you want to go back to a branch with v0.5.9 or v0.5.8, then you have to SSH into the Eon and edit the file /data/params/d/ControlsParams and rename "angle_model_bias" to "angle_offset" or your car will have Dash Errors and you'll be scratching your head for hours!
Pedal Users: Also note that you need to flash your Pedal to go to v0.5.10. If you want to go back to 0.5.9 or 0.5.8 you need to flash your pedal back to 0.5.9. Instructions are here: https://medium.com/@jfrux/comma-pedal-updating-the-firmware-over-can-fa438a3cf910. Also. After you flash your Pedal.. All hell will break loose on your dash. Traction control error, Power Steering Error, Trailer Error, OMFG the sky is falling error etc. DON'T PANIC. Just drive around a bit and it will disappear after about 2-3 restarts of the car. Don't rush it I believe it's time dependent as well. Just drive as normal. They'll go away.
-
-
diff --git a/common/dbc.py b/common/dbc.py
index d25e7be21b1fdb..aa52e40671aca2 100755
--- a/common/dbc.py
+++ b/common/dbc.py
@@ -147,22 +147,20 @@ def encode(self, msg_id, dd):
ival = dd.get(s.name)
if ival is not None:
- b2 = s.size
- if s.is_little_endian:
- b1 = s.start_bit
- else:
- b1 = (s.start_bit // 8) * 8 + (-s.start_bit - 1) % 8
- bo = 64 - (b1 + s.size)
-
ival = (ival / s.factor) - s.offset
ival = int(round(ival))
if s.is_signed and ival < 0:
- ival = (1 << b2) + ival
+ ival = (1 << s.size) + ival
- shift = b1 if s.is_little_endian else bo
- mask = ((1 << b2) - 1) << shift
- dat = (ival & ((1 << b2) - 1)) << shift
+ if s.is_little_endian:
+ shift = s.start_bit
+ else:
+ b1 = (s.start_bit // 8) * 8 + (-s.start_bit - 1) % 8
+ shift = 64 - (b1 + s.size)
+
+ mask = ((1 << s.size) - 1) << shift
+ dat = (ival & ((1 << s.size) - 1)) << shift
if s.is_little_endian:
mask = self.reverse_bytes(mask)
@@ -222,30 +220,24 @@ def decode(self, x, arr=None, debug=False):
factor = s[5]
offset = s[6]
- b2 = signal_size
- if little_endian:
- b1 = start_bit
- else:
- b1 = (start_bit // 8) * 8 + (-start_bit - 1) % 8
- bo = 64 - (b1 + signal_size)
-
if little_endian:
if le is None:
le = struct.unpack("Q", st)[0]
- shift_amount = bo
tmp = be
+ b1 = (start_bit // 8) * 8 + (-start_bit - 1) % 8
+ shift_amount = 64 - (b1 + signal_size)
if shift_amount < 0:
continue
- tmp = (tmp >> shift_amount) & ((1 << b2) - 1)
- if signed and (tmp >> (b2 - 1)):
- tmp -= (1 << b2)
+ tmp = (tmp >> shift_amount) & ((1 << signal_size) - 1)
+ if signed and (tmp >> (signal_size - 1)):
+ tmp -= (1 << signal_size)
tmp = tmp * factor + offset
diff --git a/common/params.py b/common/params.py
index 3c5a63786caf71..6065c8c1adbfbc 100755
--- a/common/params.py
+++ b/common/params.py
@@ -80,6 +80,7 @@ class UnknownKeyName(Exception):
"Passive": [TxType.PERSISTENT],
"RecordFront": [TxType.PERSISTENT],
"ReleaseNotes": [TxType.PERSISTENT],
+ "SafetyModelLock": [TxType.PERSISTENT],
"ShouldDoUpdate": [TxType.CLEAR_ON_MANAGER_START],
"SpeedLimitOffset": [TxType.PERSISTENT],
"SubscriberInfo": [TxType.PERSISTENT],
diff --git a/opendbc/honda_accord_touring_2016_can.dbc b/opendbc/honda_accord_touring_2016_can.dbc
index e8f388de08692c..744e55a9b5e3b5 100644
--- a/opendbc/honda_accord_touring_2016_can.dbc
+++ b/opendbc/honda_accord_touring_2016_can.dbc
@@ -177,14 +177,14 @@ BO_ 597 ROUGH_WHEEL_SPEED: 8 VSA
SG_ SET_TO_X55_2 : 47|8@0+ (1,0) [0|255] "" NEO
SG_ LONG_COUNTER : 55|8@0+ (1,0) [0|255] "" XXX
SG_ COUNTER : 61|2@0+ (1,0) [0|3] "" XXX
- SG_ CHECKSUM : 59|4@1+ (1,0) [0|15] "" XXX
+ SG_ CHECKSUM : 59|4@0+ (1,0) [0|15] "" XXX
BO_ 660 SCM_COMMANDS: 8 SCM
SG_ RIGHT_BLINKER : 6|1@0+ (1,0) [0|1] "" NEO
SG_ LEFT_BLINKER : 5|1@0+ (1,0) [0|1] "" NEO
SG_ WIPERS_SPEED : 4|2@0+ (1,0) [0|3] "" NEO
SG_ COUNTER : 61|2@0+ (1,0) [0|3] "" XXX
- SG_ CHECKSUM : 59|4@1+ (1,0) [0|15] "" XXX
+ SG_ CHECKSUM : 59|4@0+ (1,0) [0|15] "" XXX
BO_ 661 XXX_10: 4 XXX
SG_ COUNTER : 29|2@0+ (1,0) [0|3] "" XXX
diff --git a/selfdrive/boardd/boardd.cc b/selfdrive/boardd/boardd.cc
index bd60c34087184a..fde2b3ea21ca2d 100644
--- a/selfdrive/boardd/boardd.cc
+++ b/selfdrive/boardd/boardd.cc
@@ -49,6 +49,7 @@ const uint32_t NO_IGNITION_CNT_MAX = 2 * 60 * 60 * 24 * 3; // turn off charge a
uint32_t no_ignition_cnt = 0;
bool connected_once = false;
uint8_t ignition_last = 0;
+bool safety_model_locked = false;
pthread_t safety_setter_thread_handle = -1;
pthread_t pigeon_thread_handle = -1;
@@ -74,12 +75,12 @@ void *safety_setter_thread(void *s) {
}
LOGW("got CarVin %s", value_vin);
- pthread_mutex_lock(&usb_lock);
-
// VIN query done, stop listening to OBDII
- libusb_control_transfer(dev_handle, 0x40, 0xdc, (uint16_t)(cereal::CarParams::SafetyModel::NO_OUTPUT), 0, NULL, 0, TIMEOUT);
-
- pthread_mutex_unlock(&usb_lock);
+ if (!safety_model_locked) {
+ pthread_mutex_lock(&usb_lock);
+ libusb_control_transfer(dev_handle, 0x40, 0xdc, (uint16_t)(cereal::CarParams::SafetyModel::NO_OUTPUT), 0, NULL, 0, TIMEOUT);
+ pthread_mutex_unlock(&usb_lock);
+ }
char *value;
size_t value_sz = 0;
@@ -125,6 +126,11 @@ void *safety_setter_thread(void *s) {
bool usb_connect() {
int err;
unsigned char hw_query[1] = {0};
+ char *value_safety_model;
+ size_t value_safety_model_sz = 0;
+ int safety_model;
+ const int result = read_db_value(NULL, "SafetyModelLock", &value_safety_model, &value_safety_model_sz);
+
ignition_last = 0;
dev_handle = libusb_open_device_with_vid_pid(ctx, 0xbbaa, 0xddcc);
@@ -140,6 +146,16 @@ bool usb_connect() {
libusb_control_transfer(dev_handle, 0xc0, 0xe5, 1, 0, NULL, 0, TIMEOUT);
}
+ // check if safety mode is forced (needed to support gm)
+ if (value_safety_model_sz > 0) {
+ sscanf(value_safety_model, "%d", &safety_model);
+ // sanity check that we are not setting all output
+ assert(safety_model != (int)(cereal::CarParams::SafetyModel::ALL_OUTPUT));
+ safety_model_locked = true;
+ LOGW("Setting Locked Safety Model %s", value_safety_model);
+ libusb_control_transfer(dev_handle, 0x40, 0xdc, (uint16_t)(cereal::CarParams::SafetyModel(safety_model)), 0, NULL, 0, TIMEOUT);
+ }
+
// power off ESP
libusb_control_transfer(dev_handle, 0xc0, 0xd9, 0, 0, NULL, 0, TIMEOUT);
@@ -297,10 +313,11 @@ void can_health(void *s) {
assert((result == 0) || (result == ERR_NO_VALUE));
// diagnostic only is the default, needed for VIN query
- pthread_mutex_lock(&usb_lock);
- libusb_control_transfer(dev_handle, 0x40, 0xdc, (uint16_t)(cereal::CarParams::SafetyModel::ELM327), 0, NULL, 0, TIMEOUT);
- pthread_mutex_unlock(&usb_lock);
-
+ if (!safety_model_locked) {
+ pthread_mutex_lock(&usb_lock);
+ libusb_control_transfer(dev_handle, 0x40, 0xdc, (uint16_t)(cereal::CarParams::SafetyModel::ELM327), 0, NULL, 0, TIMEOUT);
+ pthread_mutex_unlock(&usb_lock);
+ }
if (safety_setter_thread_handle == -1) {
err = pthread_create(&safety_setter_thread_handle, NULL, safety_setter_thread, NULL);
assert(err == 0);
diff --git a/selfdrive/can/common.h b/selfdrive/can/common.h
index 4f097228432543..d6c2e4760bd40a 100644
--- a/selfdrive/can/common.h
+++ b/selfdrive/can/common.h
@@ -7,11 +7,13 @@
#define ARRAYSIZE(x) (sizeof(x)/sizeof(x[0]))
-
unsigned int honda_checksum(unsigned int address, uint64_t d, int l);
unsigned int toyota_checksum(unsigned int address, uint64_t d, int l);
unsigned int pedal_checksum(unsigned int address, uint64_t d, int l);
+void init_crc_lookup_tables();
+unsigned int volkswagen_crc(unsigned int address, uint64_t d, int l);
+
struct SignalPackValue {
const char* name;
double value;
@@ -44,6 +46,8 @@ enum SignalType {
TOYOTA_CHECKSUM,
PEDAL_CHECKSUM,
PEDAL_COUNTER,
+ VOLKSWAGEN_CHECKSUM,
+ VOLKSWAGEN_COUNTER,
};
struct Signal {
diff --git a/selfdrive/can/dbc_template.cc b/selfdrive/can/dbc_template.cc
index 776403b22f03ff..be249012e36d83 100644
--- a/selfdrive/can/dbc_template.cc
+++ b/selfdrive/can/dbc_template.cc
@@ -31,6 +31,10 @@ const Signal sigs_{{address}}[] = {
.type = SignalType::PEDAL_CHECKSUM,
{% elif address in [512, 513] and sig.name == "COUNTER_PEDAL" %}
.type = SignalType::PEDAL_COUNTER,
+ {% elif checksum_type == "volkswagen" and sig.name == "CHECKSUM" %}
+ .type = SignalType::VOLKSWAGEN_CHECKSUM,
+ {% elif checksum_type == "volkswagen" and sig.name == "COUNTER" %}
+ .type = SignalType::VOLKSWAGEN_COUNTER,
{% else %}
.type = SignalType::DEFAULT,
{% endif %}
diff --git a/selfdrive/can/libdbc_py.py b/selfdrive/can/libdbc_py.py
index fbf36a3d4d0764..36713eab0fd60c 100644
--- a/selfdrive/can/libdbc_py.py
+++ b/selfdrive/can/libdbc_py.py
@@ -41,6 +41,8 @@
TOYOTA_CHECKSUM,
PEDAL_CHECKSUM,
PEDAL_COUNTER,
+ VOLKSWAGEN_CHECKSUM,
+ VOLKSWAGEN_COUNTER,
} SignalType;
typedef struct {
diff --git a/selfdrive/can/packer.cc b/selfdrive/can/packer.cc
index d0e84197887a8f..88fca77da05c3f 100644
--- a/selfdrive/can/packer.cc
+++ b/selfdrive/can/packer.cc
@@ -51,6 +51,8 @@ namespace {
signal_lookup[std::make_pair(msg->address, std::string(sig->name))] = *sig;
}
}
+
+ init_crc_lookup_tables();
}
uint64_t pack(uint32_t address, const std::vector &signals, int counter) {
@@ -82,23 +84,30 @@ namespace {
}
auto sig = sig_it->second;
- if (sig.type != SignalType::HONDA_COUNTER){
+ if ((sig.type != SignalType::HONDA_COUNTER) && (sig.type != SignalType::VOLKSWAGEN_COUNTER)) {
WARN("COUNTER signal type not valid\n");
}
ret = set_value(ret, sig, counter);
}
- auto sig_it = signal_lookup.find(std::make_pair(address, "CHECKSUM"));
- if (sig_it != signal_lookup.end()) {
- auto sig = sig_it->second;
- if (sig.type == SignalType::HONDA_CHECKSUM){
+ auto sig_it_checksum = signal_lookup.find(std::make_pair(address, "CHECKSUM"));
+ if (sig_it_checksum != signal_lookup.end()) {
+ auto sig = sig_it_checksum->second;
+ if (sig.type == SignalType::HONDA_CHECKSUM) {
unsigned int chksm = honda_checksum(address, ret, message_lookup[address].size);
ret = set_value(ret, sig, chksm);
}
- else if (sig.type == SignalType::TOYOTA_CHECKSUM){
+ else if (sig.type == SignalType::TOYOTA_CHECKSUM) {
unsigned int chksm = toyota_checksum(address, ret, message_lookup[address].size);
ret = set_value(ret, sig, chksm);
+ }
+ else if (sig.type == SignalType::VOLKSWAGEN_CHECKSUM) {
+ // FIXME: Hackish fix for an endianness issue. The message is in reverse byte order
+ // until later in the pack process. Checksums can be run backwards, CRCs not so much.
+ // The correct fix is unclear but this works for the moment.
+ unsigned int chksm = volkswagen_crc(address, ReverseBytes(ret), message_lookup[address].size);
+ ret = set_value(ret, sig, chksm);
} else {
//WARN("CHECKSUM signal type not valid\n");
}
diff --git a/selfdrive/can/packer_impl.pyx b/selfdrive/can/packer_impl.pyx
index 7429338ac40721..d7c6119b753874 100644
--- a/selfdrive/can/packer_impl.pyx
+++ b/selfdrive/can/packer_impl.pyx
@@ -20,7 +20,9 @@ ctypedef enum SignalType:
HONDA_COUNTER,
TOYOTA_CHECKSUM,
PEDAL_CHECKSUM,
- PEDAL_COUNTER
+ PEDAL_COUNTER,
+ VOLKSWAGEN_CHECKSUM,
+ VOLKSWAGEN_COUNTER
cdef struct Signal:
const char* name
diff --git a/selfdrive/can/parser.cc b/selfdrive/can/parser.cc
index 830e8b14c066e9..f07aab8e569898 100644
--- a/selfdrive/can/parser.cc
+++ b/selfdrive/can/parser.cc
@@ -24,9 +24,11 @@
// #define DEBUG printf
#define INFO printf
-
#define MAX_BAD_COUNTER 5
+// Static lookup table for fast computation of CRC8 poly 0x2F, aka 8H2F/AUTOSAR
+uint8_t crc8_lut_8h2f[256];
+
unsigned int honda_checksum(unsigned int address, uint64_t d, int l) {
d >>= ((8-l)*8); // remove padding
d >>= 4; // remove checksum
@@ -75,6 +77,98 @@ unsigned int pedal_checksum(unsigned int address, uint64_t d, int l) {
return crc;
}
+void gen_crc_lookup_table(uint8_t poly, uint8_t crc_lut[])
+{
+ uint8_t crc;
+ int i, j;
+
+ for (i = 0; i < 256; i++) {
+ crc = i;
+ for (j = 0; j < 8; j++) {
+ if ((crc & 0x80) != 0)
+ crc = (uint8_t)((crc << 1) ^ poly);
+ else
+ crc <<= 1;
+ }
+ crc_lut[i] = crc;
+ }
+}
+
+void init_crc_lookup_tables()
+{
+ // At init time, set up static lookup tables for fast CRC computation.
+
+ gen_crc_lookup_table(0x2F, crc8_lut_8h2f); // CRC-8 8H2F/AUTOSAR for Volkswagen
+}
+
+unsigned int volkswagen_crc(unsigned int address, uint64_t d, int l)
+{
+ // Volkswagen uses standard CRC8 8H2F/AUTOSAR, but they compute it with
+ // a magic variable padding byte tacked onto the end of the payload.
+ // https://www.autosar.org/fileadmin/user_upload/standards/classic/4-3/AUTOSAR_SWS_CRCLibrary.pdf
+
+ uint8_t *dat = (uint8_t *)&d;
+ uint8_t crc = 0xFF; // Standard init value for CRC8 8H2F/AUTOSAR
+
+ // CRC the payload first, skipping over the first byte where the CRC lives.
+ for (int i = 1; i < l; i++) {
+ crc ^= dat[i];
+ crc = crc8_lut_8h2f[crc];
+ }
+
+ // Look up and apply the magic final CRC padding byte, which permutes by CAN
+ // address, and additionally (for SOME addresses) by the message counter.
+ uint8_t counter = dat[1] & 0x0F;
+ switch(address) {
+ case 0x86: // LWI_01 Steering Angle
+ crc ^= (uint8_t[]){0x86,0x86,0x86,0x86,0x86,0x86,0x86,0x86,0x86,0x86,0x86,0x86,0x86,0x86,0x86,0x86}[counter];
+ break;
+ case 0x9F: // EPS_01 Electric Power Steering
+ crc ^= (uint8_t[]){0xF5,0xF5,0xF5,0xF5,0xF5,0xF5,0xF5,0xF5,0xF5,0xF5,0xF5,0xF5,0xF5,0xF5,0xF5,0xF5}[counter];
+ break;
+ case 0xAD: // Getriebe_11 Automatic Gearbox
+ crc ^= (uint8_t[]){0x3F,0x69,0x39,0xDC,0x94,0xF9,0x14,0x64,0xD8,0x6A,0x34,0xCE,0xA2,0x55,0xB5,0x2C}[counter];
+ break;
+ case 0xFD: // ESP_21 Electronic Stability Program
+ crc ^= (uint8_t[]){0xB4,0xEF,0xF8,0x49,0x1E,0xE5,0xC2,0xC0,0x97,0x19,0x3C,0xC9,0xF1,0x98,0xD6,0x61}[counter];
+ break;
+ case 0x106: // ESP_05 Electronic Stability Program
+ crc ^= (uint8_t[]){0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07}[counter];
+ break;
+ case 0x117: // ACC_10 Automatic Cruise Control
+ crc ^= (uint8_t[]){0xAC,0xAC,0xAC,0xAC,0xAC,0xAC,0xAC,0xAC,0xAC,0xAC,0xAC,0xAC,0xAC,0xAC,0xAC,0xAC}[counter];
+ break;
+ case 0x122: // ACC_06 Automatic Cruise Control
+ crc ^= (uint8_t[]){0x37,0x7D,0xF3,0xA9,0x18,0x46,0x6D,0x4D,0x3D,0x71,0x92,0x9C,0xE5,0x32,0x10,0xB9}[counter];
+ break;
+ case 0x126: // HCA_01 Heading Control Assist
+ crc ^= (uint8_t[]){0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA,0xDA}[counter];
+ break;
+ case 0x12B: // GRA_ACC_01 Steering wheel controls for ACC
+ crc ^= (uint8_t[]){0x6A,0x38,0xB4,0x27,0x22,0xEF,0xE1,0xBB,0xF8,0x80,0x84,0x49,0xC7,0x9E,0x1E,0x2B}[counter];
+ break;
+ case 0x187: // EV_Gearshift "Gear" selection data for EVs with no gearbox
+ crc ^= (uint8_t[]){0x7F,0xED,0x17,0xC2,0x7C,0xEB,0x44,0x21,0x01,0xFA,0xDB,0x15,0x4A,0x6B,0x23,0x05}[counter];
+ break;
+ case 0x30C: // ACC_02 Automatic Cruise Control
+ crc ^= (uint8_t[]){0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F}[counter];
+ break;
+ case 0x3C0: // Klemmen_Status_01 ignition and starting status
+ crc ^= (uint8_t[]){0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3}[counter];
+ break;
+ case 0x65D: // ESP_20 Electronic Stability Program
+ crc ^= (uint8_t[]){0xAC,0xB3,0xAB,0xEB,0x7A,0xE1,0x3B,0xF7,0x73,0xBA,0x7C,0x9E,0x06,0x5F,0x02,0xD9}[counter];
+ break;
+ default: // As-yet undefined CAN message, CRC check expected to fail
+ INFO("Attempt to CRC check undefined Volkswagen message 0x%02X\n", address);
+ crc ^= (uint8_t[]){0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}[counter];
+ break;
+ }
+ crc = crc8_lut_8h2f[crc];
+
+ return crc ^ 0xFF; // Return after standard final XOR for CRC8 8H2F/AUTOSAR
+}
+
namespace {
uint64_t read_u64_be(const uint8_t* v) {
@@ -129,11 +223,11 @@ struct MessageState {
tmp -= (tmp >> (sig.b2-1)) ? (1ULL << sig.b2) : 0; //signed
}
- DEBUG("parse %X %s -> %lld\n", address, sig.name, tmp);
+ DEBUG("parse 0x%X %s -> %lld\n", address, sig.name, tmp);
if (sig.type == SignalType::HONDA_CHECKSUM) {
if (honda_checksum(address, dat, size) != tmp) {
- INFO("%X CHECKSUM FAIL\n", address);
+ INFO("0x%X CHECKSUM FAIL\n", address);
return false;
}
} else if (sig.type == SignalType::HONDA_COUNTER) {
@@ -142,12 +236,21 @@ struct MessageState {
}
} else if (sig.type == SignalType::TOYOTA_CHECKSUM) {
if (toyota_checksum(address, dat, size) != tmp) {
- INFO("%X CHECKSUM FAIL\n", address);
+ INFO("0x%X CHECKSUM FAIL\n", address);
+ return false;
+ }
+ } else if (sig.type == SignalType::VOLKSWAGEN_CHECKSUM) {
+ if (volkswagen_crc(address, dat, size) != tmp) {
+ INFO("0x%X CRC FAIL\n", address);
+ return false;
+ }
+ } else if (sig.type == SignalType::VOLKSWAGEN_COUNTER) {
+ if (!update_counter_generic(tmp, sig.b2)) {
return false;
}
} else if (sig.type == SignalType::PEDAL_CHECKSUM) {
if (pedal_checksum(address, dat, size) != tmp) {
- INFO("%X PEDAL CHECKSUM FAIL\n", address);
+ INFO("0x%X PEDAL CHECKSUM FAIL\n", address);
return false;
}
} else if (sig.type == SignalType::PEDAL_COUNTER) {
@@ -171,7 +274,7 @@ struct MessageState {
if (((old_counter+1) & ((1 << cnt_size) -1)) != v) {
counter_fail += 1;
if (counter_fail > 1) {
- INFO("%X COUNTER FAIL %d -- %d vs %d\n", address, counter_fail, old_counter, (int)v);
+ INFO("0x%X COUNTER FAIL %d -- %d vs %d\n", address, counter_fail, old_counter, (int)v);
}
if (counter_fail >= MAX_BAD_COUNTER) {
return false;
@@ -223,7 +326,9 @@ class CANParser {
}
dbc = dbc_lookup(dbc_name);
- assert(dbc);
+ assert(dbc);
+ init_crc_lookup_tables();
+
for (const auto& op : options) {
MessageState state = {
.address = op.address,
diff --git a/selfdrive/can/parser_pyx.pxd b/selfdrive/can/parser_pyx.pxd
index 28048bbc1f0e53..4d7879e1ca848a 100644
--- a/selfdrive/can/parser_pyx.pxd
+++ b/selfdrive/can/parser_pyx.pxd
@@ -14,7 +14,9 @@ ctypedef enum SignalType:
HONDA_COUNTER,
TOYOTA_CHECKSUM,
PEDAL_CHECKSUM,
- PEDAL_COUNTER
+ PEDAL_COUNTER,
+ VOLKSWAGEN_CHECKSUM,
+ VOLKSWAGEN_COUNTER
cdef struct Signal:
const char* name
diff --git a/selfdrive/can/process_dbc.py b/selfdrive/can/process_dbc.py
index 187d413584dcd7..4b8c55d448a68d 100755
--- a/selfdrive/can/process_dbc.py
+++ b/selfdrive/can/process_dbc.py
@@ -1,5 +1,4 @@
#!/usr/bin/env python3
-from __future__ import print_function
import os
import glob
import sys
@@ -39,50 +38,78 @@ def main():
if dbc_mtime < out_mtime and template_mtime < out_mtime and this_file_mtime < out_mtime:
continue #skip output is newer than template and dbc
- msgs = [(address, msg_name, msg_size, sorted(msg_sigs, key=lambda s: s.name not in (b"COUNTER", b"CHECKSUM"))) # process counter and checksums first
+ msgs = [(address, msg_name, msg_size, sorted(msg_sigs, key=lambda s: s.name not in ("COUNTER", "CHECKSUM"))) # process counter and checksums first
for address, ((msg_name, msg_size), msg_sigs) in sorted(can_dbc.msgs.items()) if msg_sigs]
def_vals = {a: set(b) for a,b in can_dbc.def_vals.items()} #remove duplicates
def_vals = [(address, sig) for address, sig in sorted(def_vals.items())]
- if can_dbc.name.startswith("honda") or can_dbc.name.startswith("acura"):
+ if can_dbc.name.startswith(("honda_", "acura_")):
checksum_type = "honda"
checksum_size = 4
- elif can_dbc.name.startswith("toyota") or can_dbc.name.startswith("lexus"):
+ counter_size = 2
+ checksum_start_bit = 3
+ counter_start_bit = 5
+ little_endian = False
+ elif can_dbc.name.startswith(("toyota_", "lexus_")):
checksum_type = "toyota"
checksum_size = 8
+ counter_size = None
+ checksum_start_bit = 7
+ counter_start_bit = None
+ little_endian = False
+ elif can_dbc.name.startswith(("vw_", "volkswagen_", "audi_", "seat_", "skoda_")):
+ checksum_type = "volkswagen"
+ checksum_size = 8
+ counter_size = 4
+ checksum_start_bit = 0
+ counter_start_bit = 0
+ little_endian = True
else:
checksum_type = None
+ checksum_size = None
+ counter_size = None
+ checksum_start_bit = None
+ counter_start_bit = None
+ little_endian = None
+ # sanity checks on expected COUNTER and CHECKSUM rules, as packer and parser auto-compute those signals
for address, msg_name, msg_size, sigs in msgs:
+ dbc_msg_name = dbc_name + " " + msg_name
for sig in sigs:
- if checksum_type is not None and sig.name == b"CHECKSUM":
- if sig.size != checksum_size:
- sys.exit("CHECKSUM is not %d bits longs %s" % (checksum_size, msg_name))
- if checksum_type == "honda" and sig.start_bit % 8 != 3:
- sys.exit("CHECKSUM starts at wrong bit %s" % msg_name)
- if checksum_type == "toyota" and sig.start_bit % 8 != 7:
- sys.exit("CHECKSUM starts at wrong bit %s" % msg_name)
- if checksum_type == "honda" and sig.name == b"COUNTER":
- if sig.size != 2:
- sys.exit("COUNTER is not 2 bits longs %s" % msg_name)
- if sig.start_bit % 8 != 5:
- sys.exit("COUNTER starts at wrong bit %s" % msg_name)
+ if checksum_type is not None:
+ # checksum rules
+ if sig.name == "CHECKSUM":
+ if sig.size != checksum_size:
+ sys.exit("%s: CHECKSUM is not %d bits long" % (dbc_msg_name, checksum_size))
+ if sig.start_bit % 8 != checksum_start_bit:
+ sys.exit("%s: CHECKSUM starts at wrong bit" % dbc_msg_name)
+ if little_endian != sig.is_little_endian:
+ sys.exit("%s: CHECKSUM has wrong endianess" % dbc_msg_name)
+ # counter rules
+ if sig.name == "COUNTER":
+ if counter_size is not None and sig.size != counter_size:
+ sys.exit("%s: COUNTER is not %d bits long" % (dbc_msg_name, counter_size))
+ if counter_start_bit is not None and sig.start_bit % 8 != counter_start_bit:
+ print(counter_start_bit, sig.start_bit)
+ sys.exit("%s: COUNTER starts at wrong bit" % dbc_msg_name)
+ if little_endian != sig.is_little_endian:
+ sys.exit("%s: COUNTER has wrong endianess" % dbc_msg_name)
+ # pedal rules
if address in [0x200, 0x201]:
- if sig.name == b"COUNTER_PEDAL" and sig.size != 4:
- sys.exit("PEDAL COUNTER is not 4 bits longs %s" % msg_name)
- if sig.name == b"CHECKSUM_PEDAL" and sig.size != 8:
- sys.exit("PEDAL CHECKSUM is not 8 bits longs %s" % msg_name)
+ if sig.name == "COUNTER_PEDAL" and sig.size != 4:
+ sys.exit("%s: PEDAL COUNTER is not 4 bits long" % dbc_msg_name)
+ if sig.name == "CHECKSUM_PEDAL" and sig.size != 8:
+ sys.exit("%s: PEDAL CHECKSUM is not 8 bits long" % dbc_msg_name)
# Fail on duplicate message names
c = Counter([msg_name for address, msg_name, msg_size, sigs in msgs])
for name, count in c.items():
if count > 1:
- sys.exit("Duplicate message name in DBC file %s" % name)
+ sys.exit("%s: Duplicate message name in DBC file %s" % (dbc_name, name))
parser_code = template.render(dbc=can_dbc, checksum_type=checksum_type, msgs=msgs, def_vals=def_vals, len=len)
-
with open(out_fn, "w") as out_f:
out_f.write(parser_code)
diff --git a/selfdrive/car/honda/interface.py b/selfdrive/car/honda/interface.py
index f8aa72f71826b8..bf4a85e22467a4 100755
--- a/selfdrive/car/honda/interface.py
+++ b/selfdrive/car/honda/interface.py
@@ -164,17 +164,17 @@ def get_params(candidate, fingerprint=gen_empty_fingerprint(), vin="", has_relay
# For modeling details, see p.198-200 in "The Science of Vehicle Dynamics (2014), M. Guiggiani"
ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]]
- ret.lateralTuning.pid.kf = 0.00006 # conservative feed-forward
+ ret.lateralTuning.pid.kf = 0.00000 # conservative feed-forward
if candidate in [CAR.CIVIC, CAR.CIVIC_BOSCH]:
stop_and_go = True
ret.mass = CivicParams.MASS
ret.wheelbase = CivicParams.WHEELBASE
ret.centerToFront = CivicParams.CENTER_TO_FRONT
- ret.steerRatio = 15.38 # 10.93 is end-to-end spec
+ ret.steerRatio = 11.6 # 10.93 is end-to-end spec
tire_stiffness_factor = 1.
- ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.8], [0.24]]
+ ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.8], [0.13]]
ret.longitudinalTuning.kpBP = [0., 5., 35.]
ret.longitudinalTuning.kpV = [3.6, 2.4, 1.5]
ret.longitudinalTuning.kiBP = [0., 35.]
@@ -319,28 +319,28 @@ def get_params(candidate, fingerprint=gen_empty_fingerprint(), vin="", has_relay
ret.mass = 4204. * CV.LB_TO_KG + STD_CARGO_KG # average weight
ret.wheelbase = 2.82
ret.centerToFront = ret.wheelbase * 0.428 # average weight distribution
- ret.steerRatio = 13.75 # Tuned value for 0.6.4 to eliminate wobble
+ ret.steerRatio = 14.35 # Tuned value for 0.6.4 to eliminate wobble
tire_stiffness_factor = 0.62 # LiveParameters Value
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.45], [0.21]]
ret.longitudinalTuning.kpBP = [0., 5., 35.]
ret.longitudinalTuning.kpV = [1.2, 0.8, 0.5]
ret.longitudinalTuning.kiBP = [0., 35.]
ret.longitudinalTuning.kiV = [0.18, 0.12]
- ret.lateralTuning.pid.kf = 0.00003 #Turn Feed forward off to eliminate wobble
+ ret.lateralTuning.pid.kf = 0.00001 #Turn Feed forward off to eliminate wobble
elif candidate == CAR.RIDGELINE:
stop_and_go = False
ret.mass = 4515. * CV.LB_TO_KG + STD_CARGO_KG
ret.wheelbase = 3.18
ret.centerToFront = ret.wheelbase * 0.41
- ret.steerRatio = 13.75 # as spec
+ ret.steerRatio = 14.35 # as spec
tire_stiffness_factor = 0.62 # not optimized yet
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.45], [0.21]]
ret.longitudinalTuning.kpBP = [0., 5., 35.]
ret.longitudinalTuning.kpV = [1.2, 0.8, 0.5]
ret.longitudinalTuning.kiBP = [0., 35.]
ret.longitudinalTuning.kiV = [0.18, 0.12]
- ret.lateralTuning.pid.kf = 0.00003
+ ret.lateralTuning.pid.kf = 0.00001
else:
raise ValueError("unsupported car %s" % candidate)
@@ -389,7 +389,7 @@ def get_params(candidate, fingerprint=gen_empty_fingerprint(), vin="", has_relay
ret.startAccel = 0.5
ret.steerActuatorDelay = 0.1
- ret.steerRateCost = 0.3
+ ret.steerRateCost = 0.35
return ret
diff --git a/selfdrive/car/lock_safety_model.py b/selfdrive/car/lock_safety_model.py
new file mode 100755
index 00000000000000..055d8c0c2b499d
--- /dev/null
+++ b/selfdrive/car/lock_safety_model.py
@@ -0,0 +1,27 @@
+#!/usr/bin/env python3
+import sys
+from cereal import car
+from common.params import Params
+
+# This script locks the safety model to a given value.
+# When the safety model is locked, boardd will preset panda to the locked safety model
+
+# run example:
+# ./lock_safety_model.py gm
+
+if __name__ == "__main__":
+
+ params = Params()
+
+ if len(sys.argv) < 2:
+ params.delete("SafetyModelLock")
+ print("Clear locked safety model")
+
+ else:
+ safety_model = getattr(car.CarParams.SafetyModel, sys.argv[1])
+ if type(safety_model) != int:
+ raise Exception("Invalid safety model: " + sys.argv[1])
+ if safety_model == car.CarParams.SafetyModel.allOutput:
+ raise Exception("Locking the safety model to allOutput is not allowed")
+ params.put("SafetyModelLock", str(safety_model))
+ print("Locked safety model: " + sys.argv[1])
diff --git a/selfdrive/car/subaru/interface.py b/selfdrive/car/subaru/interface.py
index 0fa12cf7d9bb89..e2195b00a19ca1 100644
--- a/selfdrive/car/subaru/interface.py
+++ b/selfdrive/car/subaru/interface.py
@@ -3,9 +3,9 @@
from selfdrive.config import Conversions as CV
from selfdrive.controls.lib.drive_helpers import create_event, EventTypes as ET
from selfdrive.controls.lib.vehicle_model import VehicleModel
-from selfdrive.car.subaru.values import CAR, FINGERPRINTS, ECU_FINGERPRINT, ECU
+from selfdrive.car.subaru.values import CAR
from selfdrive.car.subaru.carstate import CarState, get_powertrain_can_parser, get_camera_can_parser
-from selfdrive.car import STD_CARGO_KG, scale_rot_inertia, scale_tire_stiffness, gen_empty_fingerprint, is_ecu_disconnected
+from selfdrive.car import STD_CARGO_KG, scale_rot_inertia, scale_tire_stiffness, gen_empty_fingerprint
from selfdrive.car.interfaces import CarInterfaceBase
ButtonType = car.CarState.ButtonEvent.Type
@@ -48,7 +48,9 @@ def get_params(candidate, fingerprint=gen_empty_fingerprint(), vin="", has_relay
ret.enableCruise = True
ret.steerLimitAlert = True
- ret.enableCamera = is_ecu_disconnected(fingerprint[0], FINGERPRINTS, ECU_FINGERPRINT, candidate, ECU.CAM) or has_relay
+ # force openpilot to fake the stock camera, since car harness is not supported yet and old style giraffe (with switches)
+ # was never released
+ ret.enableCamera = True
ret.steerRateCost = 0.7
diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py
index 483da4e38787f7..a576bef88240e8 100644
--- a/selfdrive/car/toyota/values.py
+++ b/selfdrive/car/toyota/values.py
@@ -162,7 +162,8 @@ class ECU:
36: 8, 37: 8, 170: 8, 180: 8, 296: 8, 426: 6, 452: 8, 466: 8, 467: 8, 550: 8, 552: 4, 560: 7, 581: 5, 608: 8, 610: 5, 643: 7, 713: 8, 740: 5, 800: 8, 835: 8, 836: 8, 849: 4, 869: 7, 870: 7, 871: 2, 896: 8, 897: 8, 900: 6, 902: 6, 905: 8, 911: 8, 916: 3, 918: 7, 921: 8, 933: 8, 944: 8, 945: 8, 950: 8, 951: 8, 953: 3, 955: 8, 956: 8, 979: 2, 998: 5, 999: 7, 1000: 8, 1001: 8, 1005: 2, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1043: 8, 1044: 8, 1056: 8, 1059: 1, 1112: 8, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1176: 8, 1177: 8, 1178: 8, 1179: 8, 1180: 8, 1181: 8, 1184: 8, 1185: 8, 1186: 8, 1189: 8, 1190: 8, 1191: 8, 1192: 8, 1196: 8, 1197: 8, 1198: 8, 1199: 8, 1206: 8, 1212: 8, 1227: 8, 1232: 8, 1235: 8, 1237: 8, 1263: 8, 1264: 8, 1279: 8, 1552: 8, 1553: 8, 1554: 8, 1556: 8, 1557: 8, 1561: 8, 1562: 8, 1568: 8, 1569: 8, 1570: 8, 1571: 8, 1572: 8, 1584: 8, 1589: 8, 1592: 8, 1593: 8, 1595: 8, 1599: 8, 1656: 8, 1728: 8, 1745: 8, 1779: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8
},
{
- 36: 8, 37: 8, 170: 8, 180: 8, 296: 8, 426: 6, 452: 8, 466: 8, 467: 8, 550: 8, 552: 4, 560: 7, 581: 5, 608: 8, 610: 5, 643: 7, 713: 8, 740: 5, 800: 8, 835: 8, 836: 8, 849: 4, 869: 7, 870: 7, 871: 2, 896: 8, 897: 8, 900: 6, 902: 6, 905: 8, 911: 8, 916: 3, 921: 8, 933: 8, 944: 8, 945: 8, 950: 8, 951: 8, 953: 3, 955: 8, 956: 8, 979: 2, 992: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1043: 8, 1044: 8, 1056: 8, 1057: 8, 1059: 1, 1076: 8, 1077: 8, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1176: 8, 1177: 8, 1178: 8, 1179: 8, 1180: 8, 1181: 8, 1184: 8, 1185: 8, 1186: 8, 1189: 8, 1190: 8, 1191: 8, 1192: 8, 1196: 8, 1197: 8, 1198: 8, 1199: 8, 1206: 8, 1212: 8, 1227: 8, 1232: 8, 1237: 8, 1279: 8, 1552: 8, 1553: 8, 1554: 8, 1556: 8, 1557: 8, 1561: 8, 1562: 8, 1568: 8, 1569: 8, 1570: 8, 1571: 8, 1572: 8, 1584: 8, 1589: 8, 1592: 8, 1593: 8, 1595: 8, 1599: 8, 1656: 8, 1728: 8, 1745: 8, 1779: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8
+ # 2019 Highlander Hybrid Limited Platinum
+ 36: 8, 37: 8, 170: 8, 180: 8, 296: 8, 426: 6, 452: 8, 466: 8, 467: 8, 550: 8, 552: 4, 560: 7, 581: 5, 608: 8, 610: 5, 643: 7, 713: 8, 740: 5, 800: 8, 835: 8, 836: 8, 849: 4, 869: 7, 870: 7, 871: 2, 896: 8, 897: 8, 900: 6, 902: 6, 905: 8, 911: 8, 916: 3, 918: 7, 921: 8, 933: 8, 944: 8, 945: 8, 950: 8, 951: 8, 953: 3, 955: 8, 956: 8, 979: 2, 992: 8, 998: 5, 999: 7, 1000: 8, 1001: 8, 1014: 8, 1017: 8, 1020: 8, 1041: 8, 1042: 8, 1043: 8, 1044: 8, 1056: 8, 1057: 8, 1059: 1, 1076: 8, 1077: 8, 1112: 8, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1176: 8, 1177: 8, 1178: 8, 1179: 8, 1180: 8, 1181: 8, 1184: 8, 1185: 8, 1186: 8, 1189: 8, 1190: 8, 1191: 8, 1192: 8, 1196: 8, 1197: 8, 1198: 8, 1199: 8, 1206: 8, 1212: 8, 1227: 8, 1232: 8, 1235: 8, 1237: 8, 1263: 8, 1279: 8, 1552: 8, 1553: 8, 1554: 8, 1556: 8, 1557: 8, 1561: 8, 1562: 8, 1568: 8, 1569: 8, 1570: 8, 1571: 8, 1572: 8, 1584: 8, 1589: 8, 1592: 8, 1593: 8, 1595: 8, 1599: 8, 1656: 8, 1666: 8, 1667: 8, 1728: 8, 1745: 8, 1779: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8
}],
CAR.AVALON: [{
36: 8, 37: 8, 170: 8, 180: 8, 426: 6, 452: 8, 464: 8, 466: 8, 467: 8, 547: 8, 550: 8, 552: 4, 562: 6, 608: 8, 610: 5, 643: 7, 705: 8, 740: 5, 800: 8, 835: 8, 836: 8, 849: 4, 869: 7, 870: 7, 871: 2, 896: 8, 897: 8, 905: 8, 911: 1, 916: 2, 921: 8, 933: 6, 944: 8, 945: 8, 951: 8, 955: 8, 956: 8, 979: 2, 1005: 2, 1014: 8, 1017: 8, 1041: 8, 1042: 8, 1044: 8, 1056: 8, 1059: 1, 1114: 8, 1161: 8, 1162: 8, 1163: 8, 1176: 8, 1177: 8, 1178: 8, 1179: 8, 1180: 8, 1181: 8, 1190: 8, 1191: 8, 1192: 8, 1196: 8, 1200: 8, 1201: 8, 1202: 8, 1203: 8, 1206: 8, 1227: 8, 1235: 8, 1237: 8, 1264: 8, 1279: 8, 1552: 8, 1553: 8, 1554: 8, 1555: 8, 1556: 8, 1557: 8, 1558: 8, 1561: 8, 1562: 8, 1568: 8, 1569: 8, 1570: 8, 1571: 8, 1572: 8, 1584: 8, 1589: 8, 1592: 8, 1593: 8, 1595: 8, 1596: 8, 1597: 8, 1664: 8, 1728: 8, 1779: 8, 1904: 8, 1912: 8, 1990: 8, 1998: 8
diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py
index fae1d1581becf3..22f7c9352344f3 100755
--- a/selfdrive/controls/controlsd.py
+++ b/selfdrive/controls/controlsd.py
@@ -511,7 +511,7 @@ def controlsd_thread(sm=None, pm=None, can_sock=None):
# FIXME: offroad alerts should not be created with negative severity
connectivity_alert = params.get("Offroad_ConnectivityNeeded", encoding='utf8')
- internet_needed = connectivity_alert is not None and json.loads(connectivity_alert.replace("'", "\""))["severity"] >= 0
+ internet_needed = connectivity_alert is not None and json.loads(connectivity_alert)["severity"] >= 0
prof = Profiler(False) # off by default
diff --git a/selfdrive/controls/lib/alerts.py b/selfdrive/controls/lib/alerts.py
index 7ab5a4a6528ba6..202684216a7da6 100644
--- a/selfdrive/controls/lib/alerts.py
+++ b/selfdrive/controls/lib/alerts.py
@@ -92,7 +92,7 @@ def __gt__(self, alert2):
"TAKE CONTROL",
"Turn Exceeds Steering Limit",
AlertStatus.userPrompt, AlertSize.mid,
- Priority.LOW, VisualAlert.steerRequired, AudibleAlert.chimePrompt, 1., 2., 3.),
+ Priority.LOW, VisualAlert.none, AudibleAlert.none, 1., 2., 3.),
Alert(
"steerTempUnavailable",
diff --git a/selfdrive/controls/lib/lane_planner.py b/selfdrive/controls/lib/lane_planner.py
index 2266033effb9a6..fa22de29fa439c 100644
--- a/selfdrive/controls/lib/lane_planner.py
+++ b/selfdrive/controls/lib/lane_planner.py
@@ -32,7 +32,7 @@ def calc_d_poly(l_poly, r_poly, p_poly, l_prob, r_prob, lane_width):
path_from_right_lane = r_poly.copy()
path_from_right_lane[3] += lane_width / 2.0
- lr_prob = l_prob * r_prob
+ lr_prob = l_prob + r_prob - l_prob * r_prob
d_poly_lane = (l_prob * path_from_left_lane + r_prob * path_from_right_lane) / (l_prob + r_prob + 0.0001)
return lr_prob * d_poly_lane + (1.0 - lr_prob) * p_poly
diff --git a/selfdrive/controls/lib/long_mpc.py b/selfdrive/controls/lib/long_mpc.py
index 0475c5e4dcf36c..638c0d420e54cd 100644
--- a/selfdrive/controls/lib/long_mpc.py
+++ b/selfdrive/controls/lib/long_mpc.py
@@ -10,18 +10,33 @@
from selfdrive.controls.lib.drive_helpers import MPC_COST_LONG
from selfdrive.kegman_conf import kegman_conf
-
# One, two and three bar distances (in s)
-ONE_BAR_DISTANCE = 0.9 # in seconds
-TWO_BAR_DISTANCE = 1.3 # in seconds
-THREE_BAR_DISTANCE = 1.8 # in seconds
-FOUR_BAR_DISTANCE = 2.3 # in seconds
+kegman = kegman_conf()
+if "ONE_BAR_DISTANCE" in kegman.conf:
+ ONE_BAR_DISTANCE = float(kegman.conf['ONE_BAR_DISTANCE'])
+else:
+ ONE_BAR_DISTANCE = 0.9 # in seconds
+if "TWO_BAR_DISTANCE" in kegman.conf:
+ TWO_BAR_DISTANCE = float(kegman.conf['TWO_BAR_DISTANCE'])
+else:
+ TWO_BAR_DISTANCE = 1.3 # in seconds
+if "THREE_BAR_DISTANCE" in kegman.conf:
+ THREE_BAR_DISTANCE = float(kegman.conf['THREE_BAR_DISTANCE'])
+else:
+ THREE_BAR_DISTANCE = 1.8 # in seconds
+if "FOUR_BAR_DISTANCE" in kegman.conf:
+ FOUR_BAR_DISTANCE = float(kegman.conf['FOUR_BAR_DISTANCE'])
+else:
+ FOUR_BAR_DISTANCE = 2.3 # in seconds
+if "STOPPING_DISTANCE" in kegman.conf:
+ STOPPING_DISTANCE = float(kegman.conf['STOPPING_DISTANCE'])
+else:
+ STOPPING_DISTANCE = 2 # distance between you and lead car when you come to stop
TR = TWO_BAR_DISTANCE # default interval
# Variables that change braking profiles
CITY_SPEED = 19.44 # braking profile changes when below this speed based on following dynamics below [m/s]
-STOPPING_DISTANCE = 2 # increase distance from lead car when stopped
# City braking profile changes (makes the car brake harder because it wants to be farther from the lead car - increase to brake harder)
ONE_BAR_PROFILE = [ONE_BAR_DISTANCE, 2.5]
diff --git a/selfdrive/controls/lib/longitudinal_mpc/lib_mpc_export/acado_auxiliary_functions.o b/selfdrive/controls/lib/longitudinal_mpc/lib_mpc_export/acado_auxiliary_functions.o
index 65182c5bb1ee55..80da32bd596a90 100644
Binary files a/selfdrive/controls/lib/longitudinal_mpc/lib_mpc_export/acado_auxiliary_functions.o and b/selfdrive/controls/lib/longitudinal_mpc/lib_mpc_export/acado_auxiliary_functions.o differ
diff --git a/selfdrive/controls/lib/longitudinal_mpc/lib_mpc_export/acado_integrator.o b/selfdrive/controls/lib/longitudinal_mpc/lib_mpc_export/acado_integrator.o
index 0008b139779a03..26652584871061 100644
Binary files a/selfdrive/controls/lib/longitudinal_mpc/lib_mpc_export/acado_integrator.o and b/selfdrive/controls/lib/longitudinal_mpc/lib_mpc_export/acado_integrator.o differ
diff --git a/selfdrive/controls/lib/planner.py b/selfdrive/controls/lib/planner.py
index cb2921660f6451..891517e863a369 100755
--- a/selfdrive/controls/lib/planner.py
+++ b/selfdrive/controls/lib/planner.py
@@ -90,6 +90,7 @@ def __init__(self, CP):
self.params = Params()
self.kegman = kegman_conf()
+ self.mpc_frame = 0
def choose_solution(self, v_cruise_setpoint, enabled):
if enabled:
@@ -133,6 +134,12 @@ def update(self, sm, pm, CP, VM, PP):
enabled = (long_control_state == LongCtrlState.pid) or (long_control_state == LongCtrlState.stopping)
+ if self.mpc_frame % 1000 == 0:
+ self.kegman = kegman_conf()
+ self.mpc_frame = 0
+
+ self.mpc_frame += 1
+
if len(sm['model'].path.poly) and int(self.kegman.conf['slowOnCurves']):
path = list(sm['model'].path.poly)
diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit
index 557be7d88d35e9..780589159b43ac 100644
--- a/selfdrive/test/process_replay/ref_commit
+++ b/selfdrive/test/process_replay/ref_commit
@@ -1 +1 @@
-8def7e7391802f2e86498d764c953f487361f6a1
\ No newline at end of file
+a64d824f47e2f794512f1c9439a04e242e3d1676
\ No newline at end of file
diff --git a/selfdrive/thermald.py b/selfdrive/thermald.py
index 67eac1c4d2602e..0cb2a23a04ff6e 100755
--- a/selfdrive/thermald.py
+++ b/selfdrive/thermald.py
@@ -153,7 +153,6 @@ def thermald_thread():
off_ts = None
started_ts = None
- ignition_seen = False
started_seen = False
thermal_status = ThermalStatus.green
thermal_status_prev = ThermalStatus.green
@@ -176,7 +175,6 @@ def thermald_thread():
# clear car params when panda gets disconnected
if health is None and health_prev is not None:
params.panda_disconnect()
- ignition_seen = False
health_prev = health
if health is not None:
@@ -258,11 +256,6 @@ def thermald_thread():
# start constellation of processes when the car starts
ignition = health is not None and health.health.started
- ignition_seen = ignition_seen or ignition
-
- # add voltage check for ignition
- if not ignition_seen and health is not None and health.health.voltage > 13500:
- ignition = True
do_uninstall = params.get("DoUninstall") == b"1"
accepted_terms = params.get("HasAcceptedTerms") == terms_version
diff --git a/tune.py b/tune.py
index e1120157dac8a8..f411fa7e554eb4 100644
--- a/tune.py
+++ b/tune.py
@@ -41,18 +41,18 @@ def getch():
kegman = kegman_conf()
kegman.conf['tuneGernby'] = "1"
#kegman.write_config(kegman.conf)
-param = ["Kp", "Ki", "Kf", "steerRatio", "steerRateCost", "deadzone", \
+param = ["Kp", "Ki", "Kf", "steerRatio", "steerRateCost", "deadzone", "slowOnCurves", \
"1barBP0", "1barBP1", "1barMax", "2barBP0", "2barBP1", \
"2barMax", "3barBP0", "3barBP1", "3barMax", \
"1barHwy", "2barHwy", "3barHwy"]
j = 0
while True:
- print ""
- print print_letters(param[j][0:9])
- print ""
- print print_letters(kegman.conf[param[j]])
- print ""
+ print ("")
+ print (print_letters(param[j][0:9]))
+ print ("")
+ print (print_letters(kegman.conf[param[j]]))
+ print ("")
print ("1,3,5,7,r to incr 0.1,0.05,0.01,0.001,0.00001")
print ("a,d,g,j,v to decr 0.1,0.05,0.01,0.001,0.00001")
print ("0 / L to make the value 0 / 1")
@@ -62,43 +62,43 @@ def getch():
char = getch()
write_json = False
if (char == "v"):
- kegman.conf[param[j]] = str(float(kegman.conf[param[j]]) - 0.00001)
+ kegman.conf[param[j]] = str(round((float(kegman.conf[param[j]]) - 0.00001),5))
write_json = True
if (char == "r"):
- kegman.conf[param[j]] = str(float(kegman.conf[param[j]]) + 0.00001)
+ kegman.conf[param[j]] = str(round((float(kegman.conf[param[j]]) + 0.00001),5))
write_json = True
if (char == "7"):
- kegman.conf[param[j]] = str(float(kegman.conf[param[j]]) + 0.001)
+ kegman.conf[param[j]] = str(round((float(kegman.conf[param[j]]) + 0.001),5))
write_json = True
if (char == "5"):
- kegman.conf[param[j]] = str(float(kegman.conf[param[j]]) + 0.01)
+ kegman.conf[param[j]] = str(round((float(kegman.conf[param[j]]) + 0.01),5))
write_json = True
elif (char == "3"):
- kegman.conf[param[j]] = str(float(kegman.conf[param[j]]) + 0.05)
+ kegman.conf[param[j]] = str(round((float(kegman.conf[param[j]]) + 0.05),5))
write_json = True
elif (char == "1"):
- kegman.conf[param[j]] = str(float(kegman.conf[param[j]]) + 0.1)
+ kegman.conf[param[j]] = str(round((float(kegman.conf[param[j]]) + 0.1),5))
write_json = True
elif (char == "j"):
- kegman.conf[param[j]] = str(float(kegman.conf[param[j]]) - 0.001)
+ kegman.conf[param[j]] = str(round((float(kegman.conf[param[j]]) - 0.001),5))
write_json = True
elif (char == "g"):
- kegman.conf[param[j]] = str(float(kegman.conf[param[j]]) - 0.01)
+ kegman.conf[param[j]] = str(round((float(kegman.conf[param[j]]) - 0.01),5))
write_json = True
elif (char == "d"):
- kegman.conf[param[j]] = str(float(kegman.conf[param[j]]) - 0.05)
+ kegman.conf[param[j]] = str(round((float(kegman.conf[param[j]]) - 0.05),5))
write_json = True
elif (char == "a"):
- kegman.conf[param[j]] = str(float(kegman.conf[param[j]]) - 0.1)
+ kegman.conf[param[j]] = str(round((float(kegman.conf[param[j]]) - 0.1),5))
write_json = True
elif (char == "0"):
@@ -223,9 +223,8 @@ def getch():
kegman.conf['2barHwy'] = "2"
if float(kegman.conf['3barHwy']) > 2:
- kegman.conf['3barHwy'] = "2"
-
-
+ kegman.conf['3barHwy'] = "2"
+
if float(kegman.conf['Kf']) > 0.01:
kegman.conf['Kf'] = "0.01"
@@ -235,6 +234,12 @@ def getch():
#if float(kegman.conf['Kf']) < 0.00001:
kegman.conf['Kf'] = str("{:.5f}".format(float(kegman.conf['Kf'])))
+ if float(kegman.conf['slowOnCurves']) > 0.00001:
+ kegman.conf['slowOnCurves'] = "1"
+
+ if float(kegman.conf['slowOnCurves']) <= 0.99999:
+ kegman.conf['slowOnCurves'] = "0"
+
if write_json:
kegman.write_config(kegman.conf)
diff --git a/tune.sh b/tune.sh
index d13626c182b26c..510ee6e057fb95 100755
--- a/tune.sh
+++ b/tune.sh
@@ -1 +1 @@
-python2.7 tune.py
+python3 tune.py