阅读量:0
一、准备工作
有关OPENMV最大色块追踪及与STM32通信内容,详情见【STM32+HAL】与OpenMV通信
有关七针OLED屏显示内容,详情见【STM32+HAL】七针OLED(SSD1306)配置(SPI版)
二、所用工具
1、芯片:STM32F407ZGT6
2、CUBEMX配置软件
3、KEIL5
4、OPENMV
三、实现功能
二维云台追踪最大色块,并显示中心x,y坐标至OLED
四、HAL配置步骤
1、生成两路PWM波控制舵机
周期为20ms
2、中断配置
五、KEIL填写代码
1、ptz.c
#include "ptz.h" #include "string.h" #include "stdio.h" #include "stdlib.h" #include "main.h" #include "tim.h" #include "usart.h" #define RXBUFFERSIZE 256 #define CCR_UD TIM2->CCR2 //up and down.... RANGE:420-2000 #define CCR_LR TIM2->CCR3 //Left and Right.... RANGE:420-2500 #define Cen_x 160 //x轴中心坐标值 #define Cen_y 120 //y轴中心坐标值 #define sp1 7 //x轴速度 #define sp2 6 //y轴速度 #define range 40 //识别范围 char RxBuffer[RXBUFFERSIZE],rx_buf[RXBUFFERSIZE]; uint8_t aRxBuffer; uint8_t Uart1_Rx_Cnt = 0; int cnt_rx=0,cnt_dt=0; int cx=0,cy=0; void Tilt(void) { if(cx < (Cen_x-range)) CCR_LR = (CCR_LR>2450)?2450:CCR_LR+sp1; else if (cx > (Cen_x+range)) CCR_LR = (CCR_LR<450)?450:CCR_LR -sp1; else CCR_LR= CCR_LR; if(cy < (Cen_y-range)) CCR_UD = (CCR_UD<420)?420:CCR_UD -sp2; else if (cy > (Cen_y+range)) CCR_UD = (CCR_UD>1800)?1800:CCR_UD+sp2; else CCR_UD= CCR_UD; } void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { UNUSED(huart); if(huart==&huart2){ RxBuffer[Uart1_Rx_Cnt] = aRxBuffer; Uart1_Rx_Cnt++; if((RxBuffer[Uart1_Rx_Cnt-1] == 0xb3)&&(RxBuffer[Uart1_Rx_Cnt-2] == 0xb3)) cnt_rx=1; //帧头判定 else if((RxBuffer[Uart1_Rx_Cnt-2] == 0x0d)&&(RxBuffer[Uart1_Rx_Cnt-1] == 0x0a)) cnt_rx=2; //帧尾判定 else cnt_rx=0; switch (cnt_rx) { case 1: Uart1_Rx_Cnt = 0; memset(RxBuffer,0x00,sizeof(RxBuffer)); break; case 2: RxBuffer[Uart1_Rx_Cnt-1] = '\0'; RxBuffer[Uart1_Rx_Cnt-2] = '\0'; strcpy(rx_buf,RxBuffer); int st=0; //有效数值开始位置 cnt_dt=0; //空格数 for(int i=0;rx_buf[i];i++){ if(cnt_dt==4) break; if(rx_buf[i]==' ') { cnt_dt++; int temp=0; for(int j=st;j<i;j++) temp=temp*10+(rx_buf[j]-'0'); switch (cnt_dt){ case 1:cx=temp;break; case 2:cy=temp;break; } st=i+1; } } while(HAL_UART_GetState(&huart2) == HAL_UART_STATE_BUSY_TX); Uart1_Rx_Cnt = 0; memset(RxBuffer,0x00,sizeof(RxBuffer)); break; default:break; } HAL_UART_Receive_IT(&huart2, (uint8_t *)&aRxBuffer, 1); } }
2、main.c
/* USER CODE BEGIN 2 */ OLED_Init(); HAL_UART_Receive_IT(&huart2, (uint8_t *)&aRxBuffer, 1); TIM2->CCR2 = 420-1; TIM2->CCR3 = 1400-1; HAL_TIM_PWM_Start (&htim2, TIM_CHANNEL_2); HAL_TIM_PWM_Start (&htim2, TIM_CHANNEL_3); /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { OLED_ShowNum(30,20,cx,3,16); OLED_ShowNum(30,40,cy,3,16); OLED_Refresh(); /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ if(flag) Tilt(); } /* USER CODE END 3 */ }
3、按键控制暂停
/* USER CODE BEGIN 4 */ void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { if(GPIO_Pin == KEY0_Pin){ HAL_Delay(20); //延时消抖 if(GPIO_Pin == KEY0_Pin){ flag=0; } } } /* USER CODE END 4 */
六、巨人之肩
【毕业设计】基于STM32F103C8T6最小系统板与OpenMV的二维云台PID控制追踪系统
后续优化方案:PID调控
七、源码提供
【STM32+OPENMV】二维云台颜色识别及追踪【无PID版】
八、成果展示
PTZ
九、优化方案:PID控制
#include "ptz.h" #include "string.h" #include "stdio.h" #include "stdlib.h" #include "main.h" #include "tim.h" #include "usart.h" #define RXBUFFERSIZE 256 #define CCR_UD TIM1->CCR1 //up and down.... RANGE:1250-7500 #define CCR_LR TIM1->CCR2 //Left and Right.... RANGE:1250-7500 #define Cen_x 160 //x轴中心坐标值 #define Cen_y 120 //y轴中心坐标值 #define KP1 0.45 #define KD1 2 #define KP2 0.35 #define KD2 2 #define sp1 30 #define sp2 23 #define range 35 char RxBuffer[RXBUFFERSIZE],rx_buf[RXBUFFERSIZE]; uint8_t aRxBuffer; uint8_t Uart1_Rx_Cnt = 0; int cnt_rx=0,cnt_dt=0; int cx=0,cy=0; void Tilt(void) { if(PID1(cx,Cen_x)+CCR_LR>7450) CCR_LR=7450; else if(CCR_LR<1250) CCR_LR=1250; else CCR_LR+=PID1(cx,Cen_x); if(CCR_UD>4000) CCR_UD=4000; else if(CCR_UD<1250) CCR_UD=1250; else CCR_UD-=PID2(cy,Cen_y); } int PID1(int current,int target) //PID速度控制 { static int LastError; //Error[-1] int iError,Outpid; //当前误差 iError=target-current; //增量计算 Outpid=(KP1 * iError) //E[k]项 +(KD1 * (iError-LastError)); //E[k]-E[k-1]项 LastError=iError; //存储误差,用于下次计算 return Outpid; } int PID2(int current,int target) //PID速度控制 { static int LastError; //Error[-1] int iError,Outpid; //当前误差 iError=target-current; //增量计算 Outpid=(KP2 * iError) //E[k]项 +(KD2 * (iError-LastError)); //E[k]-E[k-1]项 LastError=iError; //存储误差,用于下次计算 return Outpid; } void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { UNUSED(huart); if(huart==&huart2){ RxBuffer[Uart1_Rx_Cnt] = aRxBuffer; Uart1_Rx_Cnt++; if((RxBuffer[Uart1_Rx_Cnt-1] == 0xb3)&&(RxBuffer[Uart1_Rx_Cnt-2] == 0xb3)) cnt_rx=1; //帧头判定 else if((RxBuffer[Uart1_Rx_Cnt-2] == 0x0d)&&(RxBuffer[Uart1_Rx_Cnt-1] == 0x0a)) cnt_rx=2; //帧尾判定 else cnt_rx=0; switch (cnt_rx) { case 1: Uart1_Rx_Cnt = 0; memset(RxBuffer,0x00,sizeof(RxBuffer)); break; case 2: RxBuffer[Uart1_Rx_Cnt-1] = '\0'; RxBuffer[Uart1_Rx_Cnt-2] = '\0'; strcpy(rx_buf,RxBuffer); int st=0; //有效数值开始位置 cnt_dt=0; //空格数 for(int i=0;rx_buf[i];i++){ if(cnt_dt==4) break; if(rx_buf[i]==' ') { cnt_dt++; int temp=0; for(int j=st;j<i;j++) temp=temp*10+(rx_buf[j]-'0'); switch (cnt_dt){ case 1:cx=temp;break; case 2:cy=temp;break; } st=i+1; } } while(HAL_UART_GetState(&huart2) == HAL_UART_STATE_BUSY_TX); Uart1_Rx_Cnt = 0; memset(RxBuffer,0x00,sizeof(RxBuffer)); break; default:break; } HAL_UART_Receive_IT(&huart2, (uint8_t *)&aRxBuffer, 1); } }