diff --git a/frogpilot/assets/nnff_models/CHEVROLET_VOLT_2019.json b/frogpilot/assets/nnff_models/CHEVROLET_VOLT_2019.json new file mode 100644 index 000000000..881f47c90 --- /dev/null +++ b/frogpilot/assets/nnff_models/CHEVROLET_VOLT_2019.json @@ -0,0 +1 @@ +{"input_std":[[9.342214],[1.5915664],[0.60113484],[0.048193663],[1.5680411],[1.57577],[1.5836853],[1.5711677],[1.5445132],[1.5007596],[1.4529978],[0.047915205],[0.04800539],[0.04808892],[0.04822398],[0.04817677],[0.047881734],[0.047405947]],"model_test_loss":0.019342588260769844,"input_size":18,"current_date_and_time":"2023-08-05_06-09-11","input_mean":[[22.757933],[-0.016342578],[-0.001405228],[-0.014619173],[-0.018091483],[-0.018382493],[-0.019270267],[-0.018759886],[-0.019559544],[-0.017848592],[-0.020014366],[-0.014564899],[-0.01457757],[-0.014600966],[-0.014757987],[-0.014915743],[-0.015121007],[-0.015359475]],"input_vars":["v_ego","lateral_accel","lateral_jerk","roll","lateral_accel_m03","lateral_accel_m02","lateral_accel_m01","lateral_accel_p03","lateral_accel_p06","lateral_accel_p10","lateral_accel_p15","roll_m03","roll_m02","roll_m01","roll_p03","roll_p06","roll_p10","roll_p15"],"output_size":1,"layers":[{"dense_1_b":[[-0.045577038],[-2.8160777],[-0.21418032],[2.9552083],[-0.06852827],[0.029141279],[-0.053249933]],"dense_1_W":[[0.0010664682,1.3813498,-8.153277,-0.009101015,-0.1484779,1.0008405,-1.5930991,-1.195274,0.6136762,0.3560462,-0.30077773,0.93531257,0.14550218,-0.40074933,-0.21716364,0.13834935,-0.0658936,-0.49427196],[-0.7338253,-0.037501235,-0.49922377,-1.0526338,-0.46141604,-1.3649396,0.7309814,-0.91667104,0.044683233,-0.18628967,-0.20878822,-0.2678598,0.48446324,0.51164204,0.09547851,0.41491362,-0.4524314,0.16594785],[-0.0032175342,3.5451593,-0.11421584,-0.2511033,0.27893174,0.6384996,0.80790603,1.3835542,1.8000495,2.249461,1.4026878,0.7851167,-0.35052946,0.041820426,-0.39790183,0.45703772,-0.30459648,0.18287674],[0.72289664,-0.77138704,-0.5025135,-0.49323097,-0.39893976,-0.8779149,0.6848096,-0.58729875,-0.16643623,-0.14427555,-0.15013328,-0.11467142,-0.27280045,0.48508415,0.52080667,-0.0029569597,-0.28170735,0.06367212],[0.00014026981,-2.0353239,0.0060915067,0.4794941,1.1882906,-1.512865,0.80642134,-0.26044324,-0.56213886,-0.365122,0.55078083,-0.34897435,-0.32031298,0.46106994,0.37792024,-0.14116105,0.15597256,-0.32811671],[0.0011494387,1.9060265,8.3941965,-0.3078165,-0.9530427,0.6589645,-1.2487054,-0.541133,0.13451256,0.2805466,-0.33187166,0.9900705,0.2821258,-0.51270896,-0.5130031,-0.28222615,0.042734932,0.27233443],[-0.0014444552,-1.0933362,0.003359957,-0.15052961,0.37165833,1.7087307,-1.4971043,0.673802,-0.108465396,-0.088505454,0.21561684,0.6252258,-0.15019403,-0.34727478,0.08958758,-0.1723621,-0.25557828,0.29778987]],"activation":"σ"},{"dense_2_W":[[0.20810607,-0.13481373,-0.15003344,-0.6067625,-0.31937903,-0.37380016,0.4666911],[0.71834767,0.15669753,-0.11389502,0.27131546,-0.060118295,0.039282244,0.52961355],[-0.27200606,0.43380752,-0.106262706,-0.49363258,0.35659012,-0.01706296,-1.0807354],[-0.79583454,-0.66428274,-0.42157334,-0.52979547,-0.2803004,-0.57637554,0.084149174],[0.1230394,-0.57023287,0.28639448,-0.506744,-0.9920808,0.7510901,0.8584937],[-0.41256845,0.35423175,0.13009231,0.5198333,0.7576573,-0.7053181,-0.3390053],[-0.15090485,0.33375353,-0.64164793,0.57386595,0.25700107,-0.15245672,-0.49020413],[-0.50120676,0.5210849,-0.3282951,0.4276323,1.0257447,-1.0398436,-0.8911315],[0.11402861,-0.41491523,0.247507,-0.39776865,-0.6089287,0.20646147,0.6692102],[0.09411492,0.31819808,0.41330767,0.024243973,0.2314893,0.08529045,0.14911193],[0.5179265,0.20473345,-0.36762783,-0.009045922,-0.19436747,-0.548099,-0.08656279],[-0.69121784,-0.14201449,0.3887621,0.10787631,1.0371574,-0.64747447,-0.73437464],[-0.07860244,-0.597764,0.019551078,0.010199122,-0.7493642,0.66619915,0.121666186]],"activation":"σ","dense_2_b":[[-0.04259814],[-0.053309314],[-0.28045595],[-0.23801634],[0.00944943],[-0.109921046],[-0.037457183],[0.24627604],[-0.0069056284],[-0.04725389],[-0.03361769],[0.044101644],[-0.0009850285]]},{"dense_3_W":[[-0.19631335,-0.47722518,-0.019853225,-0.29363275,-0.625923,0.35145283,0.62401354,0.14337404,-0.25707108,-0.51310915,0.2565006,0.61742216,-0.07952821],[0.5868974,-0.36786363,-0.0177682,-0.45121866,0.68608487,-0.55178356,-0.35236016,-0.7226455,-0.015394288,-0.10650332,0.5391039,0.17791761,0.34196886],[0.16821232,-0.35580373,0.26906335,0.41736925,-0.6979869,0.41801625,0.34707317,0.7784011,-0.10002936,0.32485273,-0.3644285,0.49092358,-0.43872768]],"activation":"identity","dense_3_b":[[-0.019481273],[0.031026587],[-0.03595322]]},{"dense_4_W":[[-0.72340566,0.21244061,-0.67248434]],"dense_4_b":[[0.026229527]],"activation":"identity"}]} \ No newline at end of file diff --git a/frogpilot/assets/nnff_models/CHEVROLET_VOLT_ASCM.json b/frogpilot/assets/nnff_models/CHEVROLET_VOLT_ASCM.json new file mode 100644 index 000000000..881f47c90 --- /dev/null +++ b/frogpilot/assets/nnff_models/CHEVROLET_VOLT_ASCM.json @@ -0,0 +1 @@ +{"input_std":[[9.342214],[1.5915664],[0.60113484],[0.048193663],[1.5680411],[1.57577],[1.5836853],[1.5711677],[1.5445132],[1.5007596],[1.4529978],[0.047915205],[0.04800539],[0.04808892],[0.04822398],[0.04817677],[0.047881734],[0.047405947]],"model_test_loss":0.019342588260769844,"input_size":18,"current_date_and_time":"2023-08-05_06-09-11","input_mean":[[22.757933],[-0.016342578],[-0.001405228],[-0.014619173],[-0.018091483],[-0.018382493],[-0.019270267],[-0.018759886],[-0.019559544],[-0.017848592],[-0.020014366],[-0.014564899],[-0.01457757],[-0.014600966],[-0.014757987],[-0.014915743],[-0.015121007],[-0.015359475]],"input_vars":["v_ego","lateral_accel","lateral_jerk","roll","lateral_accel_m03","lateral_accel_m02","lateral_accel_m01","lateral_accel_p03","lateral_accel_p06","lateral_accel_p10","lateral_accel_p15","roll_m03","roll_m02","roll_m01","roll_p03","roll_p06","roll_p10","roll_p15"],"output_size":1,"layers":[{"dense_1_b":[[-0.045577038],[-2.8160777],[-0.21418032],[2.9552083],[-0.06852827],[0.029141279],[-0.053249933]],"dense_1_W":[[0.0010664682,1.3813498,-8.153277,-0.009101015,-0.1484779,1.0008405,-1.5930991,-1.195274,0.6136762,0.3560462,-0.30077773,0.93531257,0.14550218,-0.40074933,-0.21716364,0.13834935,-0.0658936,-0.49427196],[-0.7338253,-0.037501235,-0.49922377,-1.0526338,-0.46141604,-1.3649396,0.7309814,-0.91667104,0.044683233,-0.18628967,-0.20878822,-0.2678598,0.48446324,0.51164204,0.09547851,0.41491362,-0.4524314,0.16594785],[-0.0032175342,3.5451593,-0.11421584,-0.2511033,0.27893174,0.6384996,0.80790603,1.3835542,1.8000495,2.249461,1.4026878,0.7851167,-0.35052946,0.041820426,-0.39790183,0.45703772,-0.30459648,0.18287674],[0.72289664,-0.77138704,-0.5025135,-0.49323097,-0.39893976,-0.8779149,0.6848096,-0.58729875,-0.16643623,-0.14427555,-0.15013328,-0.11467142,-0.27280045,0.48508415,0.52080667,-0.0029569597,-0.28170735,0.06367212],[0.00014026981,-2.0353239,0.0060915067,0.4794941,1.1882906,-1.512865,0.80642134,-0.26044324,-0.56213886,-0.365122,0.55078083,-0.34897435,-0.32031298,0.46106994,0.37792024,-0.14116105,0.15597256,-0.32811671],[0.0011494387,1.9060265,8.3941965,-0.3078165,-0.9530427,0.6589645,-1.2487054,-0.541133,0.13451256,0.2805466,-0.33187166,0.9900705,0.2821258,-0.51270896,-0.5130031,-0.28222615,0.042734932,0.27233443],[-0.0014444552,-1.0933362,0.003359957,-0.15052961,0.37165833,1.7087307,-1.4971043,0.673802,-0.108465396,-0.088505454,0.21561684,0.6252258,-0.15019403,-0.34727478,0.08958758,-0.1723621,-0.25557828,0.29778987]],"activation":"σ"},{"dense_2_W":[[0.20810607,-0.13481373,-0.15003344,-0.6067625,-0.31937903,-0.37380016,0.4666911],[0.71834767,0.15669753,-0.11389502,0.27131546,-0.060118295,0.039282244,0.52961355],[-0.27200606,0.43380752,-0.106262706,-0.49363258,0.35659012,-0.01706296,-1.0807354],[-0.79583454,-0.66428274,-0.42157334,-0.52979547,-0.2803004,-0.57637554,0.084149174],[0.1230394,-0.57023287,0.28639448,-0.506744,-0.9920808,0.7510901,0.8584937],[-0.41256845,0.35423175,0.13009231,0.5198333,0.7576573,-0.7053181,-0.3390053],[-0.15090485,0.33375353,-0.64164793,0.57386595,0.25700107,-0.15245672,-0.49020413],[-0.50120676,0.5210849,-0.3282951,0.4276323,1.0257447,-1.0398436,-0.8911315],[0.11402861,-0.41491523,0.247507,-0.39776865,-0.6089287,0.20646147,0.6692102],[0.09411492,0.31819808,0.41330767,0.024243973,0.2314893,0.08529045,0.14911193],[0.5179265,0.20473345,-0.36762783,-0.009045922,-0.19436747,-0.548099,-0.08656279],[-0.69121784,-0.14201449,0.3887621,0.10787631,1.0371574,-0.64747447,-0.73437464],[-0.07860244,-0.597764,0.019551078,0.010199122,-0.7493642,0.66619915,0.121666186]],"activation":"σ","dense_2_b":[[-0.04259814],[-0.053309314],[-0.28045595],[-0.23801634],[0.00944943],[-0.109921046],[-0.037457183],[0.24627604],[-0.0069056284],[-0.04725389],[-0.03361769],[0.044101644],[-0.0009850285]]},{"dense_3_W":[[-0.19631335,-0.47722518,-0.019853225,-0.29363275,-0.625923,0.35145283,0.62401354,0.14337404,-0.25707108,-0.51310915,0.2565006,0.61742216,-0.07952821],[0.5868974,-0.36786363,-0.0177682,-0.45121866,0.68608487,-0.55178356,-0.35236016,-0.7226455,-0.015394288,-0.10650332,0.5391039,0.17791761,0.34196886],[0.16821232,-0.35580373,0.26906335,0.41736925,-0.6979869,0.41801625,0.34707317,0.7784011,-0.10002936,0.32485273,-0.3644285,0.49092358,-0.43872768]],"activation":"identity","dense_3_b":[[-0.019481273],[0.031026587],[-0.03595322]]},{"dense_4_W":[[-0.72340566,0.21244061,-0.67248434]],"dense_4_b":[[0.026229527]],"activation":"identity"}]} \ No newline at end of file diff --git a/frogpilot/assets/other_images/frogpilot_boot_logo.png b/frogpilot/assets/other_images/frogpilot_boot_logo.png index f502d99f4..85cf7de4c 100644 Binary files a/frogpilot/assets/other_images/frogpilot_boot_logo.png and b/frogpilot/assets/other_images/frogpilot_boot_logo.png differ diff --git a/panda/board/drivers/can_common.h b/panda/board/drivers/can_common.h index 69e23a86d..5c064457a 100644 --- a/panda/board/drivers/can_common.h +++ b/panda/board/drivers/can_common.h @@ -200,7 +200,7 @@ void ignition_can_hook(CANPacket_t *to_push) { if (bus == 0) { int addr = GET_ADDR(to_push); int len = GET_LEN(to_push); - + // GM exception if ((addr == 0xC9) && (len == 8)) { // Matches SystemPowerMode (1=Run, 0=Off) @@ -220,16 +220,6 @@ void ignition_can_hook(CANPacket_t *to_push) { ignition_can = (GET_BYTE(to_push, 0) >> 5) == 0x6U; ignition_can_cnt = 0U; } - - } else if (bus == 2) { - int addr = GET_ADDR(to_push); - int len = GET_LEN(to_push); - // GM exception, SDGM cars have this message on bus 2 - if ((addr == 0x1F1) && (len == 8)) { - // SystemPowerMode (2=Run, 3=Crank Request) - ignition_can = (GET_BYTE(to_push, 0) & 0x2U) != 0U; - ignition_can_cnt = 0U; - } } } diff --git a/panda/board/obj/bootstub.panda.bin b/panda/board/obj/bootstub.panda.bin index 021ae9daf..b36512438 100755 Binary files a/panda/board/obj/bootstub.panda.bin and b/panda/board/obj/bootstub.panda.bin differ diff --git a/panda/board/obj/bootstub.panda_h7.bin b/panda/board/obj/bootstub.panda_h7.bin index c2066c76b..e391d4285 100755 Binary files a/panda/board/obj/bootstub.panda_h7.bin and b/panda/board/obj/bootstub.panda_h7.bin differ diff --git a/panda/board/obj/panda.bin.signed b/panda/board/obj/panda.bin.signed index 40a4ec65f..0b1d0c991 100644 Binary files a/panda/board/obj/panda.bin.signed and b/panda/board/obj/panda.bin.signed differ diff --git a/panda/board/obj/panda_h7.bin.signed b/panda/board/obj/panda_h7.bin.signed index 65706ef0c..0841942ae 100644 Binary files a/panda/board/obj/panda_h7.bin.signed and b/panda/board/obj/panda_h7.bin.signed differ diff --git a/panda/board/safety/safety_gm.h b/panda/board/safety/safety_gm.h index dfa936e69..916c2349a 100644 --- a/panda/board/safety/safety_gm.h +++ b/panda/board/safety/safety_gm.h @@ -10,16 +10,30 @@ const SteeringLimits GM_STEERING_LIMITS = { }; const LongitudinalLimits GM_ASCM_LONG_LIMITS = { - .max_gas = 3072, - .min_gas = 1404, - .inactive_gas = 1404, + .max_gas = 7168, + .min_gas = 5500, + .inactive_gas = 5500, + .max_brake = 400, +}; + +const LongitudinalLimits GM_ASCM_LONG_LIMITS_SPORT = { + .max_gas = 8191, + .min_gas = 5500, + .inactive_gas = 5500, .max_brake = 400, }; const LongitudinalLimits GM_CAM_LONG_LIMITS = { - .max_gas = 3400, - .min_gas = 1514, - .inactive_gas = 1554, + .max_gas = 7496, + .min_gas = 5610, + .inactive_gas = 5650, + .max_brake = 400, +}; + +const LongitudinalLimits GM_CAM_LONG_LIMITS_SPORT = { + .max_gas = 8848, + .min_gas = 5610, + .inactive_gas = 5650, .max_brake = 400, }; @@ -40,35 +54,32 @@ const CanMsg GM_CAM_TX_MSGS[] = {{0x180, 0, 4}, {0x200, 0, 6}, {0x1E1, 0, 7}, {0 {0x1E1, 2, 7}, {0x184, 2, 8}}; // camera bus const CanMsg GM_CAM_LONG_TX_MSGS[] = {{0x180, 0, 4}, {0x315, 0, 5}, {0x2CB, 0, 8}, {0x370, 0, 6}, {0x200, 0, 6}, {0xBD, 0, 7}, {0x1F5, 0, 8}, // pt bus - {0x1E1, 2, 7}, {0x184, 2, 8}}; // camera bus + {0x315, 2, 5}, {0x1E1, 2, 7}, {0x184, 2, 8}}; // camera bus -const CanMsg GM_SDGM_TX_MSGS[] = {{0x180, 0, 4}, {0x1E1, 0, 7}, {0xBD, 0, 7}, {0x1F5, 0, 8}, // pt bus - {0x184, 2, 8}}; // camera bus - -const CanMsg GM_CC_LONG_TX_MSGS[] = {{0x180, 0, 4}, {0x1E1, 0, 7}, {0xBD, 0, 7}, {0x1F5, 0, 8}, // pt bus +const CanMsg GM_CC_LONG_TX_MSGS[] = {{0x180, 0, 4}, {0x1E1, 0, 7}, {0xBD, 0, 7}, {0x1F5, 0, 8}, // pt bus {0x184, 2, 8}, {0x1E1, 2, 7}}; // camera bus // TODO: do checksum and counter checks. Add correct timestep, 0.1s for now. RxCheck gm_rx_checks[] = { {.msg = {{0x184, 0, 8, .frequency = 10U}, { 0 }, { 0 }}}, {.msg = {{0x34A, 0, 5, .frequency = 10U}, { 0 }, { 0 }}}, - {.msg = {{0x1E1, 0, 7, .frequency = 10U}, // Non-SDGM Car - {0x1E1, 2, 7, .frequency = 100000U}}}, // SDGM Car - {.msg = {{0xF1, 0, 6, .frequency = 10U}, // Non-SDGM Car - {0xF1, 2, 6, .frequency = 100000U}}}, // SDGM Car + {.msg = {{0x1E1, 0, 7, .frequency = 10U}, { 0 }, { 0 }}}, + {.msg = {{0xF1, 0, 6, .frequency = 10U}, { 0 }, { 0 }}}, {.msg = {{0x1C4, 0, 8, .frequency = 10U}, { 0 }, { 0 }}}, {.msg = {{0xC9, 0, 8, .frequency = 10U}, { 0 }, { 0 }}}, }; const uint16_t GM_PARAM_HW_CAM = 1; const uint16_t GM_PARAM_HW_CAM_LONG = 2; -const uint16_t GM_PARAM_HW_SDGM = 4; -const uint16_t GM_PARAM_CC_LONG = 8; -const uint16_t GM_PARAM_HW_ASCM_LONG = 16; -const uint16_t GM_PARAM_NO_CAMERA = 32; -const uint16_t GM_PARAM_NO_ACC = 64; -const uint16_t GM_PARAM_PEDAL_LONG = 128; // TODO: this can be inferred -const uint16_t GM_PARAM_PEDAL_INTERCEPTOR = 256; +const uint16_t GM_PARAM_CC_LONG = 4; +const uint16_t GM_PARAM_HW_ASCM_LONG = 8; +const uint16_t GM_PARAM_NO_CAMERA = 16; +const uint16_t GM_PARAM_NO_ACC = 32; +const uint16_t GM_PARAM_PEDAL_LONG = 64; // TODO: this can be inferred +const uint16_t GM_PARAM_PEDAL_INTERCEPTOR = 128; +const uint16_t GM_PARAM_ASCM_INT = 256; +const uint16_t GM_PARAM_FORCE_BRAKE_C9 = 512; +const uint16_t GM_PARAM_HW_SDGM = 1024; enum { GM_BTN_UNPRESS = 1, @@ -90,30 +101,9 @@ bool gm_pedal_long = false; bool gm_cc_long = false; bool gm_skip_relay_check = false; bool gm_force_ascm = false; - -static void handle_gm_wheel_buttons(const CANPacket_t *to_push) { - int button = (GET_BYTE(to_push, 5) & 0x70U) >> 4; - - // enter controls on falling edge of set or rising edge of resume (avoids fault) - bool set = (button != GM_BTN_SET) && (cruise_button_prev == GM_BTN_SET); - bool res = (button == GM_BTN_RESUME) && (cruise_button_prev != GM_BTN_RESUME); - if (set || res) { - controls_allowed = true; - } - - // exit controls on cancel press - if (button == GM_BTN_CANCEL) { - controls_allowed = false; - } - - cruise_button_prev = button; -} +bool gm_force_brake_c9 = false; static void gm_rx_hook(const CANPacket_t *to_push) { - if ((GET_BUS(to_push) == 2U) && (GET_ADDR(to_push) == 0x1E1) && (gm_hw == GM_SDGM)) { - // SDGM buttons are on bus 2 - handle_gm_wheel_buttons(to_push); - } if (GET_BUS(to_push) == 0U) { int addr = GET_ADDR(to_push); @@ -131,19 +121,35 @@ static void gm_rx_hook(const CANPacket_t *to_push) { vehicle_moving = (left_rear_speed > GM_STANDSTILL_THRSLD) || (right_rear_speed > GM_STANDSTILL_THRSLD); } - // ACC steering wheel buttons (GM_CAM and GM_SDGM are tied to the PCM) - if ((addr == 0x1E1) && (!gm_pcm_cruise || gm_cc_long) && (gm_hw != GM_SDGM)) { - handle_gm_wheel_buttons(to_push); + // ACC steering wheel buttons (GM_CAM is tied to the PCM) + if ((addr == 0x1E1) && (!gm_pcm_cruise || gm_cc_long)) { + int button = (GET_BYTE(to_push, 5) & 0x70U) >> 4; + + // enter controls on falling edge of set or rising edge of resume (avoids fault) + bool set = (button != GM_BTN_SET) && (cruise_button_prev == GM_BTN_SET); + bool res = (button == GM_BTN_RESUME) && (cruise_button_prev != GM_BTN_RESUME); + if (set || res) { + controls_allowed = true; + } + + // exit controls on cancel press + if (button == GM_BTN_CANCEL) { + controls_allowed = false; + } + + cruise_button_prev = button; } // Reference for brake pressed signals: // https://github.com/commaai/openpilot/blob/master/selfdrive/car/gm/carstate.py - if ((addr == 0xBE) && (gm_hw == GM_ASCM)) { + // Prefer 0xC9 (ECMEngineStatus) when gm_force_brake_c9 is set, otherwise keep legacy behavior. + // This allows SDGM/Traverse variants without 0xBE (ECMAcceleratorPos) to report brake correctly. + if ((addr == 0xC9) && gm_force_brake_c9) { + brake_pressed = GET_BIT(to_push, 40U) != 0U; + } else if ((addr == 0xBE) && ((gm_hw == GM_ASCM) || (gm_hw == GM_SDGM))) { brake_pressed = GET_BYTE(to_push, 1) >= 8U; - } - - if ((addr == 0xC9) && ((gm_hw == GM_CAM) || (gm_hw == GM_SDGM))) { - brake_pressed = GET_BIT(to_push, 40U); + } else if ((addr == 0xC9) && (gm_hw == GM_CAM)) { + brake_pressed = GET_BIT(to_push, 40U) != 0U; } if (addr == 0xC9) { @@ -172,13 +178,6 @@ static void gm_rx_hook(const CANPacket_t *to_push) { } } - // Cruise check for ACC models with pedal interceptor - block stock ACC - if ((addr == 0x1C4) && gm_has_acc && enable_gas_interceptor) { - // When pedal interceptor is active on ACC models, ignore stock cruise state - // to prevent conflicts between pedal interceptor and stock ACC - cruise_engaged_prev = false; - } - if (addr == 0xBD) { regen_braking = (GET_BYTE(to_push, 0) >> 4) != 0U; } @@ -203,7 +202,13 @@ static void gm_rx_hook(const CANPacket_t *to_push) { int addr = GET_ADDR(to_push); if ((addr == 0x370) && (GET_BUS(to_push) == 2U)) { bool cruise_engaged = (GET_BYTE(to_push, 2) >> 7) != 0U; // ACCCmdActive - cruise_engaged_prev = cruise_engaged; + // Align SDGM/camera PCM cruise behavior with ASCM path: when using stock PCM cruise, + // drive controls_allowed via pcm_cruise_check on ACC engaged edges. + if (gm_pcm_cruise && gm_has_acc) { + pcm_cruise_check(cruise_engaged); + } else { + cruise_engaged_prev = cruise_engaged; + } } } @@ -242,10 +247,10 @@ static bool gm_tx_hook(const CANPacket_t *to_send) { // GAS/REGEN: safety check if (addr == 0x2CB) { bool apply = GET_BIT(to_send, 0U); - int gas_regen = ((GET_BYTE(to_send, 2) & 0x7FU) << 5) + ((GET_BYTE(to_send, 3) & 0xF8U) >> 3); + int gas_regen = ((GET_BYTE(to_send, 1) & 0x1U) << 13) + ((GET_BYTE(to_send, 2) & 0xFFU) << 5) + ((GET_BYTE(to_send, 3) & 0xF8U) >> 3); bool violation = false; - // Allow apply bit in pre-enabled and overriding states, except for inactive gas // Allow apply bit in pre-enabled and overriding states + // Allow apply bit in pre-enabled and overriding states violation |= !controls_allowed && apply; violation |= longitudinal_gas_checks(gas_regen, *gm_long_limits); @@ -259,13 +264,8 @@ static bool gm_tx_hook(const CANPacket_t *to_send) { int button = (GET_BYTE(to_send, 5) >> 4) & 0x7U; bool allowed_btn = (button == GM_BTN_CANCEL) && cruise_engaged_prev; - // For ACC cars with pedal interceptor, allow cancel even if cruise_engaged_prev is false - // (since we set it to false to prevent conflicts, but still need to cancel cruise) - if (gm_hw == GM_CAM && enable_gas_interceptor && button == GM_BTN_CANCEL) { - allowed_btn = true; - } - // For standard CC, allow spamming of SET / RESUME - if (gm_cc_long) { + // For CC_LONG or PCM cruise vehicles, allow SET/RESUME when cruise is engaged + if (gm_cc_long || gm_pcm_cruise) { allowed_btn |= cruise_engaged_prev && (button == GM_BTN_SET || button == GM_BTN_RESUME || button == GM_BTN_UNPRESS); } @@ -273,23 +273,6 @@ static bool gm_tx_hook(const CANPacket_t *to_send) { tx = false; } } - - // REGEN PADDLE - if (addr == 0xBD) { - bool regen_apply = GET_BIT(to_send, 7) || GET_BIT(to_send, 6) || GET_BIT(to_send, 5) || GET_BIT(to_send, 4); - if (!controls_allowed && regen_apply) { - tx = false; - } - } - - // PRNDL2 regen check (7 for Gen0, Gen1. 5 For Gen2) - if (addr == 0x1F5) { - uint8_t prndl2 = GET_BYTE(to_send, 3) & 0xF; - bool prndl_apply = (prndl2 == 7) || (prndl2 == 5); - if (!controls_allowed && prndl_apply) { - tx = false; - } - } return tx; } @@ -306,13 +289,9 @@ static int gm_fwd_hook(int bus_num, int addr) { } if (bus_num == 2) { - // block lkas message and acc messages - // Block 0x370 only for experimental long without pedal interceptor + // block lkas message and acc messages if gm_cam_long, forward all others bool is_lkas_msg = (addr == 0x180); - bool is_acc_msg = (addr == 0x315) || (addr == 0x2CB); - if (gm_cam_long && !enable_gas_interceptor) { - is_acc_msg = is_acc_msg || (addr == 0x370); - } + bool is_acc_msg = (addr == 0x315) || (addr == 0x2CB) || (addr == 0x370); bool block_msg = is_lkas_msg || (is_acc_msg && gm_cam_long); if (!block_msg) { bus_fwd = 0; @@ -324,9 +303,11 @@ static int gm_fwd_hook(int bus_num, int addr) { } static safety_config gm_init(uint16_t param) { - if GET_FLAG(param, GM_PARAM_HW_CAM) { + sport_mode = alternative_experience & ALT_EXP_RAISE_LONGITUDINAL_LIMITS_TO_ISO_MAX; + const bool gm_ascm_int = GET_FLAG(param, GM_PARAM_ASCM_INT); + if (GET_FLAG(param, GM_PARAM_HW_CAM)) { gm_hw = GM_CAM; - } else if GET_FLAG(param, GM_PARAM_HW_SDGM) { + } else if (GET_FLAG(param, GM_PARAM_HW_SDGM)) { gm_hw = GM_SDGM; } else { gm_hw = GM_ASCM; @@ -334,24 +315,29 @@ static safety_config gm_init(uint16_t param) { gm_force_ascm = GET_FLAG(param, GM_PARAM_HW_ASCM_LONG); - if (gm_hw == GM_ASCM || gm_force_ascm) { - gm_long_limits = &GM_ASCM_LONG_LIMITS; + if (gm_hw == GM_ASCM || gm_force_ascm || gm_ascm_int) { + if (sport_mode) { + gm_long_limits = &GM_ASCM_LONG_LIMITS_SPORT; + } else { + gm_long_limits = &GM_ASCM_LONG_LIMITS; + } } else if ((gm_hw == GM_CAM) || (gm_hw == GM_SDGM)) { - gm_long_limits = &GM_CAM_LONG_LIMITS; + if (sport_mode) { + gm_long_limits = &GM_CAM_LONG_LIMITS_SPORT; + } else { + gm_long_limits = &GM_CAM_LONG_LIMITS; + } } else { } gm_pedal_long = GET_FLAG(param, GM_PARAM_PEDAL_LONG); gm_cc_long = GET_FLAG(param, GM_PARAM_CC_LONG); gm_cam_long = GET_FLAG(param, GM_PARAM_HW_CAM_LONG) && !gm_cc_long; - // Block ACC messages when pedal interceptor is active on ACC models - if (gm_hw == GM_CAM && enable_gas_interceptor) { - gm_cam_long = true; - } - gm_pcm_cruise = ((gm_hw == GM_CAM) && (!gm_cam_long || gm_cc_long) && !gm_force_ascm && !gm_pedal_long) || (gm_hw == GM_SDGM); + gm_pcm_cruise = (((gm_hw == GM_CAM) || (gm_hw == GM_SDGM)) && (!gm_cam_long || gm_cc_long) && !gm_force_ascm && !gm_pedal_long); gm_skip_relay_check = GET_FLAG(param, GM_PARAM_NO_CAMERA); gm_has_acc = !GET_FLAG(param, GM_PARAM_NO_ACC); enable_gas_interceptor = GET_FLAG(param, GM_PARAM_PEDAL_INTERCEPTOR); + gm_force_brake_c9 = GET_FLAG(param, GM_PARAM_FORCE_BRAKE_C9); safety_config ret = BUILD_SAFETY_CFG(gm_rx_checks, GM_ASCM_TX_MSGS); if (gm_hw == GM_CAM) { @@ -362,8 +348,6 @@ static safety_config gm_init(uint16_t param) { } else { ret = BUILD_SAFETY_CFG(gm_rx_checks, GM_CAM_TX_MSGS); } - } else if (gm_hw == GM_SDGM) { - ret = BUILD_SAFETY_CFG(gm_rx_checks, GM_SDGM_TX_MSGS); } return ret; } diff --git a/panda/python/__init__.py b/panda/python/__init__.py index 9339bfcf8..7090b78a1 100644 --- a/panda/python/__init__.py +++ b/panda/python/__init__.py @@ -211,7 +211,6 @@ class Panda: FLAG_HYUNDAI_ALT_LIMITS = 64 FLAG_HYUNDAI_CANFD_HDA2_ALT_STEERING = 128 FLAG_HYUNDAI_LFA_BTN = 256 - FLAG_HYUNDAI_TACO_TUNE_HACK = 512 FLAG_TESLA_POWERTRAIN = 1 FLAG_TESLA_LONG_CONTROL = 2 @@ -231,13 +230,15 @@ class Panda: FLAG_GM_HW_CAM = 1 FLAG_GM_HW_CAM_LONG = 2 - FLAG_GM_HW_SDGM = 4 - FLAG_GM_CC_LONG = 8 - FLAG_GM_HW_ASCM_LONG = 16 - FLAG_GM_NO_CAMERA = 32 - FLAG_GM_NO_ACC = 64 - FLAG_GM_PEDAL_LONG = 128 # TODO: This can be inferred - FLAG_GM_GAS_INTERCEPTOR = 256 + FLAG_GM_CC_LONG = 4 + FLAG_GM_HW_ASCM_LONG = 8 + FLAG_GM_NO_CAMERA = 16 + FLAG_GM_NO_ACC = 32 + FLAG_GM_PEDAL_LONG = 64 # TODO: This can be inferred + FLAG_GM_GAS_INTERCEPTOR = 128 + FLAG_GM_ASCM_INT = 256 + FLAG_GM_FORCE_BRAKE_C9 = 512 + FLAG_GM_HW_SDGM = 1024 FLAG_FORD_LONG_CONTROL = 1 FLAG_FORD_CANFD = 2 diff --git a/selfdrive/car/fingerprints.py b/selfdrive/car/fingerprints.py index 1128a31c2..d50cebe52 100644 --- a/selfdrive/car/fingerprints.py +++ b/selfdrive/car/fingerprints.py @@ -150,6 +150,7 @@ MIGRATION = { "FORD MUSTANG MACH-E 1ST GEN": FORD.FORD_MUSTANG_MACH_E_MK1, "HOLDEN ASTRA RS-V BK 2017": GM.HOLDEN_ASTRA, "CHEVROLET VOLT PREMIER 2017": GM.CHEVROLET_VOLT, + "CHEVROLET VOLT CAMERA HARNESS": GM.CHEVROLET_VOLT_CAM, "CADILLAC ATS Premium Performance 2018": GM.CADILLAC_ATS, "CHEVROLET MALIBU PREMIER 2017": GM.CHEVROLET_MALIBU, "GMC ACADIA DENALI 2018": GM.GMC_ACADIA, diff --git a/selfdrive/car/gm/carcontroller.py b/selfdrive/car/gm/carcontroller.py index ef9a32789..9122ce2c3 100644 --- a/selfdrive/car/gm/carcontroller.py +++ b/selfdrive/car/gm/carcontroller.py @@ -1,5 +1,3 @@ -from typing import Tuple -import time from cereal import car from openpilot.common.conversions import Conversions as CV from openpilot.common.filter_simple import FirstOrderFilter @@ -9,11 +7,10 @@ from openpilot.common.params_pyx import Params from opendbc.can.packer import CANPacker from openpilot.selfdrive.car import apply_driver_steer_torque_limits, create_gas_interceptor_command from openpilot.selfdrive.car.gm import gmcan -from openpilot.selfdrive.car.gm.values import DBC, AccState, CanBus, CarControllerParams, CruiseButtons, GMFlags, CC_ONLY_CAR, SDGM_CAR, EV_CAR, CC_REGEN_PADDLE_CAR +from openpilot.selfdrive.car.gm.values import DBC, AccState, CanBus, CarControllerParams, CruiseButtons, GMFlags, CC_ONLY_CAR, SDGM_CAR, EV_CAR from openpilot.selfdrive.car.interfaces import CarControllerBase from openpilot.selfdrive.controls.lib.drive_helpers import apply_deadzone from openpilot.selfdrive.controls.lib.vehicle_model import ACCELERATION_DUE_TO_GRAVITY -from openpilot.common.swaglog import cloudlog VisualAlert = car.CarControl.HUDControl.VisualAlert NetworkLocation = car.CarParams.NetworkLocation @@ -25,15 +22,7 @@ TransmissionType = car.CarParams.TransmissionType CAMERA_CANCEL_DELAY_FRAMES = 10 # Enforce a minimum interval between steering messages to avoid a fault MIN_STEER_MSG_INTERVAL_MS = 15 -# Two‑sided spacing tuned for ~33 Hz steer; target a 10 ms wide window per interval -# Paddle spoofing and scheduling constants -PADDLE_STEER_GAP_MIN_NS = 5_000_000 # ≥5 ms each side (EPS guard) -PADDLE_STEER_GAP_MAX_NS = 12_000_000 # cap for long intervals -PADDLE_GAP_TARGET_NS = 5_000_000 # aim per‑side gap even if interval//2 − early is larger -PADDLE_NONBLOCK_GAP_NS = 1_000_000 # ≥1 ms since last paddle send -PADDLE_SLOT_EARLY_NS = 1_000_000 # allow firing up to 1 ms before slot -OVERFLOW_THRESH = 1.00 # fire one extra slot whenever credits ≥ 1.0 -PADDLE_TARGET_HZ = 42.0 # desired paddle rate (Hz) when regen active; steer is ~33 Hz + # Constants for pitch compensation BRAKE_PITCH_FACTOR_BP = [5., 10.] # [m/s] smoothly revert to planned accel at low speeds BRAKE_PITCH_FACTOR_V = [0., 1.] # [unitless in [0,1]]; don't touch @@ -49,11 +38,6 @@ class CarController(CarControllerBase): self.apply_speed = 0 self.frame = 0 self.last_steer_frame = 0 - self.last_steer_ts_ns = 0 - self.last_regen_active = False - self.prev_steer_ts_ns = 0 - self.last_spoof_ts_ns = 0 - self.last_paddle_ts_ns = 0 self.last_button_frame = 0 self.cancel_counter = 0 self.pedal_steady = 0. @@ -70,71 +54,27 @@ class CarController(CarControllerBase): # FrogPilot variables self.accel_g = 0.0 - self.pitch = FirstOrderFilter(0., 0.09 * 4, DT_CTRL * 4) # runs at 25 Hz self.accel_g = 0.0 - self.regen_paddle_pressed = False - self.aego = 0.0 - self.regen_paddle_timer = 0 + @staticmethod + def calc_pedal_command(accel: float, long_active: bool) -> float: + if not long_active: return 0. + zero = 0.15625 # 40/256 + if accel > 0.: + # Scales the accel from 0-1 to 0.156-1 + pedal_gas = clip(((1 - zero) * accel + zero), 0., 1.) + else: + # if accel is negative, -0.1 -> 0.015625 + pedal_gas = clip(zero + accel, 0., zero) # Make brake the same size as gas, but clip to regen - # Midpoint + overflow spoof accumulator and flags - self.spoof_accum = 0.0 - self.spoof_mid_sent = False - self.spoof_over_sent = False - self.last_interval_ns = 0 - - def calc_pedal_command(self, accel: float, long_active: bool, car_velocity) -> Tuple[float, bool]: - if not long_active: - return 0., False - - # Regen paddle hysteresis (frame-based): hold 10 frames, with decrement dead-zone - if not hasattr(self, 'regen_paddle_timer'): - self.regen_paddle_timer = 0 # frames - - # Regen paddle hysteresis (frame‑based): count frames when decelerating hard, decrement only when truly released - if self.aego < -0.7: - self.regen_paddle_timer += 1 - elif self.aego > -0.3: - self.regen_paddle_timer = max(self.regen_paddle_timer - 1, 0) - # else: hold timer between -0.7 and -0.3 - - # Base paddle press hysteresis - self.regen_paddle_pressed = self.regen_paddle_timer >= 10 # 10 frames - press_regen_paddle = self.regen_paddle_pressed - - - # Regen gain ratios from bin-averaged 60–0 deceleration sweep; Calculates stronger decel from paddle - speed_mps = [0.559, 1.678, 2.797, 3.916, 5.035, 6.154, 7.273, 8.392, 9.511, 10.63, - 11.749, 12.868, 13.987, 15.106, 16.225, 17.344, 18.463, 19.582, 20.701, 21.820, - 22.939, 24.058, 25.177, 26.296] - regen_gain_ratio = [ - 1.000000, 1.057308, 1.131123, 1.220611, 1.270247, 1.300253, 1.339543, 1.361002, - 1.388410, 1.403253, 1.414721, 1.430949, 1.420289, 1.436787, 1.434116, 1.436805, - 1.417508, 1.402213, 1.395360, 1.360921, 1.342030, 1.292219, 1.270048, 1.239172 - ] - - gain = interp(car_velocity, speed_mps, regen_gain_ratio) - pedaloffset = interp(car_velocity, [0., 3, 6, 30], [0.10, 0.175, 0.240, 0.240]) - - # Compute raw pedal gas - raw_pedal_gas = clip((pedaloffset + (accel / gain) * 0.6), 0.0, 1.0) if press_regen_paddle else clip((pedaloffset + accel * 0.6), 0.0, 1.0) - - # --- Immediate application of raw pedal gas, no blending --- - pedal_gas = raw_pedal_gas - # Safety cap: ramp from 22% at 0 m/s to 37.25% at 10 mph (4.47 m/s), then allow full throttle - pedal_gas_max = interp(car_velocity, [0.0, 4.47, 4.48], [0.22, 0.3725, 1.0]) - pedal_gas = clip(pedal_gas, 0.0, pedal_gas_max) - return pedal_gas, press_regen_paddle + return pedal_gas def update(self, CC, CS, now_nanos, frogpilot_toggles): - self.CS = CS - self.aego = CS.out.aEgo actuators = CC.actuators accel = brake_accel = actuators.accel - press_regen_paddle = False hud_control = CC.hudControl hud_alert = hud_control.visualAlert hud_v_cruise = hud_control.setSpeed @@ -143,138 +83,6 @@ class CarController(CarControllerBase): # Send CAN commands. can_sends = [] - paddle_sends = [] - - raw_regen_active = ( - self.CP.carFingerprint in CC_REGEN_PADDLE_CAR and - self.CP.openpilotLongitudinalControl and - CC.longActive and - self.CP.enableGasInterceptor and - self.regen_paddle_timer >= 10 # raw hysteresis-only (10 frames) - ) - regen_active = raw_regen_active - - # === Spoof scheduling: midpoint + overflow (~target Hz) === - # Rising-edge reset on regen start - if raw_regen_active and not self.last_regen_active: - self.prev_steer_ts_ns = self.last_steer_ts_ns - self.last_spoof_ts_ns = 0 - self.spoof_accum = 0.0 - self.spoof_mid_sent = False - self.spoof_over_sent = False - - if raw_regen_active: - # Interval between last two bus-0 steer sends - interval_ns = self.last_steer_ts_ns - self.prev_steer_ts_ns - - # Adaptive two‑sided gap sized to the current steer interval, but capped to a target so the window stays wide enough - gap_ns = (PADDLE_STEER_GAP_MIN_NS if interval_ns <= 0 else - max(PADDLE_STEER_GAP_MIN_NS, - min(PADDLE_STEER_GAP_MAX_NS, - min((interval_ns // 2) - PADDLE_SLOT_EARLY_NS, PADDLE_GAP_TARGET_NS)))) - - # New steer interval? clear per-interval flags and add credits to reach target Hz - if interval_ns != self.last_interval_ns: - self.spoof_mid_sent = False - self.spoof_over_sent = False - self.last_interval_ns = interval_ns - # Add credits once per new steer interval to reach the desired paddle rate - if interval_ns > 0: - steer_hz = 1e9 / float(interval_ns) - extra_needed = max(0.0, (PADDLE_TARGET_HZ / steer_hz) - 1.0) # e.g., 42/33 − 1 ≈ 0.2727 - self.spoof_accum += extra_needed - - # Midpoint spoof: one per interval - if not self.spoof_mid_sent and interval_ns > 0: - midpoint_ns = self.prev_steer_ts_ns + interval_ns // 2 - cloudlog.error("PADDLE MID: Δafter=%.1fms Δbefore=%.1fms credits=%.3f timer=%d", - (now_nanos - self.last_steer_ts_ns) * 1e-6, - (now_nanos - self.prev_steer_ts_ns) * 1e-6, - self.spoof_accum, - self.regen_paddle_timer) - # Compute spacing to last and next steer (two-sided guard) - next_steer_ts_ns = self.last_steer_ts_ns + interval_ns if interval_ns > 0 else 0 - delta_after_ns = now_nanos - self.last_steer_ts_ns - delta_before_ns = (next_steer_ts_ns - now_nanos) if interval_ns > 0 else 1_000_000_000 - if (CS.out.vEgo > 2.68 - and now_nanos >= (midpoint_ns - PADDLE_SLOT_EARLY_NS) - and delta_after_ns >= gap_ns - and delta_before_ns >= gap_ns): - # Non-blocking 1 ms spacing for paddle frames - if now_nanos - self.last_paddle_ts_ns >= PADDLE_NONBLOCK_GAP_NS: - paddle_sends.append(gmcan.create_prndl2_command(self.packer_pt, CanBus.POWERTRAIN, True)) - paddle_sends.append(gmcan.create_regen_paddle_command(self.packer_pt, CanBus.POWERTRAIN, True)) - self.last_paddle_ts_ns = now_nanos - self.last_spoof_ts_ns = now_nanos - self.spoof_mid_sent = True - - # Overflow spoof: insert extra when accumulator allows - if self.spoof_accum >= OVERFLOW_THRESH and not self.spoof_over_sent and interval_ns > 0: - slot2_ns = self.prev_steer_ts_ns + (interval_ns * 2) // 3 - cloudlog.error("PADDLE OFL: Δafter=%.1fms Δbefore=%.1fms credits=%.3f thresh=%.1f timer=%d", - (now_nanos - self.last_steer_ts_ns) * 1e-6, - (now_nanos - self.prev_steer_ts_ns) * 1e-6, - self.spoof_accum, - OVERFLOW_THRESH, - self.regen_paddle_timer) - # Two-sided spacing relative to steer - next_steer_ts_ns = self.last_steer_ts_ns + interval_ns if interval_ns > 0 else 0 - delta_after_ns = now_nanos - self.last_steer_ts_ns - delta_before_ns = (next_steer_ts_ns - now_nanos) if interval_ns > 0 else 1_000_000_000 - if (CS.out.vEgo > 2.68 - and now_nanos >= (slot2_ns - PADDLE_SLOT_EARLY_NS) - and delta_after_ns >= gap_ns - and delta_before_ns >= gap_ns): - # Non-blocking 1 ms spacing for paddle frames - if now_nanos - self.last_paddle_ts_ns >= PADDLE_NONBLOCK_GAP_NS: - paddle_sends.append(gmcan.create_prndl2_command(self.packer_pt, CanBus.POWERTRAIN, True)) - paddle_sends.append(gmcan.create_regen_paddle_command(self.packer_pt, CanBus.POWERTRAIN, True)) - self.last_paddle_ts_ns = now_nanos - self.last_spoof_ts_ns = now_nanos - self.spoof_over_sent = True - self.spoof_accum -= OVERFLOW_THRESH - # === End Spoof scheduling === - - # === Off-pulse scheduling on regen release === - if not raw_regen_active and self.last_regen_active: - # schedule two off-slots at 1/3 and 2/3 of the last steer interval - if self.prev_steer_ts_ns and self.last_steer_ts_ns: - intv = self.last_steer_ts_ns - self.prev_steer_ts_ns - self.off_schedule_ns = [ - self.prev_steer_ts_ns + intv // 3, - self.prev_steer_ts_ns + (2 * intv) // 3 - ] - self.off_sent = [False, False] - - if hasattr(self, "off_schedule_ns"): - for i, t_ns in enumerate(self.off_schedule_ns): - if not self.off_sent[i] and now_nanos >= (t_ns - PADDLE_SLOT_EARLY_NS): - cloudlog.error("PADDLE OFF %d: Δafter=%.1fms Δto_slot=%.1fms timer=%d", - i, - (now_nanos - self.last_steer_ts_ns) * 1e-6, - (now_nanos - t_ns) * 1e-6, - self.regen_paddle_timer) - # Two-sided spacing to steer before sending - interval_ns = self.last_steer_ts_ns - self.prev_steer_ts_ns - gap_ns = (PADDLE_STEER_GAP_MIN_NS if interval_ns <= 0 else - max(PADDLE_STEER_GAP_MIN_NS, - min(PADDLE_STEER_GAP_MAX_NS, - min((interval_ns // 2) - PADDLE_SLOT_EARLY_NS, PADDLE_GAP_TARGET_NS)))) - next_steer_ts_ns = self.last_steer_ts_ns + interval_ns if interval_ns > 0 else 0 - delta_after_ns = now_nanos - self.last_steer_ts_ns - delta_before_ns = (next_steer_ts_ns - now_nanos) if interval_ns > 0 else 1_000_000_000 - if (delta_after_ns >= gap_ns and delta_before_ns >= gap_ns): - # Non-blocking 1 ms spacing for paddle frames - if now_nanos - self.last_paddle_ts_ns >= PADDLE_NONBLOCK_GAP_NS: - paddle_sends.append(gmcan.create_prndl2_command(self.packer_pt, CanBus.POWERTRAIN, False)) - paddle_sends.append(gmcan.create_regen_paddle_command(self.packer_pt, CanBus.POWERTRAIN, False)) - self.last_paddle_ts_ns = now_nanos - self.off_sent[i] = True - # clean up once both off pulses are sent - if hasattr(self, "off_sent") and all(self.off_sent): - del self.off_schedule_ns - del self.off_sent - # === End off-pulse scheduling === # Steering (Active: 50Hz, inactive: 10Hz) steer_step = self.params.STEER_STEP if CC.latActive else self.params.INACTIVE_STEER_STEP @@ -304,27 +112,11 @@ class CarController(CarControllerBase): else: apply_steer = 0 - # shift previous steer timestamp - self.prev_steer_ts_ns = self.last_steer_ts_ns - self.last_steer_ts_ns = now_nanos self.last_steer_frame = self.frame self.apply_steer_last = apply_steer idx = self.lka_steering_cmd_counter % 4 can_sends.append(gmcan.create_steering_control(self.packer_pt, CanBus.POWERTRAIN, apply_steer, idx, CC.latActive)) - # Update regen_active state and last_regen_paddle_pressed for next loop - self.last_regen_active = regen_active - self.last_regen_paddle_pressed = self.regen_paddle_pressed - - if paddle_sends: - interval_ns = self.last_steer_ts_ns - self.prev_steer_ts_ns - flush_gap_ns = (PADDLE_STEER_GAP_MIN_NS if interval_ns <= 0 else - max(PADDLE_STEER_GAP_MIN_NS, - min(PADDLE_STEER_GAP_MAX_NS, - min((interval_ns // 2) - PADDLE_SLOT_EARLY_NS, PADDLE_GAP_TARGET_NS)))) - if now_nanos - self.last_steer_ts_ns >= flush_gap_ns: - can_sends.extend(paddle_sends) - if self.CP.openpilotLongitudinalControl: # Gas/regen, brakes, and UI commands - all at 25Hz if self.frame % 4 == 0: @@ -350,15 +142,26 @@ class CarController(CarControllerBase): self.apply_brake = int(min(-100 * frogpilot_toggles.stopAccel, self.params.MAX_BRAKE)) else: # Normal operation - self.apply_gas = int(round(interp(accel, self.params.GAS_LOOKUP_BP, self.params.GAS_LOOKUP_V))) - self.apply_brake = int(round(interp(brake_accel, self.params.BRAKE_LOOKUP_BP, self.params.BRAKE_LOOKUP_V))) + if self.CP.carFingerprint in EV_CAR: + self.params.update_ev_gas_brake_threshold(CS.out.vEgo) + if frogpilot_toggles.sport_plus: + self.apply_gas = int(round(interp(accel, self.params.EV_GAS_LOOKUP_BP_PLUS, self.params.GAS_LOOKUP_V_PLUS))) + else: + self.apply_gas = int(round(interp(accel, self.params.EV_GAS_LOOKUP_BP, self.params.GAS_LOOKUP_V))) + self.apply_brake = int(round(interp(brake_accel, self.params.EV_BRAKE_LOOKUP_BP, self.params.BRAKE_LOOKUP_V))) + else: + if frogpilot_toggles.sport_plus: + self.apply_gas = int(round(interp(accel, self.params.GAS_LOOKUP_BP_PLUS, self.params.GAS_LOOKUP_V_PLUS))) + else: + self.apply_gas = int(round(interp(accel, self.params.GAS_LOOKUP_BP, self.params.GAS_LOOKUP_V))) + self.apply_brake = int(round(interp(brake_accel, self.params.BRAKE_LOOKUP_BP, self.params.BRAKE_LOOKUP_V))) # Don't allow any gas above inactive regen while stopping # FIXME: brakes aren't applied immediately when enabling at a stop if stopping: self.apply_gas = self.params.INACTIVE_REGEN if self.CP.carFingerprint in CC_ONLY_CAR: # gas interceptor only used for full long control on cars without ACC - interceptor_gas_cmd, press_regen_paddle = self.calc_pedal_command(actuators.accel, CC.longActive, CS.out.vEgo) + interceptor_gas_cmd = self.calc_pedal_command(actuators.accel, CC.longActive) if self.CP.enableGasInterceptor and self.apply_gas > self.params.INACTIVE_REGEN and CS.out.cruiseState.standstill: # "Tap" the accelerator pedal to re-engage ACC @@ -381,6 +184,8 @@ class CarController(CarControllerBase): if self.CP.networkLocation == NetworkLocation.fwdCamera and self.CP.carFingerprint not in CC_ONLY_CAR: at_full_stop = at_full_stop and stopping friction_brake_bus = CanBus.POWERTRAIN + if self.CP.carFingerprint in SDGM_CAR: + friction_brake_bus = CanBus.CAMERA if self.CP.autoResumeSng: resume = actuators.longControlState != LongCtrlState.starting or CC.cruiseControl.resume @@ -394,7 +199,7 @@ class CarController(CarControllerBase): # GasRegenCmdActive needs to be 1 to avoid cruise faults. It describes the ACC state, not actuation can_sends.append(gmcan.create_gas_regen_command(self.packer_pt, CanBus.POWERTRAIN, self.apply_gas, idx, acc_engaged, at_full_stop)) can_sends.append(gmcan.create_friction_brake_command(self.packer_ch, friction_brake_bus, self.apply_brake, - idx, CC.enabled, near_stop, at_full_stop, self.CP)) + idx, CC.enabled, near_stop, at_full_stop, self.CP)) # Send dashboard UI commands (ACC status) send_fcw = hud_alert == VisualAlert.fcw @@ -405,18 +210,22 @@ class CarController(CarControllerBase): accel += self.accel_g # Radar needs to know current speed and yaw rate (50hz), - # and that ADAS is alive (5hz, previously 10hz) - if not self.CP.radarUnavailable: + # and that ADAS is alive (10hz) + if not self.CP.radarUnavailable and self.CP.networkLocation != NetworkLocation.fwdCamera and self.CP.carFingerprint not in SDGM_CAR: tt = self.frame * DT_CTRL - time_and_headlights_step = 20 + time_and_headlights_step = 10 if self.frame % time_and_headlights_step == 0: idx = (self.frame // time_and_headlights_step) % 4 can_sends.append(gmcan.create_adas_time_status(CanBus.OBSTACLE, int((tt - self.start_time) * 60), idx)) can_sends.append(gmcan.create_adas_headlights_status(self.packer_obj, CanBus.OBSTACLE)) + + speed_and_accelerometer_step = 2 + if self.frame % speed_and_accelerometer_step == 0: + idx = (self.frame // speed_and_accelerometer_step) % 4 can_sends.append(gmcan.create_adas_steering_status(CanBus.OBSTACLE, idx)) can_sends.append(gmcan.create_adas_accelerometer_speed_status(CanBus.OBSTACLE, CS.out.vEgo, idx)) - if self.CP.networkLocation == NetworkLocation.gateway and self.frame % (self.params.ADAS_KEEPALIVE_STEP * 2) == 0: + if self.CP.networkLocation == NetworkLocation.gateway and self.frame % self.params.ADAS_KEEPALIVE_STEP == 0: can_sends += gmcan.create_adas_keepalive(CanBus.POWERTRAIN) # TODO: integrate this with the code block below? @@ -437,14 +246,11 @@ class CarController(CarControllerBase): if (self.frame - self.last_button_frame) * DT_CTRL > 0.04: if self.cancel_counter > CAMERA_CANCEL_DELAY_FRAMES: self.last_button_frame = self.frame - if self.CP.carFingerprint in SDGM_CAR: - can_sends.append(gmcan.create_buttons(self.packer_pt, CanBus.POWERTRAIN, CS.buttons_counter, CruiseButtons.CANCEL)) - else: - can_sends.append(gmcan.create_buttons(self.packer_pt, CanBus.CAMERA, CS.buttons_counter, CruiseButtons.CANCEL)) + can_sends.append(gmcan.create_buttons(self.packer_pt, CanBus.CAMERA, CS.buttons_counter, CruiseButtons.CANCEL)) if self.CP.networkLocation == NetworkLocation.fwdCamera: # Silence "Take Steering" alert sent by camera, forward PSCMStatus with HandsOffSWlDetectionStatus=1 - if self.frame % 20 == 0: + if self.frame % 10 == 0: can_sends.append(gmcan.create_pscm_status(self.packer_pt, CanBus.CAMERA, CS.pscm_status)) new_actuators = actuators.as_builder() diff --git a/selfdrive/car/gm/carstate.py b/selfdrive/car/gm/carstate.py index 68015ac06..bb6ea9508 100644 --- a/selfdrive/car/gm/carstate.py +++ b/selfdrive/car/gm/carstate.py @@ -5,7 +5,7 @@ from openpilot.common.numpy_fast import mean from opendbc.can.can_define import CANDefine from opendbc.can.parser import CANParser from openpilot.selfdrive.car.interfaces import CarStateBase -from openpilot.selfdrive.car.gm.values import DBC, AccState, CanBus, STEER_THRESHOLD, GMFlags, CC_ONLY_CAR, CAMERA_ACC_CAR, SDGM_CAR, CC_REGEN_PADDLE_CAR +from openpilot.selfdrive.car.gm.values import DBC, AccState, CanBus, STEER_THRESHOLD, GMFlags, CC_ONLY_CAR, CAMERA_ACC_CAR, SDGM_CAR, ASCM_INT, CAR TransmissionType = car.CarParams.TransmissionType NetworkLocation = car.CarParams.NetworkLocation @@ -39,14 +39,9 @@ class CarState(CarStateBase): self.prev_cruise_buttons = self.cruise_buttons self.prev_distance_button = self.distance_button - if self.CP.carFingerprint not in SDGM_CAR: - self.cruise_buttons = pt_cp.vl["ASCMSteeringButton"]["ACCButtons"] - self.distance_button = pt_cp.vl["ASCMSteeringButton"]["DistanceButton"] - self.buttons_counter = pt_cp.vl["ASCMSteeringButton"]["RollingCounter"] - else: - self.cruise_buttons = cam_cp.vl["ASCMSteeringButton"]["ACCButtons"] - self.distance_button = cam_cp.vl["ASCMSteeringButton"]["DistanceButton"] - self.buttons_counter = cam_cp.vl["ASCMSteeringButton"]["RollingCounter"] + self.cruise_buttons = pt_cp.vl["ASCMSteeringButton"]["ACCButtons"] + self.distance_button = pt_cp.vl["ASCMSteeringButton"]["DistanceButton"] + self.buttons_counter = pt_cp.vl["ASCMSteeringButton"]["RollingCounter"] self.pscm_status = copy.copy(pt_cp.vl["PSCMStatus"]) # This is to avoid a fault where you engage while still moving backwards after shifting to D. # An Equinox has been seen with an unsupported status (3), so only check if either wheel is in reverse (2) @@ -56,13 +51,6 @@ class CarState(CarStateBase): self.loopback_lka_steering_cmd_updated = len(loopback_cp.vl_all["ASCMLKASteeringCmd"]["RollingCounter"]) > 0 if self.loopback_lka_steering_cmd_updated: self.loopback_lka_steering_cmd_ts_nanos = loopback_cp.ts_nanos["ASCMLKASteeringCmd"]["RollingCounter"] - - # Track timestamps for OEM PRNDL2 and Regen Paddle messages (used to sync spoofing timing) - self.prndl2_ts_nanos = pt_cp.ts_nanos["ECMPRDNL2"]["PRNDL2"] - if self.CP.carFingerprint in CC_REGEN_PADDLE_CAR: - self.regen_paddle_ts_nanos = pt_cp.ts_nanos["EBCMRegenPaddle"]["RegenPaddle"] - else: - self.regen_paddle_ts_nanos = 0 if self.CP.networkLocation == NetworkLocation.fwdCamera and not self.CP.flags & GMFlags.NO_CAMERA.value: self.pt_lka_steering_cmd_counter = pt_cp.vl["ASCMLKASteeringCmd"]["RollingCounter"] self.cam_lka_steering_cmd_counter = cam_cp.vl["ASCMLKASteeringCmd"]["RollingCounter"] @@ -78,25 +66,30 @@ class CarState(CarStateBase): # sample rear wheel speeds, standstill=True if ECM allows engagement with brake ret.standstill = ret.wheelSpeeds.rl <= STANDSTILL_THRESHOLD and ret.wheelSpeeds.rr <= STANDSTILL_THRESHOLD - ret.gearShifter = self.parse_gear_shifter(self.shifter_values.get(pt_cp.vl["ECMPRDNL2"]["PRNDL2"], None)) + if pt_cp.vl["ECMPRDNL2"]["ManualMode"] == 1: + ret.gearShifter = self.parse_gear_shifter("T") + else: + ret.gearShifter = self.parse_gear_shifter(self.shifter_values.get(pt_cp.vl["ECMPRDNL2"]["PRNDL2"], None)) if self.CP.flags & GMFlags.NO_ACCELERATOR_POS_MSG.value: - ret.brake = pt_cp.vl["EBCMBrakePedalPosition"]["BrakePedalPosition"] / 0xd0 + ret.brake = pt_cp.vl.get("EBCMBrakePedalPosition", {}).get("BrakePedalPosition", 0) / 0xd0 else: - ret.brake = pt_cp.vl["ECMAcceleratorPos"]["BrakePedalPos"] - if self.CP.networkLocation == NetworkLocation.fwdCamera: + ret.brake = pt_cp.vl.get("ECMAcceleratorPos", {}).get("BrakePedalPos", 0) + + if (self.CP.flags & GMFlags.FORCE_BRAKE_C9.value) or (self.CP.networkLocation == NetworkLocation.fwdCamera): ret.brakePressed = pt_cp.vl["ECMEngineStatus"]["BrakePressed"] != 0 else: # Some Volt 2016-17 have loose brake pedal push rod retainers which causes the ECM to believe # that the brake is being intermittently pressed without user interaction. # To avoid a cruise fault we need to use a conservative brake position threshold # https://static.nhtsa.gov/odi/tsbs/2017/MC-10137629-9999.pdf - ret.brakePressed = ret.brake >= 8 + analog_thresh = 0.07 if (self.CP.flags & GMFlags.NO_ACCELERATOR_POS_MSG.value) else 8 + ret.brakePressed = ret.brake >= analog_thresh # Regen braking is braking if self.CP.transmissionType == TransmissionType.direct: ret.regenBraking = pt_cp.vl["EBCMRegenPaddle"]["RegenPaddle"] != 0 - self.single_pedal_mode = ret.gearShifter == GearShifter.low or pt_cp.vl["EVDriveMode"]["SinglePedalModeActive"] == 1 or (ret.regenBraking and GearShifter.manumatic) + self.single_pedal_mode = ret.gearShifter == GearShifter.low or pt_cp.vl["EVDriveMode"]["SinglePedalModeActive"] == 1 or (ret.regenBraking and GearShifter.manumatic) or (self.CP.carFingerprint in [CAR.CHEVROLET_BOLT_EUV, CAR.CHEVROLET_BOLT_CC] and self.CP.enableGasInterceptor) if self.CP.enableGasInterceptor: ret.gas = (pt_cp.vl["GAS_SENSOR"]["INTERCEPTOR_GAS"] + pt_cp.vl["GAS_SENSOR"]["INTERCEPTOR_GAS2"]) / 2. @@ -117,32 +110,19 @@ class CarState(CarStateBase): ret.steerFaultTemporary = self.lkas_status == 2 ret.steerFaultPermanent = self.lkas_status == 3 - if self.CP.carFingerprint not in SDGM_CAR: - # 1 - open, 0 - closed - ret.doorOpen = (pt_cp.vl["BCMDoorBeltStatus"]["FrontLeftDoor"] == 1 or - pt_cp.vl["BCMDoorBeltStatus"]["FrontRightDoor"] == 1 or - pt_cp.vl["BCMDoorBeltStatus"]["RearLeftDoor"] == 1 or - pt_cp.vl["BCMDoorBeltStatus"]["RearRightDoor"] == 1) - # 1 - latched - ret.seatbeltUnlatched = pt_cp.vl["BCMDoorBeltStatus"]["LeftSeatBelt"] == 0 - ret.leftBlinker = pt_cp.vl["BCMTurnSignals"]["TurnSignals"] == 1 - ret.rightBlinker = pt_cp.vl["BCMTurnSignals"]["TurnSignals"] == 2 + # 1 - open, 0 - closed + ret.doorOpen = (pt_cp.vl["BCMDoorBeltStatus"]["FrontLeftDoor"] == 1 or + pt_cp.vl["BCMDoorBeltStatus"]["FrontRightDoor"] == 1 or + pt_cp.vl["BCMDoorBeltStatus"]["RearLeftDoor"] == 1 or + pt_cp.vl["BCMDoorBeltStatus"]["RearRightDoor"] == 1) - ret.parkingBrake = pt_cp.vl["BCMGeneralPlatformStatus"]["ParkBrakeSwActive"] == 1 - else: - # 1 - open, 0 - closed - ret.doorOpen = (cam_cp.vl["BCMDoorBeltStatus"]["FrontLeftDoor"] == 1 or - cam_cp.vl["BCMDoorBeltStatus"]["FrontRightDoor"] == 1 or - cam_cp.vl["BCMDoorBeltStatus"]["RearLeftDoor"] == 1 or - cam_cp.vl["BCMDoorBeltStatus"]["RearRightDoor"] == 1) + # 1 - latched + ret.seatbeltUnlatched = pt_cp.vl["BCMDoorBeltStatus"]["LeftSeatBelt"] == 0 + ret.leftBlinker = pt_cp.vl["BCMTurnSignals"]["TurnSignals"] == 1 + ret.rightBlinker = pt_cp.vl["BCMTurnSignals"]["TurnSignals"] == 2 - # 1 - latched - ret.seatbeltUnlatched = cam_cp.vl["BCMDoorBeltStatus"]["LeftSeatBelt"] == 0 - ret.leftBlinker = cam_cp.vl["BCMTurnSignals"]["TurnSignals"] == 1 - ret.rightBlinker = cam_cp.vl["BCMTurnSignals"]["TurnSignals"] == 2 - - ret.parkingBrake = cam_cp.vl["BCMGeneralPlatformStatus"]["ParkBrakeSwActive"] == 1 + ret.parkingBrake = pt_cp.vl["BCMGeneralPlatformStatus"]["ParkBrakeSwActive"] == 1 ret.cruiseState.available = pt_cp.vl["ECMEngineStatus"]["CruiseMainOn"] != 0 ret.espDisabled = pt_cp.vl["ESPStatus"]["TractionControlOn"] != 1 ret.accFaulted = (pt_cp.vl["AcceleratorPedal2"]["CruiseState"] == AccState.FAULTED or @@ -153,12 +133,11 @@ class CarState(CarStateBase): if self.CP.networkLocation == NetworkLocation.fwdCamera and not self.CP.flags & GMFlags.NO_CAMERA.value: if self.CP.carFingerprint not in CC_ONLY_CAR: ret.cruiseState.speed = cam_cp.vl["ASCMActiveCruiseControlStatus"]["ACCSpeedSetpoint"] * CV.KPH_TO_MS - if self.CP.carFingerprint not in SDGM_CAR: + if self.CP.carFingerprint not in (SDGM_CAR|ASCM_INT): ret.stockAeb = cam_cp.vl["AEBCmd"]["AEBCmdActive"] != 0 - else: - ret.stockAeb = False # openpilot controls nonAdaptive when not pcmCruise - if self.CP.pcmCruise: + # 2016-2018 Volt won't identify non-adaptive cruise state since switchable cruise state was not introduced till 2019 model year / SDGM Global AAdd commentMore actions + if self.CP.pcmCruise and self.CP.carFingerprint not in ASCM_INT: ret.cruiseState.nonAdaptive = cam_cp.vl["ASCMActiveCruiseControlStatus"]["ACCCruiseState"] not in (2, 3) if self.CP.carFingerprint in CC_ONLY_CAR: ret.accFaulted = False @@ -166,19 +145,11 @@ class CarState(CarStateBase): ret.cruiseState.enabled = pt_cp.vl["ECMCruiseControl"]["CruiseActive"] != 0 if self.CP.enableBsm: - if self.CP.carFingerprint not in SDGM_CAR: - ret.leftBlindspot = pt_cp.vl["BCMBlindSpotMonitor"]["LeftBSM"] == 1 - ret.rightBlindspot = pt_cp.vl["BCMBlindSpotMonitor"]["RightBSM"] == 1 - else: - ret.leftBlindspot = cam_cp.vl["BCMBlindSpotMonitor"]["LeftBSM"] == 1 - ret.rightBlindspot = cam_cp.vl["BCMBlindSpotMonitor"]["RightBSM"] == 1 - + ret.leftBlindspot = pt_cp.vl["BCMBlindSpotMonitor"]["LeftBSM"] == 1 + ret.rightBlindspot = pt_cp.vl["BCMBlindSpotMonitor"]["RightBSM"] == 1 self.lkas_previously_enabled = self.lkas_enabled - if self.CP.carFingerprint in SDGM_CAR: - self.lkas_enabled = cam_cp.vl["ASCMSteeringButton"]["LKAButton"] - else: - self.lkas_enabled = pt_cp.vl["ASCMSteeringButton"]["LKAButton"] + self.lkas_enabled = pt_cp.vl["ASCMSteeringButton"]["LKAButton"] self.pcm_acc_status = pt_cp.vl["AcceleratorPedal2"]["CruiseState"] @@ -193,16 +164,7 @@ class CarState(CarStateBase): messages += [ ("ASCMLKASteeringCmd", 10), ] - if CP.carFingerprint in SDGM_CAR: - messages += [ - ("BCMTurnSignals", 1), - ("BCMDoorBeltStatus", 10), - ("BCMGeneralPlatformStatus", 10), - ("ASCMSteeringButton", 33), - ] - if CP.enableBsm: - messages.append(("BCMBlindSpotMonitor", 10)) - else: + if CP.carFingerprint not in (SDGM_CAR|ASCM_INT): messages += [ ("AEBCmd", 10), ] @@ -216,34 +178,25 @@ class CarState(CarStateBase): @staticmethod def get_can_parser(CP, FPCP): messages = [ + ("BCMTurnSignals", 1), + ("ECMPRDNL2", 10), ("PSCMStatus", 10), ("ESPStatus", 10), + ("BCMDoorBeltStatus", 10), + ("BCMGeneralPlatformStatus", 10), ("EBCMWheelSpdFront", 20), ("EBCMWheelSpdRear", 20), ("EBCMFrictionBrakeStatus", 20), + ("AcceleratorPedal2", 33), + ("ASCMSteeringButton", 33), + ("ECMEngineStatus", 100), ("PSCMSteeringAngle", 100), ("ECMAcceleratorPos", 80), ("SportMode", 0), ] - if CP.carFingerprint in SDGM_CAR: - messages += [ - ("ECMPRDNL2", 40), - ("AcceleratorPedal2", 40), - ("ECMEngineStatus", 80), - ] - else: - messages += [ - ("ECMPRDNL2", 40), - ("AcceleratorPedal2", 33), - ("ECMEngineStatus", 100), - ("BCMTurnSignals", 1), - ("BCMDoorBeltStatus", 10), - ("BCMGeneralPlatformStatus", 10), - ("ASCMSteeringButton", 33), - ] - if CP.enableBsm: - messages.append(("BCMBlindSpotMonitor", 10)) + if CP.enableBsm: + messages.append(("BCMBlindSpotMonitor", 10)) # Used to read back last counter sent to PT by camera if CP.networkLocation == NetworkLocation.fwdCamera: @@ -256,7 +209,7 @@ class CarState(CarStateBase): if CP.transmissionType == TransmissionType.direct: messages += [ - ("EBCMRegenPaddle", 40), + ("EBCMRegenPaddle", 50), ("EVDriveMode", 0), ] @@ -270,6 +223,7 @@ class CarState(CarStateBase): ("GAS_SENSOR", 50), ] + return CANParser(DBC[CP.carFingerprint]["pt"], messages, CanBus.POWERTRAIN) @staticmethod diff --git a/selfdrive/car/gm/fingerprints.py b/selfdrive/car/gm/fingerprints.py index d18319343..59ee7b0a2 100644 --- a/selfdrive/car/gm/fingerprints.py +++ b/selfdrive/car/gm/fingerprints.py @@ -26,6 +26,22 @@ FINGERPRINTS = { { 170: 8, 171: 8, 189: 7, 190: 6, 193: 8, 197: 8, 199: 4, 201: 8, 209: 7, 211: 2, 241: 6, 288: 5, 298: 8, 304: 1, 308: 4, 309: 8, 311: 8, 313: 8, 320: 3, 328: 1, 352: 5, 381: 6, 384: 4, 386: 8, 388: 8, 389: 2, 390: 7, 417: 7, 419: 1, 426: 7, 451: 8, 452: 8, 453: 6, 454: 8, 456: 8, 479: 3, 481: 7, 485: 8, 489: 8, 493: 8, 495: 4, 497: 8, 499: 3, 500: 6, 501: 8, 508: 8, 528: 4, 532: 6, 546: 7, 550: 8, 554: 3, 558: 8, 560: 8, 562: 8, 563: 5, 564: 5, 565: 5, 566: 5, 567: 3, 568: 1, 573: 1, 577: 8, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 647: 3, 707: 8, 711: 6, 717: 5, 761: 7, 800: 6, 810: 8, 840: 5, 842: 5, 844: 8, 866: 4, 869: 4, 961: 8, 967: 4, 969: 8, 977: 8, 979: 7, 988: 6, 989: 8, 995: 7, 1001: 8, 1005: 6, 1009: 8, 1017: 8, 1019: 2, 1020: 8, 1033: 7, 1034: 7, 1105: 6, 1187: 4, 1217: 8, 1221: 5, 1223: 3, 1225: 7, 1227: 4, 1233: 8, 1249: 8, 1257: 6, 1265: 8, 1267: 1, 1273: 3, 1275: 3, 1280: 4, 1300: 8, 1322: 6, 1323: 4, 1328: 4, 1417: 8, 1601: 8, 1905: 7, 1906: 7, 1907: 7, 1910: 7, 1912: 7, 1922: 7, 1927: 7, 1930: 7, 2017: 8, 2020: 8, 2025: 8, 2028: 8 }], + CAR.CHEVROLET_VOLT_CAM: [ + # Causes errors with normal OBD install + # { + # # CHEVROLET_VOLT with camera network location + # 170: 8, 171: 8, 189: 7, 190: 6, 193: 8, 197: 8, 199: 4, 201: 8, 209: 7, 211: 2, 241: 6, 288: 5, 298: 8, 304: 1, 308: 4, 309: 8, 311: 8, 313: 8, 320: 3, 328: 1, 352: 5, 381: 6, 384: 4, 386: 8, 388: 8, 389: 2, 390: 7, 417: 7, 419: 1, 426: 7, 451: 8, 452: 8, 453: 6, 454: 8, 456: 8, 479: 3, 481: 7, 485: 8, 489: 8, 493: 8, 495: 4, 497: 8, 499: 3, 500: 6, 501: 8, 508: 8, 528: 4, 532: 6, 546: 7, 550: 8, 554: 3, 558: 8, 560: 8, 562: 8, 563: 5, 564: 5, 565: 5, 566: 5, 567: 3, 568: 1, 573: 1, 577: 8, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 647: 3, 707: 8, 711: 6, 717: 5, 761: 7, 800: 6, 810: 8, 840: 5, 842: 5, 844: 8, 866: 4, 869: 4, 961: 8, 967: 4, 969: 8, 977: 8, 979: 7, 988: 6, 989: 8, 995: 7, 1001: 8, 1005: 6, 1009: 8, 1017: 8, 1019: 2, 1020: 8, 1033: 7, 1034: 7, 1105: 6, 1187: 4, 1217: 8, 1221: 5, 1223: 3, 1225: 7, 1227: 4, 1233: 8, 1249: 8, 1257: 6, 1265: 8, 1267: 1, 1273: 3, 1275: 3, 1280: 4, 1300: 8, 1322: 6, 1323: 4, 1328: 4, 1417: 8, 1601: 8, 1905: 7, 1906: 7, 1907: 7, 1910: 7, 1912: 7, 1922: 7, 1927: 7, 1930: 7, 2017: 8, 2020: 8, 2025: 8, 2028: 8 + # } + ], + CAR.CHEVROLET_VOLT_ASCM: [ + # Causes errors with normal OBD install + # { + # 189: 7, 193: 8, 197: 8, 201: 8, 209: 7, 211: 2, 241: 6, 288: 5, 298: 8, 304: 1, 308: 4, 309: 8, 311: 8, 313: 8, 320: 3, 328: 1, 352: 5, 381: 6, 384: 4, 386: 8, 388: 8, 451: 8, 452: 8, 453: 6, 479: 3, 481: 7, 485: 8, 489: 8, 493: 8, 497: 8, 500: 6, 501: 8, 528: 4, 532: 6, 560: 8, 562: 8, 563: 5, 565: 5, 566: 5, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 707: 8, 715: 8, 717: 5, 761: 7, 767: 4, 810: 8, 840: 5, 842: 5, 844: 8, 869: 4, 880: 6, 977: 8, 1001: 8, 1017: 8, 1020: 8, 1033: 7, 1034: 7, 1217: 8, 1221: 5, 1233: 8, 1249: 8, 1265: 8, 1267: 1, 1280: 4, 1296: 4, 1300: 8, 1922: 7, 1930: 7Add commentMore actions + # } + ], + CAR.GMC_ACADIA_ASCM: [ + # Causes errors with normal OBD install + ], CAR.BUICK_LACROSSE: [{ 190: 6, 193: 8, 197: 8, 199: 4, 201: 8, 209: 7, 211: 2, 241: 6, 249: 8, 288: 5, 298: 8, 304: 1, 309: 8, 311: 8, 313: 8, 320: 3, 322: 7, 328: 1, 352: 5, 353: 3, 381: 6, 386: 8, 388: 8, 393: 7, 398: 8, 407: 7, 413: 8, 417: 7, 419: 1, 422: 4, 426: 7, 431: 8, 442: 8, 451: 8, 452: 8, 453: 6, 455: 7, 456: 8, 463: 3, 479: 3, 481: 7, 485: 8, 487: 8, 489: 8, 495: 4, 497: 8, 499: 3, 500: 6, 501: 8, 503: 1, 508: 8, 510: 8, 528: 5, 532: 6, 534: 2, 554: 3, 560: 8, 562: 8, 563: 5, 564: 5, 565: 5, 567: 5, 573: 1, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 647: 5, 707: 8, 753: 5, 761: 7, 801: 8, 804: 3, 810: 8, 840: 5, 842: 5, 844: 8, 866: 4, 872: 1, 882: 8, 890: 1, 892: 2, 893: 1, 894: 1, 961: 8, 967: 4, 969: 8, 977: 8, 979: 8, 985: 5, 1001: 8, 1005: 6, 1009: 8, 1011: 6, 1013: 3, 1017: 8, 1019: 2, 1020: 8, 1022: 1, 1105: 6, 1217: 8, 1221: 5, 1223: 2, 1225: 7, 1233: 8, 1243: 3, 1249: 8, 1257: 6, 1259: 8, 1261: 7, 1263: 4, 1265: 8, 1267: 1, 1280: 4, 1300: 8, 1322: 6, 1328: 4, 1417: 8, 1609: 8, 1613: 8, 1649: 8, 1792: 8, 1798: 8, 1824: 8, 1825: 8, 1840: 8, 1842: 8, 1858: 8, 1860: 8, 1863: 8, 1872: 8, 1875: 8, 1882: 8, 1888: 8, 1889: 8, 1892: 8, 1904: 7, 1906: 7, 1907: 7, 1912: 7, 1913: 7, 1914: 7, 1916: 7, 1918: 7, 1919: 7, 1937: 8, 1953: 8, 1968: 8, 2001: 8, 2017: 8, 2018: 8, 2020: 8, 2026: 8 }], @@ -178,31 +194,47 @@ FINGERPRINTS = { CAR.CADILLAC_XT4: [ # Cadillac XT4 w/ ACC 2023 { - 190: 6, 193: 8, 197: 8, 199: 4, 201: 8, 209: 7, 211: 2, 241: 6, 249: 8, 257: 8, 288: 5, 289: 8, 292: 2, 298: 8, 304: 3, 309: 8, 313: 8, 320: 4, 322: 7, 328: 1, 331: 3, 352: 5, 353: 3, 368: 3, 381: 8, 384: 4, 386: 8, 388: 8, 393: 7, 398: 8, 401: 8, 407: 7, 413: 8, 417: 7, 419: 1, 422: 4, 426: 7, 431: 8, 442: 8, 451: 8, 452: 8, 453: 6, 455: 7, 479: 3, 481: 7, 485: 8, 489: 8, 497: 8, 499: 3, 500: 6, 501: 8, 503: 2, 508: 8, 532: 6, 554: 3, 560: 8, 562: 8, 563: 5, 564: 5, 565: 5, 567: 5, 573: 1, 577: 8, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 647: 6, 707: 8, 715: 8, 717: 5, 719: 5, 761: 7, 806: 1, 840: 5, 842: 5, 844: 8, 866: 4, 869: 4, 872: 1, 880: 6, 961: 8, 969: 8, 975: 2, 977: 8, 979: 8, 985: 5, 1001: 8, 1005: 6, 1009: 8, 1011: 6, 1013: 5, 1017: 8, 1020: 8, 1033: 7, 1034: 7, 1037: 5, 1105: 5, 1187: 5, 1195: 3, 1217: 8, 1221: 5, 1223: 2, 1225: 7, 1233: 8, 1236: 8, 1249: 8, 1257: 6, 1259: 8, 1261: 7, 1263: 4, 1265: 8, 1267: 1, 1268: 2, 1271: 8, 1273: 3, 1276: 2, 1277: 7, 1278: 4, 1279: 4, 1280: 4, 1296: 4, 1300: 8, 1322: 6, 1323: 4, 1328: 4, 1345: 8, 1417: 8, 1512: 8, 1517: 8, 1601: 8, 1609: 8, 1613: 8, 1649: 8, 1792: 8, 1793: 8, 1798: 8, 1824: 8, 1825: 8, 1840: 8, 1842: 8, 1858: 8, 1860: 8, 1863: 8, 1872: 8, 1875: 8, 1882: 8, 1888: 8, 1889: 8, 1892: 8, 1906: 7, 1907: 7, 1912: 7, 1919: 7, 1920: 8, 1924: 8, 1930: 7, 1937: 8, 1953: 8, 1968: 8, 1969: 8, 1971: 8, 1975: 8, 1984: 8, 1988: 8, 2000: 8, 2001: 8, 2002: 8, 2016: 8, 2017: 8, 2018: 8, 2020: 8, 2021: 8, 2024: 8, 2026: 8 - }], + 190: 6, 193: 8, 197: 8, 199: 4, 201: 8, 209: 7, 211: 2, 241: 6, 249: 8, 257: 8, 288: 5, 289: 8, 292: 2, 298: 8, 304: 3, 309: 8, 313: 8, 320: 4, 322: 7, 328: 1, 331: 3, 352: 5, 353: 3, 368: 3, 381: 8, 384: 4, 386: 8, 388: 8, 393: 7, 398: 8, 401: 8, 407: 7, 413: 8, 417: 7, 419: 1, 422: 4, 426: 7, 431: 8, 442: 8, 451: 8, 452: 8, 453: 6, 455: 7, 479: 3, 481: 7, 485: 8, 489: 8, 497: 8, 499: 3, 500: 6, 501: 8, 503: 2, 508: 8, 532: 6, 554: 3, 560: 8, 562: 8, 563: 5, 564: 5, 565: 5, 567: 5, 573: 1, 577: 8, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 647: 6, 707: 8, 715: 8, 717: 5, 719: 5, 761: 7, 767: 4, 806: 1, 840: 5, 842: 5, 844: 8, 866: 4, 869: 4, 872: 1, 880: 6, 961: 8, 969: 8, 975: 2, 977: 8, 979: 8, 985: 5, 1001: 8, 1005: 6, 1009: 8, 1011: 6, 1013: 5, 1017: 8, 1020: 8, 1033: 7, 1034: 7, 1037: 5, 1105: 5, 1187: 5, 1195: 3, 1217: 8, 1221: 5, 1223: 2, 1225: 7, 1233: 8, 1236: 8, 1249: 8, 1257: 6, 1259: 8, 1261: 7, 1263: 4, 1265: 8, 1267: 1, 1268: 2, 1271: 8, 1273: 3, 1276: 2, 1277: 7, 1278: 4, 1279: 4, 1280: 4, 1296: 4, 1300: 8, 1322: 6, 1323: 4, 1328: 4, 1345: 8, 1417: 8, 1512: 8, 1517: 8, 1601: 8, 1609: 8, 1613: 8, 1649: 8, 1792: 8, 1793: 8, 1798: 8, 1824: 8, 1825: 8, 1840: 8, 1842: 8, 1858: 8, 1860: 8, 1863: 8, 1872: 8, 1875: 8, 1882: 8, 1888: 8, 1889: 8, 1892: 8, 1906: 7, 1907: 7, 1912: 7, 1919: 7, 1920: 8, 1924: 8, 1930: 7, 1937: 8, 1953: 8, 1968: 8, 1969: 8, 1971: 8, 1975: 8, 1984: 8, 1988: 8, 2000: 8, 2001: 8, 2002: 8, 2016: 8, 2017: 8, 2018: 8, 2020: 8, 2021: 8, 2024: 8, 2026: 8 }], CAR.CADILLAC_XT5_CC: [ # TRain's 2017 XT5 { 190: 6, 193: 8, 197: 8, 199: 4, 201: 8, 208: 8, 209: 7, 211: 2, 241: 6, 249: 8, 288: 5, 298: 8, 304: 1, 309: 8, 313: 8, 320: 3, 322: 7, 328: 1, 352: 5, 353: 3, 381: 6, 384: 4, 386: 8, 388: 8, 393: 7, 398: 8, 407: 7, 413: 8, 417: 7, 419: 1, 422: 4, 426: 7, 431: 8, 442: 8, 451: 8, 452: 8, 453: 6, 454: 8, 455: 7, 462: 4, 463: 3, 479: 3, 481: 7, 485: 8, 487: 8, 489: 8, 495: 4, 497: 8, 499: 3, 500: 6, 501: 8, 503: 1, 508: 8, 510: 8, 532: 6, 554: 3, 560: 8, 562: 8, 563: 5, 564: 5, 567: 5, 647: 3, 707: 8, 717: 5, 723: 2, 753: 5, 761: 7, 800: 6, 840: 5, 842: 5, 844: 8, 866: 4, 869: 4, 872: 1, 961: 8, 967: 4, 969: 8, 977: 8, 979: 8, 985: 5, 1001: 8, 1005: 6, 1009: 8, 1011: 6, 1013: 3, 1017: 8, 1019: 2, 1020: 8, 1022: 1, 1105: 6, 1217: 8, 1221: 5, 1223: 3, 1225: 7, 1233: 8, 1243: 3, 1249: 8, 1257: 6, 1259: 8, 1261: 7, 1263: 4, 1265: 8, 1267: 1, 1280: 4, 1300: 8, 1322: 6, 1328: 4, 1417: 8, 1904: 7, 1906: 7, 1907: 7, 1912: 7, 1913: 7, 1914: 7, 1919: 7, 1920: 7 }], + CAR.CADILLAC_XT6: [ + #{} + ], CAR.CHEVROLET_TRAVERSE: [ # Chevy Traverse w/ ACC 2023 { - 190: 6, 193: 8, 197: 8, 199: 4, 201: 8, 208: 8, 209: 7, 211: 2, 241: 6, 249: 8, 257: 8, 288: 5, 289: 8, 292: 2, 298: 8, 304: 3, 309: 8, 313: 8, 320: 4, 322: 7, 328: 1, 331: 3, 352: 5, 368: 3, 381: 8, 384: 4, 386: 8, 388: 8, 393: 7, 398: 8, 401: 8, 407: 7, 413: 8, 417: 7, 419: 1, 422: 4, 426: 7, 431: 8, 442: 8, 451: 8, 452: 8, 453: 6, 454: 8, 455: 7, 479: 3, 481: 7, 485: 8, 489: 8, 497: 8, 499: 3, 500: 6, 501: 8, 508: 8, 510: 8, 532: 6, 554: 3, 560: 8, 562: 8, 563: 5, 564: 5, 567: 5, 573: 1, 577: 8, 578: 8, 579: 8, 587: 8, 603: 8, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 647: 6, 707: 8, 715: 8, 717: 5, 723: 4, 730: 4, 753: 5, 761: 7, 840: 5, 842: 5, 844: 8, 866: 4, 869: 4, 880: 6, 961: 8, 969: 8, 975: 2, 977: 8, 979: 8, 985: 5, 1001: 8, 1005: 6, 1009: 8, 1011: 6, 1013: 5, 1017: 8, 1020: 8, 1033: 7, 1034: 7, 1105: 5, 1217: 8, 1221: 5, 1223: 3, 1225: 7, 1233: 8, 1236: 8, 1249: 8, 1257: 6, 1259: 8, 1261: 7, 1263: 4, 1265: 8, 1267: 1, 1268: 2, 1271: 8, 1279: 4, 1280: 4, 1296: 4, 1300: 8, 1322: 6, 1323: 4, 1328: 4, 1345: 8, 1346: 8, 1347: 8, 1355: 8, 1362: 8, 1417: 8, 1512: 8, 1514: 8, 1601: 8, 1602: 8, 1603: 7, 1609: 8, 1611: 8, 1613: 8, 1618: 8, 1649: 8, 1792: 8, 1793: 8, 1798: 8, 1799: 8, 1810: 8, 1813: 8, 1824: 8, 1825: 8, 1840: 8, 1842: 8, 1856: 8, 1858: 8, 1859: 8, 1860: 8, 1862: 8, 1863: 8, 1871: 8, 1872: 8, 1875: 8, 1879: 8, 1882: 8, 1888: 8, 1889: 8, 1892: 8, 1906: 7, 1907: 7, 1912: 7, 1919: 7, 1920: 7, 1927: 8, 1930: 7, 1937: 8, 1953: 8, 1954: 8, 1955: 8, 1968: 8, 1969: 8, 1971: 8, 1975: 8, 1988: 8, 1990: 8, 2000: 8, 2001: 8, 2004: 8, 2016: 8, 2017: 8, 2018: 8, 2019: 8, 2020: 8, 2024: 8, 2026: 8 + 190: 6, 193: 8, 197: 8, 199: 4, 201: 8, 208: 8, 209: 7, 211: 2, 241: 6, 249: 8, 257: 8, 288: 5, 289: 8, 292: 2, 298: 8, 304: 3, 309: 8, 313: 8, 320: 4, 322: 7, 328: 1, 331: 3, 352: 5, 368: 3, 381: 8, 384: 4, 386: 8, 388: 8, 393: 7, 398: 8, 401: 8, 407: 7, 413: 8, 417: 7, 419: 1, 422: 4, 426: 7, 431: 8, 442: 8, 451: 8, 452: 8, 453: 6, 454: 8, 455: 7, 479: 3, 481: 7, 485: 8, 489: 8, 497: 8, 499: 3, 500: 6, 501: 8, 508: 8, 510: 8, 532: 6, 554: 3, 560: 8, 562: 8, 563: 5, 564: 5, 567: 5, 573: 1, 577: 8, 578: 8, 579: 8, 587: 8, 603: 8, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 647: 6, 707: 8, 715: 8, 717: 5, 723: 4, 730: 4, 753: 5, 761: 7, 767: 4, 840: 5, 842: 5, 844: 8, 866: 4, 869: 4, 880: 6, 961: 8, 969: 8, 975: 2, 977: 8, 979: 8, 985: 5, 1001: 8, 1005: 6, 1009: 8, 1011: 6, 1013: 5, 1017: 8, 1020: 8, 1033: 7, 1034: 7, 1105: 5, 1217: 8, 1221: 5, 1223: 3, 1225: 7, 1233: 8, 1236: 8, 1249: 8, 1257: 6, 1259: 8, 1261: 7, 1263: 4, 1265: 8, 1267: 1, 1268: 2, 1271: 8, 1279: 4, 1280: 4, 1296: 4, 1300: 8, 1322: 6, 1323: 4, 1328: 4, 1345: 8, 1346: 8, 1347: 8, 1355: 8, 1362: 8, 1417: 8, 1512: 8, 1514: 8, 1601: 8, 1602: 8, 1603: 7, 1609: 8, 1611: 8, 1613: 8, 1618: 8, 1649: 8, 1792: 8, 1793: 8, 1798: 8, 1799: 8, 1810: 8, 1813: 8, 1824: 8, 1825: 8, 1840: 8, 1842: 8, 1856: 8, 1858: 8, 1859: 8, 1860: 8, 1862: 8, 1863: 8, 1871: 8, 1872: 8, 1875: 8, 1879: 8, 1882: 8, 1888: 8, 1889: 8, 1892: 8, 1906: 7, 1907: 7, 1912: 7, 1919: 7, 1920: 7, 1927: 8, 1930: 7, 1937: 8, 1953: 8, 1954: 8, 1955: 8, 1968: 8, 1969: 8, 1971: 8, 1975: 8, 1988: 8, 1990: 8, 2000: 8, 2001: 8, 2004: 8, 2016: 8, 2017: 8, 2018: 8, 2019: 8, 2020: 8, 2024: 8, 2026: 8 + }], + CAR.CHEVROLET_MALIBU_SDGM: [ + # Chevy Malibu w/ SDGM Harness 2019 + { + 190: 6, 193: 8, 197: 8, 201: 8, 209: 7, 211: 2, 241: 6, 249: 8, 257: 5, 288: 5, 289: 8, 298: 8, 304: 1, 309: 8, 311: 8, 313: 8, 320: 3, 328: 1, 352: 5, 381: 8, 384: 4, 386: 8, 388: 8, 413: 8, 451: 8, 452: 8, 453: 6, 455: 7, 479: 3, 481: 7, 485: 8, 489: 8, 497: 8, 500: 6, 501: 8, 532: 6, 560: 8, 562: 8, 563: 5, 565: 5, 587: 8, 707: 8, 715: 8, 717: 5, 761: 7, 767: 4, 810: 8, 840: 5, 842: 5, 844: 8, 869: 4, 880: 6, 882: 8, 890: 1, 892: 2, 893: 2, 894: 1, 977: 8, 1001: 8, 1011: 6, 1017: 8, 1020: 8, 1217: 8, 1221: 5, 1233: 8, 1249: 8, 1259: 8, 1261: 7, 1263: 4, 1265: 8, 1267: 1, 1271: 8, 1280: 4, 1296: 4, 1300: 8, 1353: 8, 1355: 8, 1611: 8, 1792: 8, 1793: 8, 1798: 8, 1799: 8, 1810: 8, 1813: 8, 1824: 8, 1825: 8, 1840: 8, 1842: 8, 1843: 8, 1856: 8, 1858: 8, 1859: 8, 1860: 8, 1862: 8, 1863: 8, 1871: 8, 1872: 8, 1875: 8, 1879: 8, 1882: 8, 1888: 8, 1889: 8, 1892: 8, 1916: 7, 1920: 8, 1927: 8, 1930: 7, 1937: 8, 1953: 8, 1954: 8, 1955: 8, 1968: 8, 1969: 8, 1971: 8, 1975: 8, 1988: 8, 1990: 8, 2000: 8, 2001: 8, 2002: 8, 2004: 8, 2017: 8, 2018: 8, 2020: 8 }], CAR.BUICK_BABYENCLAVE: [ # Buick Baby Enclave w/ ACC 2020-23 { - 190: 6, 193: 8, 197: 8, 199: 4, 201: 8, 208: 8, 209: 7, 211: 2, 241: 6, 249: 8, 257: 8, 288: 5, 289: 8, 292: 2, 298: 8, 304: 3, 309: 8, 311: 8, 313: 8, 320: 4, 322: 7, 328: 1, 331: 3, 352: 5, 353: 3, 368: 3, 381: 8, 384: 4, 386: 8, 388: 8, 394: 7, 398: 8, 401: 8, 405: 8, 407: 7, 413: 8, 417: 7, 419: 1, 422: 4, 426: 7, 431: 8, 442: 8, 450: 4, 451: 8, 452: 8, 453: 6, 454: 8, 455: 7, 456: 8, 457: 6, 462: 4, 463: 3, 479: 3, 481: 7, 485: 8, 489: 8, 497: 8, 499: 3, 500: 6, 501: 8, 503: 2, 508: 8, 528: 5, 532: 6, 554: 3, 560: 8, 562: 8, 563: 5, 564: 5, 565: 5, 567: 5, 569: 3, 573: 1, 577: 8, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 647: 6, 707: 8, 715: 8, 717: 5, 723: 4, 730: 4, 761: 7, 810: 8, 840: 5, 842: 5, 844: 8, 869: 4, 872: 1, 880: 6, 882: 8, 890: 1, 892: 2, 893: 2, 894: 1, 961: 8, 969: 8, 975: 2, 977: 8, 979: 8, 985: 5, 1001: 8, 1005: 6, 1009: 8, 1011: 6, 1013: 6, 1017: 8, 1020: 8, 1033: 7, 1034: 7, 1037: 5, 1105: 5, 1187: 5, 1195: 3, 1201: 3, 1217: 8, 1218: 3, 1221: 5, 1223: 3, 1225: 7, 1233: 8, 1236: 8, 1249: 8, 1257: 6, 1259: 8, 1261: 7, 1263: 4, 1265: 8, 1267: 1, 1268: 2, 1271: 8, 1273: 3, 1276: 2, 1277: 7, 1278: 4, 1279: 4, 1280: 4, 1296: 4, 1300: 8, 1322: 6, 1323: 4, 1328: 4, 1345: 8, 1417: 8, 1512: 8, 1514: 8, 1517: 8, 1601: 8, 1906: 7, 1907: 7, 1910: 7, 1912: 7, 1914: 7, 1916: 7, 1919: 7, 1927: 7, 1930: 7, 2018: 8, 2020: 8, 2021: 8, 2028: 8 + 190: 6, 193: 8, 197: 8, 199: 4, 201: 8, 208: 8, 209: 7, 211: 2, 241: 6, 249: 8, 257: 8, 288: 5, 289: 8, 292: 2, 298: 8, 304: 3, 309: 8, 311: 8, 313: 8, 320: 4, 322: 7, 328: 1, 331: 3, 352: 5, 353: 3, 368: 3, 381: 8, 384: 4, 386: 8, 388: 8, 394: 7, 398: 8, 401: 8, 405: 8, 407: 7, 413: 8, 417: 7, 419: 1, 422: 4, 426: 7, 431: 8, 442: 8, 450: 4, 451: 8, 452: 8, 453: 6, 454: 8, 455: 7, 456: 8, 457: 6, 462: 4, 463: 3, 479: 3, 481: 7, 485: 8, 489: 8, 497: 8, 499: 3, 500: 6, 501: 8, 503: 2, 508: 8, 528: 5, 532: 6, 554: 3, 560: 8, 562: 8, 563: 5, 564: 5, 565: 5, 567: 5, 569: 3, 573: 1, 577: 8, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 647: 6, 707: 8, 715: 8, 717: 5, 723: 4, 730: 4, 761: 7, 767: 4, 810: 8, 840: 5, 842: 5, 844: 8, 869: 4, 872: 1, 880: 6, 882: 8, 890: 1, 892: 2, 893: 2, 894: 1, 961: 8, 969: 8, 975: 2, 977: 8, 979: 8, 985: 5, 1001: 8, 1005: 6, 1009: 8, 1011: 6, 1013: 6, 1017: 8, 1020: 8, 1033: 7, 1034: 7, 1037: 5, 1105: 5, 1187: 5, 1195: 3, 1201: 3, 1217: 8, 1218: 3, 1221: 5, 1223: 3, 1225: 7, 1233: 8, 1236: 8, 1249: 8, 1257: 6, 1259: 8, 1261: 7, 1263: 4, 1265: 8, 1267: 1, 1268: 2, 1271: 8, 1273: 3, 1276: 2, 1277: 7, 1278: 4, 1279: 4, 1280: 4, 1296: 4, 1300: 8, 1322: 6, 1323: 4, 1328: 4, 1345: 8, 1417: 8, 1512: 8, 1514: 8, 1517: 8, 1601: 8, 1906: 7, 1907: 7, 1910: 7, 1912: 7, 1914: 7, 1916: 7, 1919: 7, 1927: 7, 1930: 7, 2018: 8, 2020: 8, 2021: 8, 2028: 8 }], CAR.CHEVROLET_MALIBU_CC: [ { 190: 6, 193: 8, 197: 8, 199: 4, 201: 8, 209: 7, 211: 2, 241: 6, 249: 8, 257: 8, 288: 5, 298: 8, 304: 3, 309: 8, 311: 8, 313: 8, 320: 4, 328: 1, 352: 5, 368: 3, 381: 8, 384: 4, 386: 8, 388: 8, 393: 7, 398: 8, 401: 8, 407: 7, 409: 8, 413: 8, 417: 7, 419: 1, 422: 4, 426: 7, 431: 8, 442: 8, 451: 8, 452: 8, 453: 6, 455: 7, 479: 3, 481: 7, 485: 8, 489: 8, 497: 8, 499: 3, 500: 6, 501: 8, 508: 8, 532: 6, 554: 3, 560: 8, 562: 8, 563: 5, 564: 5, 565: 5, 567: 5, 573: 1, 577: 8, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 647: 6, 707: 8, 717: 5, 730: 4, 761: 7, 800: 6, 810: 8, 840: 5, 842: 5, 844: 8, 866: 4, 869: 4, 961: 8, 969: 8, 975: 2, 977: 8, 979: 8, 985: 5, 1001: 8, 1005: 6, 1009: 8, 1011: 6, 1013: 6, 1017: 8, 1020: 8, 1037: 5, 1105: 5, 1187: 6, 1189: 1, 1195: 3, 1217: 8, 1221: 5, 1223: 3, 1225: 7, 1233: 8, 1236: 8, 1249: 8, 1257: 6, 1259: 8, 1261: 7, 1263: 4, 1265: 8, 1267: 1, 1268: 2, 1271: 8, 1273: 3, 1279: 4, 1280: 4, 1300: 8, 1322: 6, 1323: 4, 1328: 4, 1417: 8, 1601: 8, 1906: 7, 1907: 7, 1912: 7, 1919: 7 }], + CAR.CHEVROLET_MALIBU_HYBRID_CC: [ + { + 193:8, 197:8, 201:8, 209:7, 211:2, 241:6, 249:8, 352:5, 386:8, 451:8, 452:8, 453:6, 481:7, 485:8, 489:8, 493:8, 500:6, 560:8, 562:8, 566:6, 609:6, 610:6, 611:6, 612:8, 613:8, 707:8, 717:5, 761:7, 810:8, 840:5, 842:5, 844:8, 869:4 + }], CAR.CHEVROLET_TRAX: [ { 190: 6, 193: 8, 197: 8, 201: 8, 209: 7, 211: 2, 241: 6, 249: 8, 288: 5, 298: 8, 304: 3, 309: 8, 311: 8, 313: 8, 320: 4, 322: 7, 328: 1, 352: 5, 381: 8, 384: 4, 386: 8, 388: 8, 413: 8, 451: 8, 452: 8, 453: 6, 455: 7, 479: 3, 481: 7, 485: 8, 489: 8, 497: 8, 500: 6, 501: 8, 532: 6, 560: 8, 562: 8, 563: 5, 565: 5, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 707: 8, 715: 8, 717: 5, 761: 7, 789: 5, 800: 6, 810: 8, 840: 5, 842: 5, 844: 8, 869: 4, 880: 6, 977: 8, 1001: 8, 1011: 6, 1017: 8, 1020: 8, 1217: 8, 1221: 5, 1233: 8, 1249: 8, 1259: 8, 1261: 7, 1263: 4, 1265: 8, 1267: 1, 1271: 8, 1280: 4, 1296: 4, 1300: 8, 1930: 7 }], + CAR.CHEVROLET_VOLT_2019: [ + # Chevy Volt w/ ACC 2019 + { + 170: 8, 189: 7, 190: 6, 193: 8, 197: 8, 199: 4, 201: 8, 209: 7, 211: 2, 241: 6, 257: 8, 288: 5, 289: 8, 292: 2, 298: 8, 304: 1, 308: 4, 309: 8, 311: 8, 313: 8, 320: 3, 328: 1, 331: 3, 352: 5, 368: 3, 381: 8, 384: 4, 386: 8, 388: 8, 390: 7, 417: 7, 419: 1, 426: 7, 451: 8, 452: 8, 453: 6, 454: 8, 456: 8, 479: 3, 481: 7, 485: 8, 489: 8, 493: 8, 495: 4, 497: 8, 499: 3, 500: 6, 501: 8, 508: 8, 528: 5, 532: 6, 546: 7, 550: 8, 554: 3, 558: 8, 560: 8, 562: 8, 563: 5, 564: 5, 565: 5, 566: 7, 567: 5, 573: 1, 577: 8, 587: 8, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 647: 3, 707: 8, 711: 6, 715: 8, 717: 5, 761: 7, 767: 4, 810: 8, 840: 5, 842: 5, 844: 8, 866: 4, 869: 4, 880: 6, 961: 8, 967: 4, 969: 8, 975: 2, 977: 8, 979: 7, 988: 6, 989: 8, 995: 7, 1001: 8, 1005: 6, 1009: 8, 1017: 8, 1019: 2, 1020: 8, 1033: 7, 1034: 7, 1105: 5, 1187: 4, 1217: 8, 1221: 5, 1223: 3, 1225: 7, 1227: 4, 1233: 8, 1236: 8, 1249: 8, 1257: 6, 1265: 8, 1267: 1, 1268: 2, 1273: 3, 1275: 3, 1279: 4, 1280: 4, 1296: 4, 1300: 8, 1322: 6, 1328: 4, 1345: 8, 1417: 8, 1512: 8, 1513: 8, 1516: 8, 1517: 8, 1601: 8, 1609: 8, 1611: 8, 1618: 8, 1613: 8, 1649: 8, 1792: 8, 1793: 8, 1798: 8, 1799: 8, 1810: 8, 1813: 8, 1824: 8, 1825: 8, 1840: 8, 1842: 8, 1856: 8, 1858: 8, 1859: 8, 1860: 8, 1862: 8, 1863: 8, 1871: 8, 1872: 8, 1875: 8, 1879: 8, 1882: 8, 1888: 8, 1889: 8, 1892: 8, 1905: 7, 1906: 7, 1907: 7, 1910: 7, 1912: 7, 1920: 8, 1922: 7, 1927: 7, 1930: 7, 1937: 8, 1953: 8, 1954: 8, 1955: 8, 1968: 8, 1969: 8, 1971: 8, 1975: 8, 1988: 8, 1990: 8, 2000: 8, 2001: 8, 2004: 8, 2017: 8, 2018: 8, 2020: 8, 2021: 8, 2023: 8, 2025: 8, 2028: 8, 2031: 8 + }], } FW_VERSIONS: dict[str, dict[tuple, list[bytes]]] = { diff --git a/selfdrive/car/gm/gmcan.py b/selfdrive/car/gm/gmcan.py index 3bbf2969b..32a0ca761 100644 --- a/selfdrive/car/gm/gmcan.py +++ b/selfdrive/car/gm/gmcan.py @@ -177,33 +177,6 @@ def create_lka_icon_command(bus, active, critical, steer): dat = b"\x00\x00\x00" return make_can_msg(0x104c006c, dat, bus) -def create_prndl2_command(packer, bus, press_regen_paddle): - prndl2_value = 7 if press_regen_paddle else 6 - manual_mode = 1 if press_regen_paddle else 0 - values = { - "Byte0": 0x0C, - "Byte1": 0x0C, - "Byte2": 0x00, - "PRNDL2": prndl2_value, - "Byte4": 0x00, - "ManualMode": manual_mode, - "TransmissionState": 1, - "Byte7": 0x00 - } - return packer.make_can_msg("ECMPRDNL2", bus, values) - -def create_regen_paddle_command(packer, bus, press_regen_paddle): - regen_paddle_value = 2 if press_regen_paddle else 0 - values = { - "RegenPaddle": regen_paddle_value, - "Byte1": 0, - "Byte2": 0, - "Byte3": 0, - "Byte4": 0, - "Byte5": 0, - "Byte6": 0 - } - return packer.make_can_msg("EBCMRegenPaddle", bus, values) def create_gm_cc_spam_command(packer, controller, CS, actuators): if controller.params_.get_bool("IsMetric"): diff --git a/selfdrive/car/gm/interface.py b/selfdrive/car/gm/interface.py index 632c3dfa7..90a4ff981 100644 --- a/selfdrive/car/gm/interface.py +++ b/selfdrive/car/gm/interface.py @@ -7,10 +7,12 @@ from panda import Panda from openpilot.common.conversions import Conversions as CV from openpilot.selfdrive.car import create_button_events, get_safety_config from openpilot.selfdrive.car.gm.radar_interface import RADAR_HEADER_MSG -from openpilot.selfdrive.car.gm.values import CAR, CruiseButtons, CarControllerParams, EV_CAR, CAMERA_ACC_CAR, CanBus, GMFlags, CC_ONLY_CAR, SDGM_CAR +from openpilot.selfdrive.car.gm.values import CAR, CruiseButtons, CarControllerParams, EV_CAR, CAMERA_ACC_CAR, CanBus, GMFlags, CC_ONLY_CAR, SDGM_CAR, ASCM_INT from openpilot.selfdrive.car.interfaces import CarInterfaceBase, TorqueFromLateralAccelCallbackType, FRICTION_THRESHOLD, LateralAccelFromTorqueCallbackType from openpilot.selfdrive.controls.lib.drive_helpers import get_friction + + ButtonType = car.CarState.ButtonEvent.Type FrogPilotButtonType = custom.FrogPilotCarState.ButtonEvent.Type EventName = car.CarEvent.EventName @@ -27,9 +29,10 @@ CAM_MSG = 0x320 # AEBCmd ACCELERATOR_POS_MSG = 0xbe NON_LINEAR_TORQUE_PARAMS = { - CAR.CHEVROLET_BOLT_EUV: [1.8, 1.1, 0.280, -0.045], - CAR.CHEVROLET_BOLT_CC: [1.8, 1.1, 0.280, -0.045], + CAR.CHEVROLET_BOLT_EUV: [2.6531724862969748, 1.0, 0.1919764879840985, 0.009054123646805178], + CAR.CHEVROLET_BOLT_CC: [2.6531724862969748, 1.0, 0.1919764879840985, 0.009054123646805178], CAR.GMC_ACADIA: [4.78003305, 1.0, 0.3122, 0.05591772], + CAR.GMC_ACADIA_ASCM: [4.78003305, 1.0, 0.3122, 0.05591772], CAR.CHEVROLET_SILVERADO: [3.29974374, 1.0, 0.25571356, 0.0465122] } @@ -47,7 +50,7 @@ class CarInterface(CarInterfaceBase): return 0.10006696 * sigmoid * (v_ego + 3.12485927) def get_steer_feedforward_function(self): - if self.CP.carFingerprint in (CAR.CHEVROLET_VOLT, CAR.CHEVROLET_VOLT_CC): + if self.CP.carFingerprint in (CAR.CHEVROLET_VOLT, CAR.CHEVROLET_VOLT_CAM, CAR.CHEVROLET_VOLT_2019, CAR.CHEVROLET_VOLT_CC, CAR.CHEVROLET_VOLT_ASCM): return self.get_steer_feedforward_volt else: return CarInterfaceBase.get_steer_feedforward_default @@ -108,42 +111,43 @@ class CarInterface(CarInterfaceBase): else: ret.transmissionType = TransmissionType.automatic - ret.longitudinalTuning.kiBP = [5., 35., 60.] + ret.longitudinalTuning.kiBP = [5., 35.] - if candidate in CAMERA_ACC_CAR: - ret.experimentalLongitudinalAvailable = candidate not in CC_ONLY_CAR + if candidate in (CAMERA_ACC_CAR | SDGM_CAR | ASCM_INT): + ret.experimentalLongitudinalAvailable = candidate not in (CC_ONLY_CAR | ASCM_INT | SDGM_CAR) or 0x2FF in fingerprint[CanBus.POWERTRAIN] ret.networkLocation = NetworkLocation.fwdCamera - ret.radarUnavailable = True # no radar + ret.radarUnavailable = 0x460 not in fingerprint[CanBus.OBSTACLE] ret.pcmCruise = True - ret.safetyConfigs[0].safetyParam |= Panda.FLAG_GM_HW_CAM ret.minEnableSpeed = 5 * CV.KPH_TO_MS ret.minSteerSpeed = 10 * CV.KPH_TO_MS + if candidate in SDGM_CAR: + ret.safetyConfigs[0].safetyParam |= Panda.FLAG_GM_HW_SDGM + # Use C9 brake bit only on SDGM variants that lack 0xBE (ECMAcceleratorPos) + if ACCELERATOR_POS_MSG not in fingerprint[CanBus.POWERTRAIN]: + ret.safetyConfigs[0].safetyParam |= Panda.FLAG_GM_FORCE_BRAKE_C9 + ret.flags |= GMFlags.FORCE_BRAKE_C9.value + ret.minEnableSpeed = -1. # engage speed is decided by pcm + ret.minSteerSpeed = 7 * CV.MPH_TO_MS + elif candidate in ASCM_INT: + ret.safetyConfigs[0].safetyParam |= Panda.FLAG_GM_HW_CAM + ret.minSteerSpeed = 7 * CV.MPH_TO_MS + ret.safetyConfigs[0].safetyParam |= Panda.FLAG_GM_ASCM_INT + else: + ret.safetyConfigs[0].safetyParam |= Panda.FLAG_GM_HW_CAM # Tuning for experimental long - ret.longitudinalTuning.kiV = [0.5, 0.5, 0.5] - ret.vEgoStopping = 0.1 - ret.vEgoStarting = 0.1 + ret.longitudinalTuning.kiV = [1.0, 1.0] ret.stoppingDecelRate = 1.0 # reach brake quickly after enabling ret.vEgoStopping = 0.25 ret.vEgoStarting = 0.25 - ret.stopAccel = -0.25 + ret.stopAccel = -0.20 if ret.experimentalLongitudinalAvailable and experimental_long: ret.pcmCruise = False ret.openpilotLongitudinalControl = True ret.safetyConfigs[0].safetyParam |= Panda.FLAG_GM_HW_CAM_LONG - elif candidate in SDGM_CAR: - ret.longitudinalTuning.kiV = [0., 0., 0.] # TODO: tuning - ret.experimentalLongitudinalAvailable = False - ret.networkLocation = NetworkLocation.fwdCamera - ret.pcmCruise = True - ret.radarUnavailable = True - ret.minEnableSpeed = -1. # engage speed is decided by ASCM - ret.minSteerSpeed = 30 * CV.MPH_TO_MS - ret.safetyConfigs[0].safetyParam |= Panda.FLAG_GM_HW_SDGM - else: # ASCM, OBD-II harness ret.openpilotLongitudinalControl = not frogpilot_toggles.disable_openpilot_long ret.networkLocation = NetworkLocation.gateway @@ -154,7 +158,11 @@ class CarInterface(CarInterfaceBase): ret.minSteerSpeed = 7 * CV.MPH_TO_MS # Tuning - ret.longitudinalTuning.kiV = [0.5, 0.5, 0.5] + ret.longitudinalTuning.kiV = [0.5, 0.5] + ret.stoppingDecelRate = 3 + ret.vEgoStopping = 0.75 + ret.vEgoStarting = 0.75 + ret.stopAccel = -1.5 if ret.enableGasInterceptor: # Need to set ASCM long limits when using pedal interceptor, instead of camera ACC long limits @@ -170,7 +178,7 @@ class CarInterface(CarInterfaceBase): ret.radarTimeStep = 0.0667 # GM radar runs at 15Hz instead of standard 20Hz ret.longitudinalActuatorDelay = 0.5 # large delay to initially start braking - if candidate in (CAR.CHEVROLET_VOLT, CAR.CHEVROLET_VOLT_CC): + if candidate in (CAR.CHEVROLET_VOLT, CAR.CHEVROLET_VOLT_CAM, CAR.CHEVROLET_VOLT_CC): ret.minEnableSpeed = -1 ret.lateralTuning.pid.kpBP = [0., 40.] ret.lateralTuning.pid.kpV = [0., 0.17] @@ -184,6 +192,11 @@ class CarInterface(CarInterfaceBase): ret.steerActuatorDelay = 0.2 CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) + elif candidate == CAR.GMC_ACADIA_ASCM: + ret.minEnableSpeed = -1. # engage speed is decided by pcm + ret.steerActuatorDelay = 0.2 + CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) + elif candidate == CAR.BUICK_LACROSSE: CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) @@ -205,7 +218,6 @@ class CarInterface(CarInterfaceBase): elif candidate in (CAR.CHEVROLET_BOLT_EUV, CAR.CHEVROLET_BOLT_CC): ret.steerActuatorDelay = 0.2 CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) - ret.lateralTuning.torque.kp = 1.0 if ret.enableGasInterceptor: # ACC Bolts use pedal for full longitudinal control, not just sng @@ -234,34 +246,50 @@ class CarInterface(CarInterfaceBase): ret.steerActuatorDelay = 0.2 CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) + elif candidate == CAR.CADILLAC_XT6: + ret.steerActuatorDelay = 0.2 + ret.minSteerSpeed = 7 * CV.MPH_TO_MS + CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) + elif candidate == CAR.CADILLAC_XT4: ret.steerActuatorDelay = 0.2 + if not ret.openpilotLongitudinalControl: + ret.minEnableSpeed = -1. # engage speed is decided by pcm + ret.minSteerSpeed = 30 * CV.MPH_TO_MS CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) elif candidate == CAR.CADILLAC_XT5_CC: ret.steerActuatorDelay = 0.2 CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) - elif candidate == CAR.CHEVROLET_TRAVERSE: + elif candidate in (CAR.CHEVROLET_TRAVERSE, CAR.CHEVROLET_MALIBU_SDGM): ret.steerActuatorDelay = 0.2 - ret.minSteerSpeed = 10 * CV.KPH_TO_MS + if not ret.openpilotLongitudinalControl: + ret.minEnableSpeed = -1. # engage speed is decided by pcm CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) elif candidate == CAR.BUICK_BABYENCLAVE: ret.steerActuatorDelay = 0.2 - ret.minSteerSpeed = 10 * CV.KPH_TO_MS + if not ret.openpilotLongitudinalControl: + ret.minEnableSpeed = -1. # engage speed is decided by pcm CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) elif candidate == CAR.CADILLAC_CT6_CC: CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) - - elif candidate == CAR.CHEVROLET_MALIBU_CC: + + elif candidate in (CAR.CHEVROLET_MALIBU_CC, CAR.CHEVROLET_MALIBU_HYBRID_CC): ret.steerActuatorDelay = 0.2 CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) - + elif candidate == CAR.CHEVROLET_TRAX: CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) + elif candidate == CAR.CHEVROLET_VOLT_2019: + ret.steerActuatorDelay = 0.2 + if not ret.openpilotLongitudinalControl: + ret.minEnableSpeed = -1. # engage speed is decided by pcm + CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) + if ret.enableGasInterceptor: ret.networkLocation = NetworkLocation.fwdCamera ret.safetyConfigs[0].safetyParam |= Panda.FLAG_GM_HW_CAM @@ -271,20 +299,24 @@ class CarInterface(CarInterfaceBase): ret.stoppingControl = True ret.autoResumeSng = True - if candidate in CC_ONLY_CAR: #pedal interceptor tuning + if candidate in CC_ONLY_CAR: ret.flags |= GMFlags.PEDAL_LONG.value ret.safetyConfigs[0].safetyParam |= Panda.FLAG_GM_PEDAL_LONG # Note: Low speed, stop and go not tested. Should be fairly smooth on highway - ret.longitudinalTuning.kiBP = [0., 3., 6., 35.] - ret.longitudinalTuning.kiV = [0.125, 0.175, 0.225, 0.33] - ret.longitudinalTuning.kf = 0.25 + ret.longitudinalTuning.kiBP = [0.0, 5., 35.] + ret.longitudinalTuning.kiV = [0.0, 0.35, 0.5] + ret.longitudinalTuning.kf = 0.15 ret.stoppingDecelRate = 0.8 + ret.minEnableSpeed = -1 + ret.pcmCruise = False + ret.openpilotLongitudinalControl = not frogpilot_toggles.disable_openpilot_long else: # Pedal used for SNG, ACC for longitudinal control otherwise ret.safetyConfigs[0].safetyParam |= Panda.FLAG_GM_HW_CAM_LONG ret.startingState = True ret.vEgoStopping = 0.25 ret.vEgoStarting = 0.25 + elif candidate in CC_ONLY_CAR: ret.flags |= GMFlags.CC_LONG.value ret.safetyConfigs[0].safetyParam |= Panda.FLAG_GM_CC_LONG @@ -294,21 +326,26 @@ class CarInterface(CarInterfaceBase): ret.openpilotLongitudinalControl = not frogpilot_toggles.disable_openpilot_long ret.pcmCruise = False - if not ret.enableGasInterceptor and candidate in CC_ONLY_CAR: #redneck tuning - ret.longitudinalTuning.kpBP = [10.7, 10.8, 28.] # 10.7 m/s == 24 mph - ret.longitudinalTuning.kpV = [0., 20., 20.] # set lower end to 0 since we can't drive below that speed + ret.stoppingDecelRate = 11.18 # == 25 mph/s (.04 rate) + + if candidate not in (CAR.CHEVROLET_BOLT_CC, CAR.CHEVROLET_MALIBU_HYBRID_CC): + ret.longitudinalTuning.kiBP = [10.7, 10.8, 28.] + ret.longitudinalTuning.kiV = [0., 20., 20.] # set lower end to 0 since we can't drive below that speed + else: ret.longitudinalTuning.deadzoneBP = [0.] ret.longitudinalTuning.deadzoneV = [0.56] # == 2 km/h/s, 1.25 mph/s ret.longitudinalActuatorDelay = 1. # TODO: measure this + + ret.longitudinalTuning.kpBP = [10.7, 10.8, 28.] # 10.7 m/s == 24 mph + ret.longitudinalTuning.kpV = [0., 20., 20.] # set lower end to 0 since we can't drive below that speed ret.longitudinalTuning.kiBP = [0.] ret.longitudinalTuning.kiV = [0.1] - ret.stoppingDecelRate = 11.18 # == 25 mph/s (.04 rate) if candidate in CC_ONLY_CAR: ret.safetyConfigs[0].safetyParam |= Panda.FLAG_GM_NO_ACC # Exception for flashed cars, or cars whose camera was removed - if (ret.networkLocation == NetworkLocation.fwdCamera or candidate in CC_ONLY_CAR) and CAM_MSG not in fingerprint[CanBus.CAMERA] and not candidate in SDGM_CAR: + if (ret.networkLocation == NetworkLocation.fwdCamera or candidate in CC_ONLY_CAR) and CAM_MSG not in fingerprint[CanBus.CAMERA] and not candidate in (SDGM_CAR | ASCM_INT): ret.flags |= GMFlags.NO_CAMERA.value ret.safetyConfigs[0].safetyParam |= Panda.FLAG_GM_NO_CAMERA @@ -344,10 +381,11 @@ class CarInterface(CarInterfaceBase): # TODO: verify 17 Volt can enable for the first time at a stop and allow for all GMs below_min_enable_speed = ret.vEgo < self.CP.minEnableSpeed or self.CS.moving_backward if below_min_enable_speed and not (ret.standstill and ret.brake >= 20 and - (self.CP.networkLocation == NetworkLocation.fwdCamera and not self.CP.carFingerprint in SDGM_CAR)): + self.CP.networkLocation == NetworkLocation.fwdCamera): events.add(EventName.belowEngageSpeed) if ret.cruiseState.standstill and not self.CP.autoResumeSng: events.add(EventName.resumeRequired) + if ret.vEgo < self.CP.minSteerSpeed: events.add(EventName.belowSteerSpeed) diff --git a/selfdrive/car/gm/values.py b/selfdrive/car/gm/values.py index 52ab348dd..eaa9e1972 100644 --- a/selfdrive/car/gm/values.py +++ b/selfdrive/car/gm/values.py @@ -41,7 +41,7 @@ class CarControllerParams: self.ZERO_GAS = 6144 # Coasting self.MAX_BRAKE = 400 # ~ -4.0 m/s^2 with regen - if CP.carFingerprint in CAMERA_ACC_CAR and CP.carFingerprint not in CC_ONLY_CAR and CP.carFingerprint != CAR.CHEVROLET_BOLT_EUV: + if CP.carFingerprint in (CAMERA_ACC_CAR | SDGM_CAR) and CP.carFingerprint not in CC_ONLY_CAR and CP.carFingerprint != CAR.CHEVROLET_BOLT_EUV: self.MAX_GAS = 7496 self.MAX_GAS_PLUS = 8848 self.MAX_ACC_REGEN = 5610 @@ -50,21 +50,14 @@ class CarControllerParams: # Camera transitions to MAX_ACC_REGEN from ZERO_GAS and uses friction brakes instantly self.max_regen_acceleration = 0. - elif CP.carFingerprint in SDGM_CAR: - self.MAX_GAS = 7496 - self.MAX_GAS_PLUS = 7496 - self.MAX_ACC_REGEN = 7110 - self.INACTIVE_REGEN = 5650 - self.max_regen_acceleration = 0. - else: self.MAX_GAS = 7168 # Safety limit, not ACC max. Stock ACC >8192 from standstill. self.MAX_GAS_PLUS = 8191 # 8292 uses new bit, possible but not tested. Matches Twilsonco tw-main max - self.MAX_ACC_REGEN = 7110 # Increased for stronger regen braking + self.MAX_ACC_REGEN = 5500 # Max ACC regen is slightly less than max paddle regen self.INACTIVE_REGEN = 5500 # ICE has much less engine braking force compared to regen in EVs, # lower threshold removes some braking deadzone - self.max_regen_acceleration = -3. if CP.carFingerprint in EV_CAR else -0.1 # More aggressive regen for EVs + self.max_regen_acceleration = -1. if CP.carFingerprint in EV_CAR else -0.1 self.GAS_LOOKUP_BP = [self.max_regen_acceleration, 0., self.ACCEL_MAX] self.GAS_LOOKUP_BP_PLUS = [self.max_regen_acceleration, 0., self.ACCEL_MAX_PLUS] @@ -74,7 +67,18 @@ class CarControllerParams: self.BRAKE_LOOKUP_BP = [self.ACCEL_MIN, self.max_regen_acceleration] self.BRAKE_LOOKUP_V = [self.MAX_BRAKE, 0.] + # determined by letting Volt regen to a stop in L gear from 89mph, + # and by letting off gas and allowing car to creep, for determining + # the positive threshold values at very low speed + EV_GAS_BRAKE_THRESHOLD_BP = [1.29, 1.52, 1.55, 1.6, 1.7, 1.8, 2.0, 2.2, 2.5, 5.52, 9.6, 20.5, 23.5, 35.0] # [m/s] + EV_GAS_BRAKE_THRESHOLD_V = [0.0, -0.14, -0.16, -0.18, -0.215, -0.255, -0.32, -0.41, -0.5, -0.72, -0.895, -1.125, -1.145, -1.16] # [m/s^s] + def update_ev_gas_brake_threshold(self, v_ego): + gas_brake_threshold = interp(v_ego, self.EV_GAS_BRAKE_THRESHOLD_BP, self.EV_GAS_BRAKE_THRESHOLD_V) + self.GAS_LOOKUP_BP_PLUS = [self.max_regen_acceleration, 0., self.ACCEL_MAX_PLUS] + self.EV_GAS_LOOKUP_BP = [gas_brake_threshold, max(0., gas_brake_threshold), self.ACCEL_MAX] + self.EV_GAS_LOOKUP_BP_PLUS = [gas_brake_threshold, max(0., gas_brake_threshold), self.ACCEL_MAX_PLUS] + self.EV_BRAKE_LOOKUP_BP = [self.ACCEL_MIN, gas_brake_threshold] @dataclass class GMCarDocs(CarDocs): @@ -100,8 +104,7 @@ class GMPlatformConfig(PlatformConfig): @dataclass class GMASCMPlatformConfig(GMPlatformConfig): def init(self): - # ASCM is supported, but due to a janky install and hardware configuration, we are not showing in the car docs - self.car_docs = [] + pass class CAR(Platforms): @@ -114,6 +117,16 @@ class CAR(Platforms): GMCarSpecs(mass=1607, wheelbase=2.69, steerRatio=17.7, centerToFrontRatio=0.45, tireStiffnessFactor=0.469, minEnableSpeed=-1), dbc_dict=dbc_dict('gm_global_a_powertrain_volt', 'gm_global_a_object', chassis_dbc='gm_global_a_chassis') ) + CHEVROLET_VOLT_CAM = GMPlatformConfig( + [GMCarDocs("Chevrolet Volt 2017-18 Camera", min_enable_speed=0, video_link="https://youtu.be/QeMCN_4TFfQ")], + GMCarSpecs(mass=1607, wheelbase=2.69, steerRatio=17.7, centerToFrontRatio=0.45, tireStiffnessFactor=0.469, minEnableSpeed=-1), + dbc_dict=dbc_dict('gm_global_a_powertrain_volt', 'gm_global_a_object', chassis_dbc='gm_global_a_chassis') + ) + CHEVROLET_VOLT_ASCM = GMPlatformConfig( + [GMCarDocs("Chevrolet Volt 2017-18 ASCM Harness", min_enable_speed=0, video_link="https://youtu.be/QeMCN_4TFfQ")], + GMCarSpecs(mass=1607, wheelbase=2.69, steerRatio=17.7, centerToFrontRatio=0.45, tireStiffnessFactor=0.469, minEnableSpeed=-1), + dbc_dict=dbc_dict('gm_global_a_powertrain_volt', 'gm_global_a_object', chassis_dbc='gm_global_a_chassis') + ) CADILLAC_ATS = GMASCMPlatformConfig( [GMCarDocs("Cadillac ATS Premium Performance 2018")], GMCarSpecs(mass=1601, wheelbase=2.78, steerRatio=15.3), @@ -126,6 +139,11 @@ class CAR(Platforms): [GMCarDocs("GMC Acadia 2018", video_link="https://www.youtube.com/watch?v=0ZN6DdsBUZo")], GMCarSpecs(mass=1975, wheelbase=2.86, steerRatio=14.4, centerToFrontRatio=0.4), ) + GMC_ACADIA_ASCM = GMPlatformConfig( + [GMCarDocs("GMC Acadia 2018 ASCM Harness", video_link="https://www.youtube.com/watch?v=0ZN6DdsBUZo")], + GMCarSpecs(mass=1975, wheelbase=2.86, steerRatio=14.4, centerToFrontRatio=0.4), + dbc_dict=dbc_dict('gm_global_a_powertrain_generated', 'gm_global_a_object', chassis_dbc='gm_global_a_chassis') + ) BUICK_LACROSSE = GMASCMPlatformConfig( [GMCarDocs("Buick LaCrosse 2017-19", "Driver Confidence Package 2")], GMCarSpecs(mass=1712, wheelbase=2.91, steerRatio=15.8, centerToFrontRatio=0.4), @@ -194,15 +212,15 @@ class CAR(Platforms): CHEVROLET_SUBURBAN.specs, ) GMC_YUKON_CC = GMPlatformConfig( - [GMCarDocs("GMC Yukon No ACC")], + [GMCarDocs("GMC Yukon - No-ACC")], CarSpecs(mass=2541, wheelbase=2.95, steerRatio=16.3, centerToFrontRatio=0.4), ) CADILLAC_CT6_CC = GMPlatformConfig( - [GMCarDocs("Cadillac CT6 No ACC")], + [GMCarDocs("Cadillac CT6 - No-ACC")], CarSpecs(mass=2358, wheelbase=3.11, steerRatio=17.7, centerToFrontRatio=0.4), ) CHEVROLET_TRAILBLAZER_CC = GMPlatformConfig( - [GMCarDocs("Chevrolet Trailblazer 2021-22")], + [GMCarDocs("Chevrolet Trailblazer 2021-22 - No-ACC")], CHEVROLET_TRAILBLAZER.specs, ) CADILLAC_XT4 = GMPlatformConfig( @@ -210,25 +228,41 @@ class CAR(Platforms): CarSpecs(mass=1660, wheelbase=2.78, steerRatio=14.4, centerToFrontRatio=0.4), ) CADILLAC_XT5_CC = GMPlatformConfig( - [GMCarDocs("Cadillac XT5 No ACC")], + [GMCarDocs("Cadillac XT5 - No-ACC")], CarSpecs(mass=1810, wheelbase=2.86, steerRatio=16.34, centerToFrontRatio=0.5), ) CHEVROLET_TRAVERSE = GMPlatformConfig( [GMCarDocs("Chevrolet Traverse 2023", "Driver Assist Package")], CarSpecs(mass=1955, wheelbase=3.07, steerRatio=17.9, centerToFrontRatio=0.4), ) + CHEVROLET_MALIBU_SDGM = GMPlatformConfig( + [GMCarDocs("Chevrolet Malibu 2019", "SDGM Harness (Optional SASCM)")], + CHEVROLET_MALIBU.specs, + ) BUICK_BABYENCLAVE = GMPlatformConfig( [GMCarDocs("Buick Baby Enclave 2020-23", "Driver Assist Package")], CarSpecs(mass=2050, wheelbase=2.86, steerRatio=16.0, centerToFrontRatio=0.5), ) CHEVROLET_MALIBU_CC = GMPlatformConfig( - [GMCarDocs("Chevrolet Malibu 2023 No ACC")], + [GMCarDocs("Chevrolet Malibu 2023 - No-ACC")], + CarSpecs(mass=1450, wheelbase=2.8, steerRatio=15.8, centerToFrontRatio=0.4), + ) + CHEVROLET_MALIBU_HYBRID_CC = GMPlatformConfig( + [GMCarDocs("Chevrolet Malibu Hybrid 2017 - No-ACC")], CarSpecs(mass=1450, wheelbase=2.8, steerRatio=15.8, centerToFrontRatio=0.4), ) CHEVROLET_TRAX = GMPlatformConfig( [GMCarDocs("Chevrolet TRAX 2024")], CarSpecs(mass=1365, wheelbase=2.7, steerRatio=16.4, centerToFrontRatio=0.4), ) + CHEVROLET_VOLT_2019 = GMPlatformConfig( + [GMCarDocs("Chevrolet Volt 2019")], + GMCarSpecs(mass=1607, wheelbase=2.69, steerRatio=15.7, centerToFrontRatio=0.45), + ) + CADILLAC_XT6 = GMPlatformConfig( + [GMCarDocs("Cadillac XT6 2020", "Driver Assist Package")], + GMCarSpecs(mass=2050, wheelbase=2.86, steerRatio=16.5, centerToFrontRatio=0.4), + ) class CruiseButtons: @@ -258,6 +292,7 @@ class GMFlags(IntFlag): CC_LONG = 2 NO_CAMERA = 4 NO_ACCELERATOR_POS_MSG = 8 + FORCE_BRAKE_C9 = 16 # In a Data Module, an identifier is a string used to recognize an object, @@ -309,17 +344,18 @@ FW_QUERY_CONFIG = FwQueryConfig( extra_ecus=[(Ecu.fwdCamera, 0x24b, None)], ) -EV_CAR = {CAR.CHEVROLET_VOLT, CAR.CHEVROLET_BOLT_EUV, CAR.CHEVROLET_VOLT_CC, CAR.CHEVROLET_BOLT_CC} -CC_ONLY_CAR = {CAR.CHEVROLET_VOLT_CC, CAR.CHEVROLET_BOLT_CC, CAR.CHEVROLET_EQUINOX_CC, CAR.CHEVROLET_SUBURBAN_CC, CAR.GMC_YUKON_CC, CAR.CADILLAC_CT6_CC, CAR.CHEVROLET_TRAILBLAZER_CC, CAR.CADILLAC_XT5_CC, CAR.CHEVROLET_MALIBU_CC} -CC_REGEN_PADDLE_CAR = {CAR.CHEVROLET_BOLT_CC, CAR.CHEVROLET_BOLT_EUV} +EV_CAR = {CAR.CHEVROLET_VOLT, CAR.CHEVROLET_VOLT_2019, CAR.CHEVROLET_BOLT_EUV, CAR.CHEVROLET_VOLT_CC, CAR.CHEVROLET_BOLT_CC, CAR.CHEVROLET_VOLT_ASCM, CAR.CHEVROLET_MALIBU_HYBRID_CC} +CC_ONLY_CAR = {CAR.CHEVROLET_VOLT_CC, CAR.CHEVROLET_BOLT_CC, CAR.CHEVROLET_EQUINOX_CC, CAR.CHEVROLET_SUBURBAN_CC, CAR.GMC_YUKON_CC, CAR.CADILLAC_CT6_CC, CAR.CHEVROLET_TRAILBLAZER_CC, CAR.CADILLAC_XT5_CC, CAR.CHEVROLET_MALIBU_CC, CAR.CHEVROLET_MALIBU_HYBRID_CC} # CC_ONLY_CAR = set(c for c in CAR if str(c).endswith('_CC')) # We're integrated at the Safety Data Gateway Module on these cars -SDGM_CAR = {CAR.CADILLAC_XT4, CAR.CHEVROLET_TRAVERSE, CAR.BUICK_BABYENCLAVE} +SDGM_CAR = {CAR.CADILLAC_XT4, CAR.CADILLAC_XT6, CAR.CHEVROLET_TRAVERSE, CAR.CHEVROLET_MALIBU_SDGM, CAR.BUICK_BABYENCLAVE, CAR.CHEVROLET_VOLT_2019} + +ASCM_INT = {CAR.CHEVROLET_VOLT_ASCM, CAR.GMC_ACADIA_ASCM} # We're integrated at the camera with VOACC on these cars (instead of ASCM w/ OBD-II harness) -CAMERA_ACC_CAR = {CAR.CHEVROLET_BOLT_EUV, CAR.CHEVROLET_SILVERADO, CAR.CHEVROLET_EQUINOX, CAR.CHEVROLET_TRAILBLAZER, CAR.CHEVROLET_TRAX} -CAMERA_ACC_CAR.update({CAR.CHEVROLET_VOLT_CC, CAR.CHEVROLET_BOLT_CC, CAR.CHEVROLET_EQUINOX_CC, CAR.GMC_YUKON_CC, CAR.CADILLAC_CT6_CC, CAR.CHEVROLET_TRAILBLAZER_CC, CAR.CADILLAC_XT5_CC, CAR.CHEVROLET_MALIBU_CC}) +CAMERA_ACC_CAR = {CAR.CHEVROLET_BOLT_EUV, CAR.CHEVROLET_SILVERADO, CAR.CHEVROLET_EQUINOX, CAR.CHEVROLET_TRAILBLAZER, CAR.CHEVROLET_TRAX, CAR.CHEVROLET_VOLT_CAM} +CAMERA_ACC_CAR.update({CAR.CHEVROLET_VOLT_CC, CAR.CHEVROLET_BOLT_CC, CAR.CHEVROLET_EQUINOX_CC, CAR.GMC_YUKON_CC, CAR.CADILLAC_CT6_CC, CAR.CHEVROLET_TRAILBLAZER_CC, CAR.CADILLAC_XT5_CC, CAR.CHEVROLET_MALIBU_CC, CAR.CHEVROLET_MALIBU_HYBRID_CC}) # CAMERA_ACC_CAR.update(CC_ONLY_CAR) STEER_THRESHOLD = 1.0 diff --git a/selfdrive/car/torque_data/override.toml b/selfdrive/car/torque_data/override.toml index b37817b4c..b33f1ccad 100644 --- a/selfdrive/car/torque_data/override.toml +++ b/selfdrive/car/torque_data/override.toml @@ -43,8 +43,10 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"] "CADILLAC_ESCALADE" = [1.899999976158142, 1.842270016670227, 0.1120000034570694] "CADILLAC_ESCALADE_ESV_2019" = [1.15, 1.3, 0.2] "CADILLAC_XT4" = [1.45, 1.6, 0.2] -"CHEVROLET_BOLT_EUV" = [2.0, 2.0, 0.05] +"CADILLAC_XT6" = [1.33, 1.9, 0.16] +"CHEVROLET_BOLT_EUV" = [1.0, 2.0, 0.175] "CHEVROLET_MALIBU_CC" = [1.85, 1.85, 0.075] +"CHEVROLET_MALIBU_HYBRID_CC" = [1.85, 1.85, 0.075] "CHEVROLET_SILVERADO" = [1.9, 1.9, 0.112] "CHEVROLET_TRAILBLAZER" = [1.33, 1.9, 0.16] "CHEVROLET_TRAVERSE" = [1.33, 1.33, 0.18] diff --git a/selfdrive/car/torque_data/substitute.toml b/selfdrive/car/torque_data/substitute.toml index 1525bf114..1f98a9c0a 100644 --- a/selfdrive/car/torque_data/substitute.toml +++ b/selfdrive/car/torque_data/substitute.toml @@ -56,8 +56,13 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"] "CADILLAC_ESCALADE_ESV" = "CHEVROLET_VOLT" "CADILLAC_ATS" = "CHEVROLET_VOLT" "CHEVROLET_MALIBU" = "CHEVROLET_VOLT" +"CHEVROLET_MALIBU_SDGM" = "CHEVROLET_VOLT" "HOLDEN_ASTRA" = "CHEVROLET_VOLT" "CHEVROLET_VOLT_CC" = "CHEVROLET_VOLT" +"CHEVROLET_VOLT_ASCM" = "CHEVROLET_VOLT" +"CHEVROLET_VOLT_CAM" = "CHEVROLET_VOLT" +"GMC_ACADIA_ASCM" = "GMC_ACADIA" +"CHEVROLET_VOLT_2019" = "CHEVROLET_VOLT" "CHEVROLET_BOLT_CC" = "CHEVROLET_BOLT_EUV" "CHEVROLET_EQUINOX_CC" = "CHEVROLET_EQUINOX" "CHEVROLET_SUBURBAN" = "CHEVROLET_SILVERADO"