这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 高校专区 » 湖北理工TEA » B8组 (康夏涛,符友,罗积昌) 两轮平衡小车

共13条 1/2 1 2 跳转至

B8组 (康夏涛,符友,罗积昌) 两轮平衡小车

菜鸟
2016-04-15 23:29:37     打赏
      我们组准备做一个平衡小车,预计功能会有红外寻迹,超声波避障,无线操控,用到1602显示屏,红外遥控输入密码开始运行,电机用的是减速电机,无操作时小车待机进入低耗模式,调好这些,还会增加更多功能。



关键词: 智能小车     单片机     平衡小车    

菜鸟
2016-04-15 23:42:41     打赏
2楼

     之前学了PCB,做了一个单片机最小系统的板子,考虑到预选赛,所以我加了LED灯,红外线接收头,蜂鸣器,lcd屏的接口。

     前不久材料到了,一直没焊,昨天晚上本来以为半个小时可以焊好的,没想到PCB的板子一点都不好焊,要不就怪我烙铁和锡了,反正我还是相信我的焊工的

      改一下红外线和lcd屏程序下载之后,又调了一个小时(好多虚焊的地方),还好功夫不负有心人,终于可以安心睡觉了。 

请输入一个密码

我的密码是343536,哈哈


菜鸟
2016-04-16 19:46:20     打赏
3楼

      做车嘛,电机是主要的吧,所以第一部开调电机的程序了,我用的电机是n20减速电机,查了一下资料,要用到驱动,刚好之前买了个L298N步进电机的驱动模板,试了一下,驱动模板一边接电机,另一边接单片机两个io口,赋一个高电平一个低电平,电机和单片机没有共地,电机可以工作,发现转速有一点慢,应该接更高伏的电。一开始我是想用PWM信号的方法进行调速,调好程序后确实有效果,不过后来我想用三个轮子做一个车就好了,后面装一个万向轮,就可以省了用步进电机转弯,我的想法是靠前面减速电机的速度差进行转弯,最后决定就用两个速度,一个非常慢,一个是最快速度。首先用到四个独立按键进行控制小车前后左右的效果,因为还没有搭架子,直接接两个电机看效果,调好程序后,简直完美。 


菜鸟
2016-04-16 23:00:52     打赏
4楼

      淘宝买材料时看到一家的陀螺仪资料挺多的,本来就特别想做平衡小车,立马狠心花二十几块买了,收到货发现就是挺小的一个东西

(附上原理图)

      看了那些资料,其实和没有一样,都是英文的,还好卖家给了代码,幸亏能看懂,有zyx三个轴,我取y轴的数出来,用于控制平衡小车平衡,程序是写好了,发现没有架子是根本不能调程序的。


菜鸟
2016-04-16 23:21:12     打赏
5楼

      然后今天下午就开始搭架子了

(简单的稳压电路)

