一 任务及设计要求

1.1任务

模拟飞行器(如无人机、导弹等)在空中飞行过程中使用九轴加速度/陀螺仪/磁力计模块采集姿态信息;并且能使用摄像头模块采集图像信息实现目标检测功能,从而实现飞行器朝目标飞行或者对目标实施精确打击。

二 实现功能

2.1 stm32f427开发板板载陀螺仪最终温漂造成的yaw轴误差保持在1°/1min以内;
2.2 k210开发板能够较准确地识别目标,并将图像显示在LCD屏上;
2.3 k210开发板将目标在LCD屏的位置信息通过串口发送给stm32f427开发板;
2.4 若目标在LCD中心附近(即不需要飞行器调整姿态),则stm32f427开发板蜂鸣器响;

三 系统原理框图及模块作用

3.1 系统原理框图

3.2 各模块作用

3.2.1 蜂鸣器模块
stm32f427开发板板载一个贴片蜂鸣器,该蜂鸣器需要使用PWM驱动,额定频率2700Hz,用以提示飞行器是否对准目标。

3.2.2 mpu6500+ist8310九轴陀螺仪传感器模块
stm32f427开发板集成一个IMU模块,由mpu6500陀螺仪和ist8310地磁传感器组成,用以采集姿态信息。

3.2.3 LCD模块
用以显示摄像头采集的图像,并将目标物体用矩形框标记,显示矩形框中心点坐标位置以及识别到的物体名称。

3.2.4 OV2640模块
用以采集图像,为k210目标检测提供信息。

四 硬件说明

4.1 硬件设计

4.2 硬件电路图及模块说明

4.2.1 蜂鸣器(STM32F4)

开发板板载一个贴片蜂鸣器,需要使用PWM驱动,额定频率2700Hz。
4.2.2 IMU(STM32F4)



开发板集成-一个IMU模块,其IMU由MPU6500陀螺仪和IST8310地磁传感器组成。为了解决陀螺仪温飘的问题,在MPU6500四周增加10颗加热电阻,可以通过PB5加热电阻控制管脚和MPU6500内部的温度传感器做恒温处理,加热温度一般控制在比电路板正常工作温度高15~20C为宜。10个加热电阻工作电压为24V,该电阻可以在1S内将IMU模块的温度从25C加热到50°C。板载IST8310的地址为: 0x0E。

五 程序流程图

5.1 主程序流程图

5.2 模块流程图及其说明

5.2.1 串口中断及串口虚拟示波器(STM32F427)

串口中断主要用于接收PC端发送的数据,并打印到串口助手上;并且同时要接收K210发送的8位大小的数据串(发送数据形式为:LCD屏上目标的三位数横坐标+‘/’+LCD屏上目标的三位数纵坐标+‘\n’),若当STM32F4串口接收完毕后,发生以下情况,则判断接收成功:
(1)接收到了8位数据
(2)接收到的第四位数据为‘/’
(3)接收到的第八位数据为‘\n’
以上条件缺一不可,若串口接收完毕后未能满足以上条件,则将数组清零重新接收。

串口虚拟示波器是一个PC端软件,有两种通讯协议 一种是CRC16另一种是ChkSum,我使用CRC16通信协议,简单的来说就是把我单片机的数据转换为示波器软件可以识别的形式读取并且显示。

以上为串口示波器的界面展示,有四个通道对应四条波形,界面可以实现放大、缩小以及跟随波形等功能。
串口示波器下载请移步俺的博客:
https://blog.csdn.net/Junhanie/article/details/105851994
5.2.2 九轴陀螺仪传感器初始化

MPU6500使用SPI通信,IST8310使用IIC通信。
设置的测量精度为gyro LPF 41Hz、 LPF 92Hz、±2000dps、±8G。

5.2.3 PWM+PID补偿温度误差调节姿态输出(定时器中断)

