本文使用串口1DMA中断接收OpenMV传来的色块坐标,定时器2给舵机一个20ms的时基脉冲。
- 在
main.c
中包含所需的头文件:#include "stm32f1xx_hal.h" #include "pid.h"
- 定义全局变量:
UART_HandleTypeDef huart1; TIM_HandleTypeDef htim2; PID_TypeDef x_axis_pid; PID_TypeDef y_axis_pid; uint8_t rx_data[4]; // 存储从OpenMV接收的数据 int16_t x_position = 0; int16_t y_position = 0; uint32_t pwm_x_duty = 0; uint32_t pwm_y_duty = 0;
- 初始化PID参数:
void PID_Init(void) { // X轴PID参数 x_axis_pid.Kp = 1.0; x_axis_pid.Ki = 0.1; x_axis_pid.Kd = 0.2; x_axis_pid.target = 160; // 设置目标位置(屏幕中心) x_axis_pid.output_min = 1000; x_axis_pid.output_max = 2000; // Y轴PID参数 y_axis_pid.Kp = 1.0; y_axis_pid.Ki = 0.1; y_axis_pid.Kd = 0.2; y_axis_pid.target = 120; // 设置目标位置(屏幕中心) y_axis_pid.output_min = 1000; y_axis_pid.output_max = 2000; }
- 在
main
函数中初始化PID和启动串口接收:int main(void) { // ... 省略其他初始化代码 ... PID_Init(); HAL_UART_Receive_IT(&huart1, rx_data, 4); // ... 省略其他初始化代码 ... }
- 串口接收回调函数:
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if (huart->Instance == USART1) { x_position = (int16_t)(rx_data[0] << 8 | rx_data[1]); y_position = (int16_t)(rx_data[2] << 8 | rx_data[3]); HAL_UART_Receive_IT(&huart1, rx_data, 4); } }
- 在
while
循环中计算PID并更新PWM输出:while (1) { pwm_x_duty = PID_Calculate(&x_axis_pid, x_position); pwm_y_duty = PID_Calculate(&y_axis_pid, y_position); __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, pwm_x_duty); __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_2, pwm_y_duty); HAL_Delay(10); // 控制循环周期,可根据实际情况调整 }
- 在
pid.h
中定义PID结构体和函数原型:#ifndef __PID_H #define __PID_H #include "stm32f1xx_hal.h" typedef struct { float Kp; float Ki; float Kd; float target; float output_min; float output_max; float last_error; float integral; } PID_TypeDef; uint32_t PID_Calculate(PID_TypeDef *pid, int16_t current_position); #endif
- 在
pid.c
中实现PID算法:#include "pid.h" uint32_t PID_Calculate(PID_TypeDef *pid, int16_t current_position) { float error = pid->target - current_position; float derivative; float output; pid->integral += error; if (pid->integral < pid->output_min) { pid->integral = pid->output_min; } else if (pid->integral > pid->output_max) { pid->integral = pid->output_max; } derivative = error - pid->last_error; output = pid->Kp * error + pid->Ki * pid->integral + pid->Kd * derivative; if (output < pid->output_min) { output = pid->output_min; } else if (output > pid->output_max) { output = pid->output_max; } pid->last_error = error; return (uint32_t)output; }
这样,当STM32收到从OpenMV发来的红色物体的坐标时,它将使用PID算法调整舵机的PWM输出,使舵机跟随红色物体移动。
模拟电磁炮物体追踪的PID算法
于 2023-04-29 19:51:01 首次发布