由于之前写的那篇直立车调试写的不是很直观,所以看了论坛里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了。