diff --git a/CMakeLists.txt b/CMakeLists.txt index 6b8dc36..8795a73 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,7 +10,7 @@ list(APPEND CMAKE_PREFIX_PATH "${CMAKE_SOURCE_DIR}/cmake") # Custom libs ################################# add_subdirectory(drivebrain_core) -# add_subdirectory(drivebrain_comms) +add_subdirectory(drivebrain_comms) ################################# # Find packages @@ -20,7 +20,7 @@ find_package(Protobuf REQUIRED CONFIG) find_package(Boost REQUIRED) find_package(spdlog REQUIRED) find_package(mcap REQUIRED) -find_package(GTest REQUIRED) +find_package(dbcppp REQUIRED) ################################# # Upstreams (non-conan) @@ -28,7 +28,7 @@ find_package(GTest REQUIRED) FetchContent_Declare( HT_Proto GIT_REPOSITORY https://github.com/hytech-racing/HT_proto.git - GIT_TAG f7967e90831271f9704a406a8f777d43c03d0d0b + GIT_TAG 7cdd552750e4c34d28512fbd291367a29be722d7 ) FetchContent_MakeAvailable(HT_Proto) @@ -62,6 +62,7 @@ target_link_libraries(drivebrain PUBLIC hytech_msgs_cpp_lib hytech_can_msgs_cpp_lib drivebrain_core + drivebrain_comms ) ################################# @@ -71,4 +72,4 @@ target_link_libraries(drivebrain PUBLIC if(NOT CMAKE_CROSSCOMPILING) enable_testing() add_subdirectory(tests) -endif() +endif() \ No newline at end of file diff --git a/README.md b/README.md index e029086..4c120e4 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,17 @@ -# DriveBrain Software 2026 +# DriveBrain Software + +This repo contains the main executable that runs on the Drivebrain embedded computer on HyTech Racing's cars. This code is deployed as a systemd service onto the car within HyTech's Raspberry Pi [NixOS description](https://github.com/hytech-racing/hytech_nixos/releases). This service handles, among other things: + +* high-performance control algorithm execution from both hand written c++ and MATLAB Simulink generated code c++ +* car state estimation via both hand written c++ and MATLAB Simulink generated code c++ +* Vectornav INS communication via Vectornav's driver +* live telemetry and data recording of all on-car inter-board communications (CAN and Ethernet mostly) +* car-level parameter servicing of all previously listed components via the integrated Foxglove websocket server + +This is an active rewrite of an older iteration of Drivebrain, which you can find [here.](https://github.com/hytech-racing/drivebrain_software) + + +# Development This guide explains how to build the DriveBrain Software 2026 using the provided Docker cross-compilation environment. diff --git a/build_script.sh b/build_script.sh index 191833b..a02640c 100755 --- a/build_script.sh +++ b/build_script.sh @@ -38,7 +38,8 @@ cd "$build_folder" cmake .. \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_TOOLCHAIN_FILE=../cmake/conan_toolchain.cmake \ - -DCMAKE_EXPORT_COMPILE_COMMANDS=ON + -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \ + -DCMAKE_EXE_LINKER_FLAGS="-static" \ make -j diff --git a/conanfile.py b/conanfile.py index 49eda6c..f72dfcf 100644 --- a/conanfile.py +++ b/conanfile.py @@ -20,9 +20,10 @@ def build(self): def requirements(self): self.requires("foxglove-websocket/1.4.0", transitive_headers=True) self.requires("protobuf/5.29.3", transitive_headers=True) - self.requires("boost/1.88.0") + self.requires("boost/1.80.0") self.requires("spdlog/1.15.3") self.requires("mcap/2.0.2") + self.requires("dbcppp/3.2.6") def build_requirements(self): if not self.settings_build.get_safe("cross_build"): diff --git a/dbc/hytech.dbc b/dbc/hytech.dbc new file mode 100644 index 0000000..c256594 --- /dev/null +++ b/dbc/hytech.dbc @@ -0,0 +1,1637 @@ +VERSION "6.0" + + +NS_ : + NS_DESC_ + CM_ + BA_DEF_ + BA_ + VAL_ + CAT_DEF_ + CAT_ + FILTER + BA_DEF_DEF_ + EV_DATA_ + ENVVAR_DATA_ + SGTYPE_ + SGTYPE_VAL_ + BA_DEF_SGTYPE_ + BA_SGTYPE_ + SIG_TYPE_REF_ + VAL_TABLE_ + SIG_GROUP_ + SIG_VALTYPE_ + SIGTYPE_VALTYPE_ + BO_TX_BU_ + BA_DEF_REL_ + BA_REL_ + BA_DEF_DEF_REL_ + BU_SG_REL_ + BU_EV_REL_ + BU_BO_REL_ + SG_MUL_VAL_ + +BS_: + +BU_: + + +BO_ 1025 ACU_SHUNT_MEASUREMENTS: 6 ECU + SG_ ts_out_filtered_read : 32|16@1+ (0.169047463702246,0) [0|0] "volts" Vector__XXX + SG_ pack_filtered_read : 16|16@1+ (0.16869351172632,0) [0|0] "volts" Vector__XXX + SG_ current_shunt_read : 0|16@1+ (0.291373985492,-666) [0|0] "amps" Vector__XXX + +BO_ 5 Attitude: 6 ECU + SG_ Roll_angle : 32|9@1- (0.25,0) [0|0] "deg" Vector__XXX + SG_ Pitch_angle : 16|9@1- (0.25,0) [0|0] "deg" Vector__XXX + SG_ Height : 0|12@1- (0.035,0) [0|71.645] "cm" Vector__XXX + +BO_ 226 BMS_COULOMB_COUNTS: 8 ECU + SG_ total_discharge : 32|32@1+ (0.0001,0) [0|0] "Coulombs" Vector__XXX + SG_ total_charge : 0|32@1+ (0.0001,0) [0|0] "Coulombs" Vector__XXX + +BO_ 218 BMS_CHIP_TEMPS: 5 ECU + SG_ thermistor_cell_group_temp_1 : 24|16@1- (0.01,0) [0|0] "" Vector__XXX + SG_ thermistor_cell_group_temp_0 : 8|16@1- (0.01,0) [0|0] "" Vector__XXX + SG_ thermistor_group_id : 4|4@1+ (1,0) [0|0] "" Vector__XXX + SG_ chip_id : 0|4@1+ (1,0) [0|0] "" Vector__XXX + +BO_ 216 BMS_CELL_VOLTAGES: 7 ECU + SG_ cell_group_voltage_2 : 40|16@1+ (0.0001,0) [0|0] "" Vector__XXX + SG_ cell_group_voltage_1 : 24|16@1+ (0.0001,0) [0|0] "" Vector__XXX + SG_ cell_group_voltage_0 : 8|16@1+ (0.0001,0) [0|0] "" Vector__XXX + SG_ chip_id : 4|4@1+ (1,0) [0|0] "" Vector__XXX + SG_ cell_group_id : 0|4@1+ (1,0) [0|0] "" Vector__XXX + +BO_ 214 BMS_ONBOARD_CURRENT_TEMP: 3 ECU + SG_ temp_0 : 8|16@1- (0.01,0) [0|0] "Deg C" Vector__XXX + SG_ chip_id : 0|4@1+ (1,0) [0|0] "" Vector__XXX + +BO_ 213 BMS_ONBOARD_TEMPS: 6 ECU + SG_ max_cell_temp : 32|16@1- (0.01,0) [0|0] "Deg C" Vector__XXX + SG_ min_cell_temp : 16|16@1- (0.01,0) [0|0] "Deg C" Vector__XXX + SG_ max_board_temp : 0|16@1- (0.01,0) [0|0] "Deg C" Vector__XXX + +BO_ 219 BMS_STATUS: 1 ECU + SG_ shdn_out_voltage_state : 0|8@1+ (1,0) [0|0] "" Vector__XXX + +BO_ 217 BMS_TEMPS: 6 ECU + SG_ max_cell_temp : 32|16@1- (0.01,0) [0|0] "Deg C" Vector__XXX + SG_ min_cell_temp : 16|16@1- (0.01,0) [0|0] "Deg C" Vector__XXX + SG_ max_board_temp : 0|16@1- (0.01,0) [0|0] "Deg C" Vector__XXX + +BO_ 215 BMS_VOLTAGES: 8 ECU + SG_ total_voltage : 48|16@1+ (0.01,0) [0|0] "" Vector__XXX + SG_ max_cell_voltage : 32|16@1+ (0.0001,0) [0|0] "V" Vector__XXX + SG_ min_cell_voltage : 16|16@1+ (0.0001,0) [0|0] "" Vector__XXX + SG_ average_voltage : 0|16@1+ (0.0001,0) [0|0] "V" Vector__XXX + +BO_ 203 BRAKE_PRESSURE_SENSOR: 2 ECU + SG_ brake_sensor_analog_read : 0|16@1+ (3.0517578125,-312.5) [0|0] "psi" Vector__XXX + +BO_ 221 CCU_STATUS: 1 ECU + SG_ charger_enabled : 0|1@1+ (1,0) [0|0] "" Vector__XXX + +BO_ 2550588916 CHARGER_CONTROL: 5 ECU + SG_ control : 32|8@1+ (1,0) [0|0] "" Vector__XXX + SG_ max_charging_current_low : 24|8@1+ (1,0) [0|0] "" Vector__XXX + SG_ max_charging_current_high : 16|8@1+ (1,0) [0|0] "" Vector__XXX + SG_ max_charging_voltage_low : 8|8@1+ (1,0) [0|0] "" Vector__XXX + SG_ max_charging_voltage_high : 0|8@1+ (1,0) [0|0] "" Vector__XXX + +BO_ 2566869221 CHARGER_DATA: 7 ECU + SG_ input_ac_voltage_low : 48|8@1+ (1,0) [0|0] "" Vector__XXX + SG_ input_ac_voltage_high : 40|8@1+ (1,0) [0|0] "" Vector__XXX + SG_ flags : 32|8@1+ (1,0) [0|0] "" Vector__XXX + SG_ output_current_low : 24|8@1+ (1,0) [0|0] "" Vector__XXX + SG_ output_current_high : 16|8@1+ (1,0) [0|0] "" Vector__XXX + SG_ output_dc_voltage_low : 8|8@1+ (1,0) [0|0] "" Vector__XXX + SG_ output_dc_voltage_high : 0|8@1+ (1,0) [0|0] "" Vector__XXX + +BO_ 2028 CONTROLLER_BOOLEAN: 8 ECU + SG_ controller_use_nl_tcs_slipschedu : 13|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ controller_use_rpm_tcs_gain_sche : 12|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ controller_use_nl_tcs_gain_sche : 11|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ controller_use_torque_bias : 10|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ controller_use_no_regen_5kph : 9|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ controller_use_discontin_brakes : 8|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ controller_use_dec_yaw_pid_brake : 7|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ controller_use_tcs_lim_yaw_pid : 6|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ controller_use_tcs : 5|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ controller_use_power_limit : 4|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ controller_use_pid_power_limit : 3|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ controller_use_normal_force : 2|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ controller_use_pid_tv : 1|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ controller_use_launch : 0|1@1+ (1,0) [0|0] "" Vector__XXX + +BO_ 2011 CONTROLLER_NORMAL_DIST: 8 ECU + SG_ controller_normal_percent_rr : 48|16@1- (0.0001,0) [0|0] "" Vector__XXX + SG_ controller_normal_percent_rl : 32|16@1- (0.0001,0) [0|0] "" Vector__XXX + SG_ controller_normal_percent_fr : 16|16@1- (0.0001,0) [0|0] "" Vector__XXX + SG_ controller_normal_percent_fl : 0|16@1- (0.0001,0) [0|0] "" Vector__XXX + +BO_ 2012 CONTROLLER_NORMAL_TORQUE: 8 ECU + SG_ controller_normal_torque_rr : 48|16@1- (0.001,0) [0|0] "Nm" Vector__XXX + SG_ controller_normal_torque_rl : 32|16@1- (0.001,0) [0|0] "Nm" Vector__XXX + SG_ controller_normal_torque_fr : 16|16@1- (0.001,0) [0|0] "Nm" Vector__XXX + SG_ controller_normal_torque_fl : 0|16@1- (0.001,0) [0|0] "Nm" Vector__XXX + +BO_ 1263 CONTROLLER_PID_TV_DATA: 8 ECU + SG_ controller_output : 20|20@1- (0.01,0) [0|0] "" Vector__XXX + SG_ controller_input : 0|20@1- (0.01,0) [0|0] "" Vector__XXX + +BO_ 1264 CONTROLLER_PID_TV_DELTA_DATA: 8 ECU + SG_ pid_tv_rr_delta : 30|10@1- (0.1,0) [0|0] "" Vector__XXX + SG_ pid_tv_rl_delta : 20|10@1- (0.1,0) [0|0] "" Vector__XXX + SG_ pid_tv_fr_delta : 10|10@1- (0.1,0) [0|0] "" Vector__XXX + SG_ pid_tv_fl_delta : 0|10@1- (0.1,0) [0|0] "" Vector__XXX + +BO_ 1997 CONTROLLER_PID_YAW: 8 ECU + SG_ controller_yaw_pid_output : 32|16@1- (0.001,0) [0|0] "Nm" Vector__XXX + SG_ controller_yaw_rate_error : 16|16@1- (0.0001,0) [0|0] "rad/s" Vector__XXX + SG_ vehm_kin_desired_yaw_rate_rad_s : 0|16@1- (0.0001,0) [0|0] "rad/s" Vector__XXX + +BO_ 2010 CONTROLLER_PID_YAW_TORQUE: 8 ECU + SG_ controller_yaw_torque_rr : 48|16@1- (0.001,0) [0|0] "Nm" Vector__XXX + SG_ controller_yaw_torque_rl : 32|16@1- (0.001,0) [0|0] "Nm" Vector__XXX + SG_ controller_yaw_torque_fr : 16|16@1- (0.001,0) [0|0] "Nm" Vector__XXX + SG_ controller_yaw_torque_fl : 0|16@1- (0.001,0) [0|0] "Nm" Vector__XXX + +BO_ 2014 CONTROLLER_POWER_LIM: 8 ECU + SG_ controller_power_lim_torque_adj : 20|16@1- (0.001,0) [0|0] "Nm" Vector__XXX + SG_ controller_power_lim_error : 4|16@1- (0.001,0) [0|0] "" Vector__XXX + SG_ controller_power_lim_status : 0|4@1+ (1,0) [0|0] "" Vector__XXX + +BO_ 2026 CONTROLLER_POWER_LIM_CORNER_POW: 8 ECU + SG_ controller_power_lim_cornerp_rr : 48|16@1- (0.01,0) [0|0] "kW" Vector__XXX + SG_ controller_power_lim_cornerp_rl : 32|16@1- (0.01,0) [0|0] "kW" Vector__XXX + SG_ controller_power_lim_cornerp_fr : 16|16@1- (0.01,0) [0|0] "kW" Vector__XXX + SG_ controller_power_lim_cornerp_fl : 0|16@1- (0.01,0) [0|0] "kW" Vector__XXX + +BO_ 2027 CONTROLLER_POWER_LIM_TORQUE: 8 ECU + SG_ controller_power_lim_torque_rr : 48|16@1- (0.001,0) [0|0] "Nm" Vector__XXX + SG_ controller_power_lim_torque_rl : 32|16@1- (0.001,0) [0|0] "Nm" Vector__XXX + SG_ controller_power_lim_torque_fr : 16|16@1- (0.001,0) [0|0] "Nm" Vector__XXX + SG_ controller_power_lim_torque_fl : 0|16@1- (0.001,0) [0|0] "Nm" Vector__XXX + +BO_ 1966 CONTROLLER_REGEN_5KPH_STATUS: 8 ECU + SG_ controller_regen_5kph_status_rr : 3|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ controller_regen_5kph_status_rl : 2|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ controller_regen_5kph_status_fr : 1|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ controller_regen_5kph_status_fl : 0|1@1+ (1,0) [0|0] "" Vector__XXX + +BO_ 1965 CONTROLLER_REGEN_5KPH_TORQUE: 8 ECU + SG_ controller_regen_5kph_torq_rr : 48|16@1- (0.001,0) [0|0] "Nm" Vector__XXX + SG_ controller_regen_5kph_torq_rl : 32|16@1- (0.001,0) [0|0] "Nm" Vector__XXX + SG_ controller_regen_5kph_torq_fr : 16|16@1- (0.001,0) [0|0] "Nm" Vector__XXX + SG_ controller_regen_5kph_torq_fl : 0|16@1- (0.001,0) [0|0] "Nm" Vector__XXX + +BO_ 2043 CONTROLLER_TCS_CONFIG: 8 ECU + SG_ controller_tcs_sl_nlperc_star_rr : 46|8@1+ (0.01,0) [0|0] "" Vector__XXX + SG_ controller_tcs_sl_nlperc_end_rr : 38|8@1+ (0.01,0) [0|0] "" Vector__XXX + SG_ controller_tcs_sl_nlperc_end_fr : 30|8@1+ (0.01,0) [0|0] "" Vector__XXX + SG_ controller_tcs_sl_nlperc_star_fr : 22|8@1+ (0.01,0) [0|0] "" Vector__XXX + SG_ controller_tcs_vel_thresh : 14|8@1+ (0.01,0) [0|0] "m/s" Vector__XXX + SG_ controller_tcs_launch_vel_thresh : 8|6@1+ (0.01,0) [0|0] "m/s" Vector__XXX + SG_ controller_tcs_launch_dead_zone : 0|8@1+ (0.1,0) [0|0] "Nm" Vector__XXX + +BO_ 1980 CONTROLLER_TCS_CONFIG_CONT: 8 ECU + SG_ controller_tcs_SL_end_rear : 56|8@1+ (0.01,0) [0|0] "" Vector__XXX + SG_ controller_tcs_SL_start_rear : 48|8@1+ (0.01,0) [0|0] "" Vector__XXX + SG_ controller_tcs_SL_end_front : 40|8@1+ (0.01,0) [0|0] "" Vector__XXX + SG_ controller_tcs_SL_start_front : 32|8@1+ (0.01,0) [0|0] "" Vector__XXX + SG_ controller_tcs_lauSL_end_rear : 24|8@1+ (0.01,0) [0|0] "" Vector__XXX + SG_ controller_tcs_lauSL_start_rear : 16|8@1+ (0.01,0) [0|0] "" Vector__XXX + SG_ controller_tcs_lauSL_end_front : 8|8@1+ (0.01,0) [0|0] "" Vector__XXX + SG_ controller_tcs_lauSL_start_front : 0|8@1+ (0.01,0) [0|0] "" Vector__XXX + +BO_ 1981 CONTROLLER_TCS_DIFF_CONFIG: 8 ECU + SG_ controller_tcs_launch_LRdiff : 51|13@1+ (0.01,0) [0|0] "Nm" Vector__XXX + SG_ controller_tcs_w_steer_upper_b : 39|12@1+ (0.01,0) [0|0] "deg" Vector__XXX + SG_ controller_tcs_w_steer_lower_b : 27|12@1+ (0.01,0) [0|0] "deg" Vector__XXX + SG_ controller_tcs_gen_LRdiff_upperB : 13|14@1+ (0.01,0) [0|0] "Nm" Vector__XXX + SG_ controller_tcs_gen_LRdiff_lowerB : 0|13@1+ (0.01,0) [0|0] "Nm" Vector__XXX + +BO_ 1996 CONTROLLER_TCS_NL_SCHE_CONFIG: 8 ECU + SG_ controller_tcs_startper_nl_rear : 24|8@1+ (0.01,0) [0|0] "" Vector__XXX + SG_ controller_tcs_startper_nl_front : 16|8@1+ (0.01,0) [0|0] "" Vector__XXX + SG_ controller_tcs_endper_nl_rear : 8|8@1+ (0.01,0) [0|0] "" Vector__XXX + SG_ controller_tcs_endper_nl_front : 0|8@1+ (0.01,0) [0|0] "" Vector__XXX + +BO_ 1967 CONTROLLER_TCS_PID_CONFIG: 8 ECU + SG_ controller_tcs_pid_p_rr : 48|16@1+ (0.001,0) [0|0] "" Vector__XXX + SG_ controller_tcs_pid_p_rl : 32|16@1+ (0.001,0) [0|0] "" Vector__XXX + SG_ controller_tcs_pid_p_fr : 16|16@1+ (0.001,0) [0|0] "" Vector__XXX + SG_ controller_tcs_pid_p_fl : 0|16@1+ (0.001,0) [0|0] "" Vector__XXX + +BO_ 2046 CONTROLLER_TCS_PID_INPUT: 8 ECU + SG_ controller_tcs_pid_input_rr : 48|16@1- (0.0001,0) [0|0] "Nm" Vector__XXX + SG_ controller_tcs_pid_input_rl : 32|16@1- (0.0001,0) [0|0] "Nm" Vector__XXX + SG_ controller_tcs_pid_input_fr : 16|16@1- (0.0001,0) [0|0] "Nm" Vector__XXX + SG_ controller_tcs_pid_input_fl : 0|16@1- (0.0001,0) [0|0] "Nm" Vector__XXX + +BO_ 1962 CONTROLLER_TCS_PID_OUTPUT: 8 ECU + SG_ controller_tcs_pid_output_rr : 48|16@1- (0.001,0) [0|0] "Nm" Vector__XXX + SG_ controller_tcs_pid_output_rl : 32|16@1- (0.001,0) [0|0] "Nm" Vector__XXX + SG_ controller_tcs_pid_output_fr : 16|16@1- (0.001,0) [0|0] "Nm" Vector__XXX + SG_ controller_tcs_pid_output_fl : 0|16@1- (0.001,0) [0|0] "Nm" Vector__XXX + +BO_ 1982 CONTROLLER_TCS_RPM_SCHE_CONFIG: 8 ECU + SG_ controller_tcs_upper_rpm_rear : 45|15@1+ (1,0) [0|0] "RPM" Vector__XXX + SG_ controller_tcs_upper_rpm_front : 30|15@1+ (1,0) [0|0] "RPM" Vector__XXX + SG_ controller_tcs_lower_rpm_rear : 15|15@1+ (1,0) [0|0] "RPM" Vector__XXX + SG_ controller_tcs_lower_rpm_front : 0|15@1+ (1,0) [0|0] "RPM" Vector__XXX + +BO_ 1979 CONTROLLER_TCS_SATURATION_CONFIG: 8 ECU + SG_ controller_tcs_saturation_rear : 12|12@1+ (0.01,0) [0|0] "Nm" Vector__XXX + SG_ controller_tcs_saturation_front : 0|12@1+ (0.01,0) [0|0] "Nm" Vector__XXX + +BO_ 1983 CONTROLLER_TCS_SLIP_TARGETS: 8 ECU + SG_ controller_tcs_slip_target_rear : 12|12@1+ (0.001,0) [0|0] "" Vector__XXX + SG_ controller_tcs_slip_target_front : 0|12@1+ (0.001,0) [0|0] "" Vector__XXX + +BO_ 2045 CONTROLLER_TCS_STATUS: 8 ECU + SG_ controller_tcs_status_rr : 6|2@1+ (1,0) [0|0] "" Vector__XXX + SG_ controller_tcs_status_rl : 4|2@1+ (1,0) [0|0] "" Vector__XXX + SG_ controller_tcs_status_fr : 2|2@1+ (1,0) [0|0] "" Vector__XXX + SG_ controller_tcs_status_fl : 0|2@1+ (1,0) [0|0] "" Vector__XXX + +BO_ 2044 CONTROLLER_TCS_TORQUE: 8 ECU + SG_ controller_tcs_torque_rr : 48|16@1- (0.001,0) [0|0] "Nm" Vector__XXX + SG_ controller_tcs_torque_rl : 32|16@1- (0.001,0) [0|0] "Nm" Vector__XXX + SG_ controller_tcs_torque_fr : 16|16@1- (0.001,0) [0|0] "Nm" Vector__XXX + SG_ controller_tcs_torque_fl : 0|16@1- (0.001,0) [0|0] "Nm" Vector__XXX + +BO_ 1964 CONTROLLER_TORQUE_BIAS: 8 ECU + SG_ controller_bias_torq_avg_rear : 16|16@1- (0.001,0) [0|0] "Nm" Vector__XXX + SG_ controller_bias_torq_avg_front : 0|16@1- (0.001,0) [0|0] "Nm" Vector__XXX + +BO_ 2042 CONTROLLER_TORQUE_SETUP: 8 ECU + SG_ controller_max_nl_brake_sc_front : 56|8@1+ (0.01,0) [0|0] "" Vector__XXX + SG_ controller_max_yaw_nl_accel_perc : 52|4@1+ (0.1,0) [0|0] "" Vector__XXX + SG_ controller_torque_mode : 44|8@1+ (0.1,0) [0|0] "Nm" Vector__XXX + SG_ controller_regen_limit : 32|12@1- (0.01,0) [0|0] "Nm" Vector__XXX + SG_ controller_constrained_torq_req : 16|16@1- (0.001,0) [0|0] "Nm" Vector__XXX + SG_ controller_initial_torque_req : 0|16@1- (0.001,0) [0|0] "Nm" Vector__XXX + +BO_ 1978 CONTROLLER_YAW_PID_CONFIG: 8 ECU + SG_ controller_yaw_pid_brakes_d : 54|10@1+ (0.001,0) [0|0] "" Vector__XXX + SG_ controller_yaw_pid_brakes_i : 44|10@1+ (0.001,0) [0|0] "" Vector__XXX + SG_ controller_yaw_pid_brakes_p : 33|11@1+ (0.001,0) [0|0] "" Vector__XXX + SG_ controller_yaw_pid_d : 23|10@1+ (0.001,0) [0|0] "" Vector__XXX + SG_ controller_yaw_pid_i : 13|10@1+ (0.001,0) [0|0] "" Vector__XXX + SG_ controller_yaw_pid_p : 0|13@1+ (0.001,0) [0|0] "" Vector__XXX + +BO_ 6 Configuration: 6 ECU + SG_ Velocity_Filtering : 40|3@1+ (1,0) [0|0] "" Vector__XXX + SG_ CAN_Termination_State_Bus_2 : 39|1@1+ (1,0) [0|1] "" Vector__XXX + SG_ CAN_Termination_State_Bus_1 : 38|1@1+ (1,0) [0|1] "" Vector__XXX + SG_ IMU_Filtering : 35|3@1+ (1,0) [0|0] "" Vector__XXX + SG_ Attitude_Filtering : 32|3@1+ (1,0) [0|0] "" Vector__XXX + SG_ Sensor_X_Location : 20|12@1- (0.01,0) [0|0] "m" Vector__XXX + SG_ Sensor_Y_Location : 8|12@1- (0.01,0) [0|0] "m" Vector__XXX + SG_ Height_Offset : 0|8@1- (0.5,0) [0|0] "cm" Vector__XXX + +BO_ 2033 DASHBOARD_BUZZER_CONTROL: 2 ECU + SG_ torque_limit_enum_value : 8|8@1+ (1,0) [0|0] "" Vector__XXX + SG_ in_pedal_calibration_state : 1|1@1+ (1,0) [0|1] "" Vector__XXX + SG_ dash_buzzer_flag : 0|1@1+ (1,0) [0|1] "" Vector__XXX + +BO_ 235 DASHBOARD_MCU_STATE: 6 ECU + SG_ dial_state : 40|8@1+ (1,0) [0|0] "" Vector__XXX + SG_ pack_charge_led : 32|8@1+ (1,0) [0|0] "" Vector__XXX + SG_ glv_led : 24|8@1+ (1,0) [0|0] "" Vector__XXX + SG_ drive_buzzer : 20|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ ams_led : 18|2@1+ (1,0) [0|0] "" Vector__XXX + SG_ imd_led : 16|2@1+ (1,0) [0|0] "" Vector__XXX + SG_ motor_controller_error_led : 14|2@1+ (1,0) [0|0] "" Vector__XXX + SG_ start_status_led : 12|2@1+ (1,0) [0|0] "" Vector__XXX + SG_ inertia_status_led : 10|2@1+ (1,0) [0|0] "" Vector__XXX + SG_ cockpit_brb_led : 8|2@1+ (1,0) [0|0] "" Vector__XXX + SG_ mechanical_brake_led : 6|2@1+ (1,0) [0|0] "" Vector__XXX + SG_ mode_led : 4|2@1+ (1,0) [0|0] "" Vector__XXX + SG_ launch_control_led : 2|2@1+ (1,0) [0|0] "" Vector__XXX + SG_ bots_led : 0|2@1+ (1,0) [0|0] "" Vector__XXX + +BO_ 236 DASHBOARD_STATE: 3 ECU + SG_ dial_state : 16|8@1+ (1,0) [0|0] "" Vector__XXX + SG_ tcu_recording_state : 12|2@1+ (1,0) [0|0] "" Vector__XXX + SG_ drive_buzzer : 11|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ ssok_above_threshold : 10|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ shutdown_h_above_threshold : 9|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ right_shifter_button : 8|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ left_shifter_button : 7|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ led_dimmer_button : 6|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ torque_mode_button : 5|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ launch_ctrl_button : 4|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ motor_controller_cycle_button : 3|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ mode_button : 2|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ mark_button : 1|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ start_button : 0|1@1+ (1,0) [0|0] "" Vector__XXX + +BO_ 768 DASH_INPUT: 2 ECU + SG_ dash_dial_mode : 8|8@1+ (1,0) [0|0] "" Vector__XXX + SG_ right_shifter_button : 7|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ left_shifter_button : 6|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ data_button_is_pressed : 5|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ start_button : 4|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ mode_button : 3|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ motor_controller_cycle_button : 2|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ preset_button : 1|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ led_dimmer_button : 0|1@1+ (1,0) [0|0] "" Vector__XXX + +BO_ 243 DRIVEBRAIN_DESIRED_TORQUE_INPUT: 8 ECU + SG_ drivebrain_torque_rr : 48|16@1- (0.01,0) [0|0] "" Vector__XXX + SG_ drivebrain_torque_rl : 32|16@1- (0.01,0) [0|0] "" Vector__XXX + SG_ drivebrain_torque_fr : 16|16@1- (0.01,0) [0|0] "" Vector__XXX + SG_ drivebrain_torque_fl : 0|16@1- (0.01,0) [0|0] "" Vector__XXX + +BO_ 242 DRIVEBRAIN_SPEED_SET_INPUT: 8 ECU + SG_ drivebrain_set_rpm_rr : 48|16@1+ (1,0) [0|0] "" Vector__XXX + SG_ drivebrain_set_rpm_rl : 32|16@1+ (1,0) [0|0] "" Vector__XXX + SG_ drivebrain_set_rpm_fr : 16|16@1+ (1,0) [0|0] "" Vector__XXX + SG_ drivebrain_set_rpm_fl : 0|16@1+ (1,0) [0|0] "" Vector__XXX + +BO_ 241 DRIVEBRAIN_TORQUE_LIM_INPUT: 8 ECU + SG_ drivebrain_torque_rr : 48|16@1- (0.01,0) [0|0] "" Vector__XXX + SG_ drivebrain_torque_rl : 32|16@1- (0.01,0) [0|0] "" Vector__XXX + SG_ drivebrain_torque_fr : 16|16@1- (0.01,0) [0|0] "" Vector__XXX + SG_ drivebrain_torque_fl : 0|16@1- (0.01,0) [0|0] "" Vector__XXX + +BO_ 303 DRIVETRAIN_COMMAND: 8 ECU + SG_ drivetrain_traj_torque_lim_rr : 48|16@1- (0.001,0) [0|0] "" Vector__XXX + SG_ drivetrain_traj_torque_lim_rl : 32|16@1- (0.001,0) [0|0] "" Vector__XXX + SG_ drivetrain_traj_torque_lim_fr : 16|16@1- (0.001,0) [0|0] "" Vector__XXX + SG_ drivetrain_traj_torque_lim_fl : 0|16@1- (0.001,0) [0|0] "" Vector__XXX + +BO_ 513 DRIVETRAIN_ERR_STATUS_TELEM: 8 ECU + SG_ mc4_diagnostic_number : 48|16@1+ (1,0) [0|0] "" Vector__XXX + SG_ mc3_diagnostic_number : 32|16@1+ (1,0) [0|0] "" Vector__XXX + SG_ mc2_diagnostic_number : 16|16@1+ (1,0) [0|0] "" Vector__XXX + SG_ mc1_diagnostic_number : 0|16@1+ (1,0) [0|0] "" Vector__XXX + +BO_ 516 DRIVETRAIN_FILTER_OUT_TORQUE_TEL: 8 ECU + SG_ rr_motor_torque : 48|16@1- (1,0) [0|0] "nm" Vector__XXX + SG_ rl_motor_torque : 32|16@1- (1,0) [0|0] "nm" Vector__XXX + SG_ fr_motor_torque : 16|16@1- (1,0) [0|0] "nm" Vector__XXX + SG_ fl_motor_torque : 0|16@1- (1,0) [0|0] "nm" Vector__XXX + +BO_ 512 DRIVETRAIN_RPMS_TELEM: 8 ECU + SG_ rl_motor_rpm : 48|16@1- (1,0) [0|0] "" Vector__XXX + SG_ rr_motor_rpm : 32|16@1- (1,0) [0|0] "" Vector__XXX + SG_ fl_motor_rpm : 16|16@1- (1,0) [0|0] "" Vector__XXX + SG_ fr_motor_rpm : 0|16@1- (1,0) [0|0] "" Vector__XXX + +BO_ 514 DRIVETRAIN_STATUS_TELEM: 8 ECU + SG_ accel_percent : 48|8@1+ (1,0) [0|100] "" Vector__XXX + SG_ brake_percent : 40|8@1+ (1,0) [0|100] "" Vector__XXX + SG_ brake_implausible : 33|1@1+ (1,0) [0|1] "" Vector__XXX + SG_ accel_implausible : 32|1@1+ (1,0) [0|1] "" Vector__XXX + SG_ mc4_warning : 31|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ mc4_system_ready : 30|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ mc4_quit_inverter_on : 29|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ mc4_quit_dc : 28|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ mc4_inverter_on : 27|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ mc4_error : 26|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ mc4_derating_on : 25|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ mc4_dc_on : 24|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ mc3_warning : 23|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ mc3_system_ready : 22|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ mc3_quit_inverter_on : 21|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ mc3_quit_dc : 20|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ mc3_inverter_on : 19|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ mc3_error : 18|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ mc3_derating_on : 17|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ mc3_dc_on : 16|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ mc2_warning : 15|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ mc2_system_ready : 14|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ mc2_quit_inverter_on : 13|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ mc2_quit_dc : 12|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ mc2_inverter_on : 11|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ mc2_error : 10|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ mc2_derating_on : 9|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ mc2_dc_on : 8|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ mc1_warning : 7|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ mc1_system_ready : 6|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ mc1_quit_inverter_on : 5|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ mc1_quit_dc : 4|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ mc1_inverter_on : 3|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ mc1_error : 2|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ mc1_derating_on : 1|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ mc1_dc_on : 0|1@1+ (1,0) [0|0] "" Vector__XXX + +BO_ 515 DRIVETRAIN_TORQUE_TELEM: 8 ECU + SG_ rr_motor_torque : 48|16@1- (1,0) [0|0] "nm" Vector__XXX + SG_ rl_motor_torque : 32|16@1- (1,0) [0|0] "nm" Vector__XXX + SG_ fr_motor_torque : 16|16@1- (1,0) [0|0] "nm" Vector__XXX + SG_ fl_motor_torque : 0|16@1- (1,0) [0|0] "nm" Vector__XXX + +BO_ 256 EM_MEASUREMENT: 8 ECU + SG_ em_voltage : 39|32@0- (1.52590219e-05,0) [0|0] "Volts" Vector__XXX + SG_ em_current : 7|32@0- (1.52590219e-05,0) [0|0] "Coulombs" Vector__XXX + +BO_ 1024 EM_STATUS: 2 ECU + SG_ logging : 10|1@1+ (1,0) [0|0] "none" Vector__XXX + SG_ overpower_error : 9|1@1+ (1,0) [0|0] "none" Vector__XXX + SG_ overvoltage_error : 8|1@1+ (1,0) [0|0] "none" Vector__XXX + SG_ current_gain : 4|4@1+ (1,0) [0|0] "none" Vector__XXX + SG_ voltage_gain : 0|4@1+ (1,0) [0|0] "none" Vector__XXX + +BO_ 237 FRONT_SUSPENSION: 8 ECU + SG_ fr_shock_pot : 48|16@1+ (1,0) [0|0] "" Vector__XXX + SG_ fr_load_cell : 32|16@1+ (1,0) [0|0] "" Vector__XXX + SG_ fl_shock_pot : 16|16@1+ (1,0) [0|0] "" Vector__XXX + SG_ fl_load_cell : 0|16@1+ (1,0) [0|0] "" Vector__XXX + +BO_ 245 FRONT_THERMISTORS: 8 ECU + SG_ thermistor_motor_fr : 16|16@1+ (0.005,0) [0|0] "deg C" Vector__XXX + SG_ thermistor_motor_fl : 0|16@1+ (0.005,0) [0|0] "deg C" Vector__XXX + +BO_ 1 IMU: 8 ECU + SG_ Pitch_Rate : 52|11@1- (0.01,0) [0|0] "rad/s" Vector__XXX + SG_ Yaw_Rate : 41|11@1- (0.01,0) [0|0] "rad/s" Vector__XXX + SG_ Roll_Rate : 30|11@1- (0.01,0) [0|0] "rad/s" Vector__XXX + SG_ Accel_Z : 20|10@1- (0.057,0) [0|29.127] "m/s2" Vector__XXX + SG_ Accel_Y : 10|10@1- (0.057,0) [0|29.127] "m/s2" Vector__XXX + SG_ Accel_X : 0|10@1- (0.057,0) [0|29.127] "m/s2" Vector__XXX + +BO_ 151 INV1_CONTROL_INPUT: 6 ECU + SG_ negative_torque_limit : 32|16@1- (0.0097999999999549,0) [0|0] "Mn" Vector__XXX + SG_ positive_torque_limit : 16|16@1- (0.0097999999999549,0) [0|0] "Mn" Vector__XXX + SG_ speed_setpoint_rpm : 0|16@1- (1,0) [0|0] "rpm" Vector__XXX + +BO_ 259 INV1_CONTROL_PARAMETER: 8 ECU + SG_ speed_control_kd : 32|16@1+ (1,0) [0|0] "" Vector__XXX + SG_ speed_control_ki : 16|16@1+ (1,0) [0|0] "" Vector__XXX + SG_ speed_control_kp : 0|16@1+ (1,0) [0|0] "" Vector__XXX + +BO_ 144 INV1_CONTROL_WORD: 2 ECU + SG_ remove_error : 11|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ driver_enable : 10|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ hv_enable : 9|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ inverter_enable : 8|1@1+ (1,0) [0|0] "" Vector__XXX + +BO_ 114 INV1_DYNAMICS: 8 ECU + SG_ actual_speed_rpm : 48|16@1- (1,0) [0|0] "" Vector__XXX + SG_ actual_torque_nm : 32|16@1- (0.0097999999999549,0) [0|0] "" Vector__XXX + SG_ actual_power_w : 0|32@1+ (1,0) [0|0] "" Vector__XXX + +BO_ 116 INV1_FEEDBACK: 8 ECU + SG_ speed_control_kd : 32|16@1+ (1,0) [0|0] "" Vector__XXX + SG_ speed_control_ki : 16|16@1+ (1,0) [0|0] "" Vector__XXX + SG_ speed_control_kp : 0|16@1+ (1,0) [0|0] "" Vector__XXX + +BO_ 115 INV1_POWER: 8 ECU + SG_ reactive_power_var : 32|32@1- (1,0) [0|0] "" Vector__XXX + SG_ active_power_w : 0|32@1- (1,0) [0|0] "" Vector__XXX + +BO_ 112 INV1_STATUS: 8 ECU + SG_ diagnostic_number : 32|16@1+ (1,0) [0|0] "" Vector__XXX + SG_ dc_bus_voltage : 16|16@1+ (1,0) [0|0] "V" Vector__XXX + SG_ derating_on : 15|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ inverter_on : 14|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ quit_inverter_on : 13|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ dc_on : 12|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ quit_dc_on : 11|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ warning : 10|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ error : 9|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ system_ready : 8|1@1+ (1,0) [0|0] "" Vector__XXX + +BO_ 113 INV1_TEMPS: 6 ECU + SG_ igbt_temp : 32|16@1- (0.1,0) [0|0] "C" Vector__XXX + SG_ inverter_temp : 16|16@1- (0.1,0) [0|0] "C" Vector__XXX + SG_ motor_temp : 0|16@1- (0.1,0) [0|0] "C" Vector__XXX + +BO_ 152 INV2_CONTROL_INPUT: 6 ECU + SG_ negative_torque_limit : 32|16@1- (0.0097999999999549,0) [0|0] "Mn" Vector__XXX + SG_ positive_torque_limit : 16|16@1- (0.0097999999999549,0) [0|0] "Mn" Vector__XXX + SG_ speed_setpoint_rpm : 0|16@1- (1,0) [0|0] "rpm" Vector__XXX + +BO_ 260 INV2_CONTROL_PARAMETER: 8 ECU + SG_ speed_control_kd : 32|16@1+ (1,0) [0|0] "" Vector__XXX + SG_ speed_control_ki : 16|16@1+ (1,0) [0|0] "" Vector__XXX + SG_ speed_control_kp : 0|16@1+ (1,0) [0|0] "" Vector__XXX + +BO_ 145 INV2_CONTROL_WORD: 2 ECU + SG_ remove_error : 11|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ driver_enable : 10|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ hv_enable : 9|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ inverter_enable : 8|1@1+ (1,0) [0|0] "" Vector__XXX + +BO_ 119 INV2_DYNAMICS: 8 ECU + SG_ actual_speed_rpm : 48|16@1- (1,0) [0|0] "" Vector__XXX + SG_ actual_torque_nm : 32|16@1- (0.0097999999999549,0) [0|0] "" Vector__XXX + SG_ actual_power_w : 0|32@1+ (1,0) [0|0] "" Vector__XXX + +BO_ 121 INV2_FEEDBACK: 8 ECU + SG_ speed_control_kd : 32|16@1+ (1,0) [0|0] "" Vector__XXX + SG_ speed_control_ki : 16|16@1+ (1,0) [0|0] "" Vector__XXX + SG_ speed_control_kp : 0|16@1+ (1,0) [0|0] "" Vector__XXX + +BO_ 120 INV2_POWER: 8 ECU + SG_ reactive_power_var : 32|32@1- (1,0) [0|0] "" Vector__XXX + SG_ active_power_w : 0|32@1- (1,0) [0|0] "" Vector__XXX + +BO_ 117 INV2_STATUS: 8 ECU + SG_ diagnostic_number : 32|16@1+ (1,0) [0|0] "" Vector__XXX + SG_ dc_bus_voltage : 16|16@1+ (1,0) [0|0] "V" Vector__XXX + SG_ derating_on : 15|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ inverter_on : 14|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ quit_inverter_on : 13|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ dc_on : 12|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ quit_dc_on : 11|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ warning : 10|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ error : 9|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ system_ready : 8|1@1+ (1,0) [0|0] "" Vector__XXX + +BO_ 118 INV2_TEMPS: 6 ECU + SG_ igbt_temp : 32|16@1- (0.1,0) [0|0] "C" Vector__XXX + SG_ inverter_temp : 16|16@1- (0.1,0) [0|0] "C" Vector__XXX + SG_ motor_temp : 0|16@1- (0.1,0) [0|0] "C" Vector__XXX + +BO_ 153 INV3_CONTROL_INPUT: 6 ECU + SG_ negative_torque_limit : 32|16@1- (0.0097999999999549,0) [0|0] "Mn" Vector__XXX + SG_ positive_torque_limit : 16|16@1- (0.0097999999999549,0) [0|0] "Mn" Vector__XXX + SG_ speed_setpoint_rpm : 0|16@1- (1,0) [0|0] "rpm" Vector__XXX + +BO_ 261 INV3_CONTROL_PARAMETER: 8 ECU + SG_ speed_control_kd : 32|16@1+ (1,0) [0|0] "" Vector__XXX + SG_ speed_control_ki : 16|16@1+ (1,0) [0|0] "" Vector__XXX + SG_ speed_control_kp : 0|16@1+ (1,0) [0|0] "" Vector__XXX + +BO_ 146 INV3_CONTROL_WORD: 2 ECU + SG_ remove_error : 11|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ driver_enable : 10|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ hv_enable : 9|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ inverter_enable : 8|1@1+ (1,0) [0|0] "" Vector__XXX + +BO_ 130 INV3_DYNAMICS: 8 ECU + SG_ actual_speed_rpm : 48|16@1- (1,0) [0|0] "" Vector__XXX + SG_ actual_torque_nm : 32|16@1- (0.0097999999999549,0) [0|0] "" Vector__XXX + SG_ actual_power_w : 0|32@1+ (1,0) [0|0] "" Vector__XXX + +BO_ 132 INV3_FEEDBACK: 8 ECU + SG_ speed_control_kd : 32|16@1+ (1,0) [0|0] "" Vector__XXX + SG_ speed_control_ki : 16|16@1+ (1,0) [0|0] "" Vector__XXX + SG_ speed_control_kp : 0|16@1+ (1,0) [0|0] "" Vector__XXX + +BO_ 131 INV3_POWER: 8 ECU + SG_ reactive_power_var : 32|32@1- (1,0) [0|0] "" Vector__XXX + SG_ active_power_w : 0|32@1- (1,0) [0|0] "" Vector__XXX + +BO_ 128 INV3_STATUS: 8 ECU + SG_ diagnostic_number : 32|16@1+ (1,0) [0|0] "" Vector__XXX + SG_ dc_bus_voltage : 16|16@1+ (1,0) [0|0] "V" Vector__XXX + SG_ derating_on : 15|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ inverter_on : 14|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ quit_inverter_on : 13|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ dc_on : 12|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ quit_dc_on : 11|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ warning : 10|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ error : 9|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ system_ready : 8|1@1+ (1,0) [0|0] "" Vector__XXX + +BO_ 129 INV3_TEMPS: 6 ECU + SG_ igbt_temp : 32|16@1- (0.1,0) [0|0] "C" Vector__XXX + SG_ inverter_temp : 16|16@1- (0.1,0) [0|0] "C" Vector__XXX + SG_ motor_temp : 0|16@1- (0.1,0) [0|0] "C" Vector__XXX + +BO_ 258 INV4_CONTROL_INPUT: 6 ECU + SG_ negative_torque_limit : 32|16@1- (0.0097999999999549,0) [0|0] "Mn" Vector__XXX + SG_ positive_torque_limit : 16|16@1- (0.0097999999999549,0) [0|0] "Mn" Vector__XXX + SG_ speed_setpoint_rpm : 0|16@1- (1,0) [0|0] "rpm" Vector__XXX + +BO_ 262 INV4_CONTROL_PARAMETER: 8 ECU + SG_ speed_control_kd : 32|16@1+ (1,0) [0|0] "" Vector__XXX + SG_ speed_control_ki : 16|16@1+ (1,0) [0|0] "" Vector__XXX + SG_ speed_control_kp : 0|16@1+ (1,0) [0|0] "" Vector__XXX + +BO_ 147 INV4_CONTROL_WORD: 2 ECU + SG_ remove_error : 11|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ driver_enable : 10|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ hv_enable : 9|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ inverter_enable : 8|1@1+ (1,0) [0|0] "" Vector__XXX + +BO_ 135 INV4_DYNAMICS: 8 ECU + SG_ actual_speed_rpm : 48|16@1- (1,0) [0|0] "" Vector__XXX + SG_ actual_torque_nm : 32|16@1- (0.0097999999999549,0) [0|0] "" Vector__XXX + SG_ actual_power_w : 0|32@1+ (1,0) [0|0] "" Vector__XXX + +BO_ 137 INV4_FEEDBACK: 8 ECU + SG_ speed_control_kd : 32|16@1+ (1,0) [0|0] "" Vector__XXX + SG_ speed_control_ki : 16|16@1+ (1,0) [0|0] "" Vector__XXX + SG_ speed_control_kp : 0|16@1+ (1,0) [0|0] "" Vector__XXX + +BO_ 136 INV4_POWER: 8 ECU + SG_ reactive_power_var : 32|32@1- (1,0) [0|0] "" Vector__XXX + SG_ active_power_w : 0|32@1- (1,0) [0|0] "" Vector__XXX + +BO_ 133 INV4_STATUS: 8 ECU + SG_ diagnostic_number : 32|16@1+ (1,0) [0|0] "" Vector__XXX + SG_ dc_bus_voltage : 16|16@1+ (1,0) [0|0] "V" Vector__XXX + SG_ derating_on : 15|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ inverter_on : 14|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ quit_inverter_on : 13|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ dc_on : 12|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ quit_dc_on : 11|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ warning : 10|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ error : 9|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ system_ready : 8|1@1+ (1,0) [0|0] "" Vector__XXX + +BO_ 134 INV4_TEMPS: 6 ECU + SG_ igbt_temp : 32|16@1- (0.1,0) [0|0] "C" Vector__XXX + SG_ inverter_temp : 16|16@1- (0.1,0) [0|0] "C" Vector__XXX + SG_ motor_temp : 0|16@1- (0.1,0) [0|0] "C" Vector__XXX + +BO_ 1060 LF_TTPMS_1: 8 ECU + SG_ LF_TTPMS_P_GAUGE : 55|16@0+ (1,0) [0|0] "mbar" Vector__XXX + SG_ LF_TTPMS_P : 39|16@0+ (0.1,3000) [0|0] "mbar" Vector__XXX + SG_ LF_TTPMS_BAT_V : 23|16@0+ (1,0) [0|0] "mV" Vector__XXX + SG_ LF_TTPMS_SN : 7|16@0+ (1,0) [0|0] "" Vector__XXX + +BO_ 1061 LF_TTPMS_2: 8 ECU + SG_ LF_TTPMS_T4 : 55|16@0+ (0.1,-100) [0|0] "°C" Vector__XXX + SG_ LF_TTPMS_T3 : 39|16@0+ (0.1,-100) [0|0] "°C" Vector__XXX + SG_ LF_TTPMS_T2 : 23|16@0+ (0.1,-100) [0|0] "°C" Vector__XXX + SG_ LF_TTPMS_T1 : 7|16@0+ (0.1,-100) [0|0] "°C" Vector__XXX + +BO_ 1062 LF_TTPMS_3: 8 ECU + SG_ LF_TTPMS_T8 : 55|16@0+ (0.1,-100) [0|0] "°C" Vector__XXX + SG_ LF_TTPMS_T7 : 39|16@0+ (0.1,-100) [0|0] "°C" Vector__XXX + SG_ LF_TTPMS_T6 : 23|16@0+ (0.1,-100) [0|0] "°C" Vector__XXX + SG_ LF_TTPMS_T5 : 7|16@0+ (0.1,-100) [0|0] "°C" Vector__XXX + +BO_ 1063 LF_TTPMS_4: 8 ECU + SG_ LF_TTPMS_T12 : 55|16@0+ (0.1,-100) [0|0] "°C" Vector__XXX + SG_ LF_TTPMS_T11 : 39|16@0+ (0.1,-100) [0|0] "°C" Vector__XXX + SG_ LF_TTPMS_T10 : 23|16@0+ (0.1,-100) [0|0] "°C" Vector__XXX + SG_ LF_TTPMS_T9 : 7|16@0+ (0.1,-100) [0|0] "°C" Vector__XXX + +BO_ 1064 LF_TTPMS_5: 8 ECU + SG_ LF_TTPMS_T16 : 55|16@0+ (0.1,-100) [0|0] "°C" Vector__XXX + SG_ LF_TTPMS_T15 : 39|16@0+ (0.1,-100) [0|0] "°C" Vector__XXX + SG_ LF_TTPMS_T14 : 23|16@0+ (0.1,-100) [0|0] "°C" Vector__XXX + SG_ LF_TTPMS_T13 : 7|16@0+ (0.1,-100) [0|0] "°C" Vector__XXX + +BO_ 1065 LF_TTPMS_6: 8 ECU + SG_ LF_TTPMS_NODE_ID : 55|16@0+ (1,0) [0|0] "" Vector__XXX + SG_ LF_TTPMS_T : 39|16@0+ (0.1,-100) [0|0] "°C" Vector__XXX + SG_ LF_TTPMS_RSSI : 23|16@0- (1,0) [0|0] "dBm" Vector__XXX + SG_ LF_TTPMS_TC : 7|16@0+ (1,0) [0|0] "" Vector__XXX + +BO_ 1066 RF_TTPMS_1: 8 ECU + SG_ RF_TTPMS_P_GAUGE : 55|16@0+ (1,0) [0|0] "mbar" Vector__XXX + SG_ RF_TTPMS_P : 39|16@0+ (0.1,3000) [0|0] "mbar" Vector__XXX + SG_ RF_TTPMS_BAT_V : 23|16@0+ (1,0) [0|0] "mV" Vector__XXX + SG_ RF_TTPMS_SN : 7|16@0+ (1,0) [0|0] "" Vector__XXX + +BO_ 1067 RF_TTPMS_2: 8 ECU + SG_ RF_TTPMS_T4 : 55|16@0+ (0.1,-100) [0|0] "°C" Vector__XXX + SG_ RF_TTPMS_T3 : 39|16@0+ (0.1,-100) [0|0] "°C" Vector__XXX + SG_ RF_TTPMS_T2 : 23|16@0+ (0.1,-100) [0|0] "°C" Vector__XXX + SG_ RF_TTPMS_T1 : 7|16@0+ (0.1,-100) [0|0] "°C" Vector__XXX + +BO_ 1068 RF_TTPMS_3: 8 ECU + SG_ RF_TTPMS_T8 : 55|16@0+ (0.1,-100) [0|0] "°C" Vector__XXX + SG_ RF_TTPMS_T7 : 39|16@0+ (0.1,-100) [0|0] "°C" Vector__XXX + SG_ RF_TTPMS_T6 : 23|16@0+ (0.1,-100) [0|0] "°C" Vector__XXX + SG_ RF_TTPMS_T5 : 7|16@0+ (0.1,-100) [0|0] "°C" Vector__XXX + +BO_ 1069 RF_TTPMS_4: 8 ECU + SG_ RF_TTPMS_T12 : 55|16@0+ (0.1,-100) [0|0] "°C" Vector__XXX + SG_ RF_TTPMS_T11 : 39|16@0+ (0.1,-100) [0|0] "°C" Vector__XXX + SG_ RF_TTPMS_T10 : 23|16@0+ (0.1,-100) [0|0] "°C" Vector__XXX + SG_ RF_TTPMS_T9 : 7|16@0+ (0.1,-100) [0|0] "°C" Vector__XXX + +BO_ 1070 RF_TTPMS_5: 8 ECU + SG_ RF_TTPMS_T16 : 55|16@0+ (0.1,-100) [0|0] "°C" Vector__XXX + SG_ RF_TTPMS_T15 : 39|16@0+ (0.1,-100) [0|0] "°C" Vector__XXX + SG_ RF_TTPMS_T14 : 23|16@0+ (0.1,-100) [0|0] "°C" Vector__XXX + SG_ RF_TTPMS_T13 : 7|16@0+ (0.1,-100) [0|0] "°C" Vector__XXX + +BO_ 1071 RF_TTPMS_6: 8 ECU + SG_ RF_TTPMS_NODE_ID : 55|16@0+ (1,0) [0|0] "" Vector__XXX + SG_ RF_TTPMS_T : 39|16@0+ (0.1,-100) [0|0] "°C" Vector__XXX + SG_ RF_TTPMS_RSSI : 23|16@0- (1,0) [0|0] "dBm" Vector__XXX + SG_ RF_TTPMS_TC : 7|16@0+ (1,0) [0|0] "" Vector__XXX + +BO_ 1072 LR_TTPMS_1: 8 ECU + SG_ LR_TTPMS_P_GAUGE : 55|16@0+ (1,0) [0|0] "mbar" Vector__XXX + SG_ LR_TTPMS_P : 39|16@0+ (0.1,3000) [0|0] "mbar" Vector__XXX + SG_ LR_TTPMS_BAT_V : 23|16@0+ (1,0) [0|0] "mV" Vector__XXX + SG_ LR_TTPMS_SN : 7|16@0+ (1,0) [0|0] "" Vector__XXX + +BO_ 1073 LR_TTPMS_2: 8 ECU + SG_ LR_TTPMS_T4 : 55|16@0+ (0.1,-100) [0|0] "°C" Vector__XXX + SG_ LR_TTPMS_T3 : 39|16@0+ (0.1,-100) [0|0] "°C" Vector__XXX + SG_ LR_TTPMS_T2 : 23|16@0+ (0.1,-100) [0|0] "°C" Vector__XXX + SG_ LR_TTPMS_T1 : 7|16@0+ (0.1,-100) [0|0] "°C" Vector__XXX + +BO_ 1074 LR_TTPMS_3: 8 ECU + SG_ LR_TTPMS_T8 : 55|16@0+ (0.1,-100) [0|0] "°C" Vector__XXX + SG_ LR_TTPMS_T7 : 39|16@0+ (0.1,-100) [0|0] "°C" Vector__XXX + SG_ LR_TTPMS_T6 : 23|16@0+ (0.1,-100) [0|0] "°C" Vector__XXX + SG_ LR_TTPMS_T5 : 7|16@0+ (0.1,-100) [0|0] "°C" Vector__XXX + +BO_ 1075 LR_TTPMS_4: 8 ECU + SG_ LR_TTPMS_T12 : 55|16@0+ (0.1,-100) [0|0] "°C" Vector__XXX + SG_ LR_TTPMS_T11 : 39|16@0+ (0.1,-100) [0|0] "°C" Vector__XXX + SG_ LR_TTPMS_T10 : 23|16@0+ (0.1,-100) [0|0] "°C" Vector__XXX + SG_ LR_TTPMS_T9 : 7|16@0+ (0.1,-100) [0|0] "°C" Vector__XXX + +BO_ 1076 LR_TTPMS_5: 8 ECU + SG_ LR_TTPMS_T16 : 55|16@0+ (0.1,-100) [0|0] "°C" Vector__XXX + SG_ LR_TTPMS_T15 : 39|16@0+ (0.1,-100) [0|0] "°C" Vector__XXX + SG_ LR_TTPMS_T14 : 23|16@0+ (0.1,-100) [0|0] "°C" Vector__XXX + SG_ LR_TTPMS_T13 : 7|16@0+ (0.1,-100) [0|0] "°C" Vector__XXX + +BO_ 1077 LR_TTPMS_6: 8 ECU + SG_ LR_TTPMS_NODE_ID : 55|16@0+ (1,0) [0|0] "" Vector__XXX + SG_ LR_TTPMS_T : 39|16@0+ (0.1,-100) [0|0] "°C" Vector__XXX + SG_ LR_TTPMS_RSSI : 23|16@0- (1,0) [0|0] "dBm" Vector__XXX + SG_ LR_TTPMS_TC : 7|16@0+ (1,0) [0|0] "" Vector__XXX + +BO_ 1078 RR_TTPMS_1: 8 ECU + SG_ RR_TTPMS_P_GAUGE : 55|16@0+ (1,0) [0|0] "mbar" Vector__XXX + SG_ RR_TTPMS_P : 39|16@0+ (0.1,3000) [0|0] "mbar" Vector__XXX + SG_ RR_TTPMS_BAT_V : 23|16@0+ (1,0) [0|0] "mV" Vector__XXX + SG_ RR_TTPMS_SN : 7|16@0+ (1,0) [0|0] "" Vector__XXX + +BO_ 1079 RR_TTPMS_2: 8 ECU + SG_ RR_TTPMS_T4 : 55|16@0+ (0.1,-100) [0|0] "°C" Vector__XXX + SG_ RR_TTPMS_T3 : 39|16@0+ (0.1,-100) [0|0] "°C" Vector__XXX + SG_ RR_TTPMS_T2 : 23|16@0+ (0.1,-100) [0|0] "°C" Vector__XXX + SG_ RR_TTPMS_T1 : 7|16@0+ (0.1,-100) [0|0] "°C" Vector__XXX + +BO_ 1080 RR_TTPMS_3: 8 ECU + SG_ RR_TTPMS_T8 : 55|16@0+ (0.1,-100) [0|0] "°C" Vector__XXX + SG_ RR_TTPMS_T7 : 39|16@0+ (0.1,-100) [0|0] "°C" Vector__XXX + SG_ RR_TTPMS_T6 : 23|16@0+ (0.1,-100) [0|0] "°C" Vector__XXX + SG_ RR_TTPMS_T5 : 7|16@0+ (0.1,-100) [0|0] "°C" Vector__XXX + +BO_ 1081 RR_TTPMS_4: 8 ECU + SG_ RR_TTPMS_T12 : 55|16@0+ (0.1,-100) [0|0] "°C" Vector__XXX + SG_ RR_TTPMS_T11 : 39|16@0+ (0.1,-100) [0|0] "°C" Vector__XXX + SG_ RR_TTPMS_T10 : 23|16@0+ (0.1,-100) [0|0] "°C" Vector__XXX + SG_ RR_TTPMS_T9 : 7|16@0+ (0.1,-100) [0|0] "°C" Vector__XXX + +BO_ 1082 RR_TTPMS_5: 8 ECU + SG_ RR_TTPMS_T16 : 55|16@0+ (0.1,-100) [0|0] "°C" Vector__XXX + SG_ RR_TTPMS_T15 : 39|16@0+ (0.1,-100) [0|0] "°C" Vector__XXX + SG_ RR_TTPMS_T14 : 23|16@0+ (0.1,-100) [0|0] "°C" Vector__XXX + SG_ RR_TTPMS_T13 : 7|16@0+ (0.1,-100) [0|0] "°C" Vector__XXX + +BO_ 1083 RR_TTPMS_6: 8 ECU + SG_ RR_TTPMS_NODE_ID : 55|16@0+ (1,0) [0|0] "" Vector__XXX + SG_ RR_TTPMS_T : 39|16@0+ (0.1,-100) [0|0] "°C" Vector__XXX + SG_ RR_TTPMS_RSSI : 23|16@0- (1,0) [0|0] "dBm" Vector__XXX + SG_ RR_TTPMS_TC : 7|16@0+ (1,0) [0|0] "" Vector__XXX + +BO_ 184 MC1_ENERGY: 8 ECU + SG_ feedback_torque : 48|16@1- (1,0) [0|0] "Mn" Vector__XXX + SG_ motor_power : 16|32@1+ (1,0) [0|0] "" Vector__XXX + SG_ dc_bus_voltage : 0|16@1+ (1,0) [0|0] "V" Vector__XXX + +BO_ 204 MCU_ANALOG_READINGS: 8 ECU + SG_ glv_battery_voltage : 48|16@1+ (1,0) [0|0] "" Vector__XXX + SG_ hall_effect_current : 32|16@1- (1,0) [0|0] "N/A" Vector__XXX + SG_ steering_2 : 16|16@1+ (1,0) [0|0] "" Vector__XXX + SG_ steering_1 : 0|16@1- (1,0) [0|0] "" Vector__XXX + +BO_ 257 MCU_ERROR_STATES: 8 ECU + SG_ torque_controller_mux_status : 0|3@1+ (1,0) [0|0] "" Vector__XXX + +BO_ 198 MCU_FRONT_POTS: 4 ECU + SG_ potentiometer_fr : 16|16@1+ (1,0) [0|0] "lbs" Vector__XXX + SG_ potentiometer_fl : 0|16@1+ (1,0) [0|0] "lbs" Vector__XXX + +BO_ 197 MCU_LOAD_CELLS: 4 ECU + SG_ load_cell_fr : 16|16@1+ (1,0) [0|0] "lbs" Vector__XXX + SG_ load_cell_fl : 0|16@1+ (1,0) [0|0] "lbs" Vector__XXX + +BO_ 205 MCU_PEDAL_RAW: 8 ECU + SG_ brake_2_raw : 36|12@1+ (1,0) [0|0] "" Vector__XXX + SG_ brake_1_raw : 24|12@1+ (1,0) [0|0] "" Vector__XXX + SG_ accel_2_raw : 12|12@1+ (1,0) [0|0] "" Vector__XXX + SG_ accel_1_raw : 0|12@1+ (1,0) [0|0] "" Vector__XXX + +BO_ 195 MCU_STATUS: 8 ECU + SG_ distance_traveled_m : 48|16@1+ (0.01,0) [0|0] "" Vector__XXX + SG_ torque_mode : 40|8@1+ (1,0) [0|0] "" Vector__XXX + SG_ max_torque : 32|8@1+ (1,0) [0|0] "" Vector__XXX + SG_ drive_mode : 28|4@1+ (1,0) [0|0] "" Vector__XXX + SG_ pack_charge_critical : 24|2@1+ (1,0) [0|0] "" Vector__XXX + SG_ launch_control_active : 23|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ software_ok : 22|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ energy_meter_present : 20|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ inverter_error : 19|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ ecu_state : 16|3@1+ (1,0) [0|0] "" Vector__XXX + SG_ drive_buzzer : 15|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ no_accel_or_brake_implausibility : 14|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ bspd_brake_high : 13|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ bspd_current_high : 12|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ brake_pedal_active : 11|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ no_brake_implausibility : 10|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ no_accel_implausibility : 9|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ mechanical_brake_active : 8|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ shutdown_e_above_threshold : 7|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ software_ok_high : 6|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ shutdown_d_above_threshold : 5|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ bspd_ok_high : 4|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ shutdown_c_above_threshold : 3|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ bms_ok_high : 2|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ shutdown_b_above_threshold : 1|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ imd_ok_high : 0|1@1+ (1,0) [0|0] "" Vector__XXX + +BO_ 200 MCU_SUSPENSION: 8 ECU + SG_ load_cell_fr : 48|16@1+ (1,0) [0|0] "lbs" Vector__XXX + SG_ load_cell_fl : 32|16@1+ (1,0) [0|0] "lbs" Vector__XXX + SG_ potentiometer_fr : 16|16@1+ (1,0) [0|0] "lbs" Vector__XXX + SG_ potentiometer_fl : 0|16@1+ (1,0) [0|0] "lbs" Vector__XXX + +BO_ 192 PEDALS_SYSTEM_DATA: 5 ECU + SG_ brake_pedal : 24|16@1+ (1.5259e-05,0) [0|0] "" Vector__XXX + SG_ accel_pedal : 8|16@1+ (1.5259e-05,0) [0|0] "" Vector__XXX + SG_ implaus_exceeded_max_duration : 6|1@1+ (1,0) [0|1] "" Vector__XXX + SG_ brake_accel_implausibility : 5|1@1+ (1,0) [0|1] "" Vector__XXX + SG_ mechanical_brake_active : 4|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ accel_pedal_active : 3|1@1+ (1,0) [0|1] "" Vector__XXX + SG_ brake_pedal_active : 2|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ brake_implausible : 1|1@1+ (1,0) [0|1] "" Vector__XXX + SG_ accel_implausible : 0|1@1+ (1,0) [0|1] "" Vector__XXX + +BO_ 223 PENTHOUSE_ACCUM_MSG: 8 ECU + SG_ hall_curr_signal : 16|16@1+ (1,0) [0|0] "mV" Vector__XXX + SG_ hall_curr_ref : 0|16@1+ (1,0) [0|0] "mV" Vector__XXX + +BO_ 228 REAR_SUSPENSION: 8 ECU + SG_ rr_shock_pot : 48|16@1+ (1,0) [0|0] "" Vector__XXX + SG_ rl_shock_pot : 32|16@1+ (1,0) [0|0] "" Vector__XXX + SG_ rr_load_cell : 16|16@1+ (1,0) [0|0] "" Vector__XXX + SG_ rl_load_cell : 0|16@1+ (1,0) [0|0] "" Vector__XXX + +BO_ 229 SAB_THERMISTORS_1: 8 ECU + SG_ thermistor_acc2 : 48|16@1+ (0.005,0) [0|0] "deg C" Vector__XXX + SG_ thermistor_acc1 : 32|16@1+ (0.005,0) [0|0] "deg C" Vector__XXX + SG_ thermistor_inv2 : 16|16@1+ (0.005,0) [0|0] "deg C" Vector__XXX + SG_ thermistor_inv1 : 0|16@1+ (0.005,0) [0|0] "deg C" Vector__XXX + +BO_ 230 SAB_THERMISTORS_2: 6 ECU + SG_ thermistor_pump : 32|16@1+ (0.005,0) [0|0] "deg C" Vector__XXX + SG_ thermistor_motor_rr : 16|16@1+ (0.005,0) [0|0] "deg C" Vector__XXX + SG_ thermistor_motor_rl : 0|16@1+ (0.005,0) [0|0] "deg C" Vector__XXX + +BO_ 238 REAR_THERMISTORS_DATA: 8 ECU + SG_ thermistor_3_deg_C : 48|16@1+ (0.005,0) [0|0] "deg C" Vector__XXX + SG_ thermistor_2_deg_C : 32|16@1+ (0.005,0) [0|0] "deg C" Vector__XXX + SG_ thermistor_1_deg_C : 16|16@1+ (0.005,0) [0|0] "deg C" Vector__XXX + SG_ thermistor_0_deg_C : 0|16@1+ (0.005,0) [0|0] "deg C" Vector__XXX + +BO_ 1054 STATE_OF_CHARGE: 8 ECU + SG_ charge_coulombs : 39|32@0+ (0.0001,0) [0|0] "Coulombs" Vector__XXX + SG_ min_cell_voltage_est : 16|16@1+ (0.0001,0) [0|0] "volts" Vector__XXX + SG_ charge_percentage : 7|16@0+ (0.01,0) [0|0] "percent" Vector__XXX + +BO_ 1055 STEERING_DATA: 6 ECU + SG_ steering_digital_raw : 16|32@1+ (1,0) [0|0] "" Vector__XXX + SG_ steering_analog_raw : 0|16@1+ (1,0) [0|0] "" Vector__XXX + +BO_ 3 Settings: 6 ECU + SG_ Velocity_Filtering : 43|3@1+ (1,0) [0|0] "" Vector__XXX + SG_ IMU_Filtering : 40|3@1+ (1,0) [0|0] "" Vector__XXX + SG_ Attitude_Filtering : 37|3@1+ (1,0) [0|0] "" Vector__XXX + SG_ Sensor_Y_Location : 25|12@1- (0.01,0) [0|0] "m" Vector__XXX + SG_ Sensor_X_Location : 13|12@1- (0.01,0) [0|0] "m" Vector__XXX + SG_ Height_Offset : 5|8@1- (0.5,0) [0|0] "cm" Vector__XXX + SG_ CAN_Termination_Setting_Bus_2 : 4|1@1+ (1,0) [0|1] "" Vector__XXX + SG_ CAN_Termination_Setting_Bus_1 : 3|1@1+ (1,0) [0|1] "" Vector__XXX + SG_ Broadcast_rate : 0|3@1+ (1,0) [0|0] "" Vector__XXX + +BO_ 2 State: 5 ECU + SG_ SpeedBeam_Health : 32|3@1+ (1,0) [0|0] "" Vector__XXX + SG_ sensor_3_Validity : 30|2@1+ (1,0) [0|0] "" Vector__XXX + SG_ sensor_2_Validity : 28|2@1+ (1,0) [0|0] "" Vector__XXX + SG_ sensor_1_Validity : 26|2@1+ (1,0) [0|0] "" Vector__XXX + SG_ sensor_0_Validity : 24|2@1+ (1,0) [0|0] "" Vector__XXX + SG_ Firmware_Version : 8|16@1+ (1,0) [0|0] "" Vector__XXX + SG_ Temperature_Internal : 0|8@1- (0.5,20) [0|0] "C" Vector__XXX + +BO_ 1265 TCMUX_STATUS_REPORT: 8 ECU + SG_ torque_limit : 36|16@1+ (0.001,0) [0|0] "" Vector__XXX + SG_ torque_mode : 28|8@1+ (1,0) [0|0] "" Vector__XXX + SG_ dash_dial_mode : 20|8@1+ (1,0) [0|0] "" Vector__XXX + SG_ mode_actual : 12|8@1+ (1,0) [0|0] "" Vector__XXX + SG_ mode_intended : 4|8@1+ (1,0) [0|0] "" Vector__XXX + SG_ steering_system_has_err : 3|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ tc_not_ready : 2|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ torque_delta_above_thresh : 1|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ speed_above_thresh : 0|1@1+ (1,0) [0|0] "" Vector__XXX + +BO_ 148 TCU_DRIVER_MSG: 8 ECU + SG_ target_lap_time : 40|24@1+ (1,0) [0|0] "ms" Vector__XXX + SG_ driver_msg_var_2 : 24|16@1+ (1,0) [0|1] "" Vector__XXX + SG_ driver_msg_var_1 : 8|16@1+ (1,0) [0|1] "" Vector__XXX + SG_ driver_message : 0|8@1+ (1,0) [0|0] "" Vector__XXX + +BO_ 149 TCU_LAP_TIMES: 8 ECU + SG_ lap_clock_state : 48|8@1+ (1,0) [0|0] "" Vector__XXX + SG_ prev_lap_time : 24|24@1+ (1,0) [0|0] "ms" Vector__XXX + SG_ best_lap_time : 0|24@1+ (1,0) [0|0] "ms" Vector__XXX + +BO_ 232 TCU_STATUS: 3 ECU + SG_ tcu_recording_state : 16|2@1+ (1,0) [0|0] "" Vector__XXX + SG_ shutdown_status : 0|16@1+ (1,0) [0|0] "" Vector__XXX + +BO_ 201 TC_SIMPLE: 8 ECU + SG_ accel_request_state : 48|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ rear_regen_scale : 40|8@1- (0.00787402,0) [0|0] "" Vector__XXX + SG_ front_regen_scale : 32|8@1- (0.00787402,0) [0|0] "" Vector__XXX + SG_ rear_torque_scale : 24|8@1- (0.00787402,0) [0|0] "" Vector__XXX + SG_ front_torque_scale : 16|8@1- (0.00787402,0) [0|0] "" Vector__XXX + SG_ torque_request : 0|16@1- (0.001,0) [0|0] "" Vector__XXX + +BO_ 202 TC_SIMPLE_LAUNCH: 8 ECU + SG_ speed_setpoint_rpm : 24|16@1- (1,0) [0|0] "rpm" Vector__XXX + SG_ initial_launch_target : 8|16@1+ (1,0) [0|0] "rpm" Vector__XXX + SG_ algo_active : 2|1@1+ (1,0) [0|0] "" Vector__XXX + SG_ launch_control_state : 0|2@1+ (1,0) [0|0] "" Vector__XXX + +BO_ 2047 VEHM_ALPHA: 8 ECU + SG_ vehm_alpha_deg_rr : 48|16@1- (0.001,0) [0|0] "deg" Vector__XXX + SG_ vehm_alpha_deg_rl : 32|16@1- (0.001,0) [0|0] "deg" Vector__XXX + SG_ vehm_alpha_deg_fr : 16|16@1- (0.001,0) [0|0] "deg" Vector__XXX + SG_ vehm_alpha_deg_fl : 0|16@1- (0.001,0) [0|0] "deg" Vector__XXX + +BO_ 2031 VEHM_BETA: 8 ECU + SG_ vehm_beta_deg : 0|16@1- (0.001,0) [0|0] "deg" Vector__XXX + +BO_ 1995 VEHM_KIN_DES_YAW_RATE_RAD_S_MSG: 8 ECU + SG_ vehm_kin_desired_yaw_rate_rad_s : 0|16@1- (0.0001,0) [0|0] "rad/s" Vector__XXX + +BO_ 1998 VEHM_LONG_CORNER_VEL: 8 ECU + SG_ vehm_long_corner_vel_rr : 48|16@1- (0.01,0) [0|0] "m/s" Vector__XXX + SG_ vehm_long_corner_vel_rl : 32|16@1- (0.01,0) [0|0] "m/s" Vector__XXX + SG_ vehm_long_corner_vel_fr : 16|16@1- (0.01,0) [0|0] "m/s" Vector__XXX + SG_ vehm_long_corner_vel_fl : 0|16@1- (0.01,0) [0|0] "m/s" Vector__XXX + +BO_ 1999 VEHM_SL: 8 ECU + SG_ vehm_sl_rr : 48|16@1- (0.0001,0) [0|0] "" Vector__XXX + SG_ vehm_sl_rl : 32|16@1- (0.0001,0) [0|0] "" Vector__XXX + SG_ vehm_sl_fr : 16|16@1- (0.0001,0) [0|0] "" Vector__XXX + SG_ vehm_sl_fl : 0|16@1- (0.0001,0) [0|0] "" Vector__XXX + +BO_ 1963 VEHM_WHEEL_LIN_VEL: 8 ECU + SG_ vehm_wheel_lin_vel_rr : 48|16@1- (0.01,0) [0|0] "m/s" Vector__XXX + SG_ vehm_wheel_lin_vel_rl : 32|16@1- (0.01,0) [0|0] "m/s" Vector__XXX + SG_ vehm_wheel_lin_vel_fr : 16|16@1- (0.01,0) [0|0] "m/s" Vector__XXX + SG_ vehm_wheel_lin_vel_fl : 0|16@1- (0.01,0) [0|0] "m/s" Vector__XXX + +BO_ 1994 VEHM_WHEEL_STEER_AVG_DEG_MSG: 8 ECU + SG_ vehm_wheel_steer_avg_deg : 0|16@1- (0.001,0) [0|0] "deg" Vector__XXX + +BO_ 227 VN_ANGULAR_RATE: 8 ECU + SG_ angular_rate_z : 32|16@1- (0.001,0) [0|0] "rad/s" Vector__XXX + SG_ angular_rate_y : 16|16@1- (0.001,0) [0|0] "rad/s" Vector__XXX + SG_ angular_rate_x : 0|16@1- (0.001,0) [0|0] "rad/s" Vector__XXX + +BO_ 231 VN_ECEF_POS_XY: 8 ECU + SG_ vn_ecef_pos_y : 32|32@1- (0.005,0) [0|0] "m" Vector__XXX + SG_ vn_ecef_pos_x : 0|32@1- (0.005,0) [0|0] "m" Vector__XXX + +BO_ 233 VN_ECEF_POS_Z_MSG: 8 ECU + SG_ vn_ecef_pos_z : 0|32@1- (0.005,0) [0|0] "m" Vector__XXX + +BO_ 234 VN_GNSS_COMP_SIG_HEALTH: 8 ECU + SG_ num_com_sats_rtk : 56|8@1+ (1,0) [0|0] "" Vector__XXX + SG_ num_com_sats_pvt : 48|8@1+ (1,0) [0|0] "" Vector__XXX + SG_ highest_cn0_2 : 40|8@1+ (0.5,0) [0|0] "dBHz" Vector__XXX + SG_ num_sats_rtk_2 : 32|8@1+ (1,0) [0|0] "" Vector__XXX + SG_ num_sats_pvt_2 : 24|8@1+ (1,0) [0|0] "" Vector__XXX + SG_ highest_cn0_1 : 16|8@1+ (0.5,0) [0|0] "dBHz" Vector__XXX + SG_ num_sats_rtk_1 : 8|8@1+ (1,0) [0|0] "" Vector__XXX + SG_ num_sats_pvt_1 : 0|8@1+ (1,0) [0|0] "" Vector__XXX + +BO_ 224 VN_GPS_TIME_MSG: 8 ECU + SG_ vn_gps_time : 0|64@1+ (1,0) [0|0] "ns" Vector__XXX + +BO_ 212 VN_LAT_LON: 8 ECU + SG_ vn_gps_lon : 32|32@1- (1e-06,0) [0|0] "deg" Vector__XXX + SG_ vn_gps_lat : 0|32@1- (1e-06,0) [0|0] "deg" Vector__XXX + +BO_ 209 VN_LINEAR_ACCEL: 8 ECU + SG_ vn_lin_ins_accel_z : 32|16@1- (0.001,0) [0|0] "m/s^2" Vector__XXX + SG_ vn_lin_ins_accel_y : 16|16@1- (0.001,0) [0|0] "m/s^2" Vector__XXX + SG_ vn_lin_ins_accel_x : 0|16@1- (0.001,0) [0|0] "m/s^2" Vector__XXX + +BO_ 210 VN_LINEAR_ACCEL_UNCOMP: 8 ECU + SG_ vn_lin_uncomp_accel_z : 32|16@1- (0.001,0) [0|0] "m/s^2" Vector__XXX + SG_ vn_lin_uncomp_accel_y : 16|16@1- (0.001,0) [0|0] "m/s^2" Vector__XXX + SG_ vn_lin_uncomp_accel_x : 0|16@1- (0.001,0) [0|0] "m/s^2" Vector__XXX + +BO_ 225 VN_STATUS: 8 ECU + SG_ vn_gps_status : 0|8@1+ (1,0) [0|0] "" Vector__XXX + +BO_ 208 VN_VEL: 8 ECU + SG_ vn_vel_uncertainty : 48|16@1+ (0.0005,0) [0|0] "m/s" Vector__XXX + SG_ vn_body_vel_z : 32|16@1- (0.002,0) [0|0] "m/s" Vector__XXX + SG_ vn_body_vel_y : 16|16@1- (0.002,0) [0|0] "m/s" Vector__XXX + SG_ vn_body_vel_x : 0|16@1- (0.002,0) [0|0] "m/s" Vector__XXX + +BO_ 211 VN_YPR: 8 ECU + SG_ vn_roll : 32|16@1- (0.01,0) [0|0] "deg" Vector__XXX + SG_ vn_pitch : 16|16@1- (0.01,0) [0|0] "deg" Vector__XXX + SG_ vn_yaw : 0|16@1- (0.01,0) [0|0] "deg" Vector__XXX + +BO_ 4 Velocities: 8 ECU + SG_ Velocity_z_CGCorrected : 53|9@1- (0.025,0) [0|0] "m/s" Vector__XXX + SG_ Velocity_y_CGCorrected : 43|10@1- (0.03,0) [0|0] "m/s" Vector__XXX + SG_ Velocity_x_CGCorrected : 31|12@1- (0.02,0) [0|0] "m/s" Vector__XXX + SG_ Velocity_z : 22|9@1- (0.025,0) [0|0] "m/s" Vector__XXX + SG_ Velocity_y : 12|10@1- (0.03,0) [0|0] "m/s" Vector__XXX + SG_ Velocity_x : 0|12@1- (0.02,0) [0|0] "m/s" Vector__XXX + +BO_ 1280 ACU_OK: 1 ECU + SG_ latch_ok : 2|1@1+ (1,0) [0|1] "" Vector__XXX + SG_ imd_ok : 1|1@1+ (1,0) [0|1] "" Vector__XXX + SG_ bms_ok : 0|1@1+ (1,0) [0|1] "" Vector__XXX + +BO_ 553 DRIVEBRAIN_STATE_DATA: 1 ECU + SG_ vn_gps_status : 0|8@1+ (1,0) [0|0] "" Vector__XXX + +BO_ 519 CAR_STATES: 3 ECU + SG_ drivebrain_in_control : 16|1@1+ (1,0) [0|1] "" Vector__XXX + SG_ drivetrain_state : 8|8@1+ (1,0) [0|0] "" Vector__XXX + SG_ vehicle_state : 0|8@1+ (1,0) [0|0] "" Vector__XXX + +BO_ 1220 FL_BRAKE_ROTOR_TEMP_CH1_CH4: 8 ECU + SG_ brake_temp_channel_4 : 55|16@0+ (0.1,-100) [0|0] "deg C" Vector__XXX + SG_ brake_temp_channel_3 : 39|16@0+ (0.1,-100) [0|0] "deg C" Vector__XXX + SG_ brake_temp_channel_2 : 23|16@0+ (0.1,-100) [0|0] "deg C" Vector__XXX + SG_ brake_temp_channel_1 : 7|16@0+ (0.1,-100) [0|0] "deg C" Vector__XXX + +BO_ 1221 FL_BRAKE_ROTOR_TEMP_CH5_CH8: 8 ECU + SG_ brake_temp_channel_8 : 55|16@0+ (0.1,-100) [0|0] "deg C" Vector__XXX + SG_ brake_temp_channel_7 : 39|16@0+ (0.1,-100) [0|0] "deg C" Vector__XXX + SG_ brake_temp_channel_6 : 23|16@0+ (0.1,-100) [0|0] "deg C" Vector__XXX + SG_ brake_temp_channel_5 : 7|16@0+ (0.1,-100) [0|0] "deg C" Vector__XXX + +BO_ 1222 FL_BRAKE_ROTOR_TEMP_CH9_CH12: 8 ECU + SG_ brake_temp_channel_12 : 55|16@0+ (0.1,-100) [0|0] "deg C" Vector__XXX + SG_ brake_temp_channel_11 : 39|16@0+ (0.1,-100) [0|0] "deg C" Vector__XXX + SG_ brake_temp_channel_10 : 23|16@0+ (0.1,-100) [0|0] "deg C" Vector__XXX + SG_ brake_temp_channel_9 : 7|16@0+ (0.1,-100) [0|0] "deg C" Vector__XXX + +BO_ 1224 FL_BRAKE_ROTOR_SENSOR_TEMP: 8 ECU + SG_ brake_rotor_sensor_temp : 7|16@0+ (0.1,-100) [0|0] "deg C" Vector__XXX + +BO_ 1223 FL_BRAKE_ROTOR_TEMP_CH13_CH16: 8 ECU + SG_ brake_temp_channel_16 : 55|16@0+ (0.1,-100) [0|0] "deg C" Vector__XXX + SG_ brake_temp_channel_15 : 39|16@0+ (0.1,-100) [0|0] "deg C" Vector__XXX + SG_ brake_temp_channel_14 : 23|16@0+ (0.1,-100) [0|0] "deg C" Vector__XXX + SG_ brake_temp_channel_13 : 7|16@0+ (0.1,-100) [0|0] "deg C" Vector__XXX + +BO_ 1225 FR_BRAKE_ROTOR_TEMP_CH1_CH4: 8 ECU + SG_ brake_temp_channel_4 : 55|16@0+ (0.1,-100) [0|0] "deg C" Vector__XXX + SG_ brake_temp_channel_3 : 39|16@0+ (0.1,-100) [0|0] "deg C" Vector__XXX + SG_ brake_temp_channel_2 : 23|16@0+ (0.1,-100) [0|0] "deg C" Vector__XXX + SG_ brake_temp_channel_1 : 7|16@0+ (0.1,-100) [0|0] "deg C" Vector__XXX + +BO_ 1226 FR_BRAKE_ROTOR_TEMP_CH5_CH8: 8 ECU + SG_ brake_temp_channel_8 : 55|16@0+ (0.1,-100) [0|0] "deg C" Vector__XXX + SG_ brake_temp_channel_7 : 39|16@0+ (0.1,-100) [0|0] "deg C" Vector__XXX + SG_ brake_temp_channel_6 : 23|16@0+ (0.1,-100) [0|0] "deg C" Vector__XXX + SG_ brake_temp_channel_5 : 7|16@0+ (0.1,-100) [0|0] "deg C" Vector__XXX + +BO_ 1227 FR_BRAKE_ROTOR_TEMP_CH9_CH12: 8 ECU + SG_ brake_temp_channel_12 : 55|16@0+ (0.1,-100) [0|0] "deg C" Vector__XXX + SG_ brake_temp_channel_11 : 39|16@0+ (0.1,-100) [0|0] "deg C" Vector__XXX + SG_ brake_temp_channel_10 : 23|16@0+ (0.1,-100) [0|0] "deg C" Vector__XXX + SG_ brake_temp_channel_9 : 7|16@0+ (0.1,-100) [0|0] "deg C" Vector__XXX + +BO_ 1229 FR_BRAKE_ROTOR_SENSOR_TEMP: 8 ECU + SG_ brake_rotor_sensor_temp : 7|16@0+ (0.1,-100) [0|0] "deg C" Vector__XXX + +BO_ 1228 FR_BRAKE_ROTOR_TEMP_CH13_CH16: 8 ECU + SG_ brake_temp_channel_16 : 55|16@0+ (0.1,-100) [0|0] "deg C" Vector__XXX + SG_ brake_temp_channel_15 : 39|16@0+ (0.1,-100) [0|0] "deg C" Vector__XXX + SG_ brake_temp_channel_14 : 23|16@0+ (0.1,-100) [0|0] "deg C" Vector__XXX + SG_ brake_temp_channel_13 : 7|16@0+ (0.1,-100) [0|0] "deg C" Vector__XXX + +BO_ 1219 BRAKE_ROTOR_SENSOR_COMMAND: 8 ECU + SG_ brake_temp_sensor_can_bitrate : 63|8@0+ (1,0) [0|0] "" Vector__XXX + SG_ brake_temp_sensor_ch_setting : 55|8@0+ (1,0) [0|0] "" Vector__XXX + SG_ brake_temp_sensor_sampling_freq : 47|8@0+ (1,0) [0|0] "" Vector__XXX + SG_ brake_temp_sensor_emissivity : 39|8@0+ (0.01,0) [0|0] "" Vector__XXX + SG_ brake_temp_sensor_base_can_id : 23|16@0+ (1,0) [1|2047] "" Vector__XXX + SG_ brake_temp_sensor_prog_const : 7|16@0+ (1,0) [30000|30000] "" Vector__XXX + +BO_ 1008 AERO_PRESSURE_SENSOR_11: 8 ECU + SG_ aero_channel_3 : 55|16@0+ (0.14285714285,-53000) [0|0] "uBar" Vector__XXX + SG_ aero_channel_2 : 39|16@0+ (0.14285714285,-53000) [0|0] "uBar" Vector__XXX + SG_ aero_channel_1 : 23|16@0+ (0.14285714285,-53000) [0|0] "uBar" Vector__XXX + SG_ aero_channel_0 : 7|16@0+ (0.14285714285,-53000) [0|0] "uBar" Vector__XXX + +BO_ 1584 AERO_PRESSURE_SENSOR_31: 8 ECU + SG_ aero_channel_3 : 55|16@0+ (0.14285714285,-53000) [0|0] "uBar" Vector__XXX + SG_ aero_channel_2 : 39|16@0+ (0.14285714285,-53000) [0|0] "uBar" Vector__XXX + SG_ aero_channel_1 : 23|16@0+ (0.14285714285,-53000) [0|0] "uBar" Vector__XXX + SG_ aero_channel_0 : 7|16@0+ (0.14285714285,-53000) [0|0] "uBar" Vector__XXX + +BO_ 1600 AERO_PRESSURE_SENSOR_41: 8 ECU + SG_ aero_channel_3 : 55|16@0+ (0.14285714285,-53000) [0|0] "uBar" Vector__XXX + SG_ aero_channel_2 : 39|16@0+ (0.14285714285,-53000) [0|0] "uBar" Vector__XXX + SG_ aero_channel_1 : 23|16@0+ (0.14285714285,-53000) [0|0] "uBar" Vector__XXX + SG_ aero_channel_0 : 7|16@0+ (0.14285714285,-53000) [0|0] "uBar" Vector__XXX + +BO_ 1568 AERO_PRESSURE_SENSOR_21: 8 ECU + SG_ aero_channel_3 : 55|16@0+ (0.14285714285,-53000) [0|0] "uBar" Vector__XXX + SG_ aero_channel_2 : 39|16@0+ (0.14285714285,-53000) [0|0] "uBar" Vector__XXX + SG_ aero_channel_1 : 23|16@0+ (0.14285714285,-53000) [0|0] "uBar" Vector__XXX + SG_ aero_channel_0 : 7|16@0+ (0.14285714285,-53000) [0|0] "uBar" Vector__XXX + +BO_ 1012 AERO_PRESSURE_SENSOR_12: 8 ECU + SG_ aero_channel_7 : 55|16@0+ (0.14285714285,-53000) [0|0] "uBar" Vector__XXX + SG_ aero_channel_6 : 39|16@0+ (0.14285714285,-53000) [0|0] "uBar" Vector__XXX + SG_ aero_channel_5 : 23|16@0+ (0.14285714285,-53000) [0|0] "uBar" Vector__XXX + SG_ aero_channel_4 : 7|16@0+ (0.14285714285,-53000) [0|0] "uBar" Vector__XXX + +BO_ 800 AERO_PRESSURE_SENSOR_22: 8 ECU + SG_ aero_channel_7 : 55|16@0+ (0.14285714285,-53000) [0|0] "uBar" Vector__XXX + SG_ aero_channel_6 : 39|16@0+ (0.14285714285,-53000) [0|0] "uBar" Vector__XXX + SG_ aero_channel_5 : 23|16@0+ (0.14285714285,-53000) [0|0] "uBar" Vector__XXX + SG_ aero_channel_4 : 7|16@0+ (0.14285714285,-53000) [0|0] "uBar" Vector__XXX + +BO_ 816 AERO_PRESSURE_SENSOR_32: 8 ECU + SG_ aero_channel_7 : 55|16@0+ (0.14285714285,-53000) [0|0] "uBar" Vector__XXX + SG_ aero_channel_6 : 39|16@0+ (0.14285714285,-53000) [0|0] "uBar" Vector__XXX + SG_ aero_channel_5 : 23|16@0+ (0.14285714285,-53000) [0|0] "uBar" Vector__XXX + SG_ aero_channel_4 : 7|16@0+ (0.14285714285,-53000) [0|0] "uBar" Vector__XXX + +BO_ 832 AERO_PRESSURE_SENSOR_42: 8 ECU + SG_ aero_channel_7 : 55|16@0+ (0.14285714285,-53000) [0|0] "uBar" Vector__XXX + SG_ aero_channel_6 : 39|16@0+ (0.14285714285,-53000) [0|0] "uBar" Vector__XXX + SG_ aero_channel_5 : 23|16@0+ (0.14285714285,-53000) [0|0] "uBar" Vector__XXX + SG_ aero_channel_4 : 7|16@0+ (0.14285714285,-53000) [0|0] "uBar" Vector__XXX + +BO_ 310 INV1_OVERLOAD: 8 ECU + SG_ motor_overload_percentage : 16|16@1+ (0.1,0) [0|0] "" Vector__XXX + SG_ inverter_overload_percentage : 0|16@1+ (0.1,0) [0|0] "" Vector__XXX + +BO_ 320 INV2_OVERLOAD: 4 ECU + SG_ motor_overload_percentage : 16|16@1+ (0.1,0) [0|0] "" Vector__XXX + SG_ inverter_overload_percentage : 0|16@1+ (0.1,0) [0|0] "" Vector__XXX + +BO_ 330 INV3_OVERLOAD: 4 ECU + SG_ motor_overload_percentage : 16|16@1+ (0.1,0) [0|0] "" Vector__XXX + SG_ inverter_overload_percentage : 0|16@1+ (0.1,0) [0|0] "" Vector__XXX + +BO_ 340 INV4_OVERLOAD: 4 ECU + SG_ motor_overload_percentage : 16|16@1+ (0.1,0) [0|0] "" Vector__XXX + SG_ inverter_overload_percentage : 0|16@1+ (0.1,0) [0|0] "" Vector__XXX + +BO_ 269 ENERGY_METER_MEAS: 8 ECU + SG_ voltage_V : 39|32@0+ (1,0) [0|0] "" Vector__XXX + SG_ current_A : 7|32@0+ (1,0) [0|0] "" Vector__XXX + +BO_ 1037 ENERGY_METER_STATUS: 8 ECU + SG_ em_energy_w_hr : 15|32@0+ (1,0) [0|0] "" Vector__XXX + SG_ em_logging : 1|1@1+ (1,0) [0|1] "" Vector__XXX + SG_ em_violation : 0|1@1+ (1,0) [0|1] "" Vector__XXX + +BO_ 1549 ENERGY_METER_TEMP: 8 ECU + SG_ em_temp_4 : 63|8@0+ (0.5,0) [0|0] "" Vector__XXX + SG_ em_temp_3 : 55|8@0+ (0.5,0) [0|0] "" Vector__XXX + SG_ em_temp_2 : 47|8@0+ (0.5,0) [0|0] "" Vector__XXX + SG_ em_temp_1 : 39|8@0+ (0.5,0) [0|0] "" Vector__XXX + SG_ em_temp_0 : 31|8@0+ (0.5,0) [0|0] "" Vector__XXX + SG_ em_max_temp : 23|8@0+ (0.5,0) [0|0] "" Vector__XXX + SG_ em_min_temp : 15|8@0+ (0.5,0) [0|0] "" Vector__XXX + SG_ em_temp_sig_index : 2|3@0+ (1,0) [0|1] "" Vector__XXX + SG_ em_num_sensors : 7|5@0+ (1,0) [0|0] "" Vector__XXX + +BO_ 1281 DRIVEBRAIN_LATENCY_TIMES: 8 ECU + SG_ aux_latency_millis : 32|32@1+ (1,0) [0|0] "" Vector__XXX + SG_ telem_latency_millis : 0|32@1+ (1,0) [0|0] "" Vector__XXX + +BO_ 1282 DRIVEBRAIN_LATENCY_STATUSES: 8 ECU + SG_ db_aux_timing_fault : 1|1@1+ (1,0) [0|1] "" Vector__XXX + SG_ db_telem_timing_fault : 0|1@1+ (1,0) [0|1] "" Vector__XXX + +BO_ 103 ADC_VOLTAGES_HV_1: 8 ECU + SG_ precharge_voltage : 0|32@1+ (1,0) [0|0] "" Vector__XXX + +BO_ 104 ADC_VOLTAGES_HV_2: 8 ECU + SG_ ts_out_voltage : 32|32@1+ (1,0) [0|0] "" Vector__XXX + SG_ pack_out_voltage : 0|32@1+ (1,0) [0|0] "" Vector__XXX + +BO_ 105 ADC_VOLTAGES_LV: 8 ECU + SG_ shdn_out_voltage : 32|32@1+ (1,0) [0|0] "" Vector__XXX + SG_ glv_voltage : 0|32@1+ (1,0) [0|0] "" Vector__XXX + +BO_ 1283 FLOWMETER_DATA: 8 ECU + SG_ flow_rate : 0|32@1+ (1,0) [0|0] "" Vector__XXX + +BO_TX_BU_ 1025 : ECU,Peripherals; +BO_TX_BU_ 5 : ECU,Peripherals; +BO_TX_BU_ 226 : ECU,Peripherals; +BO_TX_BU_ 218 : ECU,Peripherals; +BO_TX_BU_ 216 : ECU,Peripherals; +BO_TX_BU_ 214 : ECU,Peripherals; +BO_TX_BU_ 213 : ECU,Peripherals; +BO_TX_BU_ 219 : ECU,Peripherals; +BO_TX_BU_ 217 : ECU,Peripherals; +BO_TX_BU_ 215 : ECU,Peripherals; +BO_TX_BU_ 203 : ECU,Peripherals; +BO_TX_BU_ 221 : ECU,Peripherals; +BO_TX_BU_ 2550588916 : ECU,Peripherals; +BO_TX_BU_ 2566869221 : ECU,Peripherals; +BO_TX_BU_ 2028 : ECU,Peripherals; +BO_TX_BU_ 2011 : ECU,Peripherals; +BO_TX_BU_ 2012 : ECU,Peripherals; +BO_TX_BU_ 1263 : ECU,Peripherals; +BO_TX_BU_ 1264 : ECU,Peripherals; +BO_TX_BU_ 1997 : ECU,Peripherals; +BO_TX_BU_ 2010 : ECU,Peripherals; +BO_TX_BU_ 2014 : ECU,Peripherals; +BO_TX_BU_ 2026 : ECU,Peripherals; +BO_TX_BU_ 2027 : ECU,Peripherals; +BO_TX_BU_ 1966 : ECU,Peripherals; +BO_TX_BU_ 1965 : ECU,Peripherals; +BO_TX_BU_ 2043 : ECU,Peripherals; +BO_TX_BU_ 1980 : ECU,Peripherals; +BO_TX_BU_ 1981 : ECU,Peripherals; +BO_TX_BU_ 1996 : ECU,Peripherals; +BO_TX_BU_ 1967 : ECU,Peripherals; +BO_TX_BU_ 2046 : ECU,Peripherals; +BO_TX_BU_ 1962 : ECU,Peripherals; +BO_TX_BU_ 1982 : ECU,Peripherals; +BO_TX_BU_ 1979 : ECU,Peripherals; +BO_TX_BU_ 1983 : ECU,Peripherals; +BO_TX_BU_ 2045 : ECU,Peripherals; +BO_TX_BU_ 2044 : ECU,Peripherals; +BO_TX_BU_ 1964 : ECU,Peripherals; +BO_TX_BU_ 2042 : ECU,Peripherals; +BO_TX_BU_ 1978 : ECU,Peripherals; +BO_TX_BU_ 6 : ECU,Peripherals; +BO_TX_BU_ 2033 : ECU,Peripherals; +BO_TX_BU_ 235 : ECU,Peripherals; +BO_TX_BU_ 236 : ECU,Peripherals; +BO_TX_BU_ 768 : ECU,Peripherals; +BO_TX_BU_ 243 : ECU,Peripherals; +BO_TX_BU_ 242 : ECU,Peripherals; +BO_TX_BU_ 241 : ECU,Peripherals; +BO_TX_BU_ 303 : ECU,Peripherals; +BO_TX_BU_ 513 : ECU,Peripherals; +BO_TX_BU_ 516 : ECU,Peripherals; +BO_TX_BU_ 512 : ECU,Peripherals; +BO_TX_BU_ 514 : ECU,Peripherals; +BO_TX_BU_ 515 : ECU,Peripherals; +BO_TX_BU_ 256 : ECU,Peripherals; +BO_TX_BU_ 1024 : ECU,Peripherals; +BO_TX_BU_ 237 : ECU,Peripherals; +BO_TX_BU_ 245 : ECU,Peripherals; +BO_TX_BU_ 1 : ECU,Peripherals; +BO_TX_BU_ 151 : ECU,Peripherals; +BO_TX_BU_ 259 : ECU,Peripherals; +BO_TX_BU_ 144 : ECU,Peripherals; +BO_TX_BU_ 114 : ECU,Peripherals; +BO_TX_BU_ 116 : ECU,Peripherals; +BO_TX_BU_ 115 : ECU,Peripherals; +BO_TX_BU_ 112 : ECU,Peripherals; +BO_TX_BU_ 113 : ECU,Peripherals; +BO_TX_BU_ 152 : ECU,Peripherals; +BO_TX_BU_ 260 : ECU,Peripherals; +BO_TX_BU_ 145 : ECU,Peripherals; +BO_TX_BU_ 119 : ECU,Peripherals; +BO_TX_BU_ 121 : ECU,Peripherals; +BO_TX_BU_ 120 : ECU,Peripherals; +BO_TX_BU_ 117 : ECU,Peripherals; +BO_TX_BU_ 118 : ECU,Peripherals; +BO_TX_BU_ 153 : ECU,Peripherals; +BO_TX_BU_ 261 : ECU,Peripherals; +BO_TX_BU_ 146 : ECU,Peripherals; +BO_TX_BU_ 130 : ECU,Peripherals; +BO_TX_BU_ 132 : ECU,Peripherals; +BO_TX_BU_ 131 : ECU,Peripherals; +BO_TX_BU_ 128 : ECU,Peripherals; +BO_TX_BU_ 129 : ECU,Peripherals; +BO_TX_BU_ 258 : ECU,Peripherals; +BO_TX_BU_ 262 : ECU,Peripherals; +BO_TX_BU_ 147 : ECU,Peripherals; +BO_TX_BU_ 135 : ECU,Peripherals; +BO_TX_BU_ 137 : ECU,Peripherals; +BO_TX_BU_ 136 : ECU,Peripherals; +BO_TX_BU_ 133 : ECU,Peripherals; +BO_TX_BU_ 134 : ECU,Peripherals; +BO_TX_BU_ 1060 : ECU,Peripherals; +BO_TX_BU_ 1061 : ECU,Peripherals; +BO_TX_BU_ 1062 : ECU,Peripherals; +BO_TX_BU_ 1063 : ECU,Peripherals; +BO_TX_BU_ 1064 : ECU,Peripherals; +BO_TX_BU_ 1065 : ECU,Peripherals; +BO_TX_BU_ 1066 : ECU,Peripherals; +BO_TX_BU_ 1067 : ECU,Peripherals; +BO_TX_BU_ 1068 : ECU,Peripherals; +BO_TX_BU_ 1069 : ECU,Peripherals; +BO_TX_BU_ 1070 : ECU,Peripherals; +BO_TX_BU_ 1071 : ECU,Peripherals; +BO_TX_BU_ 1072 : ECU,Peripherals; +BO_TX_BU_ 1073 : ECU,Peripherals; +BO_TX_BU_ 1074 : ECU,Peripherals; +BO_TX_BU_ 1075 : ECU,Peripherals; +BO_TX_BU_ 1076 : ECU,Peripherals; +BO_TX_BU_ 1077 : ECU,Peripherals; +BO_TX_BU_ 1078 : ECU,Peripherals; +BO_TX_BU_ 1079 : ECU,Peripherals; +BO_TX_BU_ 1080 : ECU,Peripherals; +BO_TX_BU_ 1081 : ECU,Peripherals; +BO_TX_BU_ 1082 : ECU,Peripherals; +BO_TX_BU_ 1083 : ECU,Peripherals; +BO_TX_BU_ 184 : ECU,Peripherals; +BO_TX_BU_ 204 : ECU,Peripherals; +BO_TX_BU_ 257 : ECU,Peripherals; +BO_TX_BU_ 198 : ECU,Peripherals; +BO_TX_BU_ 197 : ECU,Peripherals; +BO_TX_BU_ 205 : ECU,Peripherals; +BO_TX_BU_ 195 : ECU,Peripherals; +BO_TX_BU_ 200 : ECU,Peripherals; +BO_TX_BU_ 192 : ECU,Peripherals; +BO_TX_BU_ 223 : ECU,Peripherals; +BO_TX_BU_ 228 : ECU,Peripherals; +BO_TX_BU_ 229 : ECU,Peripherals; +BO_TX_BU_ 230 : ECU,Peripherals; +BO_TX_BU_ 238 : ECU,Peripherals; +BO_TX_BU_ 1054 : ECU,Peripherals; +BO_TX_BU_ 1055 : ECU,Peripherals; +BO_TX_BU_ 3 : ECU,Peripherals; +BO_TX_BU_ 2 : ECU,Peripherals; +BO_TX_BU_ 1265 : ECU,Peripherals; +BO_TX_BU_ 148 : ECU,Peripherals; +BO_TX_BU_ 149 : ECU,Peripherals; +BO_TX_BU_ 232 : ECU,Peripherals; +BO_TX_BU_ 201 : ECU,Peripherals; +BO_TX_BU_ 202 : ECU,Peripherals; +BO_TX_BU_ 2047 : ECU,Peripherals; +BO_TX_BU_ 2031 : ECU,Peripherals; +BO_TX_BU_ 1995 : ECU,Peripherals; +BO_TX_BU_ 1998 : ECU,Peripherals; +BO_TX_BU_ 1999 : ECU,Peripherals; +BO_TX_BU_ 1963 : ECU,Peripherals; +BO_TX_BU_ 1994 : ECU,Peripherals; +BO_TX_BU_ 227 : ECU,Peripherals; +BO_TX_BU_ 231 : ECU,Peripherals; +BO_TX_BU_ 233 : ECU,Peripherals; +BO_TX_BU_ 234 : ECU,Peripherals; +BO_TX_BU_ 224 : ECU,Peripherals; +BO_TX_BU_ 212 : ECU,Peripherals; +BO_TX_BU_ 209 : ECU,Peripherals; +BO_TX_BU_ 210 : ECU,Peripherals; +BO_TX_BU_ 225 : ECU,Peripherals; +BO_TX_BU_ 208 : ECU,Peripherals; +BO_TX_BU_ 211 : ECU,Peripherals; +BO_TX_BU_ 4 : ECU,Peripherals; +BO_TX_BU_ 1280 : ECU,Peripherals; +BO_TX_BU_ 553 : ECU,Peripherals; +BO_TX_BU_ 519 : ECU,Peripherals; +BO_TX_BU_ 1220 : ECU,Peripherals; +BO_TX_BU_ 1221 : ECU,Peripherals; +BO_TX_BU_ 1222 : ECU,Peripherals; +BO_TX_BU_ 1224 : ECU,Peripherals; +BO_TX_BU_ 1223 : ECU,Peripherals; +BO_TX_BU_ 1225 : ECU,Peripherals; +BO_TX_BU_ 1226 : ECU,Peripherals; +BO_TX_BU_ 1227 : ECU,Peripherals; +BO_TX_BU_ 1229 : ECU,Peripherals; +BO_TX_BU_ 1228 : ECU,Peripherals; +BO_TX_BU_ 1219 : ECU,Peripherals; +BO_TX_BU_ 1008 : ECU,Peripherals; +BO_TX_BU_ 1584 : ECU,Peripherals; +BO_TX_BU_ 1600 : ECU,Peripherals; +BO_TX_BU_ 1568 : ECU,Peripherals; +BO_TX_BU_ 1012 : ECU,Peripherals; +BO_TX_BU_ 800 : ECU,Peripherals; +BO_TX_BU_ 816 : ECU,Peripherals; +BO_TX_BU_ 832 : ECU,Peripherals; +BO_TX_BU_ 310 : ECU,Peripherals; +BO_TX_BU_ 320 : ECU,Peripherals; +BO_TX_BU_ 330 : ECU,Peripherals; +BO_TX_BU_ 340 : ECU,Peripherals; +BO_TX_BU_ 269 : ECU,Peripherals; +BO_TX_BU_ 1037 : ECU,Peripherals; +BO_TX_BU_ 1549 : ECU,Peripherals; +BO_TX_BU_ 1281 : ECU,Peripherals; +BO_TX_BU_ 1282 : ECU,Peripherals; +BO_TX_BU_ 103 : ECU,Peripherals; +BO_TX_BU_ 104 : ECU,Peripherals; +BO_TX_BU_ 105 : ECU,Peripherals; +BO_TX_BU_ 1283 : ECU,Peripherals; + + +CM_ SG_ 1025 ts_out_filtered_read "Voltage across tractive system"; +CM_ SG_ 1025 pack_filtered_read "Filtered pack voltage"; +CM_ SG_ 1025 current_shunt_read "The shunt in penthouse; Measures current that goes through the whole tractive system -- used for coulumb counting"; +CM_ SG_ 5 Roll_angle "Sign convention in ISO Standard"; +CM_ SG_ 5 Pitch_angle "Sign convention in ISO Standard"; +CM_ SG_ 5 Height "Height after adjusting for height offset"; +CM_ BO_ 226 "UNUSED message to send data on the BMS current draw."; +CM_ SG_ 226 total_discharge "UNUSED SIGNAL. See legacy AMS firmware (code-2024) for usage."; +CM_ SG_ 226 total_charge "UNUSED SIGNAL. See legacy AMS firmware (code-2024) for usage."; +CM_ SG_ 2550588916 max_charging_current_low "Unused for any PCAN stuff only for Elcon Charger"; +CM_ SG_ 2550588916 max_charging_current_high "Unused for any PCAN stuff only for Elcon Charger"; +CM_ SG_ 2550588916 max_charging_voltage_low "Unused for any PCAN stuff only for Elcon Charger"; +CM_ SG_ 2550588916 max_charging_voltage_high "Unused for any PCAN stuff only for Elcon Charger"; +CM_ SG_ 6 Sensor_X_Location "This is the X position of the center of the sensor, with ISO signedness (positive is forward, negative is rearward) This is used to generate the CG_Corrected velocities"; +CM_ SG_ 6 Sensor_Y_Location "This is the Y position of the center of the sensor, with ISO signedness (positive is left (driver side in US) negative is right (passenger) This is used to generate the CG_Corrected velocities"; +CM_ SG_ 6 Height_Offset "This value will be SUBTRACTED from the height. So if you mount the sensor at 40cm, and you want that to read as 20cm, set this value to 20cm"; +CM_ SG_ 235 pack_charge_led "pack charge led has a value from 0 to 255 representing a percentage that can be displayed on dashboard as a gradient between two colors"; +CM_ SG_ 235 glv_led "glv led has a value from 0 to 255 representing a percentage that can be displayed on dashboard as a gradient between two colors"; +CM_ SG_ 236 tcu_recording_state "The current state of TCU data recording (off, requested,on,saving)"; +CM_ SG_ 768 dash_dial_mode "Dashboard dial position"; +CM_ BO_ 256 "Contains the voltage and current readings from the Energy Meter. Sent by the AMS."; +CM_ SG_ 256 em_voltage "The voltage, in Volts, measured by the Energy Meter."; +CM_ SG_ 256 em_current "The current draw, in amps, measured by the Energy Meter."; +CM_ BO_ 1024 "Forwarded directly from the Energy Meter with no modifications. See datasheet for more specifications."; +CM_ SG_ 1024 logging "Whether or not the energy meter is currently logging data."; +CM_ SG_ 1024 overpower_error "Whether or not the Energy Meter is reading an over-power error."; +CM_ SG_ 1024 overvoltage_error "Whether or not the energy meter is reading an over-voltage error."; +CM_ SG_ 1024 current_gain "This selects the \"gain\" mode for the EM current measurements. The specific multipliers for each gain mode are configured with the EMD Tool."; +CM_ SG_ 1024 voltage_gain "This selects the \"gain\" mode for the EM voltage measurements. The specific multipliers for each gain mode are configured with the EMD Tool."; +CM_ SG_ 245 thermistor_motor_fr "Motor cooling loop temperature"; +CM_ SG_ 245 thermistor_motor_fl "Motor cooling loop temperature"; +CM_ SG_ 1 Pitch_Rate "Sign convention in ISO Standard"; +CM_ SG_ 1 Roll_Rate "Sign convention in ISO Standard"; +CM_ SG_ 1 Accel_Z "Follows ISO Standard Sign Convention"; +CM_ SG_ 1 Accel_Y "Follows ISO Standard Sign Convention"; +CM_ SG_ 1 Accel_X "Follows ISO Standard Sign Convention"; +CM_ SG_ 151 negative_torque_limit "AMK made up unit"; +CM_ SG_ 151 positive_torque_limit "Made up units from AMK"; +CM_ SG_ 152 negative_torque_limit "AMK made up unit"; +CM_ SG_ 152 positive_torque_limit "Made up units from AMK"; +CM_ SG_ 153 negative_torque_limit "AMK made up unit"; +CM_ SG_ 153 positive_torque_limit "Made up units from AMK"; +CM_ SG_ 258 negative_torque_limit "AMK made up unit"; +CM_ SG_ 258 positive_torque_limit "Made up units from AMK"; +CM_ SG_ 1072 LR_TTPMS_SN "Serial Number"; +CM_ SG_ 184 feedback_torque "random made up AMK units"; +CM_ SG_ 184 motor_power "Made up units from AMK"; +CM_ BO_ 257 "this message will have states internal to the MCU code"; +CM_ SG_ 195 torque_mode "torque mode"; +CM_ SG_ 195 drive_mode "The current drive mode on the ECU irrespective of dial mapping"; +CM_ SG_ 192 brake_pedal "the scaled brake pedal value between 0 and 1"; +CM_ SG_ 192 accel_pedal "the scaled accelerator pedal value"; +CM_ SG_ 192 implaus_exceeded_max_duration "a pedal implausibility has been present for longer than allowed"; +CM_ SG_ 192 brake_accel_implausibility "brake and accel are pressed"; +CM_ SG_ 229 thermistor_acc2 "acculum cooling loop temp"; +CM_ SG_ 229 thermistor_acc1 "acculum cooling loop temp"; +CM_ SG_ 229 thermistor_inv2 "invertor cooling loop tmep"; +CM_ SG_ 229 thermistor_inv1 "inverter cooling loop temp"; +CM_ SG_ 230 thermistor_pump "temp of the pump"; +CM_ SG_ 230 thermistor_motor_rr "Motor cooling loop temperature"; +CM_ SG_ 230 thermistor_motor_rl "Motor cooling loop temperature"; +CM_ SG_ 1054 charge_coulombs "The charge in the accumulator, in Coulombs"; +CM_ SG_ 1054 min_cell_voltage_est "Lowest-cell-voltage estimate based on the state of charge, according to VOLTAGE_LOOKUP_TABLE. Ex: 87% SoC would display 3.798V."; +CM_ SG_ 1054 charge_percentage "The charge in the accumulator, as a percentage."; +CM_ BO_ 1055 "Steering reading; system and sensor status"; +CM_ SG_ 1055 steering_digital_raw "raw measurement by digital steering encoder"; +CM_ SG_ 1055 steering_analog_raw "raw measurement as measured by bottom steering analog sensor"; +CM_ SG_ 3 Sensor_Y_Location "This is the Y position of the center of the sensor, with ISO signedness (positive is left (driver side in US) negative is right (passenger) This is used to generate the CG_Corrected velocities"; +CM_ SG_ 3 Sensor_X_Location "This is the X position of the center of the sensor, with ISO signedness (positive is forward, negative is rearward) This is used to generate the CG_Corrected velocities"; +CM_ SG_ 3 Height_Offset "This value will be SUBTRACTED from the height. So if you mount the sensor at 40cm, and you want that to read as 20cm, set this value to 20cm"; +CM_ SG_ 2 Temperature_Internal "Measurement of the internal air temperature of the SpeedBeam sensor"; +CM_ SG_ 1265 torque_limit "AMK inverter torque limit in use"; +CM_ SG_ 1265 torque_mode "torque mode"; +CM_ SG_ 1265 dash_dial_mode "Dashboard dial position"; +CM_ SG_ 1265 mode_actual "actual mode in tcmux"; +CM_ SG_ 1265 mode_intended "TC mode selected by driver"; +CM_ SG_ 1265 steering_system_has_err "Steering system data in ERROR state"; +CM_ SG_ 1265 tc_not_ready "Selected TC not in ready state"; +CM_ SG_ 1265 torque_delta_above_thresh "Torque delta between old and new controllers is < 0.5Nm on every wheel"; +CM_ SG_ 1265 speed_above_thresh "Vehicle speed is above 5 m/s, TCMux does not allow driver to switch mode"; +CM_ BO_ 148 "TCU_DRIVER_MSG contains a signal that corresponds to a preset list of messages on the dashboard. It also includes two variables to customize the contents of the message with numerical values. It also includes the target lap time which is determined by the"; +CM_ SG_ 148 target_lap_time "target lap time is the time determined by the pit crew that the driver should aim for. mostly useful for guiding the driver in endurance races."; +CM_ SG_ 148 driver_message "corresponds to a pre-set list of driver messages on the dashboard that the TCU can request to be displayed in event of comms failure"; +CM_ BO_ 149 "The TCU_LAP_TIMES message contains the best and previous lap times to the dashboard as calculated by the TCU or manually input by the pit crew. It also relays the current state of the TCU's clock to the dashboard so that it can run an approximate stopwatc"; +CM_ SG_ 232 tcu_recording_state "The current state of TCU data recording (off, requested,on,saving)"; +CM_ BO_ 201 "MCU's simple torque controller"; +CM_ SG_ 201 accel_request_state "The current state of the acceleration request (0 = decelerating, 1 = accelerating)"; +CM_ SG_ 201 rear_regen_scale "the front/rear torque scaling"; +CM_ SG_ 201 front_regen_scale "the front/rear torque scaling"; +CM_ SG_ 201 rear_torque_scale "the front/rear torque scaling"; +CM_ SG_ 201 front_torque_scale "the front/rear torque scaling"; +CM_ SG_ 201 torque_request "The torque request calculated from the accelleration request and the maximum torque"; +CM_ SG_ 202 initial_launch_target "The initial launch speed target requested by the launch controller"; +CM_ SG_ 202 algo_active "State of whether the launch algorithm has taken over control from the initial launch target"; +CM_ SG_ 202 launch_control_state "The current state of the launch controller (LAUNCH_NOT_READY, LAUNCH_READY, LAUNCHING)"; +CM_ SG_ 231 vn_ecef_pos_y "earth centered earth fixed"; +CM_ SG_ 231 vn_ecef_pos_x "earth centered earth fixed"; +CM_ SG_ 233 vn_ecef_pos_z "earth centered earth fixed"; +CM_ SG_ 234 num_com_sats_rtk "num of common satelites that are used in the RTK solution on both receivers"; +CM_ SG_ 234 num_com_sats_pvt "num of common satelites that are used in the PVT solution on both receivers"; +CM_ SG_ 234 highest_cn0_2 "Highest CN0 reported on receiver B"; +CM_ SG_ 234 num_sats_rtk_2 "num of common satelites that are used in the RTK solution on receiver B"; +CM_ SG_ 234 num_sats_pvt_2 "num of common satelites that are used in the PVT solution on receiver B"; +CM_ SG_ 234 highest_cn0_1 "Highest CN0 reported on receiver A"; +CM_ SG_ 234 num_sats_rtk_1 "num of common satelites that are used in the RTK solution on receiver A"; +CM_ SG_ 234 num_sats_pvt_1 "num of common satelites that are used in the PVT solution on receiver A"; +CM_ SG_ 224 vn_gps_time "time since start of epoch 1980"; +CM_ SG_ 209 vn_lin_ins_accel_z "estimated acceleration of INS"; +CM_ SG_ 209 vn_lin_ins_accel_y "estimated acceleration of INS"; +CM_ SG_ 209 vn_lin_ins_accel_x "estimated acceleration of INS"; +CM_ SG_ 210 vn_lin_uncomp_accel_z "IMU acceleration"; +CM_ SG_ 210 vn_lin_uncomp_accel_y "IMU acceleration"; +CM_ SG_ 210 vn_lin_uncomp_accel_x "IMU acceleration"; +CM_ SG_ 225 vn_gps_status "GPS fix status"; +CM_ BO_ 208 "Vehicle body velocity measured by VN-300"; +CM_ SG_ 208 vn_vel_uncertainty "how much error there might be"; +CM_ SG_ 4 Velocity_z_CGCorrected "ISO Standard Sign, Positive is Vehicle Moving Up"; +CM_ SG_ 4 Velocity_y_CGCorrected "ISO Standard Sign, Positive is Vehicle Turning Left"; +CM_ SG_ 4 Velocity_x_CGCorrected "ISO Standard Sign, Positive is Vehicle Moving Forward"; +CM_ SG_ 4 Velocity_z "ISO Standard Sign, Positive is Vehicle Moving Up"; +CM_ SG_ 4 Velocity_y "ISO Standard Sign, Positive is Vehicle Turning Left"; +CM_ SG_ 4 Velocity_x "ISO Standard Sign, Positive is Vehicle Moving Forward"; +CM_ SG_ 553 vn_gps_status "GPS fix status"; +CM_ SG_ 1220 brake_temp_channel_4 "brake rotor temp sensor channel reading in degrees C"; +CM_ SG_ 1220 brake_temp_channel_3 "brake rotor temp sensor channel reading in degrees C"; +CM_ SG_ 1220 brake_temp_channel_2 "brake rotor temp sensor channel reading in degrees C"; +CM_ SG_ 1220 brake_temp_channel_1 "brake rotor temp sensor channel reading in degrees C"; +CM_ SG_ 1221 brake_temp_channel_8 "brake rotor temp sensor channel reading in degrees C"; +CM_ SG_ 1221 brake_temp_channel_7 "brake rotor temp sensor channel reading in degrees C"; +CM_ SG_ 1221 brake_temp_channel_6 "brake rotor temp sensor channel reading in degrees C"; +CM_ SG_ 1221 brake_temp_channel_5 "brake rotor temp sensor channel reading in degrees C"; +CM_ SG_ 1222 brake_temp_channel_12 "brake rotor temp sensor channel reading in degrees C"; +CM_ SG_ 1222 brake_temp_channel_11 "brake rotor temp sensor channel reading in degrees C"; +CM_ SG_ 1222 brake_temp_channel_10 "brake rotor temp sensor channel reading in degrees C"; +CM_ SG_ 1222 brake_temp_channel_9 "brake rotor temp sensor channel reading in degrees C"; +CM_ SG_ 1224 brake_rotor_sensor_temp "temperature internal to the sensor degrees C"; +CM_ SG_ 1223 brake_temp_channel_16 "brake rotor temp sensor channel reading in degrees C"; +CM_ SG_ 1223 brake_temp_channel_15 "brake rotor temp sensor channel reading in degrees C"; +CM_ SG_ 1223 brake_temp_channel_14 "brake rotor temp sensor channel reading in degrees C"; +CM_ SG_ 1223 brake_temp_channel_13 "brake rotor temp sensor channel reading in degrees C"; +CM_ SG_ 1225 brake_temp_channel_4 "brake rotor temp sensor channel reading in degrees C"; +CM_ SG_ 1225 brake_temp_channel_3 "brake rotor temp sensor channel reading in degrees C"; +CM_ SG_ 1225 brake_temp_channel_2 "brake rotor temp sensor channel reading in degrees C"; +CM_ SG_ 1225 brake_temp_channel_1 "brake rotor temp sensor channel reading in degrees C"; +CM_ SG_ 1226 brake_temp_channel_8 "brake rotor temp sensor channel reading in degrees C"; +CM_ SG_ 1226 brake_temp_channel_7 "brake rotor temp sensor channel reading in degrees C"; +CM_ SG_ 1226 brake_temp_channel_6 "brake rotor temp sensor channel reading in degrees C"; +CM_ SG_ 1226 brake_temp_channel_5 "brake rotor temp sensor channel reading in degrees C"; +CM_ SG_ 1227 brake_temp_channel_12 "brake rotor temp sensor channel reading in degrees C"; +CM_ SG_ 1227 brake_temp_channel_11 "brake rotor temp sensor channel reading in degrees C"; +CM_ SG_ 1227 brake_temp_channel_10 "brake rotor temp sensor channel reading in degrees C"; +CM_ SG_ 1227 brake_temp_channel_9 "brake rotor temp sensor channel reading in degrees C"; +CM_ SG_ 1229 brake_rotor_sensor_temp "temperature internal to the sensor degrees C"; +CM_ SG_ 1228 brake_temp_channel_16 "brake rotor temp sensor channel reading in degrees C"; +CM_ SG_ 1228 brake_temp_channel_15 "brake rotor temp sensor channel reading in degrees C"; +CM_ SG_ 1228 brake_temp_channel_14 "brake rotor temp sensor channel reading in degrees C"; +CM_ SG_ 1228 brake_temp_channel_13 "brake rotor temp sensor channel reading in degrees C"; +CM_ SG_ 1219 brake_temp_sensor_can_bitrate "bitrate setting for CAN on the brake temp sensor. 1 = 1M, 2 = 500k, 3 = 250k, 4 = 100k"; +CM_ SG_ 1219 brake_temp_sensor_ch_setting "40 = 4 Channels, 80 = 8 channels, 160 = 16 channels"; +CM_ SG_ 1219 brake_temp_sensor_sampling_freq "1 = 1 hz, 2 = 2hz, 3 = 4hz, 4 = 8 hz, 5=16 hz, 6=32 hz, 7 = 64hz, 8 = 100hz"; +CM_ SG_ 1219 brake_temp_sensor_emissivity "emissivity of the material (0 to 1)"; +CM_ SG_ 1219 brake_temp_sensor_prog_const "programming constant, should be set to 30000"; +CM_ SG_ 310 motor_overload_percentage "the current overload of the motor according to the i2t calc"; +CM_ SG_ 310 inverter_overload_percentage "the current overload of the inverter according to the i2t calc"; +CM_ SG_ 320 motor_overload_percentage "the current overload of the motor according to the i2t calc"; +CM_ SG_ 320 inverter_overload_percentage "the current overload of the inverter according to the i2t calc"; +CM_ SG_ 330 motor_overload_percentage "the current overload of the motor according to the i2t calc"; +CM_ SG_ 330 inverter_overload_percentage "the current overload of the inverter according to the i2t calc"; +CM_ SG_ 340 motor_overload_percentage "the current overload of the motor according to the i2t calc"; +CM_ SG_ 340 inverter_overload_percentage "the current overload of the inverter according to the i2t calc"; + + + +VAL_ 6 Velocity_Filtering 0 "NO_FILTERING_VEL" 1 "LIGHT_FILTERING_VEL" 2 "MEDIUM_FILTERING_VEL" 3 "HEAVY_FILTERING_VEL" ; +VAL_ 6 CAN_Termination_State_Bus_2 0 "CAN_BUS_UNTERMINATED_CAN2_STATUS" 1 "CAN_BUS_TERMINATED_CAN2_STATUS" ; +VAL_ 6 CAN_Termination_State_Bus_1 0 "CAN_BUS_UNTERMINATED_CAN1_STATUS" 1 "CAN_BUS_TERMINATED_CAN1_STATUS" ; +VAL_ 6 IMU_Filtering 0 "NO_FILTERING_IMU" 1 "LIGHT_FILTERING_IMU" 2 "MEDIUM_FILTERING_IMU" 3 "HEAVY_FILTERING_IMU" ; +VAL_ 6 Attitude_Filtering 0 "NO_FILTERING_ATT" 1 "LIGHT_FILTERING_ATT" 2 "MEDIUM_FILTERING_ATT" 3 "HEAVY_FILTERING_ATT" ; +VAL_ 235 dial_state 0 "MODE_0" 1 "MODE_1" 2 "MODE_2" 3 "MODE_3" 4 "MODE_4" 5 "MODE_5" ; +VAL_ 236 dial_state 0 "MODE_0" 1 "MODE_1" 2 "MODE_2" 3 "MODE_3" 4 "MODE_4" 5 "MODE_5" ; +VAL_ 257 torque_controller_mux_status 0 "NO_ERROR" 1 "ERROR_SPEED_DIFF_TOO_HIGH" 2 "ERROR_TORQUE_DIFF_TOO_HIGH" 3 "ERROR_CONTROLLER_INDEX_OUT_OF_BOUNDS" 4 "ERROR_CONTROLLER_NULL_POINTER" ; +VAL_ 3 Velocity_Filtering 0 "NO_FILTERING_VEL" 1 "LIGHT_FILTERING_VEL" 2 "MEDIUM_FILTERING_VEL" 3 "HEAVY_FILTERING_VEL" ; +VAL_ 3 IMU_Filtering 0 "NO_FILTERING_IMU" 1 "LIGHT_FILTERING_IMU" 2 "MEDIUM_FILTERING_IMU" 3 "HEAVY_FILTERING_IMU" ; +VAL_ 3 Attitude_Filtering 0 "NO_FILTERING_ATT" 1 "LIGHT_FILTERING_ATT" 2 "MEDIUM_FILTERING_ATT" 3 "HEAVY_FILTERING_ATT" ; +VAL_ 3 CAN_Termination_Setting_Bus_2 0 "CAN_BUS_UNTERMINATED_CAN2_setting" 1 "CAN_BUS_TERMINATED_CAN2_setting" ; +VAL_ 3 CAN_Termination_Setting_Bus_1 0 "CAN_BUS_UNTERMINATED_CAN1_setting" 1 "CAN_BUS_TERMINATED_CAN1_setting" ; +VAL_ 3 Broadcast_rate 0 "hz_1" 1 "hz_5" 2 "hz_10" 3 "hz_50" 4 "hz_100" 5 "hz_250" 6 "hz_500" ; +VAL_ 2 SpeedBeam_Health 0 "SENSOR_HEALTHY" 1 "NON_MEASUREMENT_MODE" 2 "DATA_OPTICAL_QUALITY_POOR" 3 "TEMPERATURE_TOO_HIGH" 4 "SAVING_CALIBRATION" 5 "SENSOR_COMMUNICATION_ERROR" 6 "SPEED_TOO_HIGH" ; +VAL_ 2 sensor_3_Validity 0 "Sensor_Valid_sense_3" 1 "Response_Timeout_sense_3" 2 "Bad_Optical_Signal_sense_3" 3 "Speed_Too_High_sense_3" ; +VAL_ 2 sensor_2_Validity 0 "Sensor_Valid_sense_2" 1 "Response_Timeout_sense_2" 2 "Bad_Optical_Signal_sense_2" 3 "Speed_Too_High_sense_2" ; +VAL_ 2 sensor_1_Validity 0 "Sensor_Valid_sense_1" 1 "Response_Timeout_sense_1" 2 "Bad_Optical_Signal_sense_1" 3 "Speed_Too_High_sense_1" ; +VAL_ 2 sensor_0_Validity 0 "Sensor_Valid_sense_0" 1 "Response_Timeout_sense_0" 2 "Bad_Optical_Signal_sense_0" 3 "Speed_Too_High_sense_0" ; +VAL_ 225 vn_gps_status 0 "NO_FIX" 1 "TIME_ONLY" 2 "FIX_2D" 3 "FIX_3D" ; +VAL_ 553 vn_gps_status 0 "NO_FIX" 1 "TIME_ONLY" 2 "FIX_2D" 3 "FIX_3D" ; +VAL_ 519 drivetrain_state 0 "NOT_CONNECTED" 1 "NOT_ENABLED_NO_HV_PRESENT" 2 "NOT_ENABLED_HV_PRESENT" 3 "INVERTERS_READY" 4 "INVERTERS_HV_ENABLED" 5 "ENABLED_DRIVE_MODE" 6 "ERROR" 7 "CLEARING_ERRORS" ; +VAL_ 519 vehicle_state 0 "TRACTIVE_SYSTEM_NOT_ACTIVE" 1 "TRACTIVE_SYSTEM_ACTIVE" 2 "WANTING_READY_TO_DRIVE" 3 "READY_TO_DRIVE" 4 "WANTING_RECALIBRATE_PEDALS" 5 "RECALIBRATING_PEDALS" ; +SIG_VALTYPE_ 1055 steering_digital_raw : 1; +SIG_VALTYPE_ 269 current_A : 1; +SIG_VALTYPE_ 269 voltage_V : 1; +SIG_VALTYPE_ 1037 em_energy_w_hr : 1; +SIG_VALTYPE_ 103 precharge_voltage : 1; +SIG_VALTYPE_ 104 pack_out_voltage : 1; +SIG_VALTYPE_ 104 ts_out_voltage : 1; +SIG_VALTYPE_ 105 glv_voltage : 1; +SIG_VALTYPE_ 105 shdn_out_voltage : 1; +SIG_VALTYPE_ 1283 flow_rate : 1; + + diff --git a/deploy_script.sh b/deploy_script.sh index 65fb159..3c242cb 100755 --- a/deploy_script.sh +++ b/deploy_script.sh @@ -1,2 +1,4 @@ scp build-arm/drivebrain hytech@192.168.203.1:/home/hytech/drivebrain/ scp config/config.json hytech@192.168.203.1:/home/hytech/drivebrain/config + +# scp build/drivebrain nixos@192.168.203.1:/home/nixos/fake_drivebrain \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index fdc5a2e..9683bed 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -7,7 +7,7 @@ services: working_dir: /app tty: true stdin_open: true - command: ["/bin/bash"] + command: sleep infinity restart: "no" volumes: diff --git a/drivebrain_app/src/main.cpp b/drivebrain_app/src/main.cpp index 21f758d..8ad3f91 100644 --- a/drivebrain_app/src/main.cpp +++ b/drivebrain_app/src/main.cpp @@ -1,5 +1,9 @@ +#include "ETHSendComms.hpp" +#include "ETHRecvComms.hpp" +#include #include #include +#include #include #include #include @@ -8,47 +12,98 @@ #include #include #include +#include #include #include +#include +#include +#include std::atomic running = true; +std::optional json_file; +std::optional dbc_file; + +int parse_arguments(int &argc, char* argv[]) { + int opt; + + while ((opt = getopt(argc, argv, "c:d:")) != -1) { + switch (opt) { + case 'c': + if (optarg != nullptr && strlen(optarg) > 0 && std::filesystem::exists(optarg)) { + json_file = optarg; + } else { + spdlog::error("Invalid json file provided: {}", optarg); + return 1; + } + break; + case 'd': + if (optarg != nullptr && strlen(optarg) > 0 && std::filesystem::exists(optarg)) { + dbc_file = optarg; + } else { + spdlog::error("Invalid dbc file provided: {}", optarg); + return 1; + } + break; + case '?': + spdlog::error("Unknown command line option: -{}", static_cast(optopt)); + return 1; + default: + spdlog::error("Could not parse command line arguments."); + return 1; + } + } + + if (!json_file) { + spdlog::error("Did not receive the required json file argument."); + return 1; + } + + if (!dbc_file) { + spdlog::error("Did not receive the required dbc file argument."); + return 1; + } + + return 0; +} void sig_handler(int signal) { if(signal == SIGINT) { - std::cout << "halting\n"; + spdlog::info("halting"); running = false; } } -void get_param_task(int wait_time, core::MsgType msg) { - while(running) { - core::MCAPLogger::instance().log_msg(static_cast(msg)); - std::this_thread::sleep_for((std::chrono::milliseconds(wait_time))); +int main(int argc, char* argv[]) { + // Argument Handling + int return_code = parse_arguments(argc, argv); + if (return_code != 0) { + spdlog::error("Expected Usage: ./drivebrain -c path/to/config.json -d path/to/hytech.dbc"); + return return_code; } -} -int main(int argc, char* argv[]) { - + comms::CANComms primary_can("can_secondary", dbc_file.value()); - core::FoxgloveServer::create(argv[1]); - core::MCAPLogger::create("recordings/", mcap::McapWriterOptions("")); + // Singleton Creation + core::FoxgloveServer::create(json_file.value()); + core::MCAPLogger::create("recordings/", mcap::McapWriterOptions(""), json_file.value()); core::MCAPLogger::instance().open_new_mcap("test_1.mcap"); core::MCAPLogger::instance().init_logging(); + std::shared_ptr all_data_msg = std::make_shared(); + std::signal(SIGINT, sig_handler); + while(running) { + std::shared_ptr speed_msg = std::make_shared(); + speed_msg->set_drivebrain_set_rpm_fl(1.0); + speed_msg->set_drivebrain_set_rpm_fr(2.0); + speed_msg->set_drivebrain_set_rpm_rl(4.0); + speed_msg->set_drivebrain_set_rpm_rr(8.0); + primary_can.send_message(speed_msg); + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + } + - auto vel_msg = std::make_shared(); - vel_msg->set_velocity_x(1000); - vel_msg->set_velocity_y(10000); - - auto acu_data = std::make_shared(); - acu_data->set_max_cell_temp_id(676767); - - std::thread t1(get_param_task, 20, vel_msg); - std::thread t2(get_param_task, 40, acu_data); - - if(t1.joinable()) t1.join(); - if(t2.joinable()) t2.join(); core::MCAPLogger::instance().close_active_mcap(); - + core::MCAPLogger::destroy(); + core::FoxgloveServer::destroy(); } diff --git a/drivebrain_comms/CMakeLists.txt b/drivebrain_comms/CMakeLists.txt index a112b11..54ba86b 100644 --- a/drivebrain_comms/CMakeLists.txt +++ b/drivebrain_comms/CMakeLists.txt @@ -5,12 +5,11 @@ find_package(Boost REQUIRED) find_package(nlohmann_json REQUIRED) find_package(foxglove-websocket REQUIRED) find_package(Protobuf REQUIRED CONFIG) +find_package(dbcppp REQUIRED) add_library(drivebrain_comms src/CANComms.cpp - # src/DBServiceImpl.cpp - # src/foxglove_server.cpp - # src/VNComms.cpp + src/ETHSendComms.cpp ) target_include_directories(drivebrain_comms PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include") @@ -24,4 +23,5 @@ target_link_libraries(drivebrain_comms PUBLIC protobuf::libprotobuf hytech_msgs_cpp_lib libvncxx + dbcppp::dbcppp ) diff --git a/drivebrain_comms/include/CANComms.hpp b/drivebrain_comms/include/CANComms.hpp index e69de29..7232b9d 100644 --- a/drivebrain_comms/include/CANComms.hpp +++ b/drivebrain_comms/include/CANComms.hpp @@ -0,0 +1,90 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hytech.pb.h" +#include "hytech_msgs.pb.h" + +#include +#include +#include + + +namespace comms { + +class CANComms { + + public: + + /** + * Initializes a new can socket communications interface with the specified device name. + * + * @param device_name the name of the can device trying to be initialized + * @param dbc_file_path the file path for the dbc + */ + CANComms(const std::string &device_name, const std::string &dbc_file_path); + + /** + * Sends a prootbuf message over CAN + * + * @param message the message to be sent + */ + void send_message(std::shared_ptr message); + + private: + + /** + * Receives and unpacks a can frame. + */ + std::shared_ptr _decode_can_frame(struct can_frame& frame); + + /** + * Encodes a protobuf message to a CAN message + */ + int _encode_can_frame(std::shared_ptr proto_message, can_frame* frame); + + + /** + * Receive handler that runs until the interface is destructed + */ + void _receive_handler(); + + /** + * Initializes the can interface, invoked by constructor. + * + * @return 0 if successful, negative error code on failure + */ + int _init(const std::string &device_name, const std::string &dbc_file_path); + + /** + * Casts a can_frame struct to a protobuf message if it exists in the descriptor pool + * + * @param frame the can frame to be processed + * @return shared ptr to the protobuf message to return + */ + std::shared_ptr _protobuf_message_receive(struct can_frame &frame); + + + public: + + private: + int _socket; + can_frame _frame; + std::thread _reader_thread; + std::unordered_map _messages; + std::unordered_map _names_to_can_id; + std::unique_ptr _net; + +}; + +} \ No newline at end of file diff --git a/drivebrain_comms/include/ETHRecvComms.hpp b/drivebrain_comms/include/ETHRecvComms.hpp new file mode 100644 index 0000000..5e43c22 --- /dev/null +++ b/drivebrain_comms/include/ETHRecvComms.hpp @@ -0,0 +1,56 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "MCAPLogger.hpp" + +namespace comms { + + /** + * @brief Ethernet driver class for receiving Protobuf messages + * @tparam MsgType The protobuf message type the initialized Ethernet class will receive. + */ + template + class ETHRecvComms { + public: + ETHRecvComms() = delete; + ~ETHRecvComms(); + + /** + * Constructor for creating a new instance of the Ethernet receiving driver + * + * @param io_context The reference to the initialized io_context + * @param port The port to listen/receive messages from + * @param handler The handler function to be called on the received message. By default the message is logged to an MCAP. + */ + ETHRecvComms(boost::asio::io_context& io_context, uint16_t port, + std::function)> handler = [](std::shared_ptr msg){ core::MCAPLogger::instance().log_msg(msg); }); + + private: + /* Deserializes the received ethernet message and logs to the MessagerLogger and state estimator */ + void _handle_receive(const boost::system::error_code &error, std::size_t size); + + /* Begins message receiving loop */ + void _start_receive(); + + private: + std::array _recv_buffer; + boost::asio::ip::udp::socket _socket; + boost::asio::ip::udp::endpoint _remote_endpoint; + std::shared_ptr _received_msg; + bool _running = false; + std::thread _output_thread; + + std::function)> _handler; + }; +} + +#include "ETHRecvComms.tpp" diff --git a/drivebrain_comms/include/ETHRecvComms.tpp b/drivebrain_comms/include/ETHRecvComms.tpp new file mode 100644 index 0000000..0541037 --- /dev/null +++ b/drivebrain_comms/include/ETHRecvComms.tpp @@ -0,0 +1,46 @@ +#include +#include + +using boost::asio::ip::udp; +namespace comms { + + template + ETHRecvComms::ETHRecvComms(boost::asio::io_context& io_context, uint16_t port, std::function)> handler) + : _socket(io_context, udp::v4()), + _handler(std::move(handler)) + { + static_assert(!std::is_same_v, "MsgType cannot be void, receive requires a message type"); + + _socket.bind(udp::endpoint(udp::v4(), port)); + _received_msg = std::make_shared(); + _running = true; + _start_receive(); + spdlog::info("Ethernet receive-only mode, port {}", port); + } + + template + ETHRecvComms::~ETHRecvComms() { + _running = false; + _socket.close(); + spdlog::warn("Destructed Ethernet receive comms"); + } + + template + void ETHRecvComms::_handle_receive(const boost::system::error_code &error, std::size_t size) { + if (_running && !error) { + _received_msg ->ParseFromArray(_recv_buffer.data(), size); + _handler(_received_msg); + _start_receive(); + } + } + + template + void ETHRecvComms::_start_receive() { + using namespace boost::placeholders; + _socket.async_receive_from( + boost::asio::buffer(_recv_buffer), _remote_endpoint, + boost::bind(ÐRecvComms::_handle_receive, this, + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred)); + } +} diff --git a/drivebrain_comms/include/ETHSendComms.hpp b/drivebrain_comms/include/ETHSendComms.hpp new file mode 100644 index 0000000..d7208e7 --- /dev/null +++ b/drivebrain_comms/include/ETHSendComms.hpp @@ -0,0 +1,56 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "DriverBus.hpp" + +namespace comms { + class ETHSendComms { + public: + using deqtype = core::ThreadSafeDeque>; + + ETHSendComms() = delete; + ~ETHSendComms(); + + /** + * Constructor for creating a new instance of the Ethernet driver (full-duplex mode) + * + * @param io_context The reference to the initialized io_context + * @param port The port to listen/receive messages from + * @param send_ip The IP address to send messages to + */ + ETHSendComms(boost::asio::io_context& io_context, uint16_t port, std::string send_ip); + + /** + * Method for adding a new message to the send queue + * + * @param send_msg The message to send + */ + void enqueue_msg_send(std::shared_ptr send_msg); + + private: + /* Logs and sends all messages in the message queue */ + void _handle_send_msg_from_queue(); + + /* Sends one message from the send buffer */ + void _send_message(std::shared_ptr msg_out); + + private: + boost::asio::ip::udp::endpoint _send_endp; + boost::asio::ip::udp::socket _socket; + boost::asio::ip::udp::endpoint _remote_endpoint; + bool _running = false; + std::thread _output_thread; + std::array _send_buffer; + deqtype _send_msg_queue; + + }; +} diff --git a/drivebrain_comms/include/EthernetComms.hpp b/drivebrain_comms/include/EthernetComms.hpp deleted file mode 100644 index 9b4aada..0000000 --- a/drivebrain_comms/include/EthernetComms.hpp +++ /dev/null @@ -1,82 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "DriverBus.hpp" -#include "hytech_msgs.pb.h" - - -namespace comms -{ - /** - * @brief Ethernet driver class for sending and receiving Protobuf messages - * @tparam MsgType The protobuf message type the initialized Ethernet class will receive. An empty (void) template type indicates send-only mode - */ - template - class ETHDriver { - public: - - using deqtype = core::ThreadSafeDeque>; - - ETHDriver() = delete; - ~ETHDriver(); - - /** - * Constructor for creating a new instance of the Ethernet driver - * - * @param io_context The reference to the initialized io_context - * @param port The port to listen/receive messages from - * @param send_ip The IP address to send messages from (empty by default if in receive-only mode) - * @param bind Whether or not the socket should bind to local endpoint - */ - ETHDriver(boost::asio::io_context &io_context, uint16_t port, std::string send_ip = ""); - - /** - * Method for adding a new message to the send queue - * - * @param send_msg The message to send - */ - void enqueue_msg_send(std::shared_ptr send_msg); - private: - /* Receive helpers */ - - /* Deserializes the received ethernet message and logs to the MessagerLogger and state estimator */ - void _handle_receive(const boost::system::error_code &error, std::size_t size); - - /* Begins message receiving loop */ - void _start_receive(); - - /* Send helpers */ - - /* Logs and sends all messages in the message queue */ - void _handle_send_msg_from_queue(); - - /* Sends one message from the send buffer */ - void _send_message(std::shared_ptr msg_out); - - private: - boost::asio::ip::udp::endpoint _send_endp; - deqtype _send_msg_queue; - std::array _send_buffer; - std::array _recv_buffer; - std::shared_ptr _received_eth_msg; - - // std::shared_ptr _state_estimator = nullptr; //TODO: uncomment when state estimator is added - std::atomic _running = false; - boost::asio::ip::udp::socket _socket; - boost::asio::ip::udp::endpoint _remote_endpoint; - std::thread _output_thread; - - }; - -} - -#include "EthernetComms.tpp" diff --git a/drivebrain_comms/include/EthernetComms.tpp b/drivebrain_comms/include/EthernetComms.tpp deleted file mode 100644 index 73a4cbb..0000000 --- a/drivebrain_comms/include/EthernetComms.tpp +++ /dev/null @@ -1,118 +0,0 @@ -#include "EthernetComms.hpp" -#include "hytech_msgs.pb.h" -#include -#include -#include -#include -#include - -using boost::asio::ip::udp; -namespace comms -{ - template - ETHDriver::ETHDriver(boost::asio::io_context &io_context, uint16_t port, std::string send_ip) - : _socket(io_context, udp::endpoint(udp::v4(), port)), - _send_endp(send_ip.empty() - ? udp::endpoint(udp::v4(), port) - : udp::endpoint(boost::asio::ip::make_address(send_ip.c_str()), port)) - { - _running = true; - _output_thread = std::thread(&comms::ETHDriver::_handle_send_msg_from_queue, this); - - if constexpr (!std::is_same_v) { - _socket.bind(udp::endpoint(udp::v4(), port)); - _received_eth_msg = std::make_shared(); - _start_receive(); - spdlog::info("ETHDriver full duplex mode initialized for port {}", port); - } else { - spdlog::info("ETHDriver send-only mode initialized for port {}", port); - } - - } - - template - ETHDriver::~ETHDriver() { - _running = false; - _send_msg_queue.cv.notify_all(); - if (_output_thread.joinable()) { - _output_thread.join(); - } - _socket.close(); - spdlog::warn("Ethernet driver destructed"); - } - - /* Receive methods */ - template - void ETHDriver::_handle_receive(const boost::system::error_code &error, std::size_t size) { - if (_running && !error) { - _received_eth_msg ->ParseFromArray(_recv_buffer.data(), size); - auto out_msg = static_cast>(_received_eth_msg); - // log to outputs - // TODO: log to state estimator - _start_receive(); - } - } - - template - void ETHDriver::_start_receive() { - using namespace boost::placeholders; - _socket.async_receive_from( - boost::asio::buffer(_recv_buffer), _remote_endpoint, - boost::bind(ÐDriver::_handle_receive, this, - boost::asio::placeholders::error, - boost::asio::placeholders::bytes_transferred)); - } - - /* Send methods */ - - template - void ETHDriver::enqueue_msg_send(std::shared_ptr send_msg) { - spdlog::debug("enqueing msg"); - std::unique_lock lk(_send_msg_queue.mtx); - _send_msg_queue.deque.push_back(send_msg); - _send_msg_queue.cv.notify_all(); - } - - template - void ETHDriver::_handle_send_msg_from_queue() { - std::deque> temp_msg_queue; - while(_running) { - /* transfer messages to temp queue for duration of lock */ - { - std::unique_lock lk(_send_msg_queue.mtx); - _send_msg_queue.cv.wait(lk, [this]() { return !_send_msg_queue.deque.empty() || !_running; }); - - if(!_running) { - break; - } - - _send_msg_queue.deque.swap(temp_msg_queue); - } - - } - - for (const auto &msg : temp_msg_queue) { - _send_message(msg); - // this->log(msg); - } - - temp_msg_queue.clear(); - } - - template - void ETHDriver::_send_message(std::shared_ptr msg_out) { - spdlog::info("sending ethernet message"); - msg_out->SerializeToArray(_send_buffer.data(), msg_out->ByteSizeLong()); - _socket.async_send_to(boost::asio::buffer(_send_buffer, msg_out->ByteSizeLong()), - _send_endp, - [](const boost::system::error_code &error, std::size_t bytes_transferred) - { - if (error) { - spdlog::error("async send failed: {}", error.message()); - } else { - spdlog::debug("async send completed: {} bytes.", bytes_transferred); - } - }); - } - -} diff --git a/drivebrain_comms/src/CANComms.cpp b/drivebrain_comms/src/CANComms.cpp index e69de29..98a728e 100644 --- a/drivebrain_comms/src/CANComms.cpp +++ b/drivebrain_comms/src/CANComms.cpp @@ -0,0 +1,235 @@ +#include +#include +#include + +/**************************************************************** + * HELPER METHODS + ****************************************************************/ +static std::string string_to_lowercase(std::string input_string) { + std::transform(input_string.begin(), input_string.end(), input_string.begin(), + [](unsigned char c){ return std::tolower(c); }); + + return input_string; +} + +static std::shared_ptr get_proto_message_from_name(const std::string &name) { + std::shared_ptr proto_message; + const google::protobuf::Descriptor *desc = google::protobuf::DescriptorPool::generated_pool()->FindMessageTypeByName("hytech." + name); + if (!desc) { + return nullptr; + } + proto_message.reset(google::protobuf::MessageFactory::generated_factory()->GetPrototype(desc)->New()); + if (!proto_message) { + return nullptr; + } + return proto_message; +} + + +/**************************************************************** + * PUBLIC CLASS METHOD IMPLEMENTATIONS + ****************************************************************/ +comms::CANComms::CANComms(const std::string &device_name, const std::string &dbc_file_path) { + if (_init(device_name, dbc_file_path) < 0) { + throw std::runtime_error("Failed to initialize CAN communications"); + } +} + +void comms::CANComms::send_message(std::shared_ptr message) { + can_frame frame{}; + int return_code = _encode_can_frame(message, &frame); + if (return_code < 0) { + std::cout << "Failed to create CAN message from protobuf" << std::endl; + return; + } + + int nbytes = write(_socket, &frame, sizeof(struct can_frame)); +} + +/**************************************************************** + * PRIVATE CLASS METHOD IMPLEMENTATIONS + ****************************************************************/ +int comms::CANComms::_init(const std::string &device_name, const std::string &dbc_file_path) { + // Initialize the CAN socket + std::cout << "Beginning CAN initialization" << std::endl; + struct sockaddr_can addr; + struct ifreq ifr; + + _socket = socket(PF_CAN, SOCK_RAW, CAN_RAW); + if (_socket < 0) { + std::cerr << "Failed to create CAN socket: " << strerror(errno) << std::endl; + return -1; + } + + strcpy(ifr.ifr_name, device_name.c_str()); + if (ioctl(_socket, SIOCGIFINDEX, &ifr) < 0) { + std::cerr << "Failed to get interface index for " << device_name << ": " << strerror(errno) << std::endl; + close(_socket); + return -1; + } + + addr.can_family = AF_CAN; + addr.can_ifindex = ifr.ifr_ifindex; + + if (bind(_socket, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + std::cerr << "Failed to bind CAN socket: " << strerror(errno) << std::endl; + close(_socket); + return -1; + } + + // Set up DBC parsing + { + std::ifstream idbc(dbc_file_path.c_str()); + if (!idbc.is_open()) { + std::cerr << "Failed to open DBC file: " << dbc_file_path << std::endl; + close(_socket); + return -1; + } + _net = dbcppp::INetwork::LoadDBCFromIs(idbc); + } + + if (!_net) { + std::cerr << "Failed to parse DBC file: " << dbc_file_path << std::endl; + close(_socket); + return -1; + } + + for (const dbcppp::IMessage& msg : _net->Messages()) { + _messages.insert(std::make_pair(msg.Id(), &msg)); + _names_to_can_id.insert(std::make_pair(string_to_lowercase(msg.Name()), msg.Id())); + } + + // Spawn reader thread + _reader_thread = std::thread(&comms::CANComms::_receive_handler, this); + + std::cout << "Successfully initialized CAN driver" << std::endl; + + return 0; +} + +void comms::CANComms::_receive_handler() { + int nbytes; + + while(true) { + nbytes = read(_socket, &_frame, sizeof(can_frame)); + + if (nbytes < 0) { + std::cout << "Error reading from can socket." << std::endl; + } + + if (nbytes < sizeof(struct can_frame)) { + std::cout << "Error reading from can socket. Incomplete CAN frame." << std::endl; + } + + std::shared_ptr dmsg = _decode_can_frame(_frame); + + core::FoxgloveServer::instance().send_live_telem_msg(dmsg); + core::MCAPLogger::instance().log_msg(dmsg); + } +} + +std::shared_ptr comms::CANComms::_decode_can_frame(struct can_frame &frame) { + + const dbcppp::IMessage* dbc_msg = _messages[frame.can_id]; + + if (dbc_msg == nullptr) { + return nullptr; + } + + std::shared_ptr proto_message = get_proto_message_from_name(string_to_lowercase(dbc_msg->Name())); + if (proto_message == nullptr) { + return nullptr; + } + + const google::protobuf::Descriptor *descriptor = proto_message->GetDescriptor(); + const google::protobuf::Reflection *reflection = proto_message->GetReflection(); + + for (const dbcppp::ISignal &sig : dbc_msg->Signals()) { + const dbcppp::ISignal *mux_sig = dbc_msg->MuxSignal(); + + if (sig.MultiplexerIndicator() != dbcppp::ISignal::EMultiplexer::MuxValue || (mux_sig && mux_sig->Decode(frame.data) == sig.MultiplexerSwitchValue())) { + dbcppp::ISignal::raw_t raw_value = sig.Decode(frame.data); + double value = sig.RawToPhys(raw_value); + + const google::protobuf::FieldDescriptor *field = descriptor->FindFieldByName(sig.Name()); + switch (field->type()) { + case google::protobuf::FieldDescriptor::TYPE_ENUM: + reflection->SetEnumValue(proto_message.get(), field, (int)value); + break; + case google::protobuf::FieldDescriptor::TYPE_FLOAT: + reflection->SetFloat(proto_message.get(), field, (float)value); + break; + case google::protobuf::FieldDescriptor::TYPE_BOOL: + reflection->SetBool(proto_message.get(), field, (bool)value); + break; + case google::protobuf::FieldDescriptor::TYPE_INT32: + reflection->SetInt32(proto_message.get(), field, (int32_t)value); + break; + default: + break; + } + } + } + + return proto_message; + +} + +int comms::CANComms::_encode_can_frame(std::shared_ptr proto_message, can_frame* frame) { + + std::string type_url = proto_message->GetTypeName(); + std::string messageTypeName = type_url.substr(type_url.find_last_of('.') + 1); // TODO validate this is not scuffed + + const google::protobuf::Descriptor *descriptor = proto_message->GetDescriptor(); + const google::protobuf::Reflection *reflection = proto_message->GetReflection(); + + if (_names_to_can_id.find(messageTypeName) == _names_to_can_id.end()) { + std::cout << "Could not find message in known CAN description. Ensure that the message is in the DBC file." << std::endl; + return -EINVAL; + } + + uint64_t id = _names_to_can_id[messageTypeName]; + auto dbc_message = _messages[id]->Clone(); + frame->can_id = id; + frame->len = dbc_message->MessageSize(); + + for (const auto &sig : dbc_message->Signals()) { + const google::protobuf::FieldDescriptor *field = descriptor->FindFieldByName(sig.Name()); + + switch(field->cpp_type()) { + case google::protobuf::FieldDescriptor::CPPTYPE_INT32: { + int32_t value = reflection->GetInt32(*proto_message, field); + sig.Encode(sig.PhysToRaw(value), frame->data); + break; + } case google::protobuf::FieldDescriptor::CPPTYPE_INT64: { + int64_t value = reflection->GetInt64(*proto_message, field); + sig.Encode(sig.PhysToRaw(value), frame->data); + break; + } case google::protobuf::FieldDescriptor::CPPTYPE_UINT32: { + uint32_t value = reflection->GetUInt32(*proto_message, field); + sig.Encode(sig.PhysToRaw(value), frame->data); + break; + } case google::protobuf::FieldDescriptor::CPPTYPE_UINT64: { + uint64_t value = reflection->GetUInt64(*proto_message, field); + sig.Encode(sig.PhysToRaw(value), frame->data); + break; + } case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE: { + double value = reflection->GetDouble(*proto_message, field); + sig.Encode(sig.PhysToRaw(value), frame->data); + break; + } case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT: { + double value = reflection->GetFloat(*proto_message, field); + sig.Encode(sig.PhysToRaw(value), frame->data); + break; + } case google::protobuf::FieldDescriptor::CPPTYPE_BOOL: { + bool value = reflection->GetBool(*proto_message, field); + sig.Encode(sig.PhysToRaw(value), frame->data); + break; + } default: + break; + } + } + + return 0; + +} diff --git a/drivebrain_comms/src/ETHSendComms.cpp b/drivebrain_comms/src/ETHSendComms.cpp new file mode 100644 index 0000000..0467f1b --- /dev/null +++ b/drivebrain_comms/src/ETHSendComms.cpp @@ -0,0 +1,74 @@ +#include +#include + +using boost::asio::ip::udp; +namespace comms { + + ETHSendComms::ETHSendComms(boost::asio::io_context& io_context, uint16_t port, std::string send_ip) + : _socket(io_context, udp::v4()), + _send_endp(udp::endpoint(boost::asio::ip::make_address(send_ip), port)) + { + + _running = true; + _output_thread = std::thread(ÐSendComms::_handle_send_msg_from_queue, this); + spdlog::info("Ethernet send-only mode, port {}", port); + } + + ETHSendComms::~ETHSendComms() { + _running = false; + _send_msg_queue.cv.notify_all(); + _socket.close(); + if(_output_thread.joinable()) { + _output_thread.join(); + } + spdlog::warn("Destructed Ethernet send comms"); + } + + + void ETHSendComms::enqueue_msg_send(std::shared_ptr send_msg) { + spdlog::debug("Enqueing msg"); + std::unique_lock lk(_send_msg_queue.mtx); + _send_msg_queue.deque.push_back(send_msg); + _send_msg_queue.cv.notify_all(); + } + + void ETHSendComms::_handle_send_msg_from_queue() { + std::deque> temp_msg_queue; + while(_running) { + /* transfer messages to temp queue for duration of lock */ + { + std::unique_lock lk(_send_msg_queue.mtx); + _send_msg_queue.cv.wait(lk, [this]() { return !_send_msg_queue.deque.empty() || !_running; }); + + if(!_running) { + break; + } + + _send_msg_queue.deque.swap(temp_msg_queue); + } + + for (const auto &msg : temp_msg_queue) { + _send_message(msg); + } + + temp_msg_queue.clear(); + } + } + + void ETHSendComms::_send_message(std::shared_ptr msg_out) { + spdlog::info("sending ethernet message"); + msg_out->SerializeToArray(_send_buffer.data(), msg_out->ByteSizeLong()); + _socket.async_send_to(boost::asio::buffer(_send_buffer, msg_out->ByteSizeLong()), + _send_endp, + [](const boost::system::error_code &error, std::size_t bytes_transferred) + { + if (error) { + spdlog::error("async send failed: {}", error.message()); + } else { + spdlog::debug("async send completed: {} bytes.", bytes_transferred); + } + }); + } + +} + diff --git a/drivebrain_core/include/Configurable.hpp b/drivebrain_core/include/Configurable.hpp deleted file mode 100644 index fabca52..0000000 --- a/drivebrain_core/include/Configurable.hpp +++ /dev/null @@ -1,44 +0,0 @@ -#include -#include -#include -#include -#include - -namespace core { - using ParamType = std::variant; - - template - struct Param { - T val; - }; - - template - class Configurable { - public: - std::string name() { return _name; } - bool register_param() {} - std::unordered_map get_params(); - - - private: - std::string _name; - std::unordered_map _params; - - std::mutex mtx; - friend ParamStruct; - }; - - - /* Syntax-sugar macros for cleanly defining and registering params */ - - #define BEGIN_PARAMS(StructName) \ - struct StructName { \ - template \ - void register_all(ConfigType* self) { - - - - #define END_PARAMS() \ - } \ - }; -} diff --git a/drivebrain_core/include/DriverBus.hpp b/drivebrain_core/include/DriverBus.hpp index b4dcc6b..29e0363 100644 --- a/drivebrain_core/include/DriverBus.hpp +++ b/drivebrain_core/include/DriverBus.hpp @@ -4,14 +4,6 @@ #include #include - -// what this should do: -// should contain the instances of the thread-safe deques, contain the thread(s) -// for communication and manage the routing of messages - -// threading paradigm (for now): -// we will still need to have threads within the drivers themselves since otherwise we wont be able to easily wait on - namespace core { template diff --git a/drivebrain_core/include/FoxgloveServer.hpp b/drivebrain_core/include/FoxgloveServer.hpp index b34023e..2aeac64 100644 --- a/drivebrain_core/include/FoxgloveServer.hpp +++ b/drivebrain_core/include/FoxgloveServer.hpp @@ -1,19 +1,25 @@ -#ifndef ETHERNET_RECEIVE_COMMS_H - -#define ETHERNET_RECEIVE_COMMS_H +#pragma once +#include #include +#include #include #include #include +#include +#include #include #include +#include +#include #include #include #include #include #include #include +#include +#include #include "hytech_msgs.pb.h" @@ -33,13 +39,18 @@ namespace core { * @retun FoxgloveServer instance */ static FoxgloveServer& instance(); + + /** + * Destroys the Foxglove server singleton instance, stopping the server and freeing resources + */ + static void destroy(); /** * Destructs the foxglove server instance by stopping the server. */ ~FoxgloveServer() { _server->stop(); - std::cout << "Destructed and stopped foxglove websocket server" << std::endl; + spdlog::info("Destructed and stopped foxglove websocket server"); } /** @@ -51,27 +62,50 @@ namespace core { */ void send_live_telem_msg(std::shared_ptr msg); + /** + * Registers a callback function to be run whenever a parameter is updated in Foxglove. + * @param The function to be reigstered, which takes the form of (const string, param) -> void + * @return The newly created boost connection + */ + boost::signals2::connection register_param_callback(std::function&)> callback); + + /** + * Returns all the current parameter values in a JSON format. Mostly used to log the current parameters in an MCAP file + */ + nlohmann::json get_all_params(); + /** * Thread-safe method to get a foxglove param * * @param param_name name of the parameter the user wants to get * @return the parameter value */ - // TODO: investigate the type conversion conflicts that arrise from this template - param_type get_param(std::string param_name) { + std::optional get_param(std::string param_name) { + std::unique_lock lock(_parameter_mutex); + std::transform(param_name.begin(), param_name.end(), param_name.begin(), + [](unsigned char c){ return static_cast(std::tolower(c)); }); - // if (_foxglove_params_map.find(param_name) == _foxglove_params_map.end()) { - // return NULL; - // } - - return _foxglove_params_map.at(param_name).getValue(); + if (_foxglove_params_map.find(param_name) == _foxglove_params_map.end()) { + spdlog::warn("The following parameter was not found in the params json: " + param_name); + return std::nullopt; + } + + try { + return _foxglove_params_map[param_name].getValue(); + } catch (const std::exception& e) { + spdlog::warn("Incorrect parameter type for param {}: {}", param_name, e.what()); + return std::nullopt; + } } private: FoxgloveServer(std::string parameters_file); + /* Registers JSON params on init. Recursively called to support multi-level JSON */ + void _init_params(const nlohmann::json &json_obj, const std::string &prefix); + /* Singleton move semantics */ FoxgloveServer(const FoxgloveServer&) = delete; FoxgloveServer& operator=(const FoxgloveServer&) = delete; @@ -79,6 +113,12 @@ namespace core { /* Singleton instance */ inline static std::atomic _s_instance; + /* Boost signal for parameter updates */ + boost::signals2::signal&)> _param_update_signal; + + /* Method to handle converting foxglove params to avoid type conflicts */ + std::optional _convert_foxglove_parameter(foxglove::Parameter current_param, foxglove::Parameter incoming_param); + std::unordered_map _foxglove_params_map; std::unordered_map _name_to_id_map; @@ -89,4 +129,3 @@ namespace core { }; } -#endif // ETHERNET_RECEIVE_COMMS_H diff --git a/drivebrain_core/include/LapTracker.hpp b/drivebrain_core/include/LapTracker.hpp index 319f8b6..73d9930 100644 --- a/drivebrain_core/include/LapTracker.hpp +++ b/drivebrain_core/include/LapTracker.hpp @@ -2,8 +2,6 @@ #include #include -// TODO Add any imports you might think are neccesary here - namespace core { class LapTracker { @@ -40,8 +38,24 @@ namespace core { /** Internal State */ inline static std::atomic _s_instance; - // TODO put variables here to keep track of the lap tracker's internal state + // Race start configs + bool _started = false; + double _start_lat; + double _start_lon; + + // Mid-Lap tracking variables + float _laptime = 0.0f; + float _max_lap_speed = 0.0f; + float _min_lap_speed = 0.0f; + + // Total Lap Metrics + int _lapcount = 0; + float _best_laptime = 0.0f; + float _last_laptime = 0.0f; + float _delta = 0.0f; + core::VehicleState _previous_state; + std::chrono::steady_clock::time_point _last_timestamp; }; } \ No newline at end of file diff --git a/drivebrain_core/include/MCAPLogger.hpp b/drivebrain_core/include/MCAPLogger.hpp index 48b32ea..d8fad41 100644 --- a/drivebrain_core/include/MCAPLogger.hpp +++ b/drivebrain_core/include/MCAPLogger.hpp @@ -1,3 +1,5 @@ +#pragma once + #include #include #include @@ -9,6 +11,7 @@ #include #include #include +#include #include namespace core { @@ -30,7 +33,7 @@ namespace core { * @param base_dir the directory in which the log file should be created * @param options options to create the mcap with */ - static void create(const std::string &base_dir, const mcap::McapWriterOptions &options); + static void create(const std::string &base_dir, const mcap::McapWriterOptions &options, const std::string ¶ms_file); /** * Fetches MCAPLogger singleton instance @@ -38,6 +41,11 @@ namespace core { * @retun MCAPLogger instance */ static MCAPLogger& instance(); + + /** + * Destroys the MCAPLogger singleton instance, stopping logging and freeing resources + */ + static void destroy(); /** * Destructs MCAPLogger instance, frees singleton instance and joins all running log threads @@ -51,6 +59,7 @@ namespace core { spdlog::info("Msg logger singleton instance released"); _param_cv.notify_all(); + _input_buffer_cv.notify_all(); if(_param_log_thread.joinable()) _param_log_thread.join(); if(_msg_log_thread.joinable()) _msg_log_thread.join(); } @@ -106,16 +115,17 @@ namespace core { int log_msg(MsgType message); /** - * Logs the json params to the current MCAP file. Doesn't need an input because the schema has already been created. - * + * Logs the json params to the current MCAP file + * + * @param The parameters to be logged, in JSON format * @return 0 on success, negative err code on failure */ - int log_params(); + int log_params(nlohmann::json params); private: /* Private constructor to be called by init method */ - MCAPLogger(const std::string &base_dir, const mcap::McapWriterOptions &options); + MCAPLogger(const std::string &base_dir, const mcap::McapWriterOptions &options, const std::string ¶ms_file); /** * Spawned by thread, loops until end of program life or error occurs. @@ -123,12 +133,6 @@ namespace core { */ void _handle_log_to_file(); - /** - * Spawned by thread, loops until end of program life or error occurs. - * Logs all active params. - */ - void _handle_param_log(); - /* Singleton move semantics */ MCAPLogger(const MCAPLogger&) = delete; MCAPLogger& operator=(const MCAPLogger&) = delete; @@ -152,9 +156,10 @@ namespace core { mcap::McapWriterOptions _options; /* State */ + nlohmann::json _params_schema_json; + nlohmann::json _initial_params; std::unordered_map _name_to_id_map; std::string _log_name = "NONE"; - bool _param_schema_written = false; bool _logging = false; bool _running = true; diff --git a/drivebrain_core/include/StateTracker.hpp b/drivebrain_core/include/StateTracker.hpp index bb24a71..3d5ec01 100644 --- a/drivebrain_core/include/StateTracker.hpp +++ b/drivebrain_core/include/StateTracker.hpp @@ -14,6 +14,18 @@ #include "hytech_msgs.pb.h" #include "hytech.pb.h" +// Tolerance for crossing finish line. Equal to ~3 meters of tolerance in latitude and longitude. +#define FINISH_LINE_POSITION_TOLERANCE 0.000027 +// Error for wheels to be considered stationary +#define STATIONARY_WHEEL_ERROR 0.001 +// Minimum rpm for car to be considered "racing" +#define MINIMUM_WHEEL_ROTATION 10 +// Minimum speed m/s for car to be considered "racing" +#define MINIMUM_CAR_SPEED 0.2 +// Minimum laptime to be considered valid to prevent false positive of lap completion +#define MINIMUM_LAPTIME 10.0f + + /** * The state tracker acts * as a thread-safe translation unit @@ -225,21 +237,21 @@ namespace core { struct VehicleState { bool is_ready_to_drive; DriverInput input; - xyz_vec current_body_vel_ms; - xyz_vec current_body_accel_mss; - xyz_vec current_angular_rate_rads; - ypr_vec current_ypr_rad; - veh_vec current_rpms; + xyz_vec current_body_vel_ms; // velocity + xyz_vec current_body_accel_mss; // accel + xyz_vec current_angular_rate_rads; // spin speed + ypr_vec current_ypr_rad; // orientation + veh_vec current_rpms; // wheel rotation speed veh_vec motor_overload_percentages; bool state_is_valid; - int prev_MCU_recv_millis; + int prev_MCU_recv_millis; // watchdog timer float steering_angle_deg; ControllerOutput prev_controller_output; TireDynamics tire_dynamics; veh_vec driver_torque; ControllerTorqueOut matlab_math_temp_out; veh_vec suspension_potentiometers_mm; - Position vehicle_position; + Position vehicle_position; // coords relative to start? veh_vec loadcells; veh_vec current_torques_nm; INSStatus ins_status; diff --git a/drivebrain_core/src/FoxgloveServer.cpp b/drivebrain_core/src/FoxgloveServer.cpp index d115d35..171d4d6 100644 --- a/drivebrain_core/src/FoxgloveServer.cpp +++ b/drivebrain_core/src/FoxgloveServer.cpp @@ -1,4 +1,13 @@ #include +#include +#include + + +static std::string to_lowercase(std::string s) { + std::transform(s.begin(), s.end(), s.begin(), + [](unsigned char c){ return static_cast(std::tolower(c)); }); + return s; +} static uint64_t nanosecondsSinceEpoch() { return uint64_t(std::chrono::duration_cast( @@ -6,7 +15,6 @@ static uint64_t nanosecondsSinceEpoch() { .count()); } - static std::vector get_pb_descriptors(const std::vector &filenames) { std::vector descriptors; @@ -14,7 +22,7 @@ static std::vector get_pb_descriptors( const google::protobuf::FileDescriptor *file_descriptor = google::protobuf::DescriptorPool::generated_pool()->FindFileByName(name); if (!file_descriptor) { - std::cout << "File descriptor not found" << std::endl; + spdlog::error("File descriptor not found {}", name); } else { descriptors.push_back(file_descriptor); @@ -61,36 +69,59 @@ core::FoxgloveServer& core::FoxgloveServer::instance() { return *instance; } +void core::FoxgloveServer::destroy() { + FoxgloveServer* instance = _s_instance.exchange(nullptr, std::memory_order_acq_rel); + if (instance) { + delete instance; + } +} + +void core::FoxgloveServer::_init_params(const nlohmann::json &json_obj, const std::string &prefix) { + for (auto &[key, value] : json_obj.items()) { + std::string param_name = prefix.empty() ? to_lowercase(key) : prefix + "/" + to_lowercase(key); + + if (value.type() == nlohmann::detail::value_t::object) { + _init_params(value, param_name); + } else { + foxglove::ParameterValue param_value; + if (value.type() == nlohmann::detail::value_t::boolean) { + bool raw_value = value.get(); + param_value = foxglove::ParameterValue(raw_value); + } else if (value.type() == nlohmann::detail::value_t::number_float) { + float raw_value = value.get(); + param_value = foxglove::ParameterValue(raw_value); + } else if (value.type() == nlohmann::detail::value_t::number_integer || value.type() == nlohmann::detail::value_t::number_unsigned) { + int64_t raw_value = value.get(); + param_value = foxglove::ParameterValue(raw_value); + } else if (value.type() == nlohmann::detail::value_t::string) { + std::string raw_value = value.get(); + param_value = foxglove::ParameterValue(raw_value); + } else { + spdlog::error("Invalid parameter config type: {} for key: {}", value.type_name(), param_name); + continue; + } + + if (_foxglove_params_map.find(param_name) != _foxglove_params_map.end()) { + spdlog::warn("Duplicate parameter detected: {}", param_name); + } else { + _foxglove_params_map[param_name] = param_value; + spdlog::info("Added parameter: {}", param_name); + } + } + } +} + core::FoxgloveServer::FoxgloveServer(std::string file_name) { // Read params data std::fstream params_file(file_name); nlohmann::json init_param_data = nlohmann::json::parse(params_file); - for (auto &[key, value]: init_param_data.items()) { - std::string param_name = key; - foxglove::ParameterValue param_value; - if (value.type() == nlohmann::detail::value_t::boolean) { - bool raw_value = value.get(); - param_value = foxglove::ParameterValue(raw_value); - } else if (value.type() == nlohmann::detail::value_t::number_float) { - float raw_value = value.get(); - param_value = foxglove::ParameterValue(raw_value); - } else if (value.type() == nlohmann::detail::value_t::number_integer || value.type() == nlohmann::detail::value_t::number_unsigned) { - int64_t raw_value = value.get(); - param_value = foxglove::ParameterValue(raw_value); - } else { - std::cerr << "Invalid parameter config type: " << value.type_name() << std::endl; - return; - } - - _foxglove_params_map[param_name] = param_value; - std::cout << "Added parameter: " << param_name << std::endl; - } + _init_params(init_param_data, ""); // Instantiate handlers and create foxglove server const auto logHandler = [](foxglove::WebSocketLogLevel, char const *msg) { - std::cout << msg << std::endl; + spdlog::info("{}", msg); }; _server_options.capabilities.push_back("parameters"); @@ -100,32 +131,38 @@ core::FoxgloveServer::FoxgloveServer(std::string file_name) { hdlrs.subscribeHandler = [&](foxglove::ChannelId chanId, foxglove::ConnHandle clientHandle) { const auto clientStr = _server->remoteEndpointString(clientHandle); - std::cout << "Client " << clientStr << " subscribed to " << chanId << std::endl; + spdlog::info("Client {} subscribed to {}", clientStr, chanId); }; hdlrs.unsubscribeHandler = [&](foxglove::ChannelId chanId, foxglove::ConnHandle clientHandle) { const auto clientStr = _server->remoteEndpointString(clientHandle); - std::cout << "Client " << clientStr << " unsubscribed from " << chanId << std::endl; + spdlog::info("Client {} unsubscribed from {}", clientStr, chanId); }; hdlrs.parameterChangeHandler = [&](const std::vector ¶ms, const std::optional &request_id, foxglove::ConnHandle clientHandle) { - - std::unordered_map params_map; - - for (const auto ¶m_to_change : params) { - params_map[param_to_change.getName()] = param_to_change.getValue(); - } - + std::unordered_map param_copy; { - std::unique_lock lock(_parameter_mutex); - _foxglove_params_map = std::move(params_map); + std::unique_lock lock(_parameter_mutex); + for (const auto &incoming_param : params) { + if (_foxglove_params_map.find(incoming_param.getName()) == _foxglove_params_map.end()) { + spdlog::warn("Couldn't find updated param in params map. Please get good."); + continue; + } + foxglove::Parameter current_param = foxglove::Parameter(incoming_param.getName(), _foxglove_params_map[incoming_param.getName()]); + std::optional converted_param = _convert_foxglove_parameter(current_param, incoming_param); + if (converted_param) { + _foxglove_params_map[incoming_param.getName()] = converted_param.value().getValue(); + } + } + param_copy = _foxglove_params_map; } + MCAPLogger::instance().log_params(get_all_params()); /* Needed for showing param updates in the outputted MCAP file */ + _param_update_signal(param_copy); }; hdlrs.parameterRequestHandler = [this](const std::vector ¶m_names, const std::optional &request_id, - foxglove::ConnHandle clientHandle) - { + foxglove::ConnHandle clientHandle) { std::vector foxglove_params; for (auto &[key, value] : _foxglove_params_map) { foxglove::Parameter param(key, value); @@ -134,20 +171,22 @@ core::FoxgloveServer::FoxgloveServer(std::string file_name) { _server->publishParameterValues(clientHandle, foxglove_params, request_id); }; - auto descriptors = get_pb_descriptors({"hytech_msgs.proto"}); + auto descriptors = get_pb_descriptors({"hytech.proto"}); std::vector channels; + int running_index = 1; for (const auto &file_descriptor : descriptors) { - for (int i = 1; i <= file_descriptor->message_type_count(); ++i) { + for (int i = 0; i < file_descriptor->message_type_count(); ++i) { const google::protobuf::Descriptor *message_descriptor = file_descriptor->message_type(i); foxglove::ChannelWithoutId server_channel; server_channel.topic = message_descriptor->name(); server_channel.encoding = "protobuf"; server_channel.schemaName = message_descriptor->full_name(); server_channel.schema = foxglove::base64Encode(SerializeFdSet(message_descriptor)); - _name_to_id_map[server_channel.topic] = i; + _name_to_id_map[server_channel.topic] = running_index; channels.push_back(server_channel); + running_index++; } } @@ -159,6 +198,48 @@ core::FoxgloveServer::FoxgloveServer(std::string file_name) { params_file.close(); } +boost::signals2::connection core::FoxgloveServer::register_param_callback(std::function &)> callback) { + return _param_update_signal.connect(callback); +} + +nlohmann::json core::FoxgloveServer::get_all_params() { + std::unique_lock lock(_parameter_mutex); + nlohmann::json params_json; + params_json["type"] = "object"; + + for (const auto& [name, param_value] : _foxglove_params_map) { + auto type = param_value.getType(); + + if (type == foxglove::ParameterType::PARAMETER_BOOL) { + params_json[name] = param_value.getValue(); + } + else if (type == foxglove::ParameterType::PARAMETER_DOUBLE) { + params_json[name] = param_value.getValue(); + } + else if (type == foxglove::ParameterType::PARAMETER_INTEGER) { + params_json[name] = param_value.getValue(); + } + else if (type == foxglove::ParameterType::PARAMETER_STRING) { + params_json[name] = param_value.getValue(); + } + } + + return params_json; +} + +std::optional core::FoxgloveServer::_convert_foxglove_parameter(foxglove::Parameter current_param, foxglove::Parameter incoming_param) { + if (current_param.getType() == incoming_param.getType()) { + return incoming_param; + } else if (current_param.getType() == foxglove::ParameterType::PARAMETER_INTEGER && incoming_param.getType() == foxglove::ParameterType::PARAMETER_DOUBLE) { + return foxglove::Parameter(current_param.getName(), static_cast(incoming_param.getValue().getValue())); + } else if (current_param.getType() == foxglove::ParameterType::PARAMETER_DOUBLE && incoming_param.getType() == foxglove::ParameterType::PARAMETER_INTEGER) { + return foxglove::Parameter(current_param.getName(), static_cast(incoming_param.getValue().getValue())); + } else { + spdlog::warn("Invalid parameter type conversion!"); + return std::nullopt; + } +} + void core::FoxgloveServer::send_live_telem_msg(std::shared_ptr msg) { auto msg_chan_id = _name_to_id_map[msg->GetDescriptor()->name()]; const auto serialized_msg = msg->SerializeAsString(); diff --git a/drivebrain_core/src/LapTracker.cpp b/drivebrain_core/src/LapTracker.cpp index 70c9b36..a646ea7 100644 --- a/drivebrain_core/src/LapTracker.cpp +++ b/drivebrain_core/src/LapTracker.cpp @@ -1,16 +1,82 @@ #include void core::LapTracker::step_tracker(core::VehicleState& latest_state) { - std::shared_ptr laptime_information = std::make_shared(); // TODO you need to fill in the fields of this protobuf message - /** - * TODO it is your responsibility to fill in this method. Look at the VehicleState - * struct to see all the things it gives you (you should see vn position from there). Using this - * and the private variables you added in the header, complete this method. It should use all of the information - * in the latest state to update it's local variables, create a LapTime protobuf, and invoke handle_receive_protobuf_message - * on the state tracker. Some of this is completed for you. Good luck! - */ - core::StateTracker::instance().handle_receive_protobuf_message(laptime_information); // What "records" the information + std::shared_ptr laptime_information = std::make_shared(); + // Create time differential + auto now = std::chrono::steady_clock::now(); + float time_differential = std::chrono::duration(now - _last_timestamp).count(); + _last_timestamp = now; + + // Logic if car has NOT started racing yet + if (!_started) { + if (latest_state.is_ready_to_drive) { + + bool car_stationary = std::abs(latest_state.current_rpms.FL) < STATIONARY_WHEEL_ERROR + && std::abs(latest_state.current_rpms.FR) < STATIONARY_WHEEL_ERROR + && std::abs(latest_state.current_rpms.RL) < STATIONARY_WHEEL_ERROR + && std::abs(latest_state.current_rpms.RR) < STATIONARY_WHEEL_ERROR + && (std::sqrt(std::pow(latest_state.current_body_vel_ms.x, 2) + std::pow(latest_state.current_body_vel_ms.y, 2)) < MINIMUM_CAR_SPEED); + bool car_racing = std::abs(latest_state.current_rpms.FL) > MINIMUM_WHEEL_ROTATION + && std::abs(latest_state.current_rpms.FR) > MINIMUM_WHEEL_ROTATION + && std::abs(latest_state.current_rpms.RL) > MINIMUM_WHEEL_ROTATION + && std::abs(latest_state.current_rpms.RR) > MINIMUM_WHEEL_ROTATION + && (std::sqrt(std::pow(latest_state.current_body_vel_ms.x, 2) + std::pow(latest_state.current_body_vel_ms.y, 2)) > MINIMUM_CAR_SPEED); + + // If the car is stationary, assume it is in the start box and set the start line latitutde and longitude position + // Elif the car is moving, assume it has started racing + if (car_stationary) { + _start_lat = latest_state.vehicle_position.lat; + _start_lon = latest_state.vehicle_position.lon; + } else if (car_racing) { + _started = true; + } + } + + // Logic if the car has already started racing + } else { + + _laptime += time_differential; + float current_speed = std::sqrt(std::pow(latest_state.current_body_vel_ms.x, 2) + std::pow(latest_state.current_body_vel_ms.y, 2)); + + bool crossed_start_lattitude = (_previous_state.vehicle_position.lat <= _start_lat && latest_state.vehicle_position.lat >= _start_lat) + || (latest_state.vehicle_position.lat <= _start_lat && _previous_state.vehicle_position.lat >= _start_lat); + bool crossed_start_longitude = (_previous_state.vehicle_position.lon <= _start_lon && latest_state.vehicle_position.lon >= _start_lon) + || (latest_state.vehicle_position.lon <= _start_lon && _previous_state.vehicle_position.lon >= _start_lon); + bool within_start_lattitude_tolerance = std::abs(latest_state.vehicle_position.lat - _start_lat) <= FINISH_LINE_POSITION_TOLERANCE; + bool within_start_longitude_tolerance = std::abs(latest_state.vehicle_position.lon - _start_lon) <= FINISH_LINE_POSITION_TOLERANCE; + + // If the car has started has passed the start box, assume the car has completed a lap and update/reset lap metrics accordingly + // Else the car has started but is not at the start line, so update mid-lap metrics normally + if ((_laptime > MINIMUM_LAPTIME) && ((crossed_start_lattitude && crossed_start_longitude) || (crossed_start_lattitude && within_start_longitude_tolerance) || (crossed_start_longitude && within_start_lattitude_tolerance))) { + + _delta = _best_laptime > 0.0f ? _laptime - _best_laptime : 0.0f; + if (_best_laptime == 0.0f || _laptime < _best_laptime) { + _best_laptime = _laptime; + } + _last_laptime = _laptime; + + _max_lap_speed = _min_lap_speed = current_speed; + _lapcount++; + _laptime = 0.0f; + + } else { + _max_lap_speed = std::max(current_speed, _max_lap_speed); + _min_lap_speed = std::min(current_speed, _min_lap_speed); + } + } + + _previous_state = latest_state; + + // Create a lap time information protobuf and send it to the state tracker + laptime_information->set_laptime_seconds(_laptime); + laptime_information->set_live_delta(_delta); // TODO: Make this live delta instead of just delta against best lap + laptime_information->set_best_laptime_seconds(_best_laptime); + laptime_information->set_last_laptime_seconds(_last_laptime); + laptime_information->set_lapcount(_lapcount); + laptime_information->set_max_lap_speed_ms(_max_lap_speed); + laptime_information->set_min_lap_speed_ms(_min_lap_speed); + core::StateTracker::instance().handle_receive_protobuf_message(laptime_information); } void core::LapTracker::create() { @@ -28,3 +94,9 @@ core::LapTracker& core::LapTracker::instance() { return *instance; } + + + + + + diff --git a/drivebrain_core/src/MCAPLogger.cpp b/drivebrain_core/src/MCAPLogger.cpp index 2aaa112..772dc3b 100644 --- a/drivebrain_core/src/MCAPLogger.cpp +++ b/drivebrain_core/src/MCAPLogger.cpp @@ -1,7 +1,7 @@ +#define MCAP_IMPLEMENTATION #include #include -#include -#define MCAP_IMPLEMENTATION +#include #include @@ -15,7 +15,7 @@ static std::vector get_pb_descriptors( const google::protobuf::FileDescriptor *file_descriptor = google::protobuf::DescriptorPool::generated_pool()->FindFileByName(name); if (!file_descriptor) { - std::cout << "File descriptor not found" << std::endl; + spdlog::error("File descriptor not found: {}", name); } else { descriptors.push_back(file_descriptor); @@ -50,14 +50,43 @@ static std::string serialize_fd_set(const google::protobuf::Descriptor *toplevel static std::string create_log_name() { } + +static nlohmann::json generate_json_schema(const nlohmann::json& obj) { + nlohmann::json schema; + + if (obj.is_object()) { + schema["type"] = "object"; + schema["properties"] = nlohmann::json::object(); + for (auto& [key, value] : obj.items()) { + schema["properties"][key] = generate_json_schema(value); + } + } else if (obj.is_array()) { + schema["type"] = "array"; + if (!obj.empty()) { + schema["items"] = generate_json_schema(obj[0]); + } + } else if (obj.is_boolean()) { + schema["type"] = "boolean"; + } else if (obj.is_number_integer()) { + schema["type"] = "integer"; + } else if (obj.is_number_float()) { + schema["type"] = "number"; + } else if (obj.is_string()) { + schema["type"] = "string"; + } else if (obj.is_null()) { + schema["type"] = "null"; + } + + return schema; +} /**************************************************************** * PUBLIC CLASS METHOD IMPLEMENTATIONS ****************************************************************/ -void core::MCAPLogger::create(const std::string &base_dir, const mcap::McapWriterOptions &options) { +void core::MCAPLogger::create(const std::string &base_dir, const mcap::McapWriterOptions &options, const std::string ¶ms_file) { MCAPLogger* expected = nullptr; - MCAPLogger* local = new MCAPLogger(base_dir, options); + MCAPLogger* local = new MCAPLogger(base_dir, options, params_file); if(!_s_instance.compare_exchange_strong(expected, local, std::memory_order_release, std::memory_order_relaxed)) { // Already initialized, delete local instance delete local; @@ -70,12 +99,19 @@ core::MCAPLogger& core::MCAPLogger::instance() { return *instance; } +void core::MCAPLogger::destroy() { + MCAPLogger* instance = _s_instance.exchange(nullptr, std::memory_order_acq_rel); + if (instance) { + delete instance; + } +} + int core::MCAPLogger::open_new_mcap(const std::string &name) { - std::cout << "Attempting to open new MCAP file" << std::endl; + spdlog::info("Attempting to open new MCAP file"); const auto res = _writer.open(name, _options); if (!res.ok()) { - std::cout << "Failed to open MCAP :(" << std::endl; + spdlog::error("Failed to open MCAP :("); return -1; } @@ -83,7 +119,7 @@ int core::MCAPLogger::open_new_mcap(const std::string &name) { auto descriptors = get_pb_descriptors(proto_names); for (const auto &file_descriptor : descriptors) { - for (int i = 1; i <= file_descriptor->message_type_count(); i++) { + for (int i = 0; i < file_descriptor->message_type_count(); i++) { const google::protobuf::Descriptor *message_descriptor = file_descriptor->message_type(i); mcap::Schema schema(message_descriptor->full_name(), "protobuf", serialize_fd_set(message_descriptor)); _writer.addSchema(schema); @@ -94,12 +130,23 @@ int core::MCAPLogger::open_new_mcap(const std::string &name) { } } - std::cout << "Successfully opened and added message descriptions to mcap" << std::endl; + spdlog::info("Successfully added message descriptions to mcap"); + + mcap::Schema config_schema("drivebrain_configuration", "jsonschema", _params_schema_json.dump()); + _writer.addSchema(config_schema); + mcap::Channel config_channel("drivebrain_configuration", "json", config_schema.id); + _writer.addChannel(config_channel); + _name_to_id_map["drivebrain_configuration"] = config_channel.id; + + log_params(_initial_params); + + spdlog::info("Successfully added params schema"); + return 0; } int core::MCAPLogger::close_active_mcap() { - std::cout << "Closing mcap" << std::endl; + spdlog::info("Closing mcap"); _writer.close(); return 0; @@ -108,9 +155,6 @@ int core::MCAPLogger::close_active_mcap() { void core::MCAPLogger::init_logging() { _msg_log_thread = std::thread([this]() { _handle_log_to_file(); }); spdlog::info("Msg log thread spawned"); - _param_log_thread = std::thread([this]() { _handle_param_log(); }); - spdlog::info("Param log thread spawned"); - _logging = true; } @@ -124,7 +168,7 @@ int core::MCAPLogger::log_msg(core::MsgType message) { std::unique_lock lock(_input_buffer_mutex); _input_buffer.push_back(new_message); _input_buffer_cv.notify_one(); - } + } return 0; } @@ -132,8 +176,11 @@ int core::MCAPLogger::log_msg(core::MsgType message) { /**************************************************************** * PRIVATE CLASS METHOD IMPLEMENTATIONS ****************************************************************/ -core::MCAPLogger::MCAPLogger(const std::string &base_dir, const mcap::McapWriterOptions &options) : _options(options) { - // TODO: spawn logging thread +core::MCAPLogger::MCAPLogger(const std::string &base_dir, const mcap::McapWriterOptions &options, const std::string ¶ms_file) : _options(options) { + std::fstream raw_param_file(params_file); + nlohmann::json params_config = nlohmann::json::parse(raw_param_file); + _initial_params = params_config; // Used in open_new_mcap to log initial params + _params_schema_json = generate_json_schema(params_config); } void core::MCAPLogger::_handle_log_to_file() { @@ -143,7 +190,7 @@ void core::MCAPLogger::_handle_log_to_file() { { std::unique_lock lock(_input_buffer_mutex); _input_buffer_cv.wait(lock, [this](){ return !_input_buffer.empty() || !_running;}); - if (_running && _input_buffer.empty()) { + if (!_running && _input_buffer.empty()) { break; } @@ -160,20 +207,24 @@ void core::MCAPLogger::_handle_log_to_file() { msg_to_log.channelId = _name_to_id_map[msg.message_name]; auto write_res = _writer.write(msg_to_log); - } + write_buffer.clear(); } } -void core::MCAPLogger::_handle_param_log() { - std::chrono::seconds param_log_time(1); - while(true) { - std::unique_lock lk(_param_mutex); - if(_param_cv.wait_for(lk, param_log_time, [this] { return !_logging; }) || !_running) { - spdlog::info("Logging stopped/logger is no longer running. Exiting..."); - return; - } +int core::MCAPLogger::log_params(nlohmann::json params) { + mcap::Timestamp log_time = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); + RawMessage_s msg; + msg.log_time = log_time; + msg.serialized_data = params.dump(); + msg.message_name = "drivebrain_configuration"; + { + std::unique_lock lock(_input_buffer_mutex); + _input_buffer.push_back(std::move(msg)); + _input_buffer_cv.notify_one(); } + + return 0; } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 019dacd..5fb4e5a 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -2,10 +2,11 @@ # Unit Testing ################################# +find_package(GTest REQUIRED) + add_executable(drivebrain_test main.cpp MCAPLoggerTest.cpp - EthernetCommsTest.cpp ) target_link_libraries(drivebrain_test PUBLIC diff --git a/tests/EthernetCommsTest.cpp b/tests/EthernetCommsTest.cpp index 941d378..f54e377 100644 --- a/tests/EthernetCommsTest.cpp +++ b/tests/EthernetCommsTest.cpp @@ -1,57 +1,57 @@ -#include "base_msgs.pb.h" -#include "hytech_msgs.pb.h" -#include -#include -#include -#include -#include -#include - -class EthernetSendTest : public testing::Test { - -protected: - boost::asio::io_context io_context; - std::thread io_thread; - comms::ETHDriver<> eth_sender{io_context, 1155, "127.0.0.1"}; - - void SetUp() override { - io_thread = std::thread([this]() { - io_context.run(); - }); - } - - void TearDown() override { - io_context.stop(); - if (io_thread.joinable()) { - io_thread.join(); - } - } - -}; - -class EthernetDuplexTest : public EthernetSendTest { -protected: - comms::ETHDriver eth_transceiver{io_context, 1155}; -}; - -TEST_F(EthernetSendTest, SendSingleMsg) { - auto msg = std::make_shared(); - msg->set_drivebrain_controller_timing_failure(true); - - ASSERT_NO_THROW(eth_sender.enqueue_msg_send(msg)); -} - -TEST_F(EthernetSendTest, SendMultipleMsgs) { - auto msg = std::make_shared(); - for (int i = 0; i < 10; i++) { - msg->set_cell_voltages(0, i); - eth_sender.enqueue_msg_send(msg); - } +// #include "base_msgs.pb.h" +// #include "hytech_msgs.pb.h" +// #include +// #include +// #include +// #include +// #include +// #include + +// class EthernetSendTest : public testing::Test { + +// protected: +// boost::asio::io_context io_context; +// std::thread io_thread; +// comms::ETHDriver<> eth_sender{io_context, 1155, "127.0.0.1"}; + +// void SetUp() override { +// io_thread = std::thread([this]() { +// io_context.run(); +// }); +// } + +// void TearDown() override { +// io_context.stop(); +// if (io_thread.joinable()) { +// io_thread.join(); +// } +// } + +// }; + +// class EthernetDuplexTest : public EthernetSendTest { +// protected: +// comms::ETHDriver eth_transceiver{io_context, 1155}; +// }; + +// TEST_F(EthernetSendTest, SendSingleMsg) { +// auto msg = std::make_shared(); +// msg->set_drivebrain_controller_timing_failure(true); + +// ASSERT_NO_THROW(eth_sender.enqueue_msg_send(msg)); +// } + +// TEST_F(EthernetSendTest, SendMultipleMsgs) { +// auto msg = std::make_shared(); +// for (int i = 0; i < 10; i++) { +// msg->set_cell_voltages(0, i); +// eth_sender.enqueue_msg_send(msg); +// } - SUCCEED(); -} +// SUCCEED(); +// } -TEST_F(EthernetDuplexTest, SendRecvMsgs) { +// // TEST_F(EthernetDuplexTest, SendRecvMsgs) { -} +// // } diff --git a/tests/MCAPLoggerTest.cpp b/tests/MCAPLoggerTest.cpp index 975a7f6..631cbbc 100644 --- a/tests/MCAPLoggerTest.cpp +++ b/tests/MCAPLoggerTest.cpp @@ -9,7 +9,7 @@ class MCAPLoggerTest : public testing::Test { protected: MCAPLoggerTest() { - core::FoxgloveServer::create(TEST_CONFIG_DIR + std::string("/fake_foxglove_params.json")); + core::FoxgloveServer::create(TEST_CONFIG_DIR + std::string("/fake_foxglove_params.json")); }; }; diff --git a/drivebrain_simple_hil_test/src/debug_can.cpp b/tests/scripts/can/debug_can.cpp similarity index 99% rename from drivebrain_simple_hil_test/src/debug_can.cpp rename to tests/scripts/can/debug_can.cpp index 26ed033..72aca4f 100644 --- a/drivebrain_simple_hil_test/src/debug_can.cpp +++ b/tests/scripts/can/debug_can.cpp @@ -49,4 +49,4 @@ int main() { } return 0; -} \ No newline at end of file +} diff --git a/tests/scripts/can/test_can_comms.cpp b/tests/scripts/can/test_can_comms.cpp new file mode 100644 index 0000000..3f0ad82 --- /dev/null +++ b/tests/scripts/can/test_can_comms.cpp @@ -0,0 +1,51 @@ +#include +#include +#include +#include +#include + +comms::CANComms* primary_can; + +void thread1_send() { + while (true) { + std::shared_ptr torque_msg = std::make_shared(); + torque_msg->set_drivebrain_torque_fl(10.0); + torque_msg->set_drivebrain_torque_fr(20.0); + torque_msg->set_drivebrain_torque_rl(30.0); + torque_msg->set_drivebrain_torque_rr(40.0); + primary_can->send_message(torque_msg); + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + } +} + +void thread2_send() { + while (true) { + std::shared_ptr speed_msg = std::make_shared(); + speed_msg->set_drivebrain_set_rpm_fl(1.0); + speed_msg->set_drivebrain_set_rpm_fr(2.0); + speed_msg->set_drivebrain_set_rpm_rl(4.0); + speed_msg->set_drivebrain_set_rpm_rr(8.0); + primary_can->send_message(speed_msg); + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + } +} + +int main(int argc, char* argv[]) { + + // // Initialize can driver (second command line argument is the dbc file path) + // primary_can = new comms::CANComms("can_primary", argv[1]); + + // std::thread thread1(thread1_send); + // std::thread thread2(thread2_send); + + // while (true) { + // std::this_thread::sleep_for(std::chrono::milliseconds(5)); + // } + + // thread1.join(); + // thread2.join(); + + // delete primary_can; + + return 0; +} diff --git a/tests/scripts/run_mcap_logger.cpp b/tests/scripts/run_mcap_logger.cpp index 21f758d..b94125e 100644 --- a/tests/scripts/run_mcap_logger.cpp +++ b/tests/scripts/run_mcap_logger.cpp @@ -15,7 +15,7 @@ std::atomic running = true; void sig_handler(int signal) { if(signal == SIGINT) { - std::cout << "halting\n"; + spdlog::info("halting"); running = false; } } @@ -31,7 +31,7 @@ int main(int argc, char* argv[]) { core::FoxgloveServer::create(argv[1]); - core::MCAPLogger::create("recordings/", mcap::McapWriterOptions("")); + core::MCAPLogger::create("recordings/", mcap::McapWriterOptions(""), argv[1]); core::MCAPLogger::instance().open_new_mcap("test_1.mcap"); core::MCAPLogger::instance().init_logging(); diff --git a/tests/test_configs/fake_foxglove_params.json b/tests/test_configs/fake_foxglove_params.json index 7bacab3..c3f68cb 100644 --- a/tests/test_configs/fake_foxglove_params.json +++ b/tests/test_configs/fake_foxglove_params.json @@ -1,5 +1,11 @@ { "enable_logging": true, "rpm_limit": 10000, - "kP": 15000 + "kP": 15000, + "test": "yes", + "level_1" : { + "name": "Warren", + "kI": 2, + "is_based": true + } }