PWM+PID补偿温度误差调节姿态输出主体程序放在定时器中断内,5ms进入一次中断。
其中,温度PID+PWM调节函数mpu_temp_control用于控制陀螺仪环境温度处于理想状态,缓解温漂对YAW轴造成的误差。在开发板第一次上电后,PWM输出以一个较大的值2000加热陀螺仪传感器模块周围电阻,当温度超过设定温度累计次数20次以上时,启动PID调节PWM输出,PID算法函数pid_calc输入量为实际温度和设定温度。
其中,一阶低通滤波函数first_order_filter_calc起到的作用是放缓PID输出数据的变化,避免因为个别数据误差较大导致PID输出量突然变化较大导致的温度不稳定情况,sampling_period采样周期为1,RC_time时间常数为100。根据一阶数字低通滤波算法Y(n)=T/(T+RCX(n))+RC/(T+RCY(n−1))改造first_order_filter_calc函数,RC即为RC_time,T即为sampling_period。

5.2.4 深度学习模型(yolov3)

对我帮助很大的是B站up主理工男的春天,参考视频请见
https://www.bilibili.com/video/BV1tT4y1573S
up主有很多视频介绍yolo等算法入门,强烈推荐

yolo代码以及环境配置参考
https://github.com/TonyZ1Min/yolo-for-k210

下次再出一个博客谈谈俺踩过的坑

六 代码分析

6.1 STM32F4 定时器部分

因为我大部分处理数据的代码都是放在定时器中断里

