作者:Edison钟
日期:2012.6
产品&技术开发背景:
- 基于之前理论学习系统性实践嵌入式产品开发
- 初步实现对摄像头的驱动及图像显示
- 了解机器视觉的基本原理及目标识别追踪
设计目标及要求:
- 驱动类型:2个DC减速电机前轮驱动,后轮采用万向轮
- 运动控制: 前进,后退,左转,右转,壁障,目标追踪
- 控制方式:红外壁障,摄像头目标追踪,PC无线控制,RF四路无线控制
- 上位机开发用于摄像头图像显示及追踪目标的RGB设置
设计思路及原理:
- 驱动摄像头读取图像传感器的原始数据RGB565格式并解码各自R,G,B值用于目标识别
- 对图像像素级扫描,识别到目标颜色后记录当前像素的X,Y坐标值判断该目标在该视场的相对位置
- 驱动前轮实现目标的追踪或者避障,驱动双舵机摄像头云台实现目标的精细追踪
- IR传感器主要用于近距离避障
- 通过VS6开发的上位机软件实现与小车的串口通信用于图像显示及目标颜色设置
硬件选型:
- 电源:DC5V
- 核心控制器:STC12C5A60S2 1T单片机,硬件资源:两个16位定时器,两路8位PWM输出,两个自带独立波特率发生器串口,两路外部中断
- 传感器:
- 红外线传感器
- OV7670 CMOS图像传感器
- 动力执行元件:
- DC电机类型:TT减速电机,额定转速180RPM, 减速比48:1
- 输出轴连接方式:腰型头
- 2路辉盛SG90 9克舵机
- 电机驱动板:
- 驱动类型:L293D双H桥
- 最大允许电压:36V
- 持续工作电流:1A
- 最高工作电流:2A
- 控制方式:电机方向控制,2路PWM 0%-100%无极调速

模型总装图

上位机图像显示及目标RGB设置

