1、调试p,i,d; http://www.360doc.com/content/14/0320/15/16303222_362183991.shtml https://www.sohu.com/a/419217458_691475 看下动图和数据趋势; 首先,三个参数都等于0; 先调节p; kp先调节。周期震荡。 初始值怎么定? 比如我调节速度,速度输入单位是r/s。这个大概是0-2.3r/s范围。但是实际是PWM控制。所以我的想法是,先大概找个范围。 PWM的范围是0–1000。实际转速范围是0—2.3r/s;
输入期望转速-------比较-----转换因子系数—速度PID------测速,返回到比较环节比较,同时输出。
期望假如是0.5r/s------------实际的是PWM,应该比较过后,速度和PWM的比例,我这里叫做转换因子。 这个比例应该是大概我猜测,就是1000/2=500。 所以用500作为P的初始化数据。后面先以100步长,加到1000–1300都可以。 狠下心,放大到KP=2000,看现象。再加Ki,,大概等于KP的0.5倍。试下。
看现象,按照上面的网址,动图的数据变化,调小,调大。。 2、借助SecureCRT,stm32和电脑通过串口进行通信,在这个软件里面,选择串口,然后这个工具可以用键盘在屏幕这里打入数据,单片机在串口中断中接收具体的信息,执行相关的动作。 具体的操作步骤。 单片机向电脑这个软件,发送printf,定向。构建这个界面。这个界面自己定义,就是人机交互界面。 最好和人的操作习惯一致,交互性好。 这个不能有中文。
比如我这个界面 怎么构建呢? 单片机端,一定要定义好printf重定向问题。stm32的正点原子的基本就可以了。 然后加入disp.h,disp.c文件。 里面有相关的函数。
disp.h
#ifndef __DISP_H
#define __DISP_H
#include "sys.h"
#include "usart.h"
void disp_clean(void);
void disp_cursor_reset(void);
void disp_gotoxy(int x,int y);
void disp_cursor_up(int y);
void disp_cursor_down(int y);
void disp_cursor_left(int x);
void disp_cursor_right(int x);
void disp_cursor_hide(void);
void disp_cursor_show(void);
#endif
disp.c
#include "disp.h"
#include "usart.h"
#include "stdio.h"
void disp_clean(void)
{
printf("\033[2J");
}
void disp_cursor_reset(void)
{
printf("\033[H");
}
void disp_gotoxy(int x,int y)
{
printf("\033[%d;%dH",y,x);
}
void disp_cursor_up(int y)
{
printf("\033[%dA",y);
}
void disp_cursor_down(int y)
{
printf("\033[%dB",y);
}
void disp_cursor_left(int x)
{
printf("\033[%dD",x);
}
void disp_cursor_right(int x)
{
printf("\033[%dC",x);
}
void disp_cursor_hide(void)
{
printf("\033[?25l");
}
void disp_cursor_show(void)
{
printf("\033[?25h");
}
我是写了个界面显示的程序,main中初始化资源之后,显示初始页面。后面再串口中断中,接收到数据,就更新数据到界面,做一个反馈,不然串口有没有接收到都不知道。
在做PID实验的时候,在采样计算PID的时候,间隔100ms,刷新一次数据。比如转速,行程等。 注意,这里的坐标x,y是从1开始的。
void DispScreen(void)
{
disp_gotoxy(1,1);
printf("speed,,,Kp=%.2f",Pid_Wheel1_Speed.Kp);
disp_gotoxy(21,1);
printf("Ki=%0.2f",Pid_Wheel1_Speed.Ki);
disp_gotoxy(33,1);
printf("Kd=%0.2f",Pid_Wheel1_Speed.Kd);
disp_gotoxy(45,1);
printf("Tar=%0.2f",Pid_Wheel1_Speed.target_val);
disp_gotoxy(1,2);
printf("locat,,,Kp=%.2f",Pid_Wheel1_Location.Kp);
disp_gotoxy(21,2);
printf("Ki=%0.2f",Pid_Wheel1_Location.Ki);
disp_gotoxy(33,2);
printf("Kd=%0.2f",Pid_Wheel1_Location.Kd);
disp_gotoxy(45,2);
printf("Tar=%0.2f",Pid_Wheel1_Location.target_val);
disp_gotoxy(1,3);
printf("pid_mode=%d",PID_mode);
disp_gotoxy(1,4);
printf("speed(r/s)=%.2f",WheelSpeed[0]);
disp_gotoxy(1,5);
printf("loc(cir)=%.2f",WheelCircles[0]);
disp_gotoxy(1,6);
printf("stepPar=%.2f",stepPar);
disp_gotoxy(1,7);
printf("TarCir=%.2f",TarCir[0]);
}
单片机用disp函数,跳到光标中,然后printf打印数据。 在timer.c定时器中断中,计算PID,20ms计算一次PID,然后10*20=200ms刷新一次具体的数据。
单片机发送到电脑的过程,就介绍到这里。 主要要注意两点: 1、要重定向printf; 2、假如我上面的h和C文件; 3、自己定义一个交互性能好的界面;
单片机如何接受电脑键盘消息呢? 当然首先要串口连接。 下载这个SecureCRT软件。
我这里没有z做校验。就是单个字符,就认为受到了,所以有时候会卡了。这时候重新按下单片机的复位。再开始了。后面可以优化代码。
在串口中断函数中。接收到不同的电脑额键盘按键字符,就执行相关动作,然后再实时更新界面的数据。 这里有几个功能: 1、调节步长:0.01,.0.1,1,10,100;用键盘的UIOP[这5个按键; 2、将步长取反,变成负数,后面就能实现减步长了。加负数,就是减法了。这里用0按键; 3、调节PIDmode,用BNM,四个。=0,=1速度PID,=2位置PID,=3串级PID,=4自己用; 4、加速度PID的数据,就用小键盘的789,7调节KP,8调节KI ,9 KD; 5、调位置PID数据,用456; 6、调节目标值,速度目标值和位置目标值,用1,2; 7、开始PID计算,用d; 8、停止PID,用s; 9、复位单片机系统,用v.
… 还有he那多的键盘按键没用用到。太方便了。 但是有时候会掉线。
void USART1_IRQHandler(void)
{
uint8_t data;
uint8_t bufcopy[128];
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
{
cmddat=USART_ReceiveData(USART1);
switch(cmddat)
{
case 's' :
disp_gotoxy(1,10);
printf("cmd:q+w+s, Action:stop PID,stop TIMER13");
set_motor_rotate(1,0);
PID_mode=0;
TIM_Cmd(TIM13,DISABLE);
break;
case 'd':
disp_gotoxy(1,10);
printf("cmd:q+w+d, Action:Start PID,start TIMER13");
TIM_Cmd(TIM13,ENABLE);
break;
case 'u':
disp_gotoxy(1,10);
printf("cmd:q+w+u, Action:Change Step=0.01");
stepPar=0.01f;
break;
case 'i':
disp_gotoxy(1,10);
printf("cmd:q+w+i, Action:Change Step=0.1");
stepPar=0.1f;
break;
case 'o':
disp_gotoxy(1,10);
printf("cmd:q+w+o, Action:Change Step=1.0");
stepPar=1.0f;
break;
case 'p':
disp_gotoxy(1,10);
printf("cmd:q+w+p, Action:Change Step=10.0");
stepPar=10.0f;
break;
case '[':
disp_gotoxy(1,10);
printf("cmd:q+w+[, Action:Change Step=100");
stepPar=100.0f;
break;
case '4':
Pid_Wheel1_Location.Kp +=stepPar;
break;
case '5':
Pid_Wheel1_Location.Ki+=stepPar;
break;
case '6':
Pid_Wheel1_Location.Kd+=stepPar;
break;
case '7':
Pid_Wheel1_Speed.Kp+=stepPar;
break;
case '8':
Pid_Wheel1_Speed.Ki+=stepPar;
break;
case '9':
Pid_Wheel1_Speed.Kd+=stepPar;
break;
case '1':
Pid_Wheel1_Speed.target_val+=stepPar;
break;
case '2':
Pid_Wheel1_Location.target_val+=stepPar;
break;
case '0':
stepPar=-stepPar;
break;
case 'b':
PID_mode=1;
break;
case 'n':
PID_mode=2;
break;
case 'm':
PID_mode=3;
break;
case ',':
PID_mode=4;
break;
case 'q':
TarCir[0]+=stepPar;
break;
case 'v':
NVIC_SystemReset();
break;
default:break;
}
DispScreen();
USART_ClearITPendingBit(USART1,USART_IT_RXNE);
}
|