#include "timer_pid.h"
#include "pid.h"
#include "delay.h"
#include "usart.h"
#include "init.h"
#include "filter.h"
#include "ahrs.h"
#include "mpu6500.h"
#include "imu.h"
#include "adc.h"
#include "global_def.h"//5ms
struct attitude mahony_atti;
struct ahrs_sensor mpu_sensor;
float mputemp2;extern float mcu_temp;
extern pid_t pid_temp;
uint8_t mpu_count=0,mpu_flag=0;static uint8_t first_temperate = 0;//µÚÒ»´ÎζÈÎȶ¨Ç° Îȶ¨ºóΪ1
static uint8_t second_temperate = 0;
const float *get_mcu_temp(void)
{return &mcu_temp;
}const struct attitude* get_imu_data(void)
{return &mahony_atti;
}/*** @brief ¶¨Ê±Æ÷1³õʼ»¯|Ħ²ÁÂÖpwmÊä³ö* @param  void* @retval void* @attention */
void timer1_init(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;GPIO_InitTypeDef GPIO_InitStruct;TIM_OCInitTypeDef TIM_OCInitStruct;GPIO_PinAFConfig(GPIOA, GPIO_PinSource8, GPIO_AF_TIM1);GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_TIM1);GPIO_PinAFConfig(GPIOE, GPIO_PinSource13, GPIO_AF_TIM1);GPIO_PinAFConfig(GPIOE, GPIO_PinSource14, GPIO_AF_TIM1);GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;GPIO_InitStruct.GPIO_Speed = GPIO_High_Speed;GPIO_Init(GPIOA, &GPIO_InitStruct);GPIO_InitStruct.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14;GPIO_Init(GPIOE, &GPIO_InitStruct);TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;TIM_TimeBaseInitStruct.TIM_Period = 2500 - 1;  TIM_TimeBaseInitStruct.TIM_Prescaler = 180 - 1;TIM_TimeBaseInit(TIM1, &TIM_TimeBaseInitStruct);TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;TIM_OCInitStruct.TIM_OCNPolarity = TIM_OCNPolarity_High;TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStruct.TIM_OutputNState = TIM_OutputNState_Disable;TIM_OCInitStruct.TIM_OCIdleState = TIM_OCIdleState_Reset;TIM_OCInitStruct.TIM_OCNIdleState = TIM_OCNIdleState_Reset; TIM_OCInitStruct.TIM_Pulse = 900;TIM_OC1Init(TIM1, &TIM_OCInitStruct);TIM_OC2Init(TIM1, &TIM_OCInitStruct);TIM_OC3Init(TIM1, &TIM_OCInitStruct);TIM_OC4Init(TIM1, &TIM_OCInitStruct);TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);TIM_OC2PreloadConfig(TIM1, TIM_OCPreload_Enable);TIM_OC3PreloadConfig(TIM1, TIM_OCPreload_Enable);TIM_OC4PreloadConfig(TIM1, TIM_OCPreload_Enable);TIM_ARRPreloadConfig(TIM1, ENABLE);TIM_CtrlPWMOutputs(TIM1, ENABLE);TIM_Cmd(TIM1, ENABLE);
}/*** @brief 定时器3初始化,PWM加热陀螺仪周围电阻* @param  void* @retval void* @attention */
void timer3_init(void)
{   TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;GPIO_InitTypeDef GPIO_InitStructure;NVIC_InitTypeDef NVIC_InitStructure;TIM_OCInitTypeDef TIM_OCInitStructure;RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);GPIO_PinAFConfig(GPIOB, GPIO_PinSource5, GPIO_AF_TIM3);RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM3, ENABLE);RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM3, DISABLE);NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 5;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);//TIM3_Int_Init(5000,1) rm????TIM_TimeBaseInitStructure.TIM_Period = 500 - 1;//50usTIM_TimeBaseInitStructure.TIM_Prescaler = 3 - 1;//90*1000000/9 = 10Mhz 0.1usTIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;//    TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);/* TIM3 */GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;GPIO_Init(GPIOB, &GPIO_InitStructure);TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;TIM_OC2Init(TIM3, &TIM_OCInitStructure);TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);TIM_ARRPreloadConfig(TIM3, ENABLE);TIM_Cmd(TIM3, ENABLE);
}void timer4_init(void)
{RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;GPIO_InitTypeDef GPIO_InitStruct;TIM_OCInitTypeDef TIM_OCInitStruct;GPIO_PinAFConfig(GPIOD, GPIO_PinSource12, GPIO_AF_TIM4);GPIO_PinAFConfig(GPIOD, GPIO_PinSource13, GPIO_AF_TIM4);GPIO_InitStruct.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13;GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;GPIO_InitStruct.GPIO_Speed = GPIO_High_Speed;GPIO_Init(GPIOD, &GPIO_InitStruct);TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;TIM_TimeBaseInitStruct.TIM_Period = 20000;       TIM_TimeBaseInitStruct.TIM_Prescaler = 90 - 1;    //90 - 1TIM_TimeBaseInit(TIM4, &TIM_TimeBaseInitStruct);TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;TIM_OC1Init(TIM4, &TIM_OCInitStruct);TIM_OC2Init(TIM4, &TIM_OCInitStruct);TIM_OC1PreloadConfig(TIM4, TIM_OCPreload_Enable);TIM_OC2PreloadConfig(TIM4, TIM_OCPreload_Enable);TIM_ARRPreloadConfig(TIM4, ENABLE);TIM_Cmd(TIM4, ENABLE);
}
//定时器5  开启定时器中断
void timer5_init(void)
{RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5,ENABLE);TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;NVIC_InitTypeDef NVIC_InitStruct;TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;TIM_TimeBaseInitStruct.TIM_Period=2000-1;TIM_TimeBaseInitStruct.TIM_Prescaler=90-1;TIM_TimeBaseInit(TIM5,&TIM_TimeBaseInitStruct);TIM_ITConfig(TIM5,TIM_IT_Update,ENABLE);TIM_Cmd(TIM5,ENABLE);NVIC_InitStruct.NVIC_IRQChannel=TIM5_IRQn;NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=1;NVIC_InitStruct.NVIC_IRQChannelSubPriority=2;NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;NVIC_Init(&NVIC_InitStruct);
}
//蜂鸣器初始化
void Buzzer_Init(void)
{RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOH,ENABLE);RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM12,ENABLE);GPIO_InitTypeDef GPIO_InitStruct;GPIO_InitStruct.GPIO_Pin=GPIO_Pin_6;GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF;GPIO_InitStruct.GPIO_Speed=GPIO_High_Speed;GPIO_InitStruct.GPIO_PuPd=GPIO_PuPd_UP;GPIO_InitStruct.GPIO_OType=GPIO_OType_PP;GPIO_Init(GPIOH,&GPIO_InitStruct);}
//蜂鸣器PWM
void Buzzer_PWMSet(int16_t f)
{TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;TIM_OCInitTypeDef TIM_OCInitStruct;GPIO_PinAFConfig(GPIOH, GPIO_PinSource6, GPIO_AF_TIM12);TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;TIM_TimeBaseInitStruct.TIM_Period = 1000000/f - 1;TIM_TimeBaseInitStruct.TIM_Prescaler = 90 - 1;TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;TIM_TimeBaseInit(TIM12, &TIM_TimeBaseInitStruct);TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_Low;TIM_OC1Init(TIM12, &TIM_OCInitStruct);TIM_OC1PreloadConfig(TIM12, TIM_OCPreload_Enable);TIM_ARRPreloadConfig(TIM12, ENABLE);TIM_Cmd(TIM12, ENABLE);     TIM_SetCompare1(TIM12, (1000000/f - 1)/2);
}
//
void Buzzer_Disable(void)
{TIM_Cmd(TIM12, DISABLE);
}
// 蜂鸣器播放音乐
void Music_Play(uint8_t flag)
{int i;if(flag == 0){Buzzer_PWMSet(D1);delay_ms(100);Buzzer_PWMSet(D5);delay_ms(100);}Buzzer_Disable();
}
float input=1000;
float d_yaw,lsat_d_yaw=0,final_yaw=0;
//定时器中断服务函数
void TIM5_IRQHandler(void)
{if(TIM_GetITStatus(TIM5,TIM_IT_Update)!=RESET){mpu_get_data(&mpu_sensor);     //获取陀螺仪信息mahony_ahrs_updateIMU(&mpu_sensor,&mahony_atti);    //用mahony_ahrs算法解算mpu_get_temp(&mahony_atti.temp);             //imu temp get by mpu/return *tmpmcu_temp=get_temprate();      //获取A板CPU温度,用ADC测量mpu_temp_control(&mahony_atti.temp);
//      VisualScope_Output(mahony_atti.pitch,mahony_atti.roll ,mahony_atti.yaw, mahony_atti.temp);
//      d_yaw=(float)mahony_atti.yaw;   //ÕâÀï²ÉÓù̶¨Ê±¼ä¼õÈ¥Õâ¶Îʱ¼äÄÚµÄÎÂƯ²úÉúµÄyawÖáÆ«²îµÄÀÛ¼ÆÖµ£¬»ººÍËäÈ»²ÉÓÃÁ˼ÓÈÈÍÓÂÝÒÇÀ´Î¬³Öζȣ¬µ«ÊÇÈÔÈ»»áÓдó¸Å1¡ã/1minµÄÇé¿ö
//      mahony_atti.yaw=constrain_judge_motion(d_yaw,lsat_d_yaw,0.05); //±È½ÏÁ½´ÎÍÓÂÝÒÇyawÖáÊý¾ÝµÄ²îÖµ£¬ÈôСÓÚ0.05£¬Ôò¼ÆÈëÍÓÂÝÒÇÎó²î·¶³ë£¬ÀÛ¼ÆÆðÀ´£¬¹ýÒ»¶Îʱ¼ä¾Í¼õµôÕâЩÀۼƲîÖµ£¬0.05Õâ¸öÊýÖµÊÇÒª±£Ö¤A°åÕý³£Ô˶¯Ï£¬yawÖáÊýÖµ±ä»¯²»±»¼ÆÈëÎó²î
//      lsat_d_yaw=(float)mahony_atti.yaw;
//      printf("yaw angle is %f, pitch angle is %f, rol angle is %f\r\nmcu temp is %f, mpu temp is %f\r\n",
//                      mahony_atti.yaw, mahony_atti.pitch, mahony_atti.roll, mcu_temp, mahony_atti.temp);TIM_ClearFlag(TIM5,TIM_IT_Update);}
}/*** @brief 陀螺仪温度控制函数,先以pwm比较值为2000加热陀螺仪,第一次达到设定温度后,启动pid* @param  void* @retval void* @attention */
void mpu_temp_control(float *temp)
{   uint16_t temp_pwm;static uint8_t temp_conunt_time = 0 ,temp_conunt_time2=0;if (first_temperate==1){ pid_temp.ilimit = 100;pid_temp.iout=60;pid_temp.p=80;pid_temp.i=0.3;pid_temp.d=100;pid_calc(&pid_temp,*temp,mahony_atti.set_temp);temp_pwm = constrain_float(pid_temp.out, 0, +1000);first_order_filter_calc(&all_control_s.first_order_lowpass_filter_imu,temp_pwm);temp_pwm=all_control_s.first_order_lowpass_filter_imu.out;imu_temp_pwm_set(temp_pwm);}else {if (*temp > (mahony_atti.set_temp-1)){temp_conunt_time ++;if(temp_conunt_time > 20){       first_temperate = 1;}}imu_temp_pwm_set(2000);}
}

6.2 串口中断部分

STM32用以接收K210发送的坐标数据,数据形式为图像在LCD屏上的x坐标+‘/’+y坐标+‘0x0d’,坐标都是3位数,百位小于一则补0如089,加起来总共8位数据,接收到的数据若第四位不是‘/’或者最后一位不是‘0x0d’则判断接收失败,失败的原因可能有串口与串口的连接线不等长或者信号干扰导致串口漏发、错位发送数据。


//USART2½ÓÊÜÖжÏ
void USART2_IRQHandler(void)
{u8 Res,len;if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)  // 接收中断,接收到的数据必须以0x0d,0x0a结尾{Res =USART_ReceiveData(USART2);//(USART2->DR);   //读取接收到的数据if((USART_RX_STA&0x8000)==0)//接收未完成{if(USART_RX_STA&0x4000)//接收到了0x0d{if(Res!=0x0a)USART_RX_STA=0;//接收错误,重新开始else USART_RX_STA|=0x8000;   //接收完成了len=USART_RX_STA&0x3fff;for(int t=0;t<len;t++){USART2->DR=USART_RX_BUF[t];while((USART2->SR&0X40)==0);}
//              printf("%d%d%d  %d%d%d \r\n",USART_RX_BUF[0],USART_RX_BUF[1],USART_RX_BUF[2],USART_RX_BUF[4],USART_RX_BUF[5],USART_RX_BUF[6]);USART_RX_STA=0;}else //还没收到0x0d{   if(Res==0x0d){USART_RX_STA|=0x4000;}else{USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;USART_RX_STA++;if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收数据错误,重新开始接收}        }} }       //  the width limit of k210-lcd:320---------the high limit of k210-lcd:240if( (Res==0x0a)&&(USART_RX_BUF[3]!='/')&&(USART_RX_BUF[7]!='\n' ) )//判断接收到的数据是否符合协议,若否,则赋予所有数据为‘w’{for(int count_r=0;count_r<8;count_r++){USART_RX_BUF[count_r]='w';}USART_RX_STA=0;}
//  Music_Play(0);if((USART_RX_BUF[0]=='1')&&(USART_RX_BUF[4]=='1')&&(USART_RX_BUF[1]=='4')&&(USART_RX_BUF[5]=='4'))//判断是否在设定坐标左右,若是,则蜂鸣器响{Music_Play(0);}
}

