• 【STM32+OPENMV】二维云台颜色识别及追踪


    一、准备工作

    有关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
    1. #include "ptz.h"
    2. #include "string.h"
    3. #include "stdio.h"
    4. #include "stdlib.h"
    5. #include "main.h"
    6. #include "tim.h"
    7. #include "usart.h"
    8. #define RXBUFFERSIZE 256
    9. #define CCR_UD TIM2->CCR2 //up and down.... RANGE:420-2000
    10. #define CCR_LR TIM2->CCR3 //Left and Right.... RANGE:420-2500
    11. #define Cen_x 160 //x轴中心坐标值
    12. #define Cen_y 120 //y轴中心坐标值
    13. #define sp1 7 //x轴速度
    14. #define sp2 6 //y轴速度
    15. #define range 40 //识别范围
    16. char RxBuffer[RXBUFFERSIZE],rx_buf[RXBUFFERSIZE];
    17. uint8_t aRxBuffer;
    18. uint8_t Uart1_Rx_Cnt = 0;
    19. int cnt_rx=0,cnt_dt=0;
    20. int cx=0,cy=0;
    21. void Tilt(void)
    22. {
    23. if(cx < (Cen_x-range)) CCR_LR = (CCR_LR>2450)?2450:CCR_LR+sp1;
    24. else if (cx > (Cen_x+range)) CCR_LR = (CCR_LR<450)?450:CCR_LR -sp1;
    25. else CCR_LR= CCR_LR;
    26. if(cy < (Cen_y-range)) CCR_UD = (CCR_UD<420)?420:CCR_UD -sp2;
    27. else if (cy > (Cen_y+range)) CCR_UD = (CCR_UD>1800)?1800:CCR_UD+sp2;
    28. else CCR_UD= CCR_UD;
    29. }
    30. void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
    31. {
    32. UNUSED(huart);
    33. if(huart==&huart2){
    34. RxBuffer[Uart1_Rx_Cnt] = aRxBuffer;
    35. Uart1_Rx_Cnt++;
    36. if((RxBuffer[Uart1_Rx_Cnt-1] == 0xb3)&&(RxBuffer[Uart1_Rx_Cnt-2] == 0xb3)) cnt_rx=1; //帧头判定
    37. else if((RxBuffer[Uart1_Rx_Cnt-2] == 0x0d)&&(RxBuffer[Uart1_Rx_Cnt-1] == 0x0a)) cnt_rx=2; //帧尾判定
    38. else cnt_rx=0;
    39. switch (cnt_rx)
    40. {
    41. case 1:
    42. Uart1_Rx_Cnt = 0;
    43. memset(RxBuffer,0x00,sizeof(RxBuffer));
    44. break;
    45. case 2:
    46. RxBuffer[Uart1_Rx_Cnt-1] = '\0';
    47. RxBuffer[Uart1_Rx_Cnt-2] = '\0';
    48. strcpy(rx_buf,RxBuffer);
    49. int st=0; //有效数值开始位置
    50. cnt_dt=0; //空格数
    51. for(int i=0;rx_buf[i];i++){
    52. if(cnt_dt==4) break;
    53. if(rx_buf[i]==' ') {
    54. cnt_dt++;
    55. int temp=0;
    56. for(int j=st;j
    57. temp=temp*10+(rx_buf[j]-'0');
    58. switch (cnt_dt){
    59. case 1:cx=temp;break;
    60. case 2:cy=temp;break;
    61. }
    62. st=i+1;
    63. }
    64. }
    65. while(HAL_UART_GetState(&huart2) == HAL_UART_STATE_BUSY_TX);
    66. Uart1_Rx_Cnt = 0;
    67. memset(RxBuffer,0x00,sizeof(RxBuffer));
    68. break;
    69. default:break;
    70. }
    71. HAL_UART_Receive_IT(&huart2, (uint8_t *)&aRxBuffer, 1);
    72. }
    73. }

    2、main.c
    1. /* USER CODE BEGIN 2 */
    2. OLED_Init();
    3. HAL_UART_Receive_IT(&huart2, (uint8_t *)&aRxBuffer, 1);
    4. TIM2->CCR2 = 420-1;
    5. TIM2->CCR3 = 1400-1;
    6. HAL_TIM_PWM_Start (&htim2, TIM_CHANNEL_2);
    7. HAL_TIM_PWM_Start (&htim2, TIM_CHANNEL_3);
    8. /* USER CODE END 2 */
    9. /* Infinite loop */
    10. /* USER CODE BEGIN WHILE */
    11. while (1)
    12. {
    13. OLED_ShowNum(30,20,cx,3,16);
    14. OLED_ShowNum(30,40,cy,3,16);
    15. OLED_Refresh();
    16. /* USER CODE END WHILE */
    17. /* USER CODE BEGIN 3 */
    18. if(flag) Tilt();
    19. }
    20. /* USER CODE END 3 */
    21. }

    3、按键控制暂停
    1. /* USER CODE BEGIN 4 */
    2. void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
    3. {
    4. if(GPIO_Pin == KEY0_Pin){
    5. HAL_Delay(20); //延时消抖
    6. if(GPIO_Pin == KEY0_Pin){
    7. flag=0;
    8. }
    9. }
    10. }
    11. /* USER CODE END 4 */

    六、巨人之肩

    【毕业设计】基于STM32及OpenMV的云台追踪装置

    电赛:二维云台控制

    【毕业设计】基于STM32F103C8T6最小系统板与OpenMV的二维云台PID控制追踪系统

    后续优化方案:PID调控

    位置式PID与增量式PID区别浅析

    七、源码提供

    【STM32+OPENMV】二维云台颜色识别及追踪【无PID版】

    八、成果展示

    PTZ

    九、优化方案:PID控制

    1. #include "ptz.h"
    2. #include "string.h"
    3. #include "stdio.h"
    4. #include "stdlib.h"
    5. #include "main.h"
    6. #include "tim.h"
    7. #include "usart.h"
    8. #define RXBUFFERSIZE 256
    9. #define CCR_UD TIM1->CCR1 //up and down.... RANGE:1250-7500
    10. #define CCR_LR TIM1->CCR2 //Left and Right.... RANGE:1250-7500
    11. #define Cen_x 160 //x轴中心坐标值
    12. #define Cen_y 120 //y轴中心坐标值
    13. #define KP1 0.45
    14. #define KD1 2
    15. #define KP2 0.35
    16. #define KD2 2
    17. #define sp1 30
    18. #define sp2 23
    19. #define range 35
    20. char RxBuffer[RXBUFFERSIZE],rx_buf[RXBUFFERSIZE];
    21. uint8_t aRxBuffer;
    22. uint8_t Uart1_Rx_Cnt = 0;
    23. int cnt_rx=0,cnt_dt=0;
    24. int cx=0,cy=0;
    25. void Tilt(void)
    26. {
    27. if(PID1(cx,Cen_x)+CCR_LR>7450) CCR_LR=7450;
    28. else if(CCR_LR<1250) CCR_LR=1250;
    29. else CCR_LR+=PID1(cx,Cen_x);
    30. if(CCR_UD>4000) CCR_UD=4000;
    31. else if(CCR_UD<1250) CCR_UD=1250;
    32. else CCR_UD-=PID2(cy,Cen_y);
    33. }
    34. int PID1(int current,int target) //PID速度控制
    35. {
    36. static int LastError; //Error[-1]
    37. int iError,Outpid; //当前误差
    38. iError=target-current; //增量计算
    39. Outpid=(KP1 * iError) //E[k]项
    40. +(KD1 * (iError-LastError)); //E[k]-E[k-1]项
    41. LastError=iError; //存储误差,用于下次计算
    42. return Outpid;
    43. }
    44. int PID2(int current,int target) //PID速度控制
    45. {
    46. static int LastError; //Error[-1]
    47. int iError,Outpid; //当前误差
    48. iError=target-current; //增量计算
    49. Outpid=(KP2 * iError) //E[k]项
    50. +(KD2 * (iError-LastError)); //E[k]-E[k-1]项
    51. LastError=iError; //存储误差,用于下次计算
    52. return Outpid;
    53. }
    54. void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
    55. {
    56. UNUSED(huart);
    57. if(huart==&huart2){
    58. RxBuffer[Uart1_Rx_Cnt] = aRxBuffer;
    59. Uart1_Rx_Cnt++;
    60. if((RxBuffer[Uart1_Rx_Cnt-1] == 0xb3)&&(RxBuffer[Uart1_Rx_Cnt-2] == 0xb3)) cnt_rx=1; //帧头判定
    61. else if((RxBuffer[Uart1_Rx_Cnt-2] == 0x0d)&&(RxBuffer[Uart1_Rx_Cnt-1] == 0x0a)) cnt_rx=2; //帧尾判定
    62. else cnt_rx=0;
    63. switch (cnt_rx)
    64. {
    65. case 1:
    66. Uart1_Rx_Cnt = 0;
    67. memset(RxBuffer,0x00,sizeof(RxBuffer));
    68. break;
    69. case 2:
    70. RxBuffer[Uart1_Rx_Cnt-1] = '\0';
    71. RxBuffer[Uart1_Rx_Cnt-2] = '\0';
    72. strcpy(rx_buf,RxBuffer);
    73. int st=0; //有效数值开始位置
    74. cnt_dt=0; //空格数
    75. for(int i=0;rx_buf[i];i++){
    76. if(cnt_dt==4) break;
    77. if(rx_buf[i]==' ') {
    78. cnt_dt++;
    79. int temp=0;
    80. for(int j=st;j
    81. temp=temp*10+(rx_buf[j]-'0');
    82. switch (cnt_dt){
    83. case 1:cx=temp;break;
    84. case 2:cy=temp;break;
    85. }
    86. st=i+1;
    87. }
    88. }
    89. while(HAL_UART_GetState(&huart2) == HAL_UART_STATE_BUSY_TX);
    90. Uart1_Rx_Cnt = 0;
    91. memset(RxBuffer,0x00,sizeof(RxBuffer));
    92. break;
    93. default:break;
    94. }
    95. HAL_UART_Receive_IT(&huart2, (uint8_t *)&aRxBuffer, 1);
    96. }
    97. }

    源码

    STM32+OPENMV二维云台颜色识别及追踪PID版

  • 相关阅读:
    【chat】2:vs2022 连接远程ubuntu服务器远程cmake开发
    js获取当前日期(年份,月份,时间)
    JavaScript的事件循环机制浅析
    关联线探究,如何连接流程图的两个节点
    FreeRTOS深入教程(任务的引入及栈的作用)
    全栈开发实战|Spring Boot文件上传与下载
    Netty 进阶学习(九)-- 粘包与半包
    进销存免费管理软件 进销存免费软件推荐 免费进销存
    【必须安排】书单|1024程序员狂欢节充能书单!
    全网最新的nacos 2.1.0集群多节点部署教程
  • 原文地址:https://blog.csdn.net/m0_60372743/article/details/136491052