(装这两个电机打孔打了半天

(安上驱动和陀螺仪)(逼格一下就出来了

(然后一切都搞好了,先用移动电源玩一玩,四个独立按键代表前后左右,就是不平衡,但拿着他还是可以走一下的

待我写好小车平衡的程序再来好好玩,确实挺好玩的

不过估计想让他平衡就不是那么简单了


菜鸟
2016-04-17 18:33:24     打赏
6楼

      今天上午调了一上午的平衡程序,发现好多问题,电机这块的程序就好多bug,然后就越调越乱,最后完全没了思路,所以准备把车全部搭出来再程序写程序。

      把各种模块都拿出来,需要的电阻,电容,烙铁,跳线,摆一排,感觉我们三是要大干一场了


(搭第二层中)


这里打孔又是最麻烦的,因为不在实验室,没有钻孔机了,我们用锤子螺丝慢慢打出来的


(红外线循迹)


(资料是在网上找的)

(原理图)


      红外发射二极管跟普通的LED二极管一样,只是LED发射的是肉眼看得到的可见光,而红外发射二极管发射的是人眼看不见的红外线,红外发射二极管的正向压降大约1.2V,发射的功率以及发射的距离跟流经的电流成正比,嘴大平均工作电流不要大于100mA,这里选用的是220欧姆的限流电阻,流经红外发射二极管电流为(5V-1.2V)/220欧姆=17.2mA。
      红外接收二极管跟光敏电阻类似,可以根据这一点在其电路上加一个10K欧姆的电阻,当有红外线照射时电阻很小,则在上图中与红外接收二极管负极相连的P2.0/P2.1/P2.2输出口输出为“0”,当没有红外线照射时,输出为“+5V”。


      可以根据这一点进行红外巡线,巡线原理如下:当红外发光二极管照射到白色地板时,反射红外线,被与之对应的红外接收二极管接收,输出为逻辑“0”。反之当红外发光二极管照射到黑线时,红外线被黑色物体吸收,则与之对应的红外接受二极管无红外线照射,输出为逻辑“1”。


我的想法是将其分为“左”“中”“右”3路,那么分别会有8中情况,情况如下


左路 中路 右路 电机动作
0 0 0 停止
0 0 1 右转
0 1 0 前进
0 1 1 右转
1 0 0 左转
1 0 1 停止
1 1 0 左转
1 1 1

程序以后供上


(电源)

从图中可以看出我接了两个电源接口,一个5V usb接口,一个接9V 电池,因为电池不怎么好,所以调程序时准备用移动电源。

(整体)

一下午搭的,是不是帅到想哭

(顺便分享一点经验,就是用排针引出VCC或GND时多接几个排针,像我们只接了四个排针,回来发现少了时再引出来特别麻烦的。)

    

然后简单的写了个lcd的程序,哈哈,感觉特别特别特别帅

(附上所用单片机IO口)

接下来的日子就只要是把一个一个的模块程序写出来,然后慢慢调吧


菜鸟
2016-04-20 21:55:28     打赏
7楼

不好意思几天没有更新了,这几天事情多,进展比较慢

首先说一下小车控制方面,小车一开始是打算用蓝牙控制的,因为运气太差,淘宝到一个坏的蓝牙模板,害我们调半天搞不懂,后来就准备用无线,我们首先是用315无线发射和接收模块,没有资料,百度说要自己编码,找几个例程和天书一样,当时就蒙了,然后试了各种方法,还是放弃了,于是我发现了一种带遥控器的无线模板

固定码,接收到信号就输出高电平,一下就简单了。


(信号问题)

这个无线模板主要问题是信号弱,我们首先想到的就是加天线,一开始我们是自己用绝缘线做的,根本没起到什么作用,百度一查,原来天线中间是空心的,然后我们果断拆了路由器的一根天线装上,效果一下就来了,距离可以到一两米了。




菜鸟
2016-04-20 22:01:54     打赏
8楼

今天我们把电机的程序程序重新写了一遍,用到PWM信号调速,方便平衡小车的自平衡

程序如下:

#include <reg51.h> 

//IO口
sbit dian1=P2^0;
sbit dian2=P2^1;
sbit dian3=P2^2;
sbit dian4=P2^3;
sbit k1=P2^6;	 
sbit k2=P2^7;
sbit k3=P3^4;
sbit k4=P3^5;

//变量
unsigned char i,n,nk,nd,fx;
	     	  //n,nk,nd     速度标识
	          //fx(1正 2反 3左 4右)  方向标识

//声明函数
void zz();	                //电机正方向
void ff();	                //电机反方向
void fz();					//电机左转
void zf();					//电机右转
void sudu();                //根据速度标识选择速度值
void dian();                //检测按键
void delay(unsigned int z);	//延时函数

//主函数
void main()
{	
	while(1)
	{
		dian();
		sudu();
		if(fx==1)	 //根据方向标识选择方向
			zz();
		if(fx==2)
			ff();
		if(fx==3)
			fz();
		if(fx==4)
			zf();
	}
}

//函数
void dian()	 //检测按键,用无线模块控制,接收到信号时输出高电平
{
	if(k1==1)	  //前进
	{
		n++;
		if(n==5)
			n=4;
		fx=1;
	}
	if(k2==1)	  //左转
	{
		n++;
		if(n==5)
			n=4;
		fx=3;
	}
	if(k3==1)	  //减速、后退
	{
		n++;
		if(n==5)
			n=4;
		fx=2;
	}
	if(k4==1)	  //右转
	{
		n++;
		if(n==5)
			n=4;
		fx=4;
	}
	if((k1!=1)&&(k2!=1)&&(k3!=1)&&(k4!=1))//没有无线信号时电机停止转动
	{
		n=0;
	}
}

void zz()	 //正方向
{
	for(i=0;i<nd;i++)
	{
		dian1=1;
		dian2=1;
		dian3=1;
		dian4=1;
		delay(5);
	}
	for(i=0;i<nk;i++)
	{
		dian1=0;
		dian2=1;
		dian3=0;
		dian4=1;
		delay(5);
	}
}

void ff()	 //反方向
{
	for(i=0;i<nd;i++)
	{
		dian1=1;
		dian2=1;
		dian3=1;
		dian4=1;
		delay(5);
	}
	for(i=0;i<nk;i++)
	{
		dian1=1;
		dian2=0;
		dian3=1;
		dian4=0;
		delay(5);
	}
}

void fz()	 //一正一反,左转
{
	for(i=0;i<nd;i++)
	{
		dian1=0;
		dian2=0;
		dian3=1;
		dian4=1;
		delay(5);
	}						
	for(i=0;i<nk;i++)
	{
		dian1=1;
		dian2=0;
		dian3=0;
		dian4=1;
		delay(5);
	}
}

void zf()	 //一反一正,右转
{
	for(i=0;i<nd;i++)
	{
		dian1=1;
		dian2=1;
		dian3=0;
		dian4=0;
		delay(5);
	}						
	for(i=0;i<nk;i++)
	{
		dian1=0;
		dian2=1;
		dian3=1;
		dian4=0;
		delay(5);
	}
}

void sudu()//根据n的值赋nk,nd来调节IO口输出的PWM信号
{
	switch(n)
	{
		case 0:
			nk=0;
			nd=4;
			break;
		case 1:
			nk=1;
			nd=3;
			break;
		case 2:
			nk=2;
			nd=2;
			break;
		case 3:
			nk=3;
			nd=1;
			break;
		case 4:
			nk=4;
			nd=0;
			break;
	}
}
	    
void delay(unsigned int z)	//延时函数 (1ms)
{													 
	unsigned int x;									         
	for(;z>0;z--)									  
		for(x=110;x>0;x--);							
}


菜鸟
2016-04-20 22:10:40     打赏
9楼
      目前我们最大的难关就是自平衡了,百度查资料都是说一些算法的,感觉不知道从哪入手,然后希望大家能多给我们指点指点,相信我们能成功的!!!

菜鸟
2016-04-21 18:30:59     打赏
10楼

陀螺仪方面已经完成了,是根据陀螺仪资料里的例程改写的,在1602上显示x,y,z轴加速度和角速度

因为是模块化编程,就只上一部分程序了

(陀螺仪头文件)

#ifndef __TLY_H__
#define __TLY_H__

#include <reg51.h>
#include "kxt.h"

sbit    SCL=P3^7;			//IIC时钟引脚定义
sbit    SDA=P3^6;			//IIC数据引脚定义

#define	SMPLRT_DIV	0x19	//陀螺仪采样率,典型值:0x07(125Hz)
#define	CONFIG		0x1A	//低通滤波频率,典型值:0x06(5Hz)
#define	GYRO_CONFIG	0x1B	//陀螺仪自检及测量范围,典型值:0x18(不自检,2000deg/s)
#define	ACCEL_CONFIG	0x1C	//加速计自检、测量范围及高通滤波频率,典型值:0x01(不自检,2G,5Hz)
#define	ACCEL_XOUT_H	0x3B
#define	ACCEL_XOUT_L	0x3C
#define	ACCEL_YOUT_H	0x3D
#define	ACCEL_YOUT_L	0x3E
#define	ACCEL_ZOUT_H	0x3F
#define	ACCEL_ZOUT_L	0x40
#define	TEMP_OUT_H	0x41
#define	TEMP_OUT_L	0x42
#define	GYRO_XOUT_H	0x43
#define	GYRO_XOUT_L	0x44	
#define	GYRO_YOUT_H	0x45
#define	GYRO_YOUT_L	0x46
#define	GYRO_ZOUT_H	0x47
#define	GYRO_ZOUT_L	0x48
#define	PWR_MGMT_1	0x6B	//电源管理,典型值:0x00(正常启用)
#define	WHO_AM_I	0x75	//IIC地址寄存器(默认数值0x68,只读)
#define	SlaveAddress	0xD0	//IIC写入时的地址字节数据,+1为读取

void  InitMPU6050();													//初始化MPU6050
void  I2C_Start();
void  I2C_Stop();
void  I2C_SendACK(bit ack);
bit   I2C_RecvACK();
void  I2C_SendByte(unsigned char dat);
unsigned char I2C_RecvByte();
void  I2C_ReadPage();
void  I2C_WritePage();
unsigned char Single_ReadI2C(unsigned char REG_Address);/读取I2C数据
void  Single_WriteI2C(unsigned char REG_Address,unsigned char REG_data);//向I2C写入数据

#endif

 

(陀螺仪I2C通信)

#include "tly.h"

void Delay10us()
{
	unsigned char a,b;
	for(b=1;b>0;b--)
		for(a=2;a>0;a--);
}
void I2C_Start()
{
    SDA = 1;                    //拉高数据线
    SCL = 1;                    //拉高时钟线
    Delay10us();                //延时
    SDA = 0;                    //产生下降沿
    Delay10us();                //延时
    SCL = 0;                    //拉低时钟线
}
void I2C_Stop()
{
    SDA = 0;                    //拉低数据线
    SCL = 1;                    //拉高时钟线
    Delay10us();                 //延时
    SDA = 1;                    //产生上升沿
    Delay10us();                 //延时
}
//I2C发送应答信号
void I2C_SendACK(bit ack)
{
    SDA = ack;                  //写应答信号
    SCL = 1;                    //拉高时钟线
    Delay10us();                 //延时
    SCL = 0;                    //拉低时钟线
    Delay10us();                 //延时
}
//I2C接收应答信号
bit I2C_RecvACK()
{
    SCL = 1;                    //拉高时钟线
    Delay10us();                 //延时
    CY = SDA;                   //读应答信号
    SCL = 0;                    //拉低时钟线
    Delay10us();                 //延时
    return CY;
}
//向I2C总线发送一个字节数据
void I2C_SendByte(uc dat)
{
    uc i;
    for (i=0; i<8; i++)         //8位计数器
    {
        dat <<= 1;              //移出数据的最高位
        SDA = CY;               //送数据口
        SCL = 1;                //拉高时钟线
        Delay10us();             //延时
        SCL = 0;                //拉低时钟线
        Delay10us();             //延时
    }
    I2C_RecvACK();
}
//从I2C总线接收一个字节数据
unsigned char I2C_RecvByte()
{
    uc i;
    uc dat = 0;
    SDA = 1;                    //使能内部上拉,准备读取数据,
    for (i=0; i<8; i++)         //8位计数器
    {
        dat <<= 1;
        SCL = 1;                //拉高时钟线
        Delay10us();             //延时
        dat |= SDA;             //读数据               
        SCL = 0;                //拉低时钟线
        Delay10us();             //延时
    }
    return dat;
}
//向I2C设备写入一个字节数据
void Single_WriteI2C(uc REG_Address,uc REG_data)
{
    I2C_Start();                  //起始信号
    I2C_SendByte(SlaveAddress);   //发送设备地址+写信号
    I2C_SendByte(REG_Address);    //内部寄存器地址,
    I2C_SendByte(REG_data);       //内部寄存器数据,
    I2C_Stop();                   //发送停止信号
}
//初始化MPU6050
void InitMPU6050()
{
	Single_WriteI2C(PWR_MGMT_1, 0x00);	//解除休眠状态
	Single_WriteI2C(SMPLRT_DIV, 0x07);
	Single_WriteI2C(CONFIG, 0x06);
	Single_WriteI2C(GYRO_CONFIG, 0x18);
	Single_WriteI2C(ACCEL_CONFIG, 0x01);
}

 

(主函数部分)

void main()
{ 
	delay(500);		//上电延时		
	LCDI();			//液晶初始化
	InitMPU6050();	//初始化MPU6050
	delay(150);
	while(1)
	{
		Display10BitData(GetData(ACCEL_XOUT_H),2,0);	//显示X轴加速度
		Display10BitData(GetData(ACCEL_YOUT_H),7,0);	//显示Y轴加速度
		Display10BitData(GetData(ACCEL_ZOUT_H),12,0);	//显示Z轴加速度
		Display10BitData(GetData(GYRO_XOUT_H),2,1);	//显示X轴角速度
		Display10BitData(GetData(GYRO_YOUT_H),7,1);	//显示Y轴角速度
		Display10BitData(GetData(GYRO_ZOUT_H),12,1);	//显示Z轴角速度
		delay(500);
	}
}

 



共13条 1/2 1 2 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]