6.3 K210部分

我使用了TF卡储存训练后转化为Kmodel文件的模型,然后K210串口与STM32F4串口相连,如何训练模型并且转化模型?请移步

B站up主理工男的春天
https://www.bilibili.com/video/BV1tT4y1573S

或者我只后有时间再详细写。。。写博客太累了吧。

from fpioa_manager import *
from fpioa_manager import fm
from machine import UART
from Maix import GPIO
import sensor
import image
import lcd
import time
import math
import KPU as kpu
#LCD初始化
lcd.init()
#摄像头初始化
sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA)
sensor.set_windowing((224, 224))
sensor.set_hmirror(0)
sensor.run(1)
clock = time.clock()
#串口初始化
fm.register(board_info.PIN15,fm.fpioa.UART1_TX)
fm.register(board_info.PIN17,fm.fpioa.UART1_RX)
uart_A = UART(UART.UART1, 115200, 8, None, 1, timeout=1000, read_buf_len=4096)
classes = ['class_1']
#载入模型
task = kpu.load("/sd/test.kmodel")
anchor = (1, 1.2, 2, 3, 4, 3, 6, 4, 5, 6.5)
a = kpu.init_yolo2(task, 0.17, 0.3, 5, anchor)
info=kpu.netinfo(task)
while(True):clock.tick()img = sensor.snapshot()code = kpu.run_yolo2(task, img)print(clock.fps())if code:for i in code:#计算目标框的几何中心坐标center_x=(  i.x()+  (i.w()//2)  )center_y=(  i.y()+  (i.h()//2)  )#画框和十字a=img.draw_rectangle(i.rect())a=img.draw_cross(center_x,center_y)a = lcd.display(img)print(i.classid(),i.value())for i in code:#显示目标类别lcd.draw_string(i.x(), i.y(), classes[i.classid()], lcd.RED, lcd.WHITE)center_x_1=center_x//100center_y_1=center_y//100#判断坐标是否为3位十进制,若不是,则在数字前填充0直至3位十进制if center_x_1<1:uart_A.write('0{}/'.format(center_x))else:uart_A.write('{}/'.format(center_x))if center_y_1<1:uart_A.write('0{}\n'.format(center_y))else:uart_A.write('{}\n'.format(center_y))else:a = lcd.display(img)
uart_A.deinit()
del uart_A
a = kpu.deinit(task)

