一、准备工作
有关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);
}
}
发表评论