2019-10-06 13:09:15 +00:00
/*
* This file is part of the hoverboard - firmware - hack project .
*
* Copyright ( C ) 2017 - 2018 Rene Hopf < renehopf @ mac . com >
* Copyright ( C ) 2017 - 2018 Nico Stute < crinq @ crinq . de >
* Copyright ( C ) 2017 - 2018 Niklas Fauth < niklas . fauth @ kit . fail >
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
# include <stdlib.h> // for abs()
# include "stm32f1xx_hal.h"
# include "defines.h"
# include "setup.h"
# include "config.h"
# include "comms.h"
//#include "hd44780.h"
// Matlab includes and defines - from auto-code generation
// ###############################################################################
# include "BLDC_controller.h" /* Model's header file */
# include "rtwtypes.h"
RT_MODEL rtM_Left_ ; /* Real-time model */
RT_MODEL rtM_Right_ ; /* Real-time model */
RT_MODEL * const rtM_Left = & rtM_Left_ ;
RT_MODEL * const rtM_Right = & rtM_Right_ ;
P rtP_Left ; /* Block parameters (auto storage) */
DW rtDW_Left ; /* Observable states */
ExtU rtU_Left ; /* External inputs */
ExtY rtY_Left ; /* External outputs */
P rtP_Right ; /* Block parameters (auto storage) */
DW rtDW_Right ; /* Observable states */
ExtU rtU_Right ; /* External inputs */
ExtY rtY_Right ; /* External outputs */
extern uint8_t errCode_Left ; /* Global variable to handle Motor error codes */
extern uint8_t errCode_Right ; /* Global variable to handle Motor error codes */
// ###############################################################################
void SystemClock_Config ( void ) ;
void poweroff ( void ) ;
extern TIM_HandleTypeDef htim_left ;
extern TIM_HandleTypeDef htim_right ;
extern ADC_HandleTypeDef hadc1 ;
extern ADC_HandleTypeDef hadc2 ;
extern volatile adc_buf_t adc_buffer ;
//LCD_PCF8574_HandleTypeDef lcd;
extern I2C_HandleTypeDef hi2c2 ;
extern UART_HandleTypeDef huart2 ;
static int cmd1 ; // normalized input values. -1000 to 1000
static int cmd2 ;
typedef struct {
int16_t steer ;
int16_t speed ;
//uint32_t crc;
} Serialcommand ;
static volatile Serialcommand command ;
static uint8_t button1 , button2 ;
static int steer ; // local variable for steering. -1000 to 1000
static int speed ; // local variable for speed. -1000 to 1000
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 buzzerFreq ; // global variable for the buzzer pitch. can be 1, 2, 3, 4, 5, 6, 7...
extern uint8_t buzzerPattern ; // global variable for the buzzer pattern. can be 1, 2, 3, 4, 5, 6, 7...
extern uint8_t enable ; // global variable for motor enable
extern volatile uint32_t timeout ; // global variable for timeout
extern float batteryVoltage ; // global variable for battery voltage
static uint32_t inactivity_timeout_counter ;
extern uint8_t nunchuck_data [ 6 ] ;
# ifdef CONTROL_PPM
extern volatile uint16_t ppm_captured_value [ PPM_NUM_CHANNELS + 1 ] ;
# endif
void poweroff ( void ) {
// if (abs(speed) < 20) { // wait for the speed to drop, then shut down -> this is commented out for SAFETY reasons
buzzerPattern = 0 ;
enable = 0 ;
for ( int i = 0 ; i < 8 ; i + + ) {
buzzerFreq = ( uint8_t ) i ;
HAL_Delay ( 100 ) ;
}
HAL_GPIO_WritePin ( OFF_PORT , OFF_PIN , 0 ) ;
while ( 1 ) { }
// }
}
int main ( void ) {
HAL_Init ( ) ;
__HAL_RCC_AFIO_CLK_ENABLE ( ) ;
HAL_NVIC_SetPriorityGrouping ( NVIC_PRIORITYGROUP_4 ) ;
/* System interrupt init*/
/* MemoryManagement_IRQn interrupt configuration */
HAL_NVIC_SetPriority ( MemoryManagement_IRQn , 0 , 0 ) ;
/* BusFault_IRQn interrupt configuration */
HAL_NVIC_SetPriority ( BusFault_IRQn , 0 , 0 ) ;
/* UsageFault_IRQn interrupt configuration */
HAL_NVIC_SetPriority ( UsageFault_IRQn , 0 , 0 ) ;
/* SVCall_IRQn interrupt configuration */
HAL_NVIC_SetPriority ( SVCall_IRQn , 0 , 0 ) ;
/* DebugMonitor_IRQn interrupt configuration */
HAL_NVIC_SetPriority ( DebugMonitor_IRQn , 0 , 0 ) ;
/* PendSV_IRQn interrupt configuration */
HAL_NVIC_SetPriority ( PendSV_IRQn , 0 , 0 ) ;
/* SysTick_IRQn interrupt configuration */
HAL_NVIC_SetPriority ( SysTick_IRQn , 0 , 0 ) ;
SystemClock_Config ( ) ;
__HAL_RCC_DMA1_CLK_DISABLE ( ) ;
MX_GPIO_Init ( ) ;
MX_TIM_Init ( ) ;
MX_ADC1_Init ( ) ;
MX_ADC2_Init ( ) ;
# if defined(DEBUG_SERIAL_USART2) || defined(DEBUG_SERIAL_USART3)
UART_Init ( ) ;
# endif
HAL_GPIO_WritePin ( OFF_PORT , OFF_PIN , 1 ) ;
HAL_ADC_Start ( & hadc1 ) ;
HAL_ADC_Start ( & hadc2 ) ;
// Matlab Init
// ###############################################################################
/* Set BLDC controller parameters */
rtP_Right = rtP_Left ; // Copy the Left motor parameters to the Right motor parameters
rtP_Left . b_selPhaABCurrMeas = 1 ; // Left motor measured current phases = {iA, iB} -> do NOT change
rtP_Left . z_ctrlTypSel = CTRL_TYP_SEL ;
rtP_Left . b_diagEna = DIAG_ENA ;
rtP_Left . b_fieldWeakEna = FIELD_WEAK_ENA ;
rtP_Left . i_max = I_MOT_MAX ;
rtP_Left . n_max = N_MOT_MAX ;
rtP_Right . b_selPhaABCurrMeas = 0 ; // Left motor measured current phases = {iB, iC} -> do NOT change
rtP_Right . z_ctrlTypSel = CTRL_TYP_SEL ;
rtP_Right . b_diagEna = DIAG_ENA ;
rtP_Right . b_fieldWeakEna = FIELD_WEAK_ENA ;
rtP_Right . i_max = I_MOT_MAX ;
rtP_Right . n_max = N_MOT_MAX ;
/* Pack LEFT motor data into RTM */
rtM_Left - > defaultParam = & rtP_Left ;
rtM_Left - > dwork = & rtDW_Left ;
rtM_Left - > inputs = & rtU_Left ;
rtM_Left - > outputs = & rtY_Left ;
/* Pack RIGHT motor data into RTM */
rtM_Right - > defaultParam = & rtP_Right ;
rtM_Right - > dwork = & rtDW_Right ;
rtM_Right - > inputs = & rtU_Right ;
rtM_Right - > outputs = & rtY_Right ;
/* Initialize BLDC controllers */
BLDC_controller_initialize ( rtM_Left ) ;
BLDC_controller_initialize ( rtM_Right ) ;
// ###############################################################################
for ( int i = 8 ; i > = 0 ; i - - ) {
buzzerFreq = ( uint8_t ) i ;
HAL_Delay ( 100 ) ;
}
buzzerFreq = 0 ;
HAL_GPIO_WritePin ( LED_PORT , LED_PIN , 1 ) ;
int lastSpeedL = 0 , lastSpeedR = 0 ;
int speedL = 0 , speedR = 0 ;
# ifdef CONTROL_PPM
PPM_Init ( ) ;
# endif
# ifdef CONTROL_NUNCHUCK
I2C_Init ( ) ;
Nunchuck_Init ( ) ;
# endif
# ifdef CONTROL_SERIAL_USART2
UART_Control_Init ( ) ;
HAL_UART_Receive_DMA ( & huart2 , ( uint8_t * ) & command , 4 ) ;
# endif
# ifdef DEBUG_I2C_LCD
I2C_Init ( ) ;
HAL_Delay ( 50 ) ;
lcd . pcf8574 . PCF_I2C_ADDRESS = 0x27 ;
lcd . pcf8574 . PCF_I2C_TIMEOUT = 5 ;
lcd . pcf8574 . i2c = hi2c2 ;
lcd . NUMBER_OF_LINES = NUMBER_OF_LINES_2 ;
lcd . type = TYPE0 ;
if ( LCD_Init ( & lcd ) ! = LCD_OK ) {
// error occured
//TODO while(1);
}
LCD_ClearDisplay ( & lcd ) ;
HAL_Delay ( 5 ) ;
LCD_SetLocation ( & lcd , 0 , 0 ) ;
LCD_WriteString ( & lcd , " Hover V2.0 " ) ;
LCD_SetLocation ( & lcd , 0 , 1 ) ;
LCD_WriteString ( & lcd , " Initializing... " ) ;
# endif
float board_temp_adc_filtered = ( float ) adc_buffer . temp ;
float board_temp_deg_c ;
enable = 0 ; // initially motors are disabled for SAFETY
while ( 1 ) {
HAL_Delay ( DELAY_IN_MAIN_LOOP ) ; //delay in ms
# ifdef CONTROL_NUNCHUCK
Nunchuck_Read ( ) ;
cmd1 = CLAMP ( ( nunchuck_data [ 0 ] - 127 ) * 8 , - 1000 , 1000 ) ; // x - axis. Nunchuck joystick readings range 30 - 230
cmd2 = CLAMP ( ( nunchuck_data [ 1 ] - 128 ) * 8 , - 1000 , 1000 ) ; // y - axis
button1 = ( uint8_t ) nunchuck_data [ 5 ] & 1 ;
button2 = ( uint8_t ) ( nunchuck_data [ 5 ] > > 1 ) & 1 ;
# endif
# ifdef CONTROL_PPM
cmd1 = CLAMP ( ( ppm_captured_value [ 0 ] - 500 ) * 2 , - 1000 , 1000 ) ;
cmd2 = CLAMP ( ( ppm_captured_value [ 1 ] - 500 ) * 2 , - 1000 , 1000 ) ;
button1 = ppm_captured_value [ 5 ] > 500 ;
float scale = ppm_captured_value [ 2 ] / 1000.0f ;
# endif
# ifdef CONTROL_ADC
// ADC values range: 0-4095, see ADC-calibration in config.h
cmd1 = CLAMP ( adc_buffer . l_tx2 - ADC1_MIN , 0 , ADC1_MAX ) / ( ADC1_MAX / 1000.0f ) ; // ADC1
cmd2 = CLAMP ( adc_buffer . l_rx2 - ADC2_MIN , 0 , ADC2_MAX ) / ( ADC2_MAX / 1000.0f ) ; // ADC2
// use ADCs as button inputs:
button1 = ( uint8_t ) ( adc_buffer . l_tx2 > 2000 ) ; // ADC1
button2 = ( uint8_t ) ( adc_buffer . l_rx2 > 2000 ) ; // ADC2
timeout = 0 ;
# endif
# ifdef CONTROL_SERIAL_USART2
cmd1 = CLAMP ( ( int16_t ) command . steer , - 1000 , 1000 ) ;
cmd2 = CLAMP ( ( int16_t ) command . speed , - 1000 , 1000 ) ;
timeout = 0 ;
# endif
// Bypass - only for testing purposes
// cmd1 = 2*(cmd1-500);
// cmd2 = 2*(cmd2-500);
// ####### MOTOR ENABLING: Only if the initial input is very small (for SAFETY) #######
if ( enable = = 0 & & ( cmd1 > - 50 & & cmd1 < 50 ) & & ( cmd2 > - 50 & & cmd2 < 50 ) ) {
enable = 1 ; // enable motors
}
// ####### LOW-PASS FILTER #######
steer = ( int ) ( steer * ( 1.0f - FILTER ) + cmd1 * FILTER ) ;
speed = ( int ) ( speed * ( 1.0f - FILTER ) + cmd2 * FILTER ) ;
// ####### MIXER #######
speedR = CLAMP ( ( int ) ( speed * SPEED_COEFFICIENT - steer * STEER_COEFFICIENT ) , - 1000 , 1000 ) ;
speedL = CLAMP ( ( int ) ( speed * SPEED_COEFFICIENT + steer * STEER_COEFFICIENT ) , - 1000 , 1000 ) ;
# ifdef ADDITIONAL_CODE
ADDITIONAL_CODE ;
# endif
// ####### SET OUTPUTS (if the target change less than +/- 50) #######
if ( ( speedL > lastSpeedL - 50 & & speedL < lastSpeedL + 50 ) & & ( speedR > lastSpeedR - 50 & & speedR < lastSpeedR + 50 ) & & timeout < TIMEOUT ) {
# ifdef INVERT_R_DIRECTION
pwmr = speedR ;
# else
pwmr = - speedR ;
# endif
# ifdef INVERT_L_DIRECTION
pwml = - speedL ;
# else
pwml = speedL ;
# endif
}
lastSpeedL = speedL ;
lastSpeedR = speedR ;
if ( inactivity_timeout_counter % 25 = = 0 ) {
// ####### CALC BOARD TEMPERATURE #######
board_temp_adc_filtered = board_temp_adc_filtered * 0.99f + ( float ) adc_buffer . temp * 0.01f ;
board_temp_deg_c = ( ( float ) TEMP_CAL_HIGH_DEG_C - ( float ) TEMP_CAL_LOW_DEG_C ) / ( ( float ) TEMP_CAL_HIGH_ADC - ( float ) TEMP_CAL_LOW_ADC ) * ( board_temp_adc_filtered - ( float ) TEMP_CAL_LOW_ADC ) + ( float ) TEMP_CAL_LOW_DEG_C ;
// ####### DEBUG SERIAL OUT #######
# ifdef CONTROL_ADC
// setScopeChannel(0, (int)adc_buffer.l_tx2); // 1: ADC1
// setScopeChannel(1, (int)adc_buffer.l_rx2); // 2: ADC2
# endif
setScopeChannel ( 0 , ( int16_t ) speedR ) ; // 1: output command: [-1000, 1000]
setScopeChannel ( 1 , ( int16_t ) speedL ) ; // 2: output command: [-1000, 1000]
setScopeChannel ( 2 , ( int16_t ) rtY_Right . n_mot ) ; // 3: Real motor speed [rpm]
setScopeChannel ( 3 , ( int16_t ) rtY_Left . n_mot ) ; // 4: Real motor speed [rpm]
setScopeChannel ( 4 , ( int16_t ) adc_buffer . batt1 ) ; // 5: for battery voltage calibration
setScopeChannel ( 5 , ( int16_t ) ( batteryVoltage * 100.0f ) ) ; // 6: for verifying battery voltage calibration
setScopeChannel ( 6 , ( int16_t ) board_temp_adc_filtered ) ; // 7: for board temperature calibration
setScopeChannel ( 7 , ( int16_t ) board_temp_deg_c ) ; // 8: for verifying board temperature calibration
consoleScope ( ) ;
}
HAL_GPIO_TogglePin ( LED_PORT , LED_PIN ) ;
// ####### POWEROFF BY POWER-BUTTON #######
if ( HAL_GPIO_ReadPin ( BUTTON_PORT , BUTTON_PIN ) ) {
enable = 0 ;
while ( HAL_GPIO_ReadPin ( BUTTON_PORT , BUTTON_PIN ) ) { }
poweroff ( ) ;
}
// ####### BEEP AND EMERGENCY POWEROFF #######
if ( ( TEMP_POWEROFF_ENABLE & & board_temp_deg_c > = TEMP_POWEROFF & & abs ( speed ) < 20 ) | | ( batteryVoltage < ( ( float ) BAT_LOW_DEAD * ( float ) BAT_NUMBER_OF_CELLS ) & & abs ( speed ) < 20 ) ) { // poweroff before mainboard burns OR low bat 3
poweroff ( ) ;
} else if ( TEMP_WARNING_ENABLE & & board_temp_deg_c > = TEMP_WARNING ) { // beep if mainboard gets hot
buzzerFreq = 4 ;
buzzerPattern = 1 ;
} else if ( batteryVoltage < ( ( float ) BAT_LOW_LVL1 * ( float ) BAT_NUMBER_OF_CELLS ) & & batteryVoltage > ( ( float ) BAT_LOW_LVL2 * ( float ) BAT_NUMBER_OF_CELLS ) & & BAT_LOW_LVL1_ENABLE ) { // low bat 1: slow beep
buzzerFreq = 5 ;
buzzerPattern = 42 ;
} else if ( batteryVoltage < ( ( float ) BAT_LOW_LVL2 * ( float ) BAT_NUMBER_OF_CELLS ) & & batteryVoltage > ( ( float ) BAT_LOW_DEAD * ( float ) BAT_NUMBER_OF_CELLS ) & & BAT_LOW_LVL2_ENABLE ) { // low bat 2: fast beep
buzzerFreq = 5 ;
buzzerPattern = 6 ;
} else if ( errCode_Left | | errCode_Right ) { // beep in case of Motor error - fast beep
buzzerFreq = 6 ;
buzzerPattern = 2 ;
} else if ( BEEPS_BACKWARD & & speed < - 50 ) { // backward beep
buzzerFreq = 5 ;
buzzerPattern = 1 ;
} else { // do not beep
buzzerFreq = 0 ;
buzzerPattern = 0 ;
}
// ####### INACTIVITY TIMEOUT #######
if ( abs ( speedL ) > 50 | | abs ( speedR ) > 50 ) {
inactivity_timeout_counter = 0 ;
} else {
inactivity_timeout_counter + + ;
}
if ( inactivity_timeout_counter > ( INACTIVITY_TIMEOUT * 60 * 1000 ) / ( DELAY_IN_MAIN_LOOP + 1 ) ) { // rest of main loop needs maybe 1ms
poweroff ( ) ;
}
}
}
/** System Clock Configuration
*/
void SystemClock_Config ( void ) {
RCC_OscInitTypeDef RCC_OscInitStruct ;
RCC_ClkInitTypeDef RCC_ClkInitStruct ;
RCC_PeriphCLKInitTypeDef PeriphClkInit ;
/**Initializes the CPU, AHB and APB busses clocks
*/
RCC_OscInitStruct . OscillatorType = RCC_OSCILLATORTYPE_HSI ;
RCC_OscInitStruct . HSIState = RCC_HSI_ON ;
RCC_OscInitStruct . HSICalibrationValue = 16 ;
RCC_OscInitStruct . PLL . PLLState = RCC_PLL_ON ;
RCC_OscInitStruct . PLL . PLLSource = RCC_PLLSOURCE_HSI_DIV2 ;
RCC_OscInitStruct . PLL . PLLMUL = RCC_PLL_MUL16 ;
HAL_RCC_OscConfig ( & RCC_OscInitStruct ) ;
/**Initializes the CPU, AHB and APB busses clocks
*/
RCC_ClkInitStruct . ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2 ;
RCC_ClkInitStruct . SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK ;
RCC_ClkInitStruct . AHBCLKDivider = RCC_SYSCLK_DIV1 ;
RCC_ClkInitStruct . APB1CLKDivider = RCC_HCLK_DIV2 ;
RCC_ClkInitStruct . APB2CLKDivider = RCC_HCLK_DIV1 ;
HAL_RCC_ClockConfig ( & RCC_ClkInitStruct , FLASH_LATENCY_2 ) ;
PeriphClkInit . PeriphClockSelection = RCC_PERIPHCLK_ADC ;
// PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV8; // 8 MHz
PeriphClkInit . AdcClockSelection = RCC_ADCPCLK2_DIV4 ; // 16 MHz
HAL_RCCEx_PeriphCLKConfig ( & PeriphClkInit ) ;
/**Configure the Systick interrupt time
*/
HAL_SYSTICK_Config ( HAL_RCC_GetHCLKFreq ( ) / 1000 ) ;
/**Configure the Systick
*/
HAL_SYSTICK_CLKSourceConfig ( SYSTICK_CLKSOURCE_HCLK ) ;
/* SysTick_IRQn interrupt configuration */
HAL_NVIC_SetPriority ( SysTick_IRQn , 0 , 0 ) ;
}
2019-10-06 20:43:08 +00:00
// ===========================================================
/* Low pass filter fixed-point 16 bits: fixdt(1,16,4)
* Max : 2047.9375
* Min : - 2048
* Res : 0.0625
* coef : [ 0 , 65535U ] = fixdt ( 0 , 16 , 16 )
*
* Call function example :
* If coef = 0.8 ( in floating point ) , then coef = 0.8 * 2 ^ 16 = 52429 ( in fixed - point )
* y = filtLowPass16 ( u , 52429 , y ) ;
*/
int16_t filtLowPass16 ( int16_t u , uint16_t coef , int16_t yPrev )
{
int32_t tmp ;
int16_t y ;
tmp = ( ( ( int16_t ) ( u < < 4 ) * coef ) > > 16 ) +
( ( ( int32_t ) ( 65535U - coef ) * yPrev ) > > 16 ) ;
// Overflow protection
if ( tmp > 32767 ) {
tmp = 32767 ;
} else {
if ( tmp < - 32768 ) {
tmp = - 32768 ;
}
}
y = ( int16_t ) tmp ;
return y ;
}
// ===========================================================
/* Low pass filter fixed-point 32 bits: fixdt(1,32,16)
* Max : 32767.99998474121
* Min : - 32768
* Res : 1.52587890625e-5
* coef : [ 0 , 65535U ] = fixdt ( 0 , 16 , 16 )
*
* Call function example :
* If coef = 0.8 ( in floating point ) , then coef = 0.8 * 2 ^ 16 = 52429 ( in fixed - point )
* y = filtLowPass16 ( u , 52429 , y ) ;
*/
int32_t filtLowPass32 ( int32_t u , uint16_t coef , int32_t yPrev )
{
int32_t q0 ;
int32_t q1 ;
int32_t y ;
q0 = ( int32_t ) ( ( ( int64_t ) ( u < < 16 ) * coef ) > > 16 ) ;
q1 = ( int32_t ) ( ( ( int64_t ) ( 65535U - coef ) * yPrev ) > > 16 ) ;
// Overflow protection
if ( ( q0 < 0 ) & & ( q1 < MIN_int32_T - q0 ) ) {
y = MIN_int32_T ;
} else if ( ( q0 > 0 ) & & ( q1 > MAX_int32_T - q0 ) ) {
y = MAX_int32_T ;
} else {
y = q0 + q1 ;
}
return y ;
}
// ===========================================================