七 结果展示

7.1 陀螺仪效果展示


上图为串口示波器界面,其中CH1通道1为陀螺仪PITCH轴数据、CH2通道2为陀螺仪ROLL轴数据、CH3通道为陀螺仪YAW轴数据、CH4通道为陀螺仪实时温度。
其中,横坐标为时间坐标轴(1min/30000),纵坐标为数值大小,串口示波器的数值表现形式均为整数形式,解释了曲线部分地方为锯齿状的原因。

放大纵坐标轴对陀螺仪PITCH/ROLL/YAW轴数据进行观察,结合图 7.1可以发现在0-20000(时间坐标轴)时间段内,即大约40s内,陀螺仪传感器模块温度达到设定值,在此期间陀螺仪PITCH/ROLL/YAW轴数据抖动变化较明显。
而在大约50000-350000(1min40s-12min)温度稳定期间可以得出以下结果:
(1)陀螺仪PITCH数据(红色)稳定在2°-3°内
(2)陀螺仪ROLL数据(黄色)稳定在(-2)°-(-3)°内
(3)陀螺仪YAW数据(蓝色)稳定在1°-3°内,平均3min变化1°

7.2 STM32F4串口接收K210数据效果展示

若检测到目标(浣熊)则发送坐标信息给STM32F4,反之则正常显示摄像头图像

