这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » 中科院的两轮平衡车创造进程帖

共15条 2/2 1 2 跳转至
助工
2015-10-23 22:53:58     打赏
11楼

虽然在调试的过程中遇到了各种各样的困难和各种各样的繁杂事情,但是我一直觉得这个小车带给我无比的快乐,就像是认识身边的一个美女,从觉得人长得非常的漂亮,后来慢慢了解到她的世界丰富多彩,了解到她的过去到现在,知道她为什么是这样的性格,还是要不可不说stm32的强大,以前只知道单片机怎么去制作一个小的控制设备,所以对一个喜欢折腾的人来说,真的是非常的难受在这么晚的时候才接触到这样的系统工程,这里还要重新写一下电机编码器的数据获取
电机的编码器其实就是一种传感器,可以把旋转位移转换成一串数字脉冲信号,MCU可以读取这段脉冲信号通过计数来获取电机的转速。



可以看出小车的原理图中显示编码器的接口分别为PA0和PA1,PB6和PB7:

PA0和PA1对应着TIM2,PB6和PB7对应着TIM4.所以系统应该采用定时器2和4分别对编码器结果进行计数。参考数据手册中定时器用作编码器接口模式的内容:选择编码器接口模式的方法是:如果计数器只在TI2的边沿计数,则置TIMx_SMCR寄存器中的SMS=001;如果只在TI1边沿计数,则置SMS=010;如果计数器同时在TI1和TI2边沿计数,则置SMS=011。 通过设置TIMx_CCER寄存器中的CC1P和CC2P位,可以选择TI1和TI2极性;如果需要,还可以对输入滤波器编程。 两个输入TI1和TI2被用来作为增量编码器的接口。参看表77,假定计数器已经启动(TIMx_CR1寄存器中的CEN=’1’),计数器由每次在TI1FP1或TI2FP2上的有效跳变驱动。TI1FP1和TI2FP2是TI1和TI2在通过输入滤波器和极性控制后的信号;如果没有滤波和变相,则TI1FP1=TI1,TI2FP2=TI2。根据两个输入信号的跳变顺序,产生了计数脉冲和方向信号。依据两个输入信号的跳变顺序,计数器向上或向下计数,同时硬件对TIMx_CR1寄存器的DIR位进行相应的设置。不管计数器是依靠TI1计数、依靠TI2计数或者同时依靠TI1和TI2计数。在任一输入端(TI1或者TI2)的跳变都会重新计算DIR位。 编码器接口模式基本上相当于使用了一个带有方向选择的外部时钟。这意味着计数器只在0到TIMx_ARR寄存器的自动装载值之间连续计数(根据方向,或是0到ARR计数,或是ARR到0计数)。所以在开始计数之前必须配置TIMx_ARR;同样,捕获器、比较器、预分频器、触发输出特性等仍工作如常。

void Encoder_Init_TIM2(void)  
{  
    RCC->APB1ENR|=1<<0; RCC->APB2ENR|=1<<2; GPIOA->CRL&=0XFFFFFF00;//PA0 PA1  
    GPIOA->CRL|=0X00000044;  
    TIM2->PSC = 0x0;  
    TIM2->ARR = ENCODER_TIM_PERIOD-1;  
    TIM2->CCMR1 |= 1<<0; TIM2->CCMR1 |= 1<<8; TIM2->CCER |= 0<<1; TIM2->CCER |= 0<<5; TIM2->SMCR |= 3<<0; //SMS='011' TIM2->CR1 |= 0x01;     
}  

int Read_Encoder(u8 TIMX)  
{  
    int Encoder_TIM;      
    switch(TIMX)  
     {  
       case 2:  Encoder_TIM= (short)TIM2 -> CNT; TIM2 ->CNT=0;break;  
       case 3:  Encoder_TIM= (short)TIM3 -> CNT; TIM3 -> CNT=0;break;    
       case 4:  Encoder_TIM= (short)TIM4 -> CNT; TIM4 -> CNT=0;break;    
       default:  Encoder_TIM=0;  
     }  
        return Encoder_TIM;  
}  




助工
2015-10-23 23:09:17     打赏
12楼

