毕业设计|STM32+OpenMV的云台追踪装置

毕业设计|STM32+OpenMV的云台追踪装置

编码文章call10242024-12-17 11:45:0142A+A-

11月份,很多同学开始了自己的毕业设计。达尔闻毕业设计分享系列已有50+个毕设项目(下拉文末查看全部),我们希望通过这些项目,给做毕设的同学一些启发或参考,可以转发给自己的同学、学弟们。

大学最后一个作业,大家一定要用心去做哦。欢迎所有毕业或即将毕业的同学来分享自己毕设。

本次毕设由番杰(B站ID:番杰阿)设计,通过OpenMV识别被测物体(以红色小球为例)。当其识别到红色小球后,判断小球中心点所在的区域信息,并将其区域标志位通过串口发送给STM32,当STM32接收到位置信息后对x轴、y轴的两个舵机参数进行操作,最后通过定时器输出合适的PWM波,控制舵机旋转相应的角度,使OpenMV摄像头对准被测物体,以实现物体追踪功能。如果有遇到问题,可以到番杰B站或csdn博客进行交流。

实现效果,来自番杰B站

以下是项目的整理思路及部分主要代码,很简单的,在追踪部分没有用到PID控制哦!大家可以放心食用(手动滑稽)!很容易复刻的!


整体功能分析

在进行设计之前,需要确定一下本设计要实现的功能,然后再进行相应的设计。在本设计中使用OpenMV作为视觉模块,STM32作为主控制MCU去控制舵机旋转,以实现追踪功能。整体功能流程图如下图所示:

OpenMV:作为识别模块,主要实现物体识别的功能,并将识别到的物体的位置信息通过串口传递给STM32。

STM32的串口部分:主要功能是与OpenMV进行数据交互,接收OpenMV发来的位置信息。

STM32的定时器部分:主要功能是通过库函数输出PWM波,从而控制X、Y轴的两个舵机旋转,以达到追踪效果。


硬件选型

1)OpenMV4 Cam H7

OpenMV选用星瞳科技代理的OpenMV4 Cam H7。选择哪一个型号的OpenMV都可以,主要影响的只是图像的清晰度(图像大小),性能越好的OpenMV可以在更高的清晰度下运行,而差的可能会在该清晰度下报错。

OpenMV部分主要实现三个功能:完成被测物体的识别(以红色小球为例)、寻找最大色块区域、通过串口发送被测物体的位置信息。在这儿强调一下,其引脚3.3v-5v耐压,过高的电压会烧掉其中的芯片。

2)STM32F103ZET6

本次设计中使用STM32F103ZET6最小系统板作为核心MCU,实物如图3.3所示。使用其他的芯片已ok的,只需要确定该芯片可以输出两路PWM波、一个串口就行。

STM32部分主要使用串口和定时器来实现:通过串口接收OpenMV发来的数据、通过定时器输出PWM波,以实现控制舵机旋转追踪的目的。

3)DS3120舵机

舵机选用达盛舵机科技有限公司生产的DS3120型号的舵机,运行温度在-15℃~70℃,工作电压范围为4.8v-6.8v,驱动方式为PWM波,脉冲范围为500~2500μsec,控制角度为:180° 。这里我虽然使用了180°舵机,但是在追踪过程中,我通过在软件中限制了舵机的最大旋转角度,避免追踪过程中舵机旋转角度过大对舵机后面的接线造成影响。

工作原理:通过给舵机的信号线(橙黄色)输入周期为20ms的PWM波,通高电平的时间为:0.5 ~ 2.5ms,可以使舵机旋转0~180°。

4)LED补光板

因为OpenMV进行颜色识别时,对环境的光照有一定的要求,光照强度的变换会直接对识别造成影响,所以为避免环境光线变化的影响,在本次设计中加入LED补光板,补光板由6个贴片LED及电阻组成,贴片LED选用CF12V3T3R00,电阻选用100欧姆,供电则直接接3S锂电池,11.1v供电。

5)供电及稳压

供电使用3S锂电池作为整体装置的供电,3S锂电池可以提供11.1V的电压。

因为OpenMV、舵机、STM32都不能直接11.1V电压,所以需要对电压进行稳压到5V,才能给它们供电,使用稳压板进行稳压,稳压板选用基于LM2596芯片的DC-DC稳压模块,稳压板的输入端连接3S锂电池,用电压表测量输出端电压,用螺丝刀旋转稳压板上的可调节电位器,直到输出端输出电压为5V即可。