上图为正确接收到正确数字的情况,通过debug观察USART_RX_BUF[]数组的内容[0]-[2]为x坐标,[4]-[6]为y坐标轴。[3]和[7]起到校验作用。

上图为接收到错误数字的情况,将给SART_RX_BUF[]数组赋值为‘w’。

若检测到目标(浣熊)则在LCD上以框的形式标记,反之则正常显示摄像头图像。效果展示以视频的形式展示,请参考附件视频。
检测15张照片,其中11张浣熊照片,2张猫照片,2张狗照片,能够稳定有效检测到9张浣熊照片,不稳定检测到2张浣熊照片,对其他照片没有反应。效果良好,影响效果的因素主要是摄像头像素太低,或者我没有调焦好

视频展示请参考
链接:https://pan.baidu.com/s/1Cwxrqzl-WnnkeEv9fUg3tA
提取码:iuvn

STM32F427主控(大疆A板)+K210视觉处理相关推荐

  1. 大疆开发板A型基于HAL库驱动M3508直流无刷电机及PID控制

    1.首先,我们先了解一下大疆开发板A型的资料,官方有提供 官网:RoboMaster 机甲大师赛 芯片型号STM32F427IIH6 2.了解M3508直流无刷电机的资料,官网有提供  3.于是我找到 ...

  2. 大疆A板STM32427用CAN通信进行M2006/M3508位置闭环和往复转动

    前言 首先先介绍下自己的情况,博主没上过单片机的课,单片机的基础很薄弱,大一没有任何基础就直接上了恩智浦的K66,一直处于囫囵吞枣.赶鸭子上架的状态,所以写的代码跟屎一样,仅仅只是能实现功能而已,从中 ...

  3. 大疆C板利用BMI088传感器进行姿态解算

    实物教程--大疆C板读取BMI088传感器数据_操气的小虫儿的博客-CSDN博客_bmi088代码 这是我写的上一篇文章,用SPI实现了读取BMI088传感器数据. 现在要做的就是在读取BMI088传 ...

  4. 2.STM32F427llHX(大疆A板) 点亮小灯(库函数版本)

    基于空白模板点亮小灯 1.在Template文件夹中新建HARDWARE文件夹 2.在HARDWARE文件夹中新建LED文件夹 3.从正点原子实验1中复制led.c和led.h到LED文件夹中 4.右 ...

  5. 1.STM32F427llHX(大疆A板) 模板创建(库函数版本)

    本文从正点原子stm32f407例程(库函数)修改移植至stm32f427, 正点原子stm32f407例程链接 提取码:1234 新建文件夹 新建一个文件夹,后面所建立的工程都可以放在这个文件夹下面 ...

  6. 从零开始,用CubeMX让M2006电机转起来,大疆C板控制M2006电机

    发现网上很少有关于这个的文章,到处找,搜索引擎试了个遍,还在Robomaster的论坛里找了找,最终也是没有找到类似的文章.还好在B站上找到了一个视频教程,帮助很多,致敬前辈!,视频链接在文末.但是这 ...

  7. CAN通信紊乱解决办法 关于大疆6020电机与2006电机同时挂在CAN2上通信紊乱的解决办法

    大疆C板例程改动 CAN通信紊乱解决办法 关于大疆6020电机与2006电机同时挂在CAN2上通信紊乱的解决办法 C板例程的standard_robot里六个电机都是挂在CAN1总线上,由于6020电 ...

  8. App开发日报 2015-05-15 大疆无人机IOS开发之搭建DJI Phantom和iOS视觉平台

    App开发日报 2015-05-15 @好东西传送门 出品, 过刊见 http://app.memect.com 订阅:给 hao@memect.com 发封空信, 标题: 订阅App开发日报 可点击 ...

  9. 大疆M100无人机 妙算Manifold 深度学习视觉伺服系统 学习历程(一)妙算Manifold环境配置

    实验室有一架 DJI M100 无人机和若干台 DJI Manifold ,由于与我的研究方向有相关性,因此打算将其利用起来做一些深度学习视觉伺服的开发工作,本系列文章将一些我在学习和研究过程中经历的 ...

