模拟电磁炮物体追踪的PID算法

        本文使用串口1DMA中断接收OpenMV传来的色块坐标,定时器2给舵机一个20ms的时基脉冲。

  1. main.c中包含所需的头文件:
    #include "stm32f1xx_hal.h"
    #include "pid.h"
  2. 定义全局变量:
    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;
  3. 初始化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;
    }
  4. main函数中初始化PID和启动串口接收:
    int main(void) {
        // ... 省略其他初始化代码 ...
    
        PID_Init();
        HAL_UART_Receive_IT(&huart1, rx_data, 4);
    
        // ... 省略其他初始化代码 ...
    }
  5. 串口接收回调函数:
    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);
        }
    }
  6. 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); // 控制循环周期,可根据实际情况调整
    }
  7. 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
  8. 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输出,使舵机跟随红色物体移动。        

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值