硬件连接部分使用杜邦线连接,连接如下:3S锂电池接稳压板输入端以及直接给LED补光板供电,稳压板输出端接OpenMV的VIN和GND引脚、STM32的5V和GND引脚以及两个舵机的正(红色)负(棕色)极。OpenMV的P4引脚(串口3的TX)接STM32的PA10引脚(串口1的RX),OpenMV的P5引脚(串口3的RX)接STM32的PA9引脚(串口1的TX),STM32的PC7引脚(定时器3通道2)接x轴的舵机的信号线(橙黄色),STM32的PC7引脚(定时器3通道1)接y轴的舵机的信号线(橙黄色)。


软件功能实现

软件部分的功能主要分为两部分,一个是OpenMV部分,另一是STM32部分,OpenMV主要实现功能:完成被测物体的识别、寻找最大色块区域、判断被测物体所在区域、通过串口发送被测物体的位置信息。STM32部分主要实现功能:使用串口接收OpenMV发来的数据、通过定时器输出PWM波、以及实现控制舵机旋转追踪的目的。

OpenMV部分的功能实现:

首先对OpenMV部分实现功能:首先进行摄像头的初始化,确保其可以正常的使用。其次设置图像格式,选用RGB模式,使其图像为彩色模式,然后设置图像大小,设置为QVGA格式,分辨率为320*240 dpi。而后设置颜色阈值,确保OpenMV可以识别到此颜色。然后设置白平衡,关闭自动白平衡,避免对识别的影响。接着对串口初始化,确保串口可以正常的发送数据。到此准备工作完成,进入识别部分,首先截取图像并返回,然后判断图像内是否识别到红色区域:否则循环等待,是则判断区域是否为最大区域,否则返回等待,是则用矩形框标出中心位置,判断中心位置所在的区域,并将位置信息通过串口发出。以上部分除了判断所在区域外的所有代码都可以在星瞳科技的官网上找到,并且官方还有配套的详细讲解。

对被测物体的识别:

本设计中被测物体为一个红色小球,因此对于物体的识别主要为颜色识别,在编程中首先需要对OpenMV的红色的阈值进行调整,打开阈值编辑器,对LAB的阈值进行调整,使二进制图像中只有红色区域的映像。

注:在不同的光照环境下会对颜色识别造成很大的影,所以请在稳定的光照环境下调整阈值以及识别。

调整好红色阈值后,赋值LAB阈值的参数,并赋值给red_threshold,调用MicroPython函数库中的image.find_blobs()函数,对该色域进行识别。该功能部分程序如下:

import sensor, image, time, pyb
from pyb import UART


red_threshold   = (14, 68, 11, 70, 9, 56) #红色阈值设定


sensor.reset() # 初始化摄像头传感器.
sensor.set_pixformat(sensor.RGB565) # 使用RGB565.
sensor.set_framesize(sensor.QVGA) # 使用QVGA.
sensor.skip_frames(10) # 让新设置生效.
sensor.set_auto_whitebal(False) # 关闭自动白平衡.
clock = time.clock() # Tracks FPS.


while(True):
    img = sensor.snapshot() # 拍照并返回图像.
    blobs = img.find_blobs([red_threshold])
    if blobs:
        img.draw_rectangle(blobs.rect())
        img.draw_cross(blobs.cx(), blobs.cy())

while循环之前为OpenMV初始化部分:

RGB565为彩色模式(颜色识别嘛,肯定得用彩色模式);

QVGA为图像大小(320dpi * 160dpi,像素点),这个可以根据选的OpenMV的性能来选择;

关闭白平衡:是指关闭系统的自动白平衡,自动白平衡会对颜色识别造成影响。

while循环内:

image.find_blobs()函数:参数主要为6个:LAB的最大最小值(可以通过之前的阈值编辑器中得到)。

img.draw_rectangle()函数:则是用矩形框框出识函数参数的区域。

img.draw_cross()函数:在参数位置上绘制出十字架。其中函数参数blobs.cx(), blobs.cy():分别为blobs区域的中心x、y轴坐标。

寻找最大色块区域:

在OpenMV追踪识别的过程中,可能出现背景或是其他区域出现小面积的红色区域,如图所示。这会对识别造成影响,所以需要用程序过滤掉那些小的红色区域。

