openpilot is an open source driver assistance system. openpilot performs the functions of Automated Lane Centering and Adaptive Cruise Control for over 200 supported car makes and models.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

381 lines
16 KiB

#include <stdint.h>
#include <stdbool.h>
#include "libc.h"
#include "stm32f4xx_hal.h"
#include "defines.h"
#include "config.h"
#include "setup.h"
#include "util.h"
#include "bldc/BLDC_controller.h" /* BLDC's header file */
#include "bldc/rtwtypes.h"
#include "version.h"
#include "obj/gitversion.h"
#include "comms.h"
#include "drivers/clock.h"
#include "early_init.h"
#include "drivers/i2c_soft.h"
#include "drivers/angle_sensor.h"
#include "boards.h"
//------------------------------------------------------------------------
// Global variables set externally
//------------------------------------------------------------------------
extern TIM_HandleTypeDef htim_left;
extern TIM_HandleTypeDef htim_right;
extern ADC_HandleTypeDef hadc;
extern volatile adc_buf_t adc_buffer;
// Matlab defines - from auto-code generation
//---------------
extern P rtP_Left; /* Block parameters (auto storage) */
extern P rtP_Right; /* Block parameters (auto storage) */
extern ExtY rtY_Left; /* External outputs */
extern ExtY rtY_Right; /* External outputs */
extern ExtU rtU_Left; /* External inputs */
extern ExtU rtU_Right; /* External inputs */
//---------------
// TODO: remove both, unneeded. Also func in util.c too
extern int16_t speedAvg; // Average measured speed
extern int16_t speedAvgAbs; // Average measured speed in absolute
extern volatile int pwml; // global variable for pwm left. -1000 to 1000
extern volatile int pwmr; // global variable for pwm right. -1000 to 1000
extern uint8_t enable_motors; // global variable for motor enable
extern int16_t batVoltage; // global variable for battery voltage
extern int32_t motPosL;
extern int32_t motPosR;
extern board_t board;
//------------------------------------------------------------------------
// Global variables set here in main.c
//------------------------------------------------------------------------
extern volatile uint32_t buzzerTimer;
volatile uint32_t torque_cmd_timeout = 0U;
volatile uint32_t ignition_off_counter = 0U;
uint16_t cnt_press = 0;
int16_t batVoltageCalib; // global variable for calibrated battery voltage
int16_t board_temp_deg_c; // global variable for calibrated temperature in degrees Celsius
volatile int16_t cmdL; // global variable for Left Command
volatile int16_t cmdR; // global variable for Right Command
uint8_t hw_type; // type of the board detected(0 - base, 3 - knee)
uint8_t ignition = 0; // global variable for ignition on SBU2 line
uint8_t charger_connected = 0; // status of the charger port
uint8_t pkt_idx = 0; // For CAN msg counter
//------------------------------------------------------------------------
// Local variables
//------------------------------------------------------------------------
static uint32_t tick_prev = 0U;
static uint32_t main_loop_1Hz = 0U;
static uint32_t main_loop_1Hz_runtime = 0U;
static uint32_t main_loop_10Hz = 0U;
static uint32_t main_loop_10Hz_runtime = 0U;
static uint32_t main_loop_100Hz = 0U;
static uint32_t main_loop_100Hz_runtime = 0U;
void __initialize_hardware_early(void) {
early_initialization();
}
int main(void) {
HAL_Init();
HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);
HAL_NVIC_SetPriority(MemoryManagement_IRQn, 0, 0);
HAL_NVIC_SetPriority(BusFault_IRQn, 0, 0);
HAL_NVIC_SetPriority(UsageFault_IRQn, 0, 0);
HAL_NVIC_SetPriority(SVCall_IRQn, 0, 0);
HAL_NVIC_SetPriority(DebugMonitor_IRQn, 0, 0);
HAL_NVIC_SetPriority(PendSV_IRQn, 0, 0);
HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
SystemClock_Config();
MX_GPIO_Clocks_Init();
__HAL_RCC_DMA2_CLK_DISABLE();
board_detect();
MX_GPIO_Common_Init();
MX_TIM_Init();
MX_ADC_Init();
BLDC_Init();
HAL_ADC_Start(&hadc);
if (hw_type == HW_TYPE_BASE) {
out_enable(POWERSWITCH, true);
out_enable(IGNITION, ignition);
out_enable(TRANSCEIVER, true);
// Loop until button is released, only for base board
while(HAL_GPIO_ReadPin(BUTTON_PORT, BUTTON_PIN)) { HAL_Delay(10); }
} else {
out_enable(POWERSWITCH, false);
ignition = 1;
knee_detected = 1;
}
// Reset LEDs on startup
out_enable(LED_RED, false);
out_enable(LED_GREEN, false);
out_enable(LED_BLUE, false);
llcan_set_speed(board.CAN, 5000, false, false);
llcan_init(board.CAN);
SW_I2C_init();
IMU_soft_init();
poweronMelody();
int32_t board_temp_adcFixdt = adc_buffer.temp << 16; // Fixed-point filter output initialized with current ADC converted to fixed-point
int16_t board_temp_adcFilt = adc_buffer.temp;
uint16_t sensor_angle[2] = { 0 };
uint16_t hall_angle_offset[2] = { 0 };
uint16_t unknown_imu_data[6] = { 0 };
if (hw_type == HW_TYPE_KNEE) {
angle_sensor_read(sensor_angle); // Initial data to set offsets between angle sensor and hall sensor
hall_angle_offset[0] = (sensor_angle[0] * ANGLE_TO_DEGREES);
hall_angle_offset[1] = (sensor_angle[1] * ANGLE_TO_DEGREES);
}
while(1) {
if ((HAL_GetTick() - tick_prev) >= 1) { // 1kHz loop
// runs at 100Hz
if ((HAL_GetTick() - (main_loop_100Hz - main_loop_100Hz_runtime)) >= 10) {
main_loop_100Hz_runtime = HAL_GetTick();
calcAvgSpeed();
if (ignition == 0) {
cmdL = cmdR = 0;
enable_motors = 0;
}
if (!enable_motors || (torque_cmd_timeout > 10)) {
cmdL = cmdR = 0;
}
if (ignition == 1 && enable_motors == 0 && (!rtY_Left.z_errCode && !rtY_Right.z_errCode) && (ABS(cmdL) < 50 && ABS(cmdR) < 50)) {
beepShort(6); // make 2 beeps indicating the motor enable
beepShort(4);
HAL_Delay(100);
cmdL = cmdR = 0;
enable_motors = 1; // enable motors
}
if (hw_type == HW_TYPE_KNEE) {
// Safety to stop operation if angle sensor reading failed TODO: adjust sensivity and add lowpass to angle sensor?
fault_status.left_angle = (ABS((hall_angle_offset[0] + ((motPosL / 15 / GEARBOX_RATIO_LEFT) % 360)) - (sensor_angle[0] * ANGLE_TO_DEGREES)) > 5);
fault_status.right_angle = (ABS((hall_angle_offset[1] + ((motPosR / 15 / GEARBOX_RATIO_RIGHT) % 360)) - (sensor_angle[1] * ANGLE_TO_DEGREES)) > 5);
if (fault_status.left_angle || fault_status.right_angle) {
cmdL = cmdR = 0;
}
// Safety to stop movement when reaching dead angles, around 20 and 340 degrees
if (((sensor_angle[0] < 900) && (cmdL < 0)) || ((sensor_angle[0] > 15500) && (cmdL > 0))) {
cmdL = 0;
}
if (((sensor_angle[1] < 900) && (cmdR < 0)) || ((sensor_angle[1] > 15500) && (cmdR > 0))) {
cmdR = 0;
}
}
if (ABS(cmdL) < 10) {
rtP_Left.n_cruiseMotTgt = 0;
rtP_Left.b_cruiseCtrlEna = 1;
} else {
rtP_Left.b_cruiseCtrlEna = 0;
if (hw_type == HW_TYPE_KNEE) {
pwml = -CLAMP((int)cmdL, -TRQ_LIMIT_LEFT, TRQ_LIMIT_LEFT);
} else {
pwml = CLAMP((int)cmdL, -TORQUE_BASE_MAX, TORQUE_BASE_MAX);
}
}
if (ABS(cmdR) < 10) {
rtP_Right.n_cruiseMotTgt = 0;
rtP_Right.b_cruiseCtrlEna = 1;
} else {
rtP_Right.b_cruiseCtrlEna = 0;
if (hw_type == HW_TYPE_KNEE) {
pwmr = -CLAMP((int)cmdR, -TRQ_LIMIT_RIGHT, TRQ_LIMIT_RIGHT);
} else {
pwmr = -CLAMP((int)cmdR, -TORQUE_BASE_MAX, TORQUE_BASE_MAX);
}
}
if (ignition_off_counter <= IGNITION_OFF_DELAY) {
// MOTORS_DATA: speed_L(2), speed_R(2), counter(1), checksum(1)
uint8_t dat[8];
uint16_t speedL = rtY_Left.n_mot;
uint16_t speedR = -(rtY_Right.n_mot); // Invert speed sign for the right wheel
dat[0] = (speedL >> 8U) & 0xFFU;
dat[1] = speedL & 0xFFU;
dat[2] = (speedR >> 8U) & 0xFFU;
dat[3] = speedR & 0xFFU;
dat[4] = 0;
dat[5] = 0;
dat[6] = pkt_idx;
dat[7] = crc_checksum(dat, 7, crc_poly);
can_send_msg((0x201U + board.can_addr_offset), ((dat[7] << 24U) | (dat[6] << 16U) | (dat[5]<< 8U) | dat[4]), ((dat[3] << 24U) | (dat[2] << 16U) | (dat[1] << 8U) | dat[0]), 8U);
++pkt_idx;
pkt_idx &= 0xFU;
//MOTORS_CURRENT: left_pha_ab(2), left_pha_bc(2), right_pha_ab(2), right_pha_bc(2)
dat[0] = (rtU_Left.i_phaAB >> 8U) & 0xFFU;
dat[1] = rtU_Left.i_phaAB & 0xFFU;
dat[2] = (rtU_Left.i_phaBC >> 8U) & 0xFFU;
dat[3] = rtU_Left.i_phaBC & 0xFFU;
dat[4] = (rtU_Right.i_phaAB >> 8U) & 0xFFU;
dat[5] = rtU_Right.i_phaAB & 0xFFU;
dat[6] = (rtU_Right.i_phaBC >> 8U) & 0xFFU;
dat[7] = rtU_Right.i_phaBC & 0xFFU;
can_send_msg((0x204U + board.can_addr_offset), ((dat[7] << 24U) | (dat[6] << 16U) | (dat[5] << 8U) | dat[4]), ((dat[3] << 24U) | (dat[2] << 16U) | (dat[1] << 8U) | dat[0]), 8U);
uint16_t left_hall_angle;
uint16_t right_hall_angle;
if (hw_type == HW_TYPE_KNEE) {
angle_sensor_read(sensor_angle);
left_hall_angle = hall_angle_offset[0] + ((motPosL / 15 / GEARBOX_RATIO_LEFT) % 360);
right_hall_angle = hall_angle_offset[1] + ((motPosR / 15 / GEARBOX_RATIO_RIGHT) % 360);
} else {
left_hall_angle = motPosL / 15;
right_hall_angle = -motPosR / 15;
}
//MOTORS_ANGLE: left angle sensor(2), right angle sensor(2), left hall angle(2), right hall angle(2)
dat[0] = (sensor_angle[0]>>8U) & 0xFFU;
dat[1] = sensor_angle[0] & 0xFFU;
dat[2] = (sensor_angle[1]>>8U) & 0xFFU;
dat[3] = sensor_angle[1] & 0xFFU;
dat[4] = (left_hall_angle>>8U) & 0xFFU;
dat[5] = left_hall_angle & 0xFFU;
dat[6] = (right_hall_angle>>8U) & 0xFFU;
dat[7] = right_hall_angle & 0xFFU;
can_send_msg((0x205U + board.can_addr_offset), ((dat[7] << 24U) | (dat[6] << 16U) | (dat[5] << 8U) | dat[4]), ((dat[3] << 24U) | (dat[2] << 16U) | (dat[1] << 8U) | dat[0]), 8U);
IMU_soft_sensor_read(unknown_imu_data);
//BOARD_IMU_RAW1: FIXME: add comment after discovering data, looks like magnetometer
dat[0] = (unknown_imu_data[0]>>8U) & 0xFFU;
dat[1] = unknown_imu_data[0] & 0xFFU;
dat[2] = (unknown_imu_data[1]>>8U) & 0xFFU;
dat[3] = unknown_imu_data[1] & 0xFFU;
dat[4] = (unknown_imu_data[2]>>8U) & 0xFFU;
dat[5] = unknown_imu_data[2] & 0xFFU;
can_send_msg((0x206U + board.can_addr_offset), ((dat[5] << 8U) | dat[4]), ((dat[3] << 24U) | (dat[2] << 16U) | (dat[1] << 8U) | dat[0]), 6U);
//BOARD_IMU_RAW2: FIXME: add comment after discovering data, looks like acceleration?
dat[0] = (unknown_imu_data[3]>>8U) & 0xFFU;
dat[1] = unknown_imu_data[3] & 0xFFU;
dat[2] = (unknown_imu_data[4]>>8U) & 0xFFU;
dat[3] = unknown_imu_data[4] & 0xFFU;
dat[4] = (unknown_imu_data[5]>>8U) & 0xFFU;
dat[5] = unknown_imu_data[5] & 0xFFU;
can_send_msg((0x207U + board.can_addr_offset), ((dat[5] << 8U) | dat[4]), ((dat[3] << 24U) | (dat[2] << 16U) | (dat[1] << 8U) | dat[0]), 6U);
}
torque_cmd_timeout = (torque_cmd_timeout < MAX_uint32_T) ? (torque_cmd_timeout+1) : 0;
main_loop_100Hz_runtime = HAL_GetTick() - main_loop_100Hz_runtime;
main_loop_100Hz = HAL_GetTick();
}
// runs at 10Hz
if ((HAL_GetTick() - (main_loop_10Hz - main_loop_10Hz_runtime)) >= 100) {
main_loop_10Hz_runtime = HAL_GetTick();
if (ignition_off_counter <= IGNITION_OFF_DELAY) {
// VAR_VALUES: fault_status(0:4), enable_motors(0:1), ignition(0:1), left motor error(1), right motor error(1)
uint8_t dat[2];
dat[0] = ((fault_status.right_angle << 5U) | (fault_status.right_i2c << 4U) | (fault_status.left_angle << 3U) | (fault_status.left_i2c << 2U) | (enable_motors << 1U) | ignition);
dat[1] = rtY_Left.z_errCode;
dat[2] = rtY_Right.z_errCode;
can_send_msg((0x202U + board.can_addr_offset), 0x0U, ((dat[2] << 16U) | (dat[1] << 8U) | dat[0]), 3U);
}
out_enable(LED_GREEN, ignition);
main_loop_10Hz_runtime = HAL_GetTick() - main_loop_10Hz_runtime;
main_loop_10Hz = HAL_GetTick();
}
// runs at 1Hz
if ((HAL_GetTick() - (main_loop_1Hz - main_loop_1Hz_runtime)) >= 1000) {
main_loop_1Hz_runtime = HAL_GetTick();
// ####### CALC BOARD TEMPERATURE #######
filtLowPass32(adc_buffer.temp, TEMP_FILT_COEF, &board_temp_adcFixdt);
board_temp_adcFilt = (int16_t)(board_temp_adcFixdt >> 16); // convert fixed-point to integer
board_temp_deg_c = (TEMP_CAL_HIGH_DEG_C - TEMP_CAL_LOW_DEG_C) * (board_temp_adcFilt - TEMP_CAL_LOW_ADC) / (TEMP_CAL_HIGH_ADC - TEMP_CAL_LOW_ADC) + TEMP_CAL_LOW_DEG_C;
// ####### CALC CALIBRATED BATTERY VOLTAGE #######
batVoltageCalib = batVoltage * BAT_CALIB_REAL_VOLTAGE / BAT_CALIB_ADC;
charger_connected = !HAL_GPIO_ReadPin(CHARGER_PORT, CHARGER_PIN);
uint8_t battery_percent = 100 - (((420 * BAT_CELLS) - batVoltageCalib) / BAT_CELLS / VOLTS_PER_PERCENT / 100); // Battery % left
// BODY_DATA: MCU temp(2), battery voltage(2), battery_percent(0:7), charger_connected(0:1)
uint8_t dat[4];
dat[0] = board_temp_deg_c & 0xFFU;
dat[1] = (batVoltageCalib >> 8U) & 0xFFU;
dat[2] = batVoltageCalib & 0xFFU;
dat[3] = (((battery_percent & 0x7FU) << 1U) | charger_connected);
can_send_msg((0x203U + board.can_addr_offset), 0x0U, ((dat[3] << 24U) | (dat[2] << 16U) | (dat[1] << 8U) | dat[0]), 4U);
out_enable(LED_BLUE, false); // Reset LED after CAN RX
out_enable(LED_GREEN, true); // Always use LED to show that body is on
if ((hw_type == HW_TYPE_BASE) && ignition) {
ignition_off_counter = 0;
} else {
ignition_off_counter = (ignition_off_counter < MAX_uint32_T) ? (ignition_off_counter+1) : 0;
}
if ((TEMP_POWEROFF_ENABLE && board_temp_deg_c >= TEMP_POWEROFF && speedAvgAbs < 20) || (batVoltage < BAT_DEAD && speedAvgAbs < 20)) { // poweroff before mainboard burns OR low bat 3
poweroff();
} else if (rtY_Left.z_errCode || rtY_Right.z_errCode) { // 1 beep (low pitch): Motor error, disable motors
enable_motors = 0;
beepCount(1, 24, 1);
} else if (fault_status.left_angle || fault_status.left_i2c || fault_status.right_angle || fault_status.right_i2c) { // 2 beeps (low pitch): Motor error, disable motors
beepCount(2, 24, 1);
} else if (TEMP_WARNING_ENABLE && board_temp_deg_c >= TEMP_WARNING) { // 5 beeps (low pitch): Mainboard temperature warning
beepCount(5, 24, 1);
} else if (batVoltage < BAT_LVL1) { // 1 beep fast (medium pitch): Low bat 1
beepCount(0, 10, 6);
out_enable(LED_RED, true);
} else if (batVoltage < BAT_LVL2) { // 1 beep slow (medium pitch): Low bat 2
beepCount(0, 10, 30);
} else { // do not beep
beepCount(0, 0, 0);
out_enable(LED_RED, false);
}
main_loop_1Hz_runtime = HAL_GetTick() - main_loop_1Hz_runtime;
main_loop_1Hz = HAL_GetTick();
}
if (hw_type == HW_TYPE_BASE) {
if (HAL_GPIO_ReadPin(BUTTON_PORT, BUTTON_PIN)) {
cnt_press += 1;
if (cnt_press == (2 * 1008)) {
poweroff();
}
} else if (cnt_press >= 10) {
ignition = !ignition;
out_enable(IGNITION, ignition);
beepShort(5);
cnt_press = 0;
}
}
process_can();
tick_prev = HAL_GetTick();
}
}
}