由于之前写的那篇直立车调试写的不是很直观,所以看了论坛里5,6篇有关于直立车调试的帖子,被吸引了好久,其中夏季在下季同学的文章非常不错,所以我复制了过来,以后可以多看看。

    实验目的:按键修改PID各个参数值,通过Nrf24l01无线通讯把修改的数据传递给小车,进行调试,参数内容实时显示在OLED屏上。

    PID这个东西还是比较难的。不仅需要理论基础,还需要多年的调试经验,掌握起来比较困难。和我一样的初学者可以看看这个PID通俗易懂.pdf

   源程序中涉及到的PID控制主要有直立PD控制、速度PI控制、转向PD控制。

(1)直立PD控制






    最上面红圈数值为平衡的角度中值,也就是小车重心,注释已经很清楚了。这一数值要先调好,否则会影响后面参数的调试。我的方法是,看小车平衡时OLED屏上的

angle角度值,会在一个范围变化,取最大值与最小值的中间值。例如:我的小车在359度与2度之间徘徊,所以我取0.5。

    下面两个参数分别为直立时P参数和D参数,需要后面调的。我用变量BP和BD代替。

(2)速度PI控制










     如果没有速度PI控制,小车会往重心方向加速运行,并倒下。

     红圈两个参数分别为速度P参数和I参数,我用变量VP和VI代替。

(3)转向PD控制








     如果没有转向PD控制,小车会在原地慢慢的打转。

     红圈两个参数分别为转向P参数和D参数,我用变量TP和TD代替。



来看看另一块板子上的按键排布如下













    只用到前4个按键:


 S1用于BP,BD,VP,VI,TB,TD六个参数的选择键;

 S2用于BP,BD,VP,VI,TB,TD六个参数的选择键(相反方向);

 S3用于BP,BD,VP,VI,TB,TD六个参数数值增加键;

 S4用于BP,BD,VP,VI,TB,TD六个参数数值减少键;


软件修改

(1)修改按键程序key.c和key.h