通过对识别到的红色区域进行比较,找出所有红色区域中最大的区域,即可避免背景中的小面积红色区域对识别的影响,该部分程序如下:

def find_max(blobs):
    max_size=0
    for blob in blobs:
        if blob.pixels() > max_size:
            max_blob=blob
            max_size = blob.pixels()
    return max_blob
if blobs:
    max_blob=find_max(blobs)

该程序中,定义一个名为find_max()的子函数,该函数主要实现的功能就是寻找最大的红色区域,在主函数中调用该函数以实现该功能,避免背景中的小面积红色区域对识别的影响。结果如图所示。

判断被测物体所在区域:

本段程序是判断被测物体所在区域,将OpenMV拍摄到的画面分为五个区域,分别为中心区域、左上区域、右上区域、左下区域、右下区域,分布结构如图所示。

区域分布主要是按照像素分布,我使用到QVGA格式(320*240),使用其他大小的格式,可以按照大小自行进行分配。

本段程序主要通过识别到物体的中心点所在像素位置判断其所在区域所完成,部分程序如下:

x_max = 320
x_min = 0
x_1 = 135 #中心区域左边界
x_2 = 175 #中心区域右边界
    
y_max = 240
y_min = 0
y_1 = 110 #中心区域上边界
y_2 = 130 #中心区域下边界
flag = 0#位置信息标志
if max_blob.cx()>= x_min  and max_blob.cx() <= 160 and\
       max_blob.cy() >= 120 and max_blob.cy() <= y_max :
            flag = 1
if max_blob.cx()>=160 and max_blob.cx() <= x_max and\
       max_blob.cy() >=120 and max_blob.cy() <= y_max :
            flag = 2
if max_blob.cx()>= x_min and max_blob.cx() <= 160 and \
      max_blob.cy() >= y_min and max_blob.cy() <= 120 :
            flag = 3
if max_blob.cx()>= 160 and max_blob.cx() <= x_max and \
     max_blob.cy() >= y_min and max_blob.cy() <= 120 :
            flag = 4
if max_blob.cx()>= x_1 and max_blob.cx() <= x_2 and \
     max_blob.cy() >= y_1 and max_blob.cy() < =y_2 :
            flag = 5

本部分程序逻辑为先判断被测物体的中心位置是否在左上区域,如果在则标志位flag被赋值为1,否则为不变(初始值为0),判断被测物体的中心位置是否在右上区域,如果在则标志位flag被赋值为2,否则为不变,判断被测物体的中心位置是否在左下区域,如果在则标志位flag被赋值为3,否则为不变,判断被测物体的中心位置是否在右下区域,如果在则标志位flag被赋值为4,否则为不变,判断被测物体的中心位置是否在中心区域,如果在则标志位flag被赋值为5,否则为不变。流程图如图所示:

串口发送数据:

本部分主要介绍串口发送数据给STM32的程序,发送的数据则是上一部分判断物体中心位置所在区域的标志位,主要使用uart.write()函数来实现本功能。该函数为封装好的库函数,直接调用即可,部分程序如下:

import pyb
from pyb import UART
uart = UART(3, 115200)  #串口3初始化,波特率115200
while(True):
output_str="%d" %flag #方式1
    print('you send:',output_str) 
    uart.write(output_str+'\r\n')

STM32部分软件功能的实现:

对STM32部分实现功能的整体逻辑进行分析,首先进行系统时钟的初始化,确保STM32的时钟周期正常运行。其次中断优先级的初始化,本程序中主要用到了串口1的接收中断,所以只需要配置串口1的中断优先级。然后进行串口1的初始化,确保串口1可以正常的接收数据。而后进行定时器3通道1以及通道2的初始化,确保可以使其输出PWM波控制舵机旋转。舵机回归初始位置,能够使装置上电后,舵机回到初始位置。最后判断串口是否接收到数据,如果串口接收到数据,则进入串口中断,执行相应的程序。反之,则进行等待。整体流程图如图所示。其次在使用串口接收OpenMV发来的数据、通过定时器输出PWM波的功能进行独立的分析。

串口接收数据:

本部分程序主要为串口初始化,以及串口中断函数的编写,主要实现STM32通过串口1 接收OpenMV发送来的数据。当接收到数据时,STM32的串口1接收完成位USART_IT_RXNE会被置1。进入串口1中断,运行串口中断内的程序。使用库函数编程,部分程序如下。