最新文章

  1. Android 获取手机系统信息
  2. 洛谷P5273 【模板】多项式幂函数 (加强版)
  3. Maven修改默认本地资源库文件夹
  4. python量化交易书_Python量化交易
  5. matlab群延时函数,群延迟函数(group delay function)群延迟滤波器 | 学步园
  6. Xiki Shell Kickstarter,HummingBoard计算机等
  7. 图标选择器_【小技巧】巧用CSS属性值正则匹配选择器
  8. 两位小数乘两位小数竖式_人教版小学数学五年级上册小数乘整数公开课优质课课件教案视频...
  9. 四则运算 来源:一位热心的网友 http://www.tqcto.com/article/software/336297.html
  10. PAT(Basic Level)--个位数统计
  11. Spring2.5整合ActiveMQ 5.2(P2P文本消息)
  12. [转]Android--多线程之Handler
  13. 浅谈C++ Lambda 表达式(简称LB)
  14. xci转nsp工具_再谈xci、nsz、nsp
  15. 计算机联锁系统硬件结构,计算机联锁系统各部硬件.ppt
  16. Photoshop之渐变工具使用
  17. suger数据库使用1
  18. 10M独享带宽,能承受多少人下载文件?
  19. [Python从零到壹] 四.网络爬虫之入门基础及正则表达式抓取博客案例
  20. 响应式织梦模板智能安防监控类网站

热门文章

  1. (转)IE和火狐的css兼容性问题归总
  2. Vuforia提高识别以及稳定性方法总结
  3. 微信分享自定义多次分享设置
  4. 倍福EK1110模块介绍
  5. my.宝石 --- --- ZC 收集
  6. 科创、创业板块崛起,天弘科创创业50指数基金缘何备受热捧?
  7. 需求工程的“拨乱反正”
  8. 使用百度网盘上传大文件到云服务器
  9. wait waitpid waitid wait3 wait4
  10. Gradle构造Spring boot项目(使用私服地址)