}
float fmw_encoder_get_linear_velocity(const FMW_Encoder *encoder) {
- float meters = METERS_FROM_TICKS(encoder->ticks,
- encoder->wheel_circumference,
- encoder->ticks_per_revolution);
+ float meters = FMW_METERS_FROM_TICKS(encoder->ticks,
+ encoder->wheel_circumference,
+ encoder->ticks_per_revolution);
float deltatime = encoder->current_millis - encoder->previous_millis;
float linear_velocity = deltatime > 0.f ? (meters / (deltatime / 1000.f)) : 0.f;
return linear_velocity;
// ============================================================
// LEDs
void fmw_led_init(FMW_Led *led) {
- HAL_TIM_PWM_Start(led->timer, led->channel);
- __HAL_TIM_SET_COMPARE(led->timer, led->channel, 0);
+ HAL_TIM_PWM_Start(led->timer, led->timer_channel);
+ __HAL_TIM_SET_COMPARE(led->timer, led->timer_channel, 0);
}
-void fmw_led_update(FMW_Led *led, float vin) {
+void fmw_led_update(FMW_Led *led) {
+ HAL_ADC_Start(led->adc);
+ HAL_ADC_PollForConversion(led->adc, HAL_MAX_DELAY);
+ uint32_t adc_val = HAL_ADC_GetValue(led->adc);
+ float v_adc = ((float)adc_val / FMW_ADC_RESOLUTION) * FMW_V_REF;
+ float vin = v_adc * FMW_VIN_SCALE_FACTOR;
+
uint32_t duty = 0;
uint32_t arr = led->timer->Instance->ARR;
} break;
}
- __HAL_TIM_SET_COMPARE(led->timer, led->channel, duty);
+ __HAL_TIM_SET_COMPARE(led->timer, led->timer_channel, duty);
}
/* Private includes ----------------------------------------------------------*/\r
/* USER CODE BEGIN Includes */\r
\r
+#include <math.h> // M_PI\r
#include <string.h> // memcpy\r
\r
#include "firmware/fmw_inc.h"\r
} encoders = {\r
.right = {\r
.timer = &htim3,\r
- .ticks_per_revolution = 200,\r
- .wheel_circumference = 0.1f,\r
+ .ticks_per_revolution = 19150,\r
+ .wheel_circumference = (200.f * M_PI) / 1000.f,\r
},\r
.left = {\r
.timer = &htim2,\r
- .ticks_per_revolution = 200,\r
- .wheel_circumference = 0.1f,\r
+ .ticks_per_revolution = 19150,\r
+ .wheel_circumference = (200.f * M_PI) / 1000.f,\r
},\r
};\r
\r
},\r
};\r
\r
+FMW_Led pled = {\r
+ .adc = &hadc1,\r
+ .timer = &htim1,\r
+ .timer_channel = TIM_CHANNEL_1,\r
+ .voltage_red = 11.5f,\r
+ .voltage_orange = 12.5f,\r
+ .voltage_hysteresis = 0.05f,\r
+ .state = FMW_LedState_Red,\r
+};\r
+\r
int32_t pid_max = 0;\r
int32_t pid_min = 0;\r
\r
+static uint32_t led_update_period = 200;\r
+\r
static volatile int32_t ticks_left = 0;\r
static volatile int32_t ticks_right = 0;\r
static volatile float previous_tx_millis;\r
static volatile uint8_t tx_done_flag = 1;\r
/* volatile MessageStatusCode otto_status = MessageStatusCode_Waiting4Config; */\r
+\r
+static volatile uint32_t time_aux_press = 0;\r
+static volatile uint32_t time_aux2_press = 0;\r
+static volatile uint32_t time_last_motors = 0;\r
static volatile FMW_State fmw_state = FMW_State_Init;\r
\r
/* USER CODE END PV */\r
\r
fmw_encoder_init(encoders.values);\r
fmw_motor_init(motors.values);\r
+ fmw_led_init(&pled);\r
\r
//right and left motors have the same parameters\r
pid_max = (int32_t)htim4.Instance->ARR;\r
HAL_UART_Receive_DMA(&huart6, (uint8_t*) &vel_msg, 12);\r
#endif\r
\r
- while (1);\r
+ for (uint32_t time_last_led_update = 0;;) {\r
+ uint32_t time_now = HAL_GetTick();\r
+ if (time_now - time_last_led_update >= led_update_period) {\r
+ time_last_led_update = time_now;\r
+ fmw_led_update(&pled);\r
+ }\r
+ }\r
}\r
\r
void fmw_message_handle(FMW_State state, UART_HandleTypeDef *huart, int32_t wait_ms) {\r
FMW_Message msg = {0};\r
HAL_StatusTypeDef uart_packet_status = HAL_UART_Receive(huart, (uint8_t*)&msg, sizeof(msg), wait_ms);\r
- fmw_report_unless(uart_packet_status == HAL_OK, FMW_Error_UART_ReceiveTimeoutElapsed);\r
- fmw_report_unless(msg.header.type < FMW_MessageType_COUNT, FMW_Error_Command_NotRecognized);\r
+ FMW_REPORT_UNLESS(uart_packet_status == HAL_OK, FMW_Error_UART_ReceiveTimeoutElapsed);\r
+ FMW_REPORT_UNLESS(msg.header.type < FMW_MessageType_COUNT, FMW_Error_Command_NotRecognized);\r
\r
uint32_t crc_received = msg.header.crc;\r
msg.header.crc = 0;\r
switch (msg.header.type) {\r
case FMW_MessageType_Run: {\r
uint32_t crc_computed = HAL_CRC_Calculate(&hcrc, (uint32_t*)&msg, sizeof msg.header);\r
- fmw_report_unless(crc_received == -1 || crc_computed == crc_received, FMW_Error_UART_Crc);\r
+ FMW_REPORT_UNLESS(crc_received == -1 || crc_computed == crc_received, FMW_Error_UART_Crc);\r
fmw_state = FMW_State_Running;\r
} break;\r
case FMW_MessageType_Config_Robot: {\r
uint32_t crc_computed = HAL_CRC_Calculate(&hcrc, (uint32_t*)&msg, sizeof msg.header.type + sizeof msg.config_robot);\r
- fmw_report_unless(crc_received == -1 || crc_computed == crc_received, FMW_Error_UART_Crc);\r
+ FMW_REPORT_UNLESS(crc_received == -1 || crc_computed == crc_received, FMW_Error_UART_Crc);\r
\r
odometry.baseline = msg.config_robot.baseline;\r
encoders.left.wheel_circumference = msg.config_robot.left_wheel_circumference;\r
} break;\r
case FMW_MessageType_Config_PID: {\r
uint32_t crc_computed = HAL_CRC_Calculate(&hcrc, (uint32_t*)&msg, sizeof msg.header.type + sizeof msg.config_pid);\r
- fmw_report_unless(crc_received == -1 || crc_computed == crc_received, FMW_Error_UART_Crc);\r
+ FMW_REPORT_UNLESS(crc_received == -1 || crc_computed == crc_received, FMW_Error_UART_Crc);\r
\r
memcpy(&pid_left.ks, &msg.config_pid.left, sizeof pid_left.ks);\r
memcpy(&pid_right.ks, &msg.config_pid.right, sizeof pid_right.ks);\r
memcpy(&pid_cross.ks, &msg.config_pid.cross, sizeof pid_cross.ks);\r
} break;\r
+ case FMW_MessageType_Config_LED: {\r
+ uint32_t crc_computed = HAL_CRC_Calculate(&hcrc, (uint32_t*)&msg, sizeof msg.header.type + sizeof msg.config_led);\r
+ FMW_REPORT_UNLESS(crc_received == -1 || crc_computed == crc_received, FMW_Error_UART_Crc);\r
+\r
+ pled.voltage_red = msg.config_led.voltage_red;\r
+ pled.voltage_orange = msg.config_led.voltage_orange;\r
+ pled.voltage_hysteresis = msg.config_led.voltage_hysteresis;\r
+ led_update_period = msg.config_led.update_period;\r
+ } break;\r
}\r
} break;\r
}\r
for (;;) {}\r
}\r
\r
+// TODO(lb): move to fmw. maybe create a FMW_Buzzer?\r
+void buzzer_set(bool on) {\r
+ if (on) {\r
+ __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2, htim1.Init.Period / 2);\r
+ HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_2);\r
+ } else {\r
+ HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_2);\r
+ }\r
+}\r
+\r
// TIMER 100Hz PID control\r
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {\r
// NOTE(lb): for transmission\r
}\r
\r
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {\r
- //Blue user button on the NUCLEO board\r
+ uint32_t time_now = HAL_GetTick();\r
+\r
switch (GPIO_Pin) {\r
+ case aux_Pin: {\r
+ if (time_now - time_aux_press > FMW_DEBOUNCE_DELAY) {\r
+ time_aux_press = time_now;\r
+ HAL_GPIO_TogglePin(GPIOB, LD1_Pin);\r
+ HAL_GPIO_TogglePin(GPIOB, LD2_Pin);\r
+ HAL_GPIO_TogglePin(GPIOB, LD3_Pin);\r
+ /* char msg[] = "AUX1 button pressed\r\n"; */\r
+ /* HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY); */\r
+ }\r
+ } break;\r
+ case aux2_Pin: {\r
+ if (time_now - time_aux2_press > FMW_DEBOUNCE_DELAY) {\r
+ time_aux2_press = time_now;\r
+ /* char msg[] = "AUX2 button pressed\r\n"; */\r
+ /* HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY); */\r
+ }\r
+ } break;\r
+ case motors_btn_Pin: {\r
+ if (time_now - time_last_motors > FMW_DEBOUNCE_DELAY) {\r
+ time_last_motors = time_now;\r
+ /* char msg[] = "Motors button pressed\r\n"; */\r
+ /* HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY); */\r
+ if(motors.left.active && motors.right.active) {\r
+ fmw_motor_disable(&motors.left);\r
+ fmw_motor_disable(&motors.right);\r
+ HAL_GPIO_WritePin(SLED_GPIO_Port, SLED_Pin, GPIO_PIN_RESET);\r
+ buzzer_set(false);\r
+ /* char msg[] = "Motors OFF\r\n"; */\r
+ /* HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY); */\r
+ } else {\r
+ fmw_motor_enable(&motors.left);\r
+ fmw_motor_enable(&motors.right);\r
+ HAL_GPIO_WritePin(SLED_GPIO_Port, SLED_Pin, GPIO_PIN_SET);\r
+ buzzer_set(false);\r
+ /* char msg[] = "Motors ON\r\n"; */\r
+ /* HAL_UART_Transmit(&huart3, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY); */\r
+ }\r
+ }\r
+ } break;\r
case fault1_Pin:\r
case fault2_Pin: {\r
fmw_motor_brake(&motors.left);\r
fmw_motor_brake(&motors.right);\r
- //stop TIM6 interrupt (used for PID control)\r
+ // stop TIM6 interrupt (used for PID control)\r
HAL_TIM_Base_Stop_IT(&htim6);\r
/* otto_status = MessageStatusCode_Fault_HBridge; */\r
} break;\r