//串口1时钟使能:
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
//串口1引脚配置:
  GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;//TX串口输出PA9
  GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;   //复用推挽输出
  GPIO_Init(GPIOA,&GPIO_InitStructure);  
  GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;//RX  串口输入PA10
  GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING; //模拟输入
  GPIO_Init(GPIOA,&GPIO_InitStructure); /*初始化GPIO*/
//串口1初始化设置:
  USART_InitStructure.USART_BaudRate = bound;//波特率设置
  USART_InitStructure.USART_WordLength = USART_WordLength_8b; 
  USART_InitStructure.USART_StopBits = USART_StopBits_1; 
  USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
  USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;  
  USART_Init(USART1,&USART_InitStructure); //初始化串口1
  USART_Cmd(USART1, ENABLE);  //使能串口1 
//中断优先级配置:
  NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;//串口1中断通道
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3;//抢占优先级3
  NVIC_InitStructure.NVIC_IRQChannelSubPriority =3;    //子优先级3
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 
  NVIC_Init(&NVIC_InitStructure);  //根据指定的参数初始化VIC寄存器

定时器输出PWM波:

本部分程序主要为定时器3通道1和通道2的初始化,并使用STM32的固件库中函数TIM_SetCompare1(TIM_TypeDef* TIMx,uint16_t Compare1)输出PWM波,使舵机旋转。该函数有两个参数,第一个参数为定时器号,第二个参数为占空比的参数。部分程序如下。

//使能定时器3的时钟:
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
//配置定时器3的引脚:
  GPIO_InitStructure.GPIO_Pin=GPIO_Pin_7;
  GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;//复用推挽输出
  GPIO_Init(GPIOC,&GPIO_InitStructure);
  GPIO_PinRemapConfig(GPIO_FullRemap_TIM3,ENABLE);
//初始化定时器3的基本配置:
  TIM_TimeBaseInitStructure.TIM_Period=per;   //自动装载值
  TIM_TimeBaseInitStructure.TIM_Prescaler=psc; //分频系数
  TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;
  TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; 
  TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructure);  
//初始化输出比较通道2:
  TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;
  TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_Low;
  TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;
  TIM_OC2Init(TIM3,&TIM_OCInitStructure); //输出比较通道2初始化
//使能定时器3:
  TIM_OC2PreloadConfig(TIM3,TIM_OCPreload_Enable); 
  TIM_ARRPreloadConfig(TIM3,ENABLE);//使能预装载寄存器
  TIM_Cmd(TIM3,ENABLE); //使能定时器

控制舵机旋转:

舵机旋转角度主要是由占空比决定,所以通过传递给函数TIM_SetCompareX()的参数即可控制舵机旋转的角度,编程思路在STM32接收到OpenMV发送的数据后,进入串口中断,在串口中断函数内编写控制舵机旋转的程序,接收到的数据分为5种情况,即接收到被测物体所在的区域信息:1、2、3、4、5分别对应左上、右上、左下、右下、中心五个区域。接收到不同的标志位信息进行不同的动作。流程如图所示。

同时防止舵机追踪时出现旋转角度过大,可通过软件进行限制,部分程序如下:

    Data=USART_ReceiveData(USART1); //读取接收到的数据  
    switch (Data)
    {
      case '1':Variable_X( 1 ); Control_X (pwm_x);
                     Variable_Y( 0 ); Control_Y (pwm_y);break;
      case '2': Variable_X( 0 ); Control_X (pwm_x);
                      Variable_Y( 0 ); Control_Y (pwm_y);break;
      case '3': Variable_X( 1 ); Control_X (pwm_x);
                      Variable_Y( 1 ); Control_Y (pwm_y);break;
      case '4': Variable_X( 0 ); Control_X (pwm_x);
                      Variable_Y( 1 ); Control_Y (pwm_y);break;
      case '5':break;  
       }

以上程序中,定义了Variable_X( )、Variable_Y( )两个子函数,子函数中有两个参数:0和1 ,主要实现对x、y轴舵机参数的减小和增加。同时在两个子函数中加入if语句,当舵机旋转参数增加到一定时,保持固定不变。同理减小到一定值时,也固定保持不变。以Variable_X( )子函数为例,部分程序如下:

unsigned int Variable_X(unsigned char flag)
{
  if (flag == 1)
  {
    pwm_x += para; 
    if (pwm_x >18600)     //x轴的左边界
      pwm_x = 18600 ;
  }
  else 
  {
    pwm_x -= para;
    if (pwm_x <17600)   //x轴的右边界
      pwm_x = 17600;
  }
  return pwm_x;
}

其中,para代表着x、y轴两个舵机每次旋转的角度,通过宏定义,在调试过程中修改宏定义即可。


总结

到这里呢,就算是把我做毕设时的思路写了下来,也是我写毕业论文的思路,总体来说,我在实现追踪的功能上取巧了,只是能实现简单的、“粗糙的” 追踪目标,而没有使用PID控制,也欢迎大家使用PID控制去实现追踪的效果,大概的思路差不多:在OpenMv的部分,在识别到目标后,返回物体中心点的横纵坐标的值,通过串口发给Stm32,32在收到数据后与图像的中心点坐标进行比较(我用的是320*240,那么中心点坐标就是160,120),将二者的差值作为参数,通过PID控制舵机旋转,可以更加准确跟快速的对目标进行追踪。

欢迎大家给出宝贵的意见!

第一次补充内容

关于PID控制代码部分

依旧分为两部分:OpenMV的代码和STM32的代码

OpenMV代码相比于之前的OpenMV的代码,改动的部分仅仅为将串口传递的“区域信息”改为“被测物体中心点的x、y轴坐标”。

   ...
   x = max_blob.cx()
   y = max_blob.cy()
   ...
   output_str="%d,%d,%dE" %(x,y,flag) #方式1
   uart.write(output_str)

其中:

x: 表示为被测物体的中心点x轴坐标

y: 表示为被测物体的中心点y轴坐标

, : 为英文下的逗号,作为数据间的分隔符

flag:为标志位,取值为0,1,2;

flag取值说明:

0表示并没有识别到物体

1识别到物体,但物体没有在中心区域

2识别到物体,且物体在中心区域

E: 表示数据帧的结束,可以以任何字符作为结束,本代码中以’E’为例

嵌入式物联网需要学的东西真的非常多,千万不要学错了路线和内容,导致工资要不上去!

无偿分享大家一个资料包,差不多150多G。里面学习内容、面经、项目都比较新也比较全!某鱼上买估计至少要好几十。

点击这里找小助理0元领取:加微信领取资料

STM32代码

主要改动为:对串口接收到的数据帧处理、PID控制部分

1)数据帧处理