void KEY_Init(void)
{
RCC->APB2ENR|=1<<3;    //使能PORTB时钟	   
GPIOB->CRH&=0X0000FFFF; 
GPIOB->CRH|=0X88880000;//PB12 PB13 PB15 PB15 上拉输入
  GPIOB->ODR|=0X0000F000; //PB12 PB13 PB15 PB15 上拉 
} 
void KEY_Scan (void)
{
if(s1==0)
{
delay_ms(10);
if(s1==0)
{
s1num++;
while(!s1);
if(s1num==7) s1num=0;
}
  }
if(s2==0)
{
delay_ms(10);
if(s2==0)
{
s1num--;
while(!s2);
}
  }
if(s1num!=0)
{
if(s3==0)
{
delay_ms(10);
if(s3==0)
{
while(!s3);
if(s1num==1) BP+=1;
if(s1num==2) BD+=0.005;
if(s1num==3) VP+=0.5;
if(s1num==4) VI+=0.001;
if(s1num==5) TP+=0.5;
if(s1num==6) TD+=0.002;
}
}
if(s4==0)
{
delay_ms(10);
if(s4==0)
{
while(!s4);
if(s1num==1) BP-=1;
if(s1num==2) BD-=0.005;
if(s1num==3) VP-=0.5;
if(s1num==4) VI-=0.001;
if(s1num==5) TP-=0.5;
if(s1num==6) TD-=0.002;
}
}
}

 


(2)修改无线通讯程序24l01.c中的void NRF24L01()函数

void NRF24L01(void)
{
u8 mode=1,count;	 
u8 tmp_buf[33];
if(mode==0)//RX模式
{
RX_Mode();	 
while(1)
{	 	   	   	 
if(NRF24L01_RxPacket(tmp_buf)==0)//一旦接收到信息,则显示出来.
{
key_flag=1;
BP=(tmp_buf[1]*256+tmp_buf[2])/10.0;
BD=(tmp_buf[3]*256+tmp_buf[4])/1000.000;
VP=(tmp_buf[5]*256+tmp_buf[6])/10.0; 
VI=(tmp_buf[7]*256+tmp_buf[8])/1000.000; 
TP=(tmp_buf[9]*256+tmp_buf[10])/10.0;
TD=(tmp_buf[11]*256+tmp_buf[12])/1000.000;
s1num=tmp_buf[13];
oled_show();
}else break;	  
  
}; 
}else//TX模式
{	   
TX_Mode();
while(1) 
{	 
     if(++count>100)count=0;
tmp_buf[1]=BP*10/256; 
tmp_buf[2]=(u16)(BP*10)%256;
tmp_buf[3]=BD*1000/256;
tmp_buf[4]=(u16)(BD*1000)%256;
tmp_buf[5]=VP*10/256;
tmp_buf[6]=(u16)(VP*10)%256;
tmp_buf[7]=VI*1000/256;
tmp_buf[8]=(u16)(VI*1000)%256;
tmp_buf[9]=TP*10/256;
tmp_buf[10]=(u16)(TP*10)%256;
tmp_buf[11]=TD*1000/236;
tmp_buf[12]=(u16)(TD*1000)%256;
tmp_buf[13]=s1num;
        
if(NRF24L01_TxPacket(tmp_buf)==TX_OK)
{
key_flag=1;
}else	  
break; 
 
}
}      
}

 

(3)修改显示程序show.c中oled_show()程序

void oled_show(void)
{
OLED_Display_On();  //显示屏打开
//=============显示BP=======================// 
                     OLED_ShowString(00,0,"BP");
                     OLED_ShowNumber(30,0, BP,3,12);
                     OLED_ShowString(48,0,".");
                     OLED_ShowNumber(54,0, (u16)(BP*10)%10,1,12);
if(s1num==0)	OLED_ShowString(100,0,"  ");
if(s1num==1)	OLED_ShowString(100,0,"BP");
//=============显示BD=======================// 
                     OLED_ShowString(00,10,"BD");
                     OLED_ShowNumber(30,10, BD,3,12);
                     OLED_ShowString(48,10,".");
                     OLED_ShowNumber(54,10, (u16)(BD*1000)%1000,3,12);
if(s1num==2)	OLED_ShowString(100,0,"BD");
//=============显示VP=======================// 
                     OLED_ShowString(00,20,"VP");
                     OLED_ShowNumber(30,20, VP,3,12);
                     OLED_ShowString(48,20,".");
                     OLED_ShowNumber(54,20, (u16)(VP*10)%10,1,12);
if(s1num==3)	OLED_ShowString(100,0,"VP");
  //=============显示VI=======================// 
                     OLED_ShowString(00,30,"VI");
                     OLED_ShowNumber(30,30, VI,3,12);
                     OLED_ShowString(48,30,".");
                     OLED_ShowNumber(54,30, (u16)(VI*1000)%1000,3,12);
if(s1num==4)	OLED_ShowString(100,0,"VI");
//=============显示TP=======================//
                     OLED_ShowString(00,40,"TP");
                     OLED_ShowNumber(30,40, TP,3,12);
                     OLED_ShowString(48,40,".");
                     OLED_ShowNumber(54,40, (u16)(TP*10)%10,1,12);
if(s1num==5)	OLED_ShowString(100,0,"TP");
//=============显示TD=======================//
                     OLED_ShowString(00,50,"TD");
                     OLED_ShowNumber(30,50, TD,3,12);
                     OLED_ShowString(48,50,".");
                     OLED_ShowNumber(54,50, (u16)(TD*1000)%1000,3,12);
if(s1num==6)	OLED_ShowString(100,0,"TD");
if(key_flag==1) OLED_ShowString(100,50,"OK");
//=============刷新=======================//
OLED_Refresh_Gram(); 
}

 

观察现象

    先看看OLED屏的显示状态












    一手要按键,另一只手要拍摄,没有多余的手去扶小车,所以上电直接给源程序中的PID初值。

    小车装上测距模块和无线模块,拆下OLED屏(因为只有一个,不够使),装在另一块板子上。

    视频不知道怎么了,在自己电脑上播放器播放正常,传到优酷就倒过来了,不太影响效果,就不更改了。

    一开始上电,传给小车的是源程序的PID参数值,小车左右摆动大约7cm。按键增加BP值,增加到BP=70,小车左右摆动大约4cm。重启板子,小车PID值恢复到初始状态,小车左右摆动恢复到大约7cm。哈哈,接下来可以尽情的调试PID了。


助工
2015-10-26 20:01:50     打赏
13楼

一直琢磨,怎么样可以写的更好一些,稍微和大家已经发的帖子内容不一样,给大家新鲜的鸡汤的感觉,但是说到这里就不得不说一下自己的惰性了,这里的惰性就是思维上面只是需要得到更多的知识,却不喜欢去思考为什么,从小学一直到中学,大学里面就是感觉大家许多知识的欠缺。

平时别人问什么,我都可以说一个大概。有人说,这没有什么不好啊,你显得比较博学,有学问家的潜质,但我觉得这就是最可怕的事情,我做过飞行器,做过四轴,做过扑翼飞机,会写控制代码,却对为什么不是很了解,像这次的小车我也是看的懂代码,会写一部分代码,去讲原理,也说的上一个大概。

如果要深入问我一部分问题,我十有八九是回答不上。

其中许多的联系点,我多一笔带过,这就是为什么我学东西,做事情很快,比别人要高效多,但是过了之后却没有什么圆通之处,就像我理解stm32的定时器的用法,却不可以了解为什么是这样的,已经整体上是什么情况。

这些都是不喜欢思考,只喜欢死记硬背的最可怕的结果。就是你只能停留在一个层次上面,你不可能去从多个角度和多个层次去融会贯通,所以,我接下来写的一些学习报告就努力多向多层次靠拢。


助工
2015-10-27 23:20:15     打赏
14楼
由于我的不当操作,导致电机被损毁,真的非常的郁闷,不过最近和学校的一些老师联系得知最近许多公司要赞助我们,其中有一个比较好的公司提供了许多型号的电机,我就可以借一个用,最近同时在玩stm32F7的板子,真的感觉到微电子技术的快速发展,昨天看的一本采访集里面才采访到了一些对电脑发展牵了很大头的人物,其中有比尔盖茨,他说当时他在写BASIC语言解释器的时候,对软件硬件都要有非常非常深的理解,他说忙几个月就为可以把程序控制在4k内,想想现在的比较差的微处理器也可以运行比较大的程序了,而这些只是在30年前,30年之后,也就是2045年,Arm M7也许就是今天的51单片机,而且看了一个同学的分享,正在学习使用matlab的硬件控制部分,一直在使用keil,对其他的软件也没有太多的了解。大概1个月前有个大牛告诉我说clion会变成未来的硬件开发的利器,我就去下了一个试了一下,对于这个平台怎么样开发硬件程序不是非常的熟悉,网络上面也没有什么教程,不过它的许多的特性真的是非常的先进,值得大家好好研究一番,而且那个大神说他早就不思用keil这个软件了,他说可以geek eclipse,选择好的研发平台真的是非常的重要,最近获得一个英特尔的内部的硬件开发工具平台,感觉真的是高大上,之前觉得要很麻烦的设置时钟,配置引脚。配置I2C,SPI全部变成了可视化配置,这样如果是小孩的话那么他的学习成本就非常的低了,没错,intel这个工具居然是以教育和快速开发有关的,想到在不远未来的一天有人可以直接通过软件来写控制小车,操作小车的场景,真的是非常期待。

助工
2015-10-29 23:14:22     打赏
15楼
在今天的看点之中,我要排一下开发软件方面的排列。 之前一直使用keil,iar之类的开发平台,感觉效率也就那样,都是差不多的,拿哪个都可以进行开发的。但是,一个开发嵌入式超过10年的大神(大师)给我讲了他的看法,我就试着去体验不同的IDE,我才知道原来VS,ECLIPSE,CLION等等都是硬件开发的利器啊;互联网上找不到相关平台的配置,也就没一个人默默搞了,直接问大师相关的方法,他就给我一个网站,在原来的开发中,你觉得gdb不好用,加断点,你觉得coding不智能,换IDE,各种平台,都可以使用,各种芯片,都可以智能排版,我准备写个详细教程,然后以word发上来,各位vs党什么的福利来了。

共15条 2/2 1 2 跳转至

回复

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