这篇文章用来分享第六届全国光电设计大赛智能车组的源码,本次比赛的赛题如下:
本队小车:
本队比赛现场的部分视频:
http://www.iqiyi.com/w_19s2h925xd.html
本次比赛我们组采用树莓派+opencv+wiringpi的解决方案,编程语言是c++,借助QT开发
一、基本设计思路:
1.1、读取摄像头数据,将图像转为HSV(色调,饱和度,明度)颜色空间;
1.2、提取色调(H)和明度(V)通道,设置阈值,将图像二值化;
1.3、找到图像中最大的目标,并求出包围 该目标的矩形中心坐标;
1.4、根据pid算法,控制小车舵机转向和车速的高低,向目标点前进;
1.5、小车靠近目标一定距离后,会刹车减速,将红外接近开关调节到20cm触发,当检测到触发信号,小车停车,进入灭灯状态;
1.6、灭灯后小车会后退,并且绕圆旋转,直到找到下一个目标为止;
二、程序源码
2.0、声明三个全局变量
#include "mainwindow.h"
#include
#include
using namespace std;
using namespace cv;
int m_timer=1;
int back = 1;
int speed = 0;
2.1、初始化IO口
wiringPiSetup(); //初始化wiringpi
pinMode(21,OUTPUT); //21-27:post
pinMode(22,OUTPUT);
pinMode(23,OUTPUT);
pinMode(24,OUTPUT);
pinMode(25,OUTPUT);
pinMode(26,INPUT); //后方红外对管
pinMode(27,INPUT); //前方红外对管
pinMode(28,INPUT); //编码器
softPwmCreate(1,22,100); //挡板控制,25收回,5展开
softPwmCreate(2,0,100); //电机后退控制
softPwmCreate(3,10,100); //舵机控制
softPwmCreate(4,25,100); //电机前进控制
小车总共需要控制两个舵机,一个电机;
为了控制电机的速度及前进倒退,小车采用了mos管电机驱动(淘宝网买的),通过wiringpi输出两路软件pwm值控制电机的前进后退,舵机同样如此;
事实上wiringpi的软件pwm精度非常低,舵机调节范围为5~25,精度为1,对应舵机的0~180度;
电机调节范围为0~100;
这里的两个主要函数为
pinMode(25,OUTPUT);
softPwmCreate(1,22,100);
pinmode的第一个参数为树莓派的硬件io口,第二个参数为OUTPUT代表输出,INPUT代表输入,整行意思是将25口设置为输出模式
softpwmcreate第一个参数为io口,第二个参数为pwm输出的初始值,第三个参数为最大值
2.2、初始化摄像头并设置摄像头参数
VideoCapture cap(0);
cap.set(CV_CAP_PROP_FRAME_WIDTH,320); //设置为320*240
cap.set(CV_CAP_PROP_FRAME_HEIGHT,240);
cap.set(CV_CAP_PROP_BRIGHTNESS,0.28 ); //设置亮度
cap.set(CV_CAP_PROP_SATURATION,0.87); //设置饱和度
cap.set(CV_CAP_PROP_CONTRAST,0.53); //设置对比度
饱和度亮度和对比度要根据现场情况进行调节
2.3、变量初始化
float P = 0.04125; //x轴pid算法中的p值
float D = 0.009; //x轴pid算法中的d值
int pwm_x =0;
int pwm_y = 50;
float P_Y = w.m_p_y; //y轴pid算法中的p值
float D_Y = 0.05; //y轴pid算法中的p值
int ThisError_Y = 0;
int LastError_Y = 0;
int ThisError_x = 0;
int LastError_x = 0;
Mat frame; //用于承载摄像头的图像数据
Mat edges;
vector channels; //提取图像通道时用到
vector> contours; //目标坐标时用到
vector hierarchy;
2.4、线程的初始化
w.workthread[1] = new WorkThread;
w.workthread[1]->flag = 1;
w.workthread[1]->close = 1;
w.timethread[1] = new TimeThread;
workthread用来处理小车从将要接近目标到小车灭灯再到后退等一系列动作
timethread起到一个定时器和标志位改变的作用
至此,程序的初始化已经完成,接下来将会进入程序的while循环模块,我将在下一篇继续分享