if(str[i-1] == 'E')
{
  for(i = 0;str[i] != 'E';i++ )
  {  
    if(str[i]  ==  ',' )
    {  
      if(number_flag ==  0)
      {
        x_long  = j; // x的位数
      }
      else if (number_flag ==  1)
      {
        y_long = j; // y的位数
      }
      number_flag ++;
      j = 0;
    }
    else
    {
      if(number_flag == 0)
      {
        x_array[j] = str[i] -'0';
        j++;
      }
      else if(number_flag == 1)
      {
        y_array[j] = str[i] -'0';
        j++;
      }
      else if(number_flag == 2)
      {
        RED_flag = str[i] - '0';
      }
    }


  }
  if(RED_flag == 1)
  {
    switch(x_long)
    {
      case 1 : x_location = x_array[0]; break ;
      case 2 : x_location = x_array[0]*10 + x_array[1]; break ;
      case 3 : x_location = x_array[0]*100 + x_array[1]*10 + x_array[2]; break ;
      default: break ;
    }
    switch(y_long)
    {
      case 1 : y_location = y_array[0]; break ;
      case 2 : y_location = y_array[0]*10 + y_array[1]; break ;
      case 3 : y_location = y_array[0]*100 + y_array[1]*10 + y_array[2]; break ;
      default: break ;  
    }
  PID_realize(x_location,y_location); // pid控制
  Control_X(pwm_x); // 输出x轴PWM
  Control_Y(pwm_y); // 输出y轴PWM
  }
  else
  {
    PID_init(); 
  }  
  i = 0;  

(2)PID参数初始化部分

  pid_x.Set=160.0; // 图像x轴的中心位置  本代码对应OpenMV使用QVGA格式(320*240)所以为160,视情况更改
  pid_x.Actual=0.0;
  pid_x.err=0.0;
  pid_x.err_last=0.0;
  pid_x.err_next=0.0;


  pid_y.Set=120.0;// 图像y轴的中心位置 
  pid_y.Actual=0.0;
  pid_y.err=0.0;
  pid_y.err_last=0.0;
  pid_y.err_next=0.0;


  Kp=KP; // 使用宏定义,参数整定直接对pid.h中的宏定义进行修改即可
  Ki=KI; //同上
  Kd=KD; //同上

(3)PID控制部分

  pid_x.Actual = x;
  pid_x.err = pid_x.Set - pid_x.Actual;
  float increment_x = Kp*(pid_x.err-pid_x.err_next)+Ki*pid_x.err+Kd*(pid_x.err-2*pid_x.err_next+pid_x.err_last);
  pwm_x -=(int)increment_x;
  if(pwm_x >= 18500)  // 限制x轴舵机的临界值
    pwm_x = 18500;
  else if(pwm_x <=17700)
    pwm_x = 17700;


  pid_x.err_last = pid_x.err_next;
  pid_x.err_next = pid_x.err;


  pid_y. Actual = y;
  pid_y.err = pid_y.Set - pid_y.Actual;
  float increment_y = Kp*(pid_y.err-pid_y.err_next)+Ki*pid_y.err+Kd*(pid_y.err-2*pid_y.err_next+pid_y.err_last);
  pwm_y += (int)increment_y;
  
  if(pwm_y >= 19100) // 限制y轴舵机的临界值
    pwm_y = 19100;
  else if(pwm_y <=18300)
    pwm_y = 18300;
    
  pid_y.err_last=pid_y.err_next;
  pid_y.err_next=pid_y.err;

本来在最初准备做这个毕设的时候,就是准备使用PID进行追踪的,后来因为时间的原因,取巧只使用比例控制,这次用PID实现了,也算是完成了当时的一个小小的心愿吧。

最后希望希望诸君共勉吧,哦对了,在写PID代码的时候,我突然想到可以在openmv部分加上人脸识别,然后实现追踪人脸的效果,哈哈哈哈这个我就不一定什么时候做了,算是留一个小小的坑吧,希望以后的我会给这个坑填上。


第二次补充

本次补充内容为硬件部分更改为PCB,代码部分优化了OpenMV部分代码,MCU从STM32F103ZET6替换为STM32F103C8T6,程序部分进行修改和优化。加之3D打印的支架,整体较之前更加小巧美观。

主控PCB:之前的洞洞板更改为PCB,整体部分看起来更加简洁,更加小巧,而且将主控从STM32F103ZET6系统板替换为STM32F103C8T6最小系统板,大幅降低成本,除了OpenMV之外,剩下的器件所有加起来用不到100块,OpenMV4 H7官方价格429元,闲鱼250-300之间,若是只用OpenMV做毕设后续不准备再用了,推荐在闲鱼上(或是其他二手途径),若是过后还准备继续深入的了解,我建议在官网上买,若是预算比较充足可以购买H7 plus。主控PCB尺寸:4.8cm*7.48。

焊接后:

其他补充内容,大家可以至番杰的csdn博客查看:

https://blog.csdn.net/JIE15164031299/article/details/119617832

本以为第二次补充会是对人脸进行追踪,没想到是更新了硬件,不过用洞洞板确实是比较麻烦,走线看起来还特别的乱,pcb看起来就好太多太多了;主控的话,从zet6替换为c8t6,成本大幅降低,尺寸也大幅降低,当然哈,性能丝毫不受影响;本来我是准备直接使用c8t6芯片,不使用最小系统板的,但是考虑到可能有的小伙伴没办法完好无损的焊上LQFP48封装,所以最后选择了最小系统板;整体而言,新版设计较旧版的更加的容易复刻,不能说是有手就行,只要是多少用点心,想把毕设做出来,就肯定能复刻出来。


END


转载自:达尔闻说

文章来源于毕业设计| STM32+OpenMV的云台追踪装置

原文链接:https://mp.weixin.qq.com/s/fe2lMZ820Ykf2spszhg0Pg

点击这里复制本文地址 以上内容由文彬编程网整理呈现,请务必在转载分享时注明本文地址!如对内容有疑问,请联系我们,谢谢!
qrcode

文彬编程网 © All Rights Reserved.  蜀ICP备2024111239号-4