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
381 lines
16 KiB
2 years ago
|
#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();
|
||
|
}
|
||
|
}
|
||
|
}
|