实测避障算法初步测试
视频链接: 小车避障测试-CSDN直播
设计注意事项:
- 红外壁障如何去除可见光干扰
- 摄像头如何通过算法对目标的识别
- 后续建议加入三轴磁力计实现方位的精准建模
项目回顾及展望:
- 通过前期的理论学习第一次实现了对整个系统各硬件的驱动与控制
- 初步实现了目标的识别和追踪
- 践行了概念到原型机落地测试的整个开发过程
- 为后续项目的概念开发及验证打下坚实基础
控制软件版本更改记录:
V0.1:
- 原始版本
- MCU: STC90C516RD@11.0592MHz
- 定时器0产生38KHz PWM信号用于红外壁障
- 定时器1用于串口波特率发生器
- 串口波特率为57600
V0.2:
- MCU: STC12C5A60S2@10592MHz
- 更改红外发射延时时间
V0.3:
- 增加2舵机以控制摄像头上下左右转动追踪目标
- 定时器0产生8路PWM信号控制2路舵机
- 因定时器0用于产生PWM信号控制舵机,红外壁障功能被取消
最新软件代码:
/*******************************************V0.3*******************************************/
/**************************************************************************
This program is to control the robot to run automatically, the robot can
detect the barriers in front of it by using 2 IR sensors, and can execute
responding actions preprogrammed to avoid crashing the barrier.
Sensors like acceleration detect, IR human detect could be added to extend
the function and make it smarter.
MCU: STC12C5A60S2
晶震频率:11.0592MHz
**************************************************************************/
#include <REG51.h>
#include "Robot_Driver.h"
#include "MCU_Setting.h"
#include "OV7670.h"
#include "Servo_Driver.h"
//#include "LCD_GYTF018LB35B0M.h"
#define uchar unsigned char
#define uint unsigned int
#define RGBVALUE 0x00
#define COMMAND 0x01
#define STOP 0xff
#define red 0xf800
#define green 0x07e0
#define blue 0x001f
#define white 0xffff
#define black 0x0000
uchar ReData[4],SenData[],PCCommand=0;
uchar KEY_A=0;
uchar Capture=0,OV7670_flag=0;
uchar Quit=1;
uchar i=0;
uchar temp;
uchar Target_R=255,Target_G=0,Target_B=0;
uchar Robot_EN=0;
uchar order_flag,Deg_1,Deg_2,Deg_3,Deg_4,Deg_5,Deg_6,Deg_7,Deg_8;
uint T_1,T_2,T_3,T_4,T_5,T_6,T_7,T_8;
bit servo_3;
bit servo_4;
bit servo_5;
bit servo_6;
bit servo_7;
bit servo_8;
/*****************************************************
入口函数
*****************************************************/
void main(void)
{
MCU_init(); //MCU初始化
//LCD_init(); //LCD初始化
OV7670_init(); //摄像头初始化
//LCD_paint(black); //LCD刷黑色
while(1)
{
//ET0=0;
/****************************************************
if(RF_INPUT_A==1) //遥控控制模式切换
{
while(RF_INPUT_A);
KEY_A++;
Robot_EN=1;
if(KEY_A>3) KEY_A=0;
}
/****************************************************/
if(ReData==10) KEY_A=0; //PC控制模式切换
if(ReData==11) KEY_A=1;
if(ReData==12) KEY_A=2;
if(ReData==13) KEY_A=3;
/****************************************************/
//KEY_A=3;
if(KEY_A==0) PC_control(); //控制模式
if(KEY_A==1) RF_control();
if(KEY_A==2) IR_control();
if(KEY_A==3) camera_control();
}
}
/*****************************************************
定时器中断函数
/****************************************************/
void timer0(void) interrupt 1 using 1
{
//PWM_output=!PWM_output; //产生38KHz脉冲用于发送红外信号
switch(order_flag)
{
case 1:
servo_1=1;
TH0=T_1>>8; //TH0=-t1/256;
TL0=T_1; //TH0=-t1%256;
break;
case 2:
servo_1=0;
TH0=(0xf700-T_1)>>8; //-(2700-t1)/256
TL0=(0xf700-T_1); //-(2700-t1)%256
break;
case 3:
servo_2=1;
TH0=T_2>>8;
TL0=T_2;
break;
case 4:
servo_2=0;
TH0=(0xf700-T_2)>>8;
TL0=(0xf700-T_2);
break;
case 5:
servo_3=1;
TH0=T_3>>8;
TL0=T_3;
break;
case 6:
servo_3=0 ;
TH0=(0xf700-T_3)>>8;
TL0=(0xf700-T_3);
break;
case 7:
servo_4=1;
TH0=T_4>>8;
TL0=T_4;
break;
case 8:
servo_4=0;
TH0=(0xf700-T_4)>>8;
TL0=(0xf700-T_4);
break;
case 9:
servo_5=1;
TH0=T_5>>8;
TL0=T_5;
break;
case 10:
servo_5=0;
TH0=(0xf700-T_5)>>8;
TL0=(0xf700-T_5);
break;
case 11:
servo_6=1;
TH0=T_6>>8;
TL0=T_6;
break;
case 12:
servo_6=0;
TH0=(0xf700-T_6)>>8;
TL0=(0xf700-T_6);
break;
case 13:
servo_7=1;
TH0=T_7>>8;
TL0=T_7;
break;
case 14:
servo_7=0;
TH0=(0xf700-T_7)>>8;
TL0=(0xf700-T_7);
break;
case 15:
servo_8=1;
TH0=T_8>>8;
TL0=T_8;
break;
case 16:
servo_8=0;
order_flag=0;
TH0=(0xf700-T_8)>>8;
TL0=(0xf700-T_8);
break;
}
order_flag++;
}
/*****************************************************
串口中断程序
*****************************************************/
void ser_int (void) interrupt 4 using 1
{
if(RI == 1) //RI接受中断标志
{
RI = 0; //清除RI接受中断标志
ReData[i] = SBUF; //SUBF接受/发送缓冲器
i++;
if(i==4&&ReData[0]==COMMAND)
{
//ES=0;
if(ReData[1] ==10) {KEY_A=0;Robot_EN=0;Quit=0;} //PC控制模式切换
else if(ReData[1]==11) {KEY_A=1;Robot_EN=0;Quit=0;}
else if(ReData[1]==12) {KEY_A=2;Robot_EN=0;Quit=0;}
else if(ReData[1]==13) {KEY_A=3;Robot_EN=0;Quit=0;}
else if(ReData[1]==14) {Robot_EN=1;}
else if(ReData[1]==15) {Robot_EN=0;}
else PCCommand=ReData[1];
i=0;
/*
SBUF=ReData[0];
while(!TI);
TI=0;
SBUF=ReData[1];
while(!TI);
TI=0;
SBUF=ReData[2];
while(!TI);
TI=0;
SBUF=ReData[3];
while(!TI);
TI=0;
//ES=1;
*/
}
else if(i==4&&ReData[0]==RGBVALUE)
{
//ES=0;
Target_R=ReData[1]; //PC控制模式切换
Target_G=ReData[2];
Target_B=ReData[3];
i=0;
/*
SBUF=ReData[0];
while(!TI);
TI=0;
SBUF=ReData[1];
while(!TI);
TI=0;
SBUF=ReData[2];
while(!TI);
TI=0;
SBUF=ReData[3];
while(!TI);
TI=0;
//ES=1;*/
}
else if(i>=4)i=0;
}
}

611

被折叠的 条评论
为什么被折叠?



