飞思卡尔PID程序

合集下载

电机PID(重要)

电机PID(重要)

飞思卡尔智能车电机PID提到小车的控制必然想到的PID控制,这也是各技术报告都不会漏掉的名词,在飞思卡尔XS128系列(二)PWM模块中已经提到了一些电机控制方面的东西,主要讲了用PID和BANG-BANG 控制相结合的方式来控制电机,就是由BANG-BANG来控制力度,用PID来控制精度,下面就具体来讲讲。

先说控制,所谓控制首先由闭环控制和开环控制之分,就是所谓的有反馈和无反馈,当然PID显然是有反馈的控制。

所谓的闭环控制就是要根据被控制量的实际情况参与运算来决定操作量的大小或者方向。

因为在单回路控制系统中,由于扰动的作用使被控参数偏离给定值,从而产生偏差,而自动控制系统的调节单元将来自变送器的测量值与给定值相比较后产生的偏差进行比例、积分和微分运算,并输出统一标准信号,去控制执行机构的动作,以实现对温度、压力、流量和速度等的自动控制。

然而牵扯到高级PID,像有自适应控制、模糊控制、预测控制、神经网络控制、专家智能控制等等,里面也就模糊控制搞过一定时间,其它我也不懂,就不瞎扯了。

比例、积分和微分的线性组合,构成控制量u(t),称为:比例(Proportional)、积分(Integrating)和微分(Differentiation)控制,简称PID控制。

比例作用P只与偏差成正比,积分作用I是偏差对时间的累积,而微分作用D是偏差的变化率。

用一句形象的比喻,比例P代表着现在,积分I代表着过去,而微分D则代表着未来。

公式如图:具体于比例、积分和微分,网上有很多这方面的资料,我就不多说了。

下面是关于参数的调整,比例系数、积分系数和微分系数的合理调整时整个PID系统可以正常温度工作的关键。

而最好的寻找PID参数的办法是从系统的数学模型出发,从想要的反应来计算参数。

很多时候一个详细的数学描述是不存在的,这时候就需要从实际出发去调整PID参数了。

Ziegler——Nichols方法Ziegler——Nichols方法是基于系统稳定性分析的PID整定方法,在设计过程中无需要考虑任何特性要求,整定方法简单。

第五界飞思卡尔智能车大赛程序(光电组)

第五界飞思卡尔智能车大赛程序(光电组)
speed_expect=speed_set[0];
}
else if(turn_value==direction_turn[0])
{
turn_value=direction_turn[0];
speed_expect=speed_set[0];
}
break;
case 2:if(turn_value==direction_turn[0])
//The PIT module has no external pins.
//PIT 模式没有外部引脚
unsigned char light=0; //激光管检测标志
unsigned short turn_value=0; //转向的PWM数值
unsigned short direction_turn[7]={333,430,560,647,705,780,888}; //转向给定值初始化
{
turn_value=direction_turn[6];
speed_expect=speed_set[6];
}
else if(turn_value==direction_turn[6])
{
turn_value=direction_turn[6];
speed_expect=speed_set[6];
}
else if(turn_value==direction_turn[2])
{
turn_value=direction_turn[1];
speed_expect=speed_set[1];
}
break;
case 4:if(turn_value==direction_turn[1])

飞思卡尔程序调试技巧

飞思卡尔程序调试技巧

一、前言调试程序,是软件开发过程中的一个必不可少的环节。

这篇帖子,匠人试着来整理一下一些调试的技巧。

说到“技巧”,这个词自从被所长批臭之后,匠人就吓得不敢再提,生怕一不小心就暴露了思想的浅薄和眼光的局限,呵呵。

所以咱们不叫“技巧”,干脆低调点,就叫“雕虫小技”吧。

这里所讨论的“调试”技巧,有些是必须结合开发工具本身的功能来实现,而有些可以通过烧录芯片来验证。

各种开发工具,提供的功能多少强弱也不尽相同,这些方法也未必都能套用。

仅供参考吧。

最后说明一下,这是没有草稿的帖子,匠人仍然以不定期连载的方式,边写边发边改。

可能结构会比较混乱。

欢迎大家一起参与讨论。

二、磨刀不误砍柴功在调试之前,需要掌握以下一些基本功:1、熟悉当前的开发(调试)环境,比如:设置断点、单步运行、全速运行、终止运行,查看RAM、查看堆栈、查看IO口状态……总之,要熟练掌握基本操作的方法,并深刻了解其中意义。

2、了解芯片本身的资源和特性。

3、了解一点汇编语言的知识。

(本来匠人是准备写“精通”的,但考虑到现状,还是“放低”这方面的要求罢了)。

4、掌握基本的电路知识和排错能力。

(软件调试有时也会牵涉到硬件原因。

总不能连三极管的好坏都不能识别吧?)5、万用表、示波器、信号发生器……这些工具总该会用吧?6、搜索、鉴别资料的能力。

(内事问百度、外事问古狗、有事没事上21ic网)7、与人沟通,描述问题的能力。

(调试36计的最后一计——就是向他人讨教。

当然,你得把话说明白才行)差不多了,如果上述7把砍柴刀磨好了,就可以开始调试了。

接下来,请调入你的程序……三、优先调试人机界面面对程序中的一大堆模块,无从下手是吗?好吧,匠人告诉你,先调显示模块,然后是键盘。

为什么要先调显示模块?道理很简单,我们说“眼睛是心灵的窗户”,同样,“显示是程序的窗户”。

一旦把显示模块调试好了,就可以通过这个窗口,偷窥(天呐,这两个居然是敏感字!)程序内部的数据和状态了。

然后紧接着,就是调试键盘模块。

PID控制算法(PID控制原理与程序流程)

PID控制算法(PID控制原理与程序流程)

PID控制算法(PID控制原理与程序流程)⼀、PID控制原理与程序流程(⼀)过程控制的基本概念过程控制――对⽣产过程的某⼀或某些物理参数进⾏的⾃动控制。

1、模拟控制系统图5-1-1 基本模拟反馈控制回路被控量的值由传感器或变送器来检测,这个值与给定值进⾏⽐较,得到偏差,模拟调节器依⼀定控制规律使操作变量变化,以使偏差趋近于零,其输出通过执⾏器作⽤于过程。

控制规律⽤对应的模拟硬件来实现,控制规律的修改需要更换模拟硬件。

2、微机过程控制系统图5-1-2 微机过程控制系统基本框图以微型计算机作为控制器。

控制规律的实现,是通过软件来完成的。

改变控制规律,只要改变相应的程序即可。

3、数字控制系统DDC图5-1-3 DDC系统构成框图DDC(Direct Digital Congtrol)系统是计算机⽤于过程控制的最典型的⼀种系统。

微型计算机通过过程输⼊通道对⼀个或多个物理量进⾏检测,并根据确定的控制规律(算法)进⾏计算,通过输出通道直接去控制执⾏机构,使各被控量达到预定的要求。

由于计算机的决策直接作⽤于过程,故称为直接数字控制。

DDC系统也是计算机在⼯业应⽤中最普遍的⼀种形式。

(⼆)模拟PID调节器1、模拟PID控制系统组成图5-1-4 模拟PID控制系统原理框图2、模拟PID调节器的微分⽅程和传输函数PID调节器是⼀种线性调节器,它将给定值r(t)与实际输出值c(t)的偏差的⽐例(P)、积分(I)、微分(D)通过线性组合构成控制量,对控制对象进⾏控制。

a、PID调节器的微分⽅程式中b、PID调节器的传输函数3、PID调节器各校正环节的作⽤a、⽐例环节:即时成⽐例地反应控制系统的偏差信号e(t),偏差⼀旦产⽣,调节器⽴即产⽣控制作⽤以减⼩偏差。

b、积分环节:主要⽤于消除静差,提⾼系统的⽆差度。

积分作⽤的强弱取决于积分时间常数TI,TI越⼤,积分作⽤越弱,反之则越强。

c、微分环节:能反应偏差信号的变化趋势(变化速率),并能在偏差信号的值变得太⼤之前,在系统中引⼊⼀个有效的早期修正信号,从⽽加快系统的动作速度,减⼩调节时间。

飞思卡尔智能车电磁组分区算法介绍

飞思卡尔智能车电磁组分区算法介绍

飞思卡尔智能车电磁组分区算法介绍写在之前的话:1、⽬前我是⼀名在校学⽣,这也是我第⼀次写博客,不周之处,请多谅解;2、此算法并⾮原创,借鉴⾃⼭东德州学院第⼋届⽩杨队(PS:个⼈看法,对于⼀些⼈把别⼈的开源东西改头换⾯⼀下就说是⾃⼰的原创⾏为⼗分鄙视);3、对于此算法的理解和说明并⾮纸上谈兵,算法已经被我运⽤到了⼩车⽐赛中并取得好的成绩(具体就不多说了,⽐赛时车莫名其妙坏了,⽐赛前调试的速度绝对能进国赛,⽐较遗憾),总之这算法是我尝试过的最好的算法;4、这⼀次所介绍的只是路径算法和⼀些知识普及,后⾯有时间会介绍其余部分算法及许多好的思路(舵机电机控制思路(不只是简单的PID),双车策略);5、希望对于这⽅⾯有涉及的⼈能与我联系并交流或指出不⾜之处。

---------------------------------------------------------------分割线-----------------------------------------------------------------------------⼀、没有这⽅⾯了解的可以看看 飞思卡尔智能车分为三组:摄像头、光电、电磁,我做的是电磁车,三种车队区别在于传感器的不同,所以获得路径信息的⽅法也不⼀样,摄像头和光电识别的是赛道上的⿊线(⽩底赛道),⽽电磁车则是检测埋在赛道下的通⼊100mh电流的漆包线,摄像头和光电采⽤的是摄像头和ccd作为传感器,电磁则是⽤电感放在漆包线周围,则电感上就会产⽣感应电动势,且感应电动势的⼤⼩于通过线圈回路的磁通量成正⽐,⼜因为漆包线周围的磁感应强度不同,因此不同位置的电感的感应电动势就不同,因此就可以去确定电感位置;因此在车⼦前⾯设置了50cm的前瞻,电感布局如下(怎么发不了图⽚):分为两排,前排3个,编号0,1,2(前期还加了两个竖直电感⽤来帮助过直⾓弯,后来改为了⼋字电感);后排2个,编号3,4;现在车⼦获得了不同位置的感应电动势的⼤⼩了,但这些值是不能处理的:1、感应电动势太微弱;2、是模拟信号,信号太微弱就放⼤它;这就涉及到模拟电路的知识了,就不多说了(因为要把这讲完到PCB绘制的篇幅就⾜够写另开⼀号专门写这些⽅⾯来(PS:题外话(我的题外话⽐较多)):放⼤部分外围你设计的再好也抵不过⼀个更好的芯⽚,有两个例⼦,⼀个是我⾃⼰的:之前⽤的是NE5532,但是效果不理想,加了好多什么滤波,补偿,都⽤上,没⽤,软件⾥处理后⾯再说,后来⼀狠⼼换了AD620,感觉像是春天来了,因为它是仪⽤放⼤器,还有就是贵。

摄像头pid算法思路

摄像头pid算法思路

基于CCD摄像头智能车分段PID控制算法设计自动寻迹智能车涉及到当前高技术领域内的许多先进技术,其中最主要的是传感技术、路径规划和运动控制。

本课题是以飞思卡尔智能车竞赛为背景,以单片机作为核心控制单元,以摄像头作为路径识别传感器,以直流电机作为小车的驱动装置,以舵机控制小车转向。

车模竞赛的赛道是一个具有特定几何尺寸约束、摩擦系数及光学特性的KT板,其中心贴有对可见光及不可见光均有较强吸收特性的黑色条带作为引导线,宽度为2.5 cm。

在行驶过程中,系统通过摄像头获取前方赛道的图像数据,同时通过测速传感器实时获取智能车的速度,采用路径搜索算法进行寻线判断和速度分析,然后作控制决策,控制转向舵机和直流驱动电机工作。

智能车通过实时对自身运动速度及方向等进行调整来“沿”赛道快速行驶。

本文主要介绍摄像头通过提取赛道黑线信息交予单片机处理,通过单片机输出控制信号控制舵机转向来控制车模的转向,从而很好的自动循迹。

1 总体软硬件结构及思路此智能车辆定位系统用摄像头拍摄车辆前方的赛道,通过MC9S12XS128采样视频信号,获得图像数据。

然后用合适的算法,如跟踪边缘检测算法,分析图像数据,提取目标指引线。

然后,系统根据目标指引线的位置信息,对舵机和电机施以合适的控制。

本智能车运动系统的结构图如图1所示。

因为系统是一个有机的整体,所以需配合好系统的摄像头、控制单片机、电机(包括直流伺服电动机、光电编码器)、舵机和辅助电路(电源板、电机驱动板)等各个部分。

舵机是实时控制车模的转向,是比赛快速性和稳定性的关键,舵机控制有很多的控制算法,如:PID经典控制算法、模糊算法、人工智能算法等。

2 系统程序总体控制流程系统的基本软件流程是:首先,对各功能模块和控制参数进行初始化;然后,通过图像采集模块获取前方赛道的图像数据,同时通过速度传感器模块获取赛车的速度。

采用PID对舵机进行反馈控制。

另外根据检测到的速度,结合速度控制策略,对赛车速度不断进行适当调整,使赛车在符合比赛规则的前提下,沿赛道快速行驶。

四轴PID调试心得

四轴PID调试心得

本人曾在大二,大三参加过第六,第七届飞思卡尔智能车比赛,之后在考研过后在飞思卡尔智能车为我打下的良好基础下开始制作四轴飞行器.在年中到现在陆续调试了两架四轴,一架十字,一架X.其中四轴的平衡是很重要的一环,其中涉及到的PID整定,因为听闻今年摄像头也要站起来了,个人认为PID整定过程都有可以互相借鉴之处,顾在此一贴,也顺便为我的ARM-ST校园比赛求支持。

PID调试心得本人不是自动化出身,也没有受过专业训练,都是自己摸索,在这里浅述一下自己的PID参数整定心得。

所言之物皆由实践及自己的理解得出,如有不当之处还请指正.首先例举第一个例子,我调的第一台四轴飞行器,十字型四轴飞行器,讲下配置:网上一百多的650机架,好赢20A电调,新西达2212 1000kV,1045的桨,2200mah 电池.采用位置式PID控制,位置式PID公式如下PID的基本意义我在次就不作阐述了,我只讲我的设计,我以姿态角作为被控制对象,所以e(k) = 期望—测量 = 给定值—测量姿态角对于微分项D,我做了一点改变,标准PID的微分项D=kd*(e(k)—e(k-1)),我在实践过程中因为角度的微分就是角速度,而陀螺仪可以直接测出角速度,所以我没有将微分项作为偏差的差而是直接用D=kd*Gyro实现代码如下float pidUpdate(pidsuite* pid, const float measured,float expect,float gyro){float output;static float lastoutput=0;pid—〉desired=expect;//获取期望角度pid—>error = pid-〉desired - measured; //偏差:期望-测量值 pid—>integ += pid—>error * IMU_UPDATE_DT; //偏差积分if (pid—>integ > pid—>iLimit) //作积分限制{pid->integ = pid-〉iLimit;}else if (pid-〉integ 〈—pid-〉iLimit){pid-〉integ = —pid->iLimit;}// pid—〉deriv = (pid—>error — pid—>prevError) / IMU_UPDATE_DT;//微分应该可用陀螺仪角速度代替pid->deriv = -gyro;if(fabs(pid—>error)>Piddeadband)//pid死区{pid—〉outP = pid-〉kp * pid—〉error;//方便独立观察pid->outI = pid—>ki * pid—〉integ;pid—>outD = pid-〉kd * pid-〉deriv;output = (pid-〉kp * pid—>error) +(pid-〉ki * pid->integ) +(pid—〉kd * pid-〉deriv);}else{output=lastoutput;}pid->prevError = pid->error; //更新前一次偏差lastoutput=output;return output;}我这么做的原因是因为,如果使用传统的D的形式,在我快速打舵时会产生输入的设定值变化频繁且幅度较大,四轴飞行器会迅速回到新的期望点,说白了就是非常灵活,四轴回复很猛,也许造成系统的振荡,对PID参数要求较高。

PID控制原理及编程方法

PID控制原理及编程方法

PID控制原理及编程方法PID控制是一种常见的控制算法,用于调节系统输出与期望输入之间的偏差。

PID控制的原理是根据当前的误差、误差变化率和误差累积值来调整系统输出,从而使系统输出逐渐接近期望输入。

PID控制具有简单易实现、调节性能良好的特点,被广泛应用于各种自动控制系统中。

比例项是根据当前误差的大小来调整系统输出,比例增益参数Kp决定了比例项的权重。

当误差较大时,比例项的影响较大,系统输出会迅速调整;当误差较小时,比例项的影响较小。

积分项是根据误差累积值来调整系统输出,积分增益参数Ki决定了积分项的权重。

积分项可以弥补比例项无法完全消除的稳态误差,使系统更加准确地跟踪期望输入。

微分项是根据误差变化率来调整系统输出,微分增益参数Kd决定了微分项的权重。

微分项可以抑制系统的震荡和超调,使系统响应更加平滑。

u(t) = Kp * e(t) + Ki * ∫e(t)dt + Kd * de(t)/dt其中,u(t)为系统输出,e(t)为当前误差,de(t)/dt为误差变化率。

离散PID控制适用于基于采样的离散系统,通常在嵌入式系统中应用较多。

离散PID控制的基本步骤如下:1.初始化PID参数:设置比例增益Kp、积分增益Ki和微分增益Kd的初值,以及误差累积值和上一次误差的初值。

2.读取当前输入和期望输入。

3.计算当前误差:e(t)=期望输入-当前输入。

4. 计算比例项:Proportional = Kp * e(t)。

5. 计算积分项:Integral = Ki * ∑e(t)dt。

其中,∑e(t)dt是误差累积值,可以通过将当前误差加到上一次误差累积值上来计算。

6. 计算微分项:Derivative = Kd * (e(t) - 上一次误差)。

7. 计算PID输出:u(t) = Proportional + Integral + Derivative。

8.将PID输出作为系统控制信号。

9.更新上一次误差和误差累积值。

pid使用例程

pid使用例程

pid使用例程
PID使用例程是一个程序示例,用于展示如何使用PID控制器来控制一个系统。

一般情况下,PID控制器用于调节系统的输出,使其达到所期望的目标值。

该例程包括以下步骤:
1. 初始化PID对象:在程序开始时,需要初始化一个PID对象,该对象包括控制参数(比例系数、积分系数和微分系数)以及控制器的输出范围。

2. 读取输入:根据需要控制的系统,需要读取相应的输入量,例如传感器读数或者用户设置的目标值。

3. 计算控制器输出:根据读取到的输入值和控制参数,计算PID 控制器的输出值。

4. 更新系统状态:根据控制器的输出值,更新系统的状态,例如改变电机的转速或者调整阀门的开度。

5. 循环迭代:重复执行以上步骤,直到系统输出达到所期望的目标值或者达到设定的最大控制次数。

通过该例程,程序员可以更好地理解PID控制器的工作原理,并将其应用于自己的系统中,以实现更加精确的控制。

- 1 -。

飞思卡尔单片机编程

飞思卡尔单片机编程

关于Codewarrior 中的 .prm 文件网上广泛流传的一篇文章讲述的是8位飞思卡尔单片机的内存映射,这几天,研究了一下Codewarrior 5.0 prm文件,基于16位单片机MC9S12XS128,一点心得,和大家分享。

有什么错误请指正。

正文:关于Codewarrior 中的.prm 文件要讨论单片机的地址映射,就必须要接触.prm文件,本篇的讨论基于Codewarrior 5.0 编译器,单片机采用MC9S12XS128。

通过项目模板建立的新项目中都有一个名字为“project.prm”的文件,位于Project Settings->Linker Files文件夹下。

一个标准的基于XS128的.prm文件起始内容如下:.prm文件范例:NAMESENDSEGMENTSRAM = READ_WRITE DATA_NEAR 0x2000 TO 0x3FFF;ROM_4000 = READ_ONLY DATA_NEAR IBCC_NEAR 0x4000 TO 0x7FFF;ROM_C000 = READ_ONLY DATA_NEAR IBCC_NEAR 0xC000 TO 0xFEFF; //OSVECTORS = READ_ONLY 0xFF10 TO 0xFFFF;EEPROM_01 = READ_ONLY DATA_FAR IBCC_FAR 0x010800 TO 0x010BFF; EEPROM_02 = READ_ONLY DATA_FAR IBCC_FAR 0x020800 TO 0x020BFF; EEPROM_03 = READ_ONLY DATA_FAR IBCC_FAR 0x030800 TO 0x030BFF; EEPROM_04 = READ_ONLY DATA_FAR IBCC_FAR 0x040800 TO 0x040BFF; EEPROM_05 = READ_ONLY DATA_FAR IBCC_FAR 0x050800 TO 0x050BFF; EEPROM_06 = READ_ONLY DATA_FAR IBCC_FAR 0x060800 TO 0x060BFF; EEPROM_07 = READ_ONLY DATA_FAR IBCC_FAR 0x070800 TO 0x070BFF;PAGE_F8 = READ_ONLY DATA_FAR IBCC_FAR 0xF88000 TO 0xF8BFFF; PAGE_F9 = READ_ONLY DATA_FAR IBCC_FAR 0xF98000 TO 0xF9BFFF; PAGE_FA = READ_ONLY DATA_FAR IBCC_FAR 0xFA8000 TO 0xFABFFF; PAGE_FB = READ_ONLY DATA_FAR IBCC_FAR 0xFB8000 TO 0xFBBFFF; PAGE_FC = READ_ONLY DATA_FAR IBCC_FAR 0xFC8000 TO 0xFCBFFF;ENDPLACEMENT_PRESTART,STARTUP,ROM_VAR,STRINGS,VIRTUAL_TABLE_SEGMENT,//.ostext,DEFAULT_ROM, NON_BANKED,COPYINTO ROM_C000 ;OTHER_ROM INTO PAGE_FE, PAGE_FC, PAGE_FB, PAGE_FA, PAGE_F9, PAGE_F8;//.stackstart,SSTACK,//.stackend,PAGED_RAM,DEFAULT_RAMINTO RAM;DISTRIBUTE DISTRIBUTE_INTOROM_4000, PAGE_FE, PAGE_FC, PAGE_FB, PAGE_FA, PAGE_F9, PAGE_F8;CONST_DISTRIBUTE DISTRIBUTE_INTOROM_4000, PAGE_FE, PAGE_FC, PAGE_FB, PAGE_FA, PAGE_F9, PAGE_F8;DATA_DISTRIBUTE DISTRIBUTE_INTORAM;//.vectors INTO OSVECTORS;ENDENTRIES//_vectab OsBuildNumber _OsOrtiStackStart _OsOrtiStartENDSTACKSIZE 0x100VECTOR 0 _Startup//VECTOR 0 Entry//INIT Entry1 .prm文件组成结构按所含的信息的不同.prm文件有六个组成部分构成,这里仅讨论和内存空间映射关系紧密的三个部分,其他的不做讨论。

飞思卡尔单片机机器码文件资料烧写方法

飞思卡尔单片机机器码文件资料烧写方法

飞思卡尔单片机机器码文件烧写方法
第一步:将飞思卡尔编程器(BDM)与需要烧写的PCB板连接,其中BDM中GND引脚要与空调控制器GND引脚对准,之后将飞思卡尔编程器(BDM)的USB接口插上电脑。

第二步:找到ST008-CW_MCUs_V6_3软件的安装目录,打开安装软件的文件夹。

第三步:打开prog文件夹
第四步:在prog文件夹下打开hiwave.exe文件
第五步:打开component-set connection
第六步:打开后会看到这样一个页面,在processor中选择HCS08,在connection中选择P&E Multilink/cyclone pro,选择完后点击OK。

中点击Connect(Reset)
第八步:选择MultilinkCyclonePro-Load,要是编程器没有与电脑连接成功,会出现No communication框,若是连接成功,会显示Load executable file框。

第九步:选择文件类型为Motorolala S-Record(*.s?*)
第十步:选择机器码文件(S19文件),找到需要下载的机器码文件,之后选中文件。

项打勾,之后点击Load Code。

器码文件(S19文件).
第十三步:机器码文件(S19文件)正在下载中……。

PID Bang-Bang双模控制系统

PID Bang-Bang双模控制系统

《计算机控制仿真》课程设计报告2012年6月26日飞思卡尔电机PID+Bang-Bang双模控制系统摘要:本文结合飞思卡尔电机,介绍了飞思卡尔电机控制系统的工作原理。

经过推导,建立了该电机的数学模型。

在MATLAB/Simulink中搭建了电机的仿真模型,分别对PID 控制和Bang-Bang控制进行了仿真,仿真结果表明这两种控制方法无法获得满意的控制效果。

为取得良好的控制效果,将PID控制和Bang-Bang控制相结合,设计了PID+Bang-Bang双模控制器,提高了系统的控制效果。

关键词:PID控制Bang-Bang控制稳定性快速性目录一、引言 (1)1.1 计算机控制仿真简介 (1)1.2 飞思卡尔智能车电机控制系统与课程设计的关系 (1)二、设计要求 (2)2.1 直流伺服电机的物理模型 (2)2.2 直流伺服电机的数学模型 (2)2.3 设计要求 (3)三、系统设计及结果分析 (4)3.1 PID调节 (4)3.1.1 比例控制校正 (4)3.1.2 比例微分控制校正 (6)3.1.3 PID控制器校正 (8)3.2 Bang-Bang控制 (10)3.3 PID+Bang-Bang双模控制 (11)3.3.1 控制原理 (11)3.3.2 鲁棒性分析 (12)四、实际应用 (13)五、设计总结 (15)5.1 PID各参数对系统性能的影响 (15)5.1.1 比例参数对系统性能的影响 (15)5.1.2 微分参数对系统性能的影响 (15)5.1.3 积分参数对系统性能的影响 (16)5.2 PID+Bang-Bang双模控制 (16)六、致谢 (16)七、参考文献 (17)一、引言1.1 计算机控制仿真简介计算机仿真是用计算机科学和技术的成果建立被仿真的系统的模型,并在某些实验条件下对模型进行动态实验的一门综合性技术。

它具有高效、安全、受环境条件的约束较少、可改变时间比例尺等优点,已成为分析、设计、运行、评价、培训系统(尤其是复杂系统)的重要工具。

飞思卡尔智能车程序

飞思卡尔智能车程序

#include <hidef.h> /* common defines and macros */#include <MC9S12XS128.h> /* derivative-specific definitions */#pragma LINK_INFO DERIV ATIVE "MC9S12XS128.h"/////////////////////////////////////////////////////word AD_Value[16];//AD转换结int Done_cache[20]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};//记忆int Angle_cache[20]={50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50};//记忆//////////////////////////////////////////////////////#define PAEN 6/////////////////////////////////////////////////////unsigned int i=0,Xmax=0,Ymax=0,Xmax2=0,Ymax2=0;unsigned int flag=0;unsigned int Snake_flag=0;unsigned int SenA=50;unsigned int Out_flag=0;unsigned int DuoJi_angle;unsigned int Turn_flag=0;unsigned int Keep_flag=0;unsigned int Run_Time_Count=0;///////////////////////////////////////////////////////////////////unsigned int Speed=0, Count=0;//count=2即4秒测一次速度unsigned int ii=0,tt=0;int Goal_speed=15;int E1=0;int E2=0;int DE=0;int B1=0;int B2=0;int OUT=0;//////////////////////////////////////////////////////#include "Initiate.h"#include "Basic.h"#include "5110.h"#include "Control.h"//////////////////////////////////////////////////////////////////////void main(void){SetBusCLK_64M();Dly_ms(600);DisableInterrupts;PWMINIT();initPIT(); //内部中断SciInit() ; //串口LCD_init(); //LCDADCInit(); //ADCInit_Event_Count(); //测速初始化PWMDTY0=0;PWMDTY1=0;PWMDTY23=1450;Dly_ms(100);DDRB=0x00;while(PORTB_PB6==1) ; //等待开始键按下PWMDTY1=0;PWMDTY0=0;DuoJi_angle=1450;PWMDTY23=DuoJi_angle;Dly_ms(600);EnableInterrupts;while(1);}//////////////////////////////////////////////////////////////////////////////// void Scan_A2(){Xmax=0;Ymax=0;Xmax2=0;Ymax2=0;for(i=0;i<8;i++){if(AD_Value[i]<=10) AD_Value[i]=0;}for(i=0;i<8;i++) ///////////max{if(AD_Value[i]>Ymax){Ymax=AD_Value[i];Xmax=i;}}for(i=0;i<8;i++) ///////////max2{if(AD_Value[i]>Ymax2 && AD_Value[i]<Ymax){Ymax2=AD_Value[i];Xmax2=i;}}if(Ymax!=0){if(Xmax>Xmax2) SenA=(90*(Xmax+Xmax2)+Ymax-Ymax2)/12; //SenA else if(Xmax<Xmax2){if((90*(Xmax+Xmax2))<(Ymax-Ymax2)) SenA=0;else SenA=(90*(Xmax+Xmax2)+Ymax2-Ymax)/12;}else SenA=(90*(Xmax+Xmax2))/12;if(SenA>100) SenA=100;if(Xmax<1 /*&& Xmax2==1 && Ymax2<40*/ ) //////Out_flag 0/1/2{Out_flag=1;}else if(Xmax>6 /*&& Xmax2==6 && Ymax2<40*/ ){Out_flag=2;}else Out_flag=0;}switch(Out_flag){case 1 : SenA=0;break;case 2 : SenA=100;break;}}///////////////////////////////////////////////////////////////////////////////////void Change_angle(){if(SenA>50) DuoJi_angle=(65*(SenA-50)+14500)/10;else DuoJi_angle=(14500-65*(50-SenA))/10;PWMDTY23=DuoJi_angle;}/////////////////////////////////////////////////////////////////////////////////////void Rem_angle() //记忆传感器角度20个{if(SenA<40) Done_cache[20]=1;else if(SenA>60) Done_cache[20]=2;else Done_cache[20]=0;Angle_cache[20]=SenA;for(ii=0;ii<20;ii++){Done_cache[ii]=Done_cache[ii+1];Angle_cache[ii]=Angle_cache[ii+1];}}///////////////////////////////////////////////////////////////////////////////////void Mod(){if(Done_cache[0]==0 && Done_cache[1]==0 && Done_cache[2]==0 && Done_cache[3]==0 && Done_cache[4]==0 && Done_cache[5]==0 && Done_cache[6]==0 && Done_cache[7]==0 && Done_cache[8]==0 && Done_cache[9]==0 && Done_cache[10]==0 && Done_cache[11]==0 && Done_cache[12]==0 && Done_cache[13]==0 && Done_cache[14]==0 && Done_cache[15]==0 && Done_cache[16]==0 && Done_cache[17]==1 && Done_cache[18]==1 && Done_cache[19]==1 && Done_cache[20]==1 && Angle_cache[19]<Angle_cache[18] && Angle_cache[18]<Angle_cache[17] ){Keep_flag=1;//直道左弯}else if(Done_cache[0]==0 && Done_cache[1]==0 && Done_cache[2]==0 && Done_cache[3]==0 && Done_cache[4]==0 && Done_cache[5]==0 && Done_cache[6]==0 && Done_cache[7]==0 && Done_cache[8]==0 && Done_cache[9]==0 && Done_cache[10]==0 && Done_cache[11]==0 && Done_cache[12]==0 && Done_cache[13]==0 && Done_cache[14]==0 && Done_cache[15]==0 && Done_cache[16]==0 && Done_cache[17]==2 &&Done_cache[18]==2 && Done_cache[19]==2 && Done_cache[20]==2 && Angle_cache[19]>Angle_cache[18] && Angle_cache[18]>Angle_cache[17] ){Keep_flag=2;//直道右弯}else if(Done_cache[0]==1 && Done_cache[1]==1 && Done_cache[2]==1 && Done_cache[3]==1 && Done_cache[4]==1 && Done_cache[5]==1 && Done_cache[6]==1 && Done_cache[7]==1 && Done_cache[8]==1 && Done_cache[9]==1 && Done_cache[10]==1 && Done_cache[11]==1 && Done_cache[12]==1 && Done_cache[13]==1 && Done_cache[14]==1 && Done_cache[15]==1 && Done_cache[16]==1 && Done_cache[17]==1 && Done_cache[18]==1 && Done_cache[19]==1 && Done_cache[20]==1 ){Keep_flag=3;//左弯}else if(Done_cache[0]==2 && Done_cache[1]==2 && Done_cache[2]==2 && Done_cache[3]==2 && Done_cache[4]==2 && Done_cache[5]==2 && Done_cache[6]==2 && Done_cache[7]==2 && Done_cache[8]==2 && Done_cache[9]==2 && Done_cache[10]==2 && Done_cache[11]==2 && Done_cache[12]==2 && Done_cache[13]==2 && Done_cache[14]==2 && Done_cache[15]==2 && Done_cache[16]==2 && Done_cache[17]==2 && Done_cache[18]==2 && Done_cache[19]==2 && Done_cache[20]==2 ){Keep_flag=4;//左弯}else Keep_flag=0;}///////////////////////////////////////////////////////////////////////////////////*误差----------E = 实际值-设定值误差变化------dE = 本次误差-上次误差中间变量1-----B1= E + dE中间变量2-----B2= E*E + dE*dE输出----------OUT= B2/B1一次修改后: IF E=0 AND dE=0 THAN OUT=0 ELSE OUT=B2/B1二次修改后: IF B1=0 THAN OUT=0 ELSE OUT=B2/B1*///////////////////////////////////////////////////////////void Speed_pid(){E2=Speed-Goal_speed;DE=E2-E1;B1=E2+DE;B2=E2*E2+DE*DE;E1=E2;if(B1==0) OUT=0;else OUT=B2/B1;PWMDTY1=OUT;}//////////////////////内部中断///////////////////////////////////////////////#pragma CODE_SEG __NEAR_SEG NON_BANKEDvoid interrupt 66 PIT0(void) //2ms{PITTF_PTF0=1;//清中断标志位if(Keep_flag==1 || Keep_flag==2 || Keep_flag==3 || Keep_flag==4){tt++;if(tt==160){Keep_flag=0;tt=0;}}while(ATD0STA T2_CCF0==0); // 等待转换结束while(A TDOSTAT2_CCF0==0) AD_GetValue();Count++;if(Count>1){Speed=PACNT;Scan_A2();Rem_angle();PACNT=0;Count=0;}if(Keep_flag==0){Mod();Goal_speed=17;}else if(Keep_flag==1){//SenA=0;Goal_speed=6;}else if(Keep_flag==2){//SenA=100;Goal_speed=6;}else if(Keep_flag==3 || Keep_flag==4){Goal_speed=15;}PID();Change_angle();}void interrupt 67 PIT1(void) //100ms {PITTF_PTF1=1;//清中断标志位Run_Time_Count++;//PWMDTY23=DuoJi_Middle;//DuoJi_Middle++;/*LCD_Show_Number(30,0,DuoJi_angle);LCD_Show_Number(0,0,SenA);LCD_Show_Number(0,1,Xmax);LCD_Show_Number(30,1,PWMDTY1);LCD_Show_Number(0,2,Ymax);LCD_Show_Number(30,2,Speed);LCD_Show_Number(0,3,Xmax2);LCD_Show_Number(0,4,Ymax2);LCD_Show_Number(0,5,Out_flag);LCD_Show_Number(30,5,flag);*/LCD_Show_Number(0,0,PWMDTY1);LCD_Show_Number(30,0,SenA);LCD_Show_Number(0,1,Speed);LCD_Show_Number(30,1,Goal_speed);LCD_Show_Number(0,2,Keep_flag);LCD_Show_Number(30,2,tt);LCD_Show_Number(0,3,Done_cache[0]);LCD_Show_Number(30,3,Done_cache[5]);LCD_Show_Number(0,4,Done_cache[10]);LCD_Show_Number(30,4,Done_cache[15]);LCD_Show_Number(0,5,Done_cache[19]);LCD_Show_Number(30,5,Done_cache[20]);if(Run_Time_Count>180) stop();}/***************************************************************************/ /*****常用操作**************************************************************/ /* enable global interrupts */#define GIE (SREG |= BIT(7))/* disable global interrupts */#define GID (SREG &= ~BIT(7))#define SLEEP() asm("sleep")/* enables an unsigned char to be used as a series of booleans */#define BIT(x) (1 << (x))#define SETBIT(x, y) (x |= y)#define CLEARBIT(x, y) (x &= ~y)#define CHECKBIT(x, y) (x & y)// ***** Define I/O pins *****#define BIT7 0x80#define BIT6 0x40#define BIT5 0x20#define BIT4 0x10#define BIT3 0x08#define BIT2 0x04#define BIT1 0x02#define BIT0 0x01#define true 1#define True 1#define false 0#define False 0#define SCLK BIT4#define SDIN BIT3#define LCD_DC BIT2#define LCD_CE BIT0#define LCD_RST BIT1#define LCD_PORT PTT#define LCD_DIR DDRT//#define LCD_IN aa/************************************************************************/void LCD_init(void);void LCD_clear(void);void delay_1us(void);void LCD_set_XY(unsigned char x,unsigned char y);void LCD_write_char(unsigned char c);void LCD_write_english_string(unsigned char X,unsigned char Y,char *s);void LCD_write_chinese_string(unsigned char X, unsigned char Y,unsigned char ch_with,unsigned char num,unsigned char line,unsigned char row);void LCD_draw_bmp_pixel(unsigned char X,unsigned char Y,unsigned char *map,unsigned char Pix_x,unsigned char Pix_y);void LCD_write_byte(unsigned char dat, unsigned char command);const tabpoint[9]={0x00,0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};//***********************电机PID控制变量声明和初始化*******************************static unsigned int Kp=100;static unsigned int Kp2=100;static unsigned int Ki=3;static unsigned int Kd=30;unsigned short E = 5;unsigned char q = 1;int Mp = 0;int Mi = 0;int Md = 0;int Mp2 = 0;int MPWM=0;int L_u[3];/*************************电机PID调节***************************************************************************/ void PID(){L_u[2] = L_u[1];L_u[1] = L_u[0];L_u[0] = Goal_speed - Speed;//p_speed是根据传感器的检测情况在软件中给定的理论速度,search_PACN10就是PACN10表实际速度Mp = Kp * L_u[0];//偏差的放大倍数,KP值大可以加快调节,但会使稳定性下降Mi = Mi + Ki * L_u[0];//积分累加,可以消稳态误差,但是会使稳定下降,动态响应变慢Md = Kd * (L_u[0] - 2 * L_u[1] + L_u[2]);//改善动态性能,减少超调,太大会有干扰Mp2 = Kp2 * (L_u[0] - L_u[1]);if(((Ki * L_u[0]) > E)||((Ki * L_u[0]) < -E)) //初始化q=1,E=5 用这个if来决定是否需要用积分来调节,如果刚开始的积分已经很大了,就不需要用积分来调节了q = 0;else q = 1;MPWM = MPWM + Mp + q * Mi + Md +Mp2;// MPWM = MPWM + Mp+ Md +Mp2;if(MPWM > 1000) MPWM = 1000;//保证不溢出if(MPWM < 0) MPWM = 0;MPWM=MPWM/3;if(MPWM>100) MPWM=100;if(MPWM<0) MPWM=0;PWMDTY01=MPWM;Mp = 0;//调节一次后要把PID值清0Mi = 0;Md = 0;Mp2 = 0;}/////////////////////////////////////////////////////////////////////////////////////////////unsigned int Key_Scan2() // 返回1,2,4,8{unsigned int i=0;DDRB=0x00;i=PORTB&0x0f;return i;}////////////////////////////////////////////////////////////////////////////////////////////////// void AD_GetValue(){AD_Value[0]=A TD0DR0; //读取结果寄存器的值AD_Value[1]=A TD0DR1;AD_Value[2]=A TD0DR2;AD_Value[3]=A TD0DR3;AD_Value[4]=A TD0DR4;AD_Value[5]=A TD0DR5;AD_Value[6]=A TD0DR6;AD_Value[7]=A TD0DR7;AD_Value[8]=A TD0DR8; //读取结果寄存器的值AD_Value[9]=A TD0DR9;AD_Value[10]=A TD0DR10;AD_Value[11]=ATD0DR11;AD_Value[12]=A TD0DR12;AD_Value[13]=A TD0DR13;AD_Value[14]=A TD0DR14;AD_Value[15]=A TD0DR15;}////////////////////////////////////////////////////////////////////////////////////////////////// void Show_AD(){LCD_Show_Number(0,0,AD_Value[0]);LCD_Show_Number(30,0,AD_V alue[1]);LCD_Show_Number(0,1,AD_Value[2]);LCD_Show_Number(30,1,AD_V alue[3]);LCD_Show_Number(0,2,AD_Value[4]);LCD_Show_Number(30,2,AD_V alue[5]);LCD_Show_Number(0,3,AD_Value[6]);LCD_Show_Number(30,3,AD_V alue[7]);LCD_Show_Number(0,4,AD_Value[8]);LCD_Show_Number(30,4,AD_V alue[9]);LCD_Show_Number(0,5,AD_Value[10]);LCD_Show_Number(30,5,AD_V alue[11]);LCD_Show_Number(0,6,AD_Value[12]);LCD_Show_Number(30,6,AD_V alue[13]);LCD_Show_Number(60,0,AD_V alue[14]);LCD_Show_Number(60,1,AD_V alue[15]);LCD_Show_Number(60,2,AD_V alue[16]);}////////////////////////////////////////////////////////////////////////////////////////////////void SetBusCLK_64M(void){CLKSEL=0X00; //disengage PLL to systemPLLCTL_PLLON=1; //turn on PLLSYNR =0xc0 | 0x07;REFDV=0x80 | 0x01;POSTDIV=0x00; //pllclock=2*osc*(1+SYNR)/(1+REFDV)=128MHz;_asm(nop); //BUS CLOCK=64M_asm(nop);while(!(CRGFLG_LOCK==1)); //when pll is steady ,then use it;CLKSEL_PLLSEL =1; //engage PLL to system;}/////////////////////////////////////////////////////////////////////////////////////////////////void Dly_ms(int ms){int ii,jj;if (ms<1) ms=1;for(ii=0;ii<ms;ii++)for(jj=0;jj<5341;jj++); //64MHz--1ms}////////////////////////////////////////////////////////////////////////////////////////////////unsigned char SciRead() //串口接受函数{if(SCI1SR1_RDRF==1) //表明数据从位移寄存器传输到SCI数据寄存器{SCI1SR1_RDRF=1; //读取数据寄存器会将RDRF清除重新置位return SCI1DRL; //返回数据寄存器的数据}}void uart_putchar(unsigned char message)//串口发送函数{while(SCI1SR1_TC!=1); //这句话很重要,第一个发送完在发送第二个,否则发送错误//PORTB=~PORTB; //改变一次发送一次SCI1DRL=message;}///////////////////////////////////////////////////////////////////////////////////void stop(){DisableInterrupts;PWMDTY0=50;PWMDTY1=0;Dly_ms(900);PWMDTY0=0;PWMDTY1=0;while(PORTB_PB6==1) ; //等待开始键按下{while(1){LCD_Show_Number(0,0,Angle_cache[0]);LCD_Show_Number(27,0,Angle_cache[1]);LCD_Show_Number(54,0,Angle_cache[2]);LCD_Show_Number(0,1,Angle_cache[3]);LCD_Show_Number(27,1,Angle_cache[4]);LCD_Show_Number(54,1,Angle_cache[5]);LCD_Show_Number(0,2,Angle_cache[6]);LCD_Show_Number(27,2,Angle_cache[7]);LCD_Show_Number(54,2,Angle_cache[8]);LCD_Show_Number(0,3,Angle_cache[9]);LCD_Show_Number(27,3,Angle_cache[10]);LCD_Show_Number(54,3,Angle_cache[11]);LCD_Show_Number(0,4,Angle_cache[12]);LCD_Show_Number(27,4,Angle_cache[13]);LCD_Show_Number(54,4,Angle_cache[14]);LCD_Show_Number(0,5,Angle_cache[15]);LCD_Show_Number(27,5,Angle_cache[16]);LCD_Show_Number(54,5,Angle_cache[17]);/////////////////////////////////////////////////显示记忆数据}}}/////////////////////////*while(1){for(i=1150;i<1750;i++){PWMDTY23=i;LCD_Show_Number(0,1,i);Dly_ms(100);}} */////////////////////////////****************************************************************************** **************************************/void LCD_init(void){//先设置为输出SETBIT(LCD_DIR,SCLK);// DDRD|=SCLK;SETBIT(LCD_DIR,SDIN);//DDRC|=SDIN;SETBIT(LCD_DIR,LCD_DC);//DDRC|=LCD_DC;SETBIT(LCD_DIR,LCD_CE);//DDRC|=LCD_CE;SETBIT(LCD_DIR,LCD_RST);//DDRC|=LCD_RST;// 产生一个让LCD复位的低电平脉冲CLEARBIT(LCD_PORT,LCD_RST);//LCD_RST = 0;delay_1us();SETBIT(LCD_PORT,LCD_RST);//LCD_RST = 1;// 关闭LCDCLEARBIT(LCD_PORT,LCD_CE);//LCD_CE = 0;delay_1us();// 使能LCDSETBIT(LCD_PORT,LCD_CE);//LCD_CE = 1;delay_1us();LCD_write_byte(0x21, 0); // 使用扩展命令设置LCD模式LCD_write_byte(0xc8, 0); // 设置偏置电压LCD_write_byte(0x06, 0); // 温度校正LCD_write_byte(0x13, 0); // 1:48LCD_write_byte(0x20, 0); // 使用基本命令LCD_clear(); // 清屏LCD_write_byte(0x0c, 0); // 设定显示模式,正常显示LCD_set_XY(0,1);// 关闭LCDCLEARBIT(LCD_PORT,LCD_CE);//LCD_CE = 0;}/****************************************************************************** **************************************/void LCD_clear(void){unsigned int i;LCD_write_byte(0x0c, 0);LCD_write_byte(0x80, 0);for (i=0; i<500; i++){LCD_write_byte(0, 1);}}/****************************************************************************** **************************************/void delay_1us(void) //1us延时函数{unsigned int i;for(i=0;i<5;i++);}/********************************************************************************************************************/void LCD_set_XY(unsigned char X, unsigned char Y){LCD_write_byte(0x40 | Y, 0);// columnLCD_write_byte(0x80 | X, 0);// row}/****************************************************************************** **************************************/LCD_write_point(unsigned char X, unsigned char Y){unsigned int temp=0;if(poy!=X){potemp1=0x00;potemp2=0x00;potemp3=0x00;potemp4=0x00;potemp5=0x00;potemp6=0x00;}poy=X;if(Y<=8){if(pox!=1) potemp1=0x00;pox=1;temp=potemp1|tabpoint[Y];LCD_set_XY(X,8);LCD_write_byte(temp, 1);potemp1=temp;}else if(Y<=16){if(pox!=2) potemp2=0x00;pox=2;temp=potemp2|tabpoint[Y-8];LCD_set_XY(X,9);LCD_write_byte(temp, 1);potemp2=temp;}else if(Y<=24)if(pox!=3) potemp3=0x00;pox=3;temp=potemp3|tabpoint[Y-16]; LCD_set_XY(X,10);LCD_write_byte(temp, 1); potemp3=temp;}else if(Y<=32){if(pox!=4) potemp4=0x00;pox=4;temp=potemp4|tabpoint[Y-24]; LCD_set_XY(X,11);LCD_write_byte(temp, 1); potemp4=temp;}else if(Y<=40){if(pox!=5) potemp5=0x00;pox=5;temp=potemp5|tabpoint[Y-32]; LCD_set_XY(X,12);LCD_write_byte(temp, 1); potemp5=temp;}else if(Y<=48){if(pox!=6) potemp6=0x00;pox=6;temp=potemp6|tabpoint[Y-40]; LCD_set_XY(X,13);LCD_write_byte(temp, 1); potemp6=temp;}//for(temp=0;temp<50000;temp++);/****************************************************************************** **************************************/void LCD_write_char(unsigned char c){unsigned char line;c -= 32;for (line=0; line<6; line++){LCD_write_byte(font6x8[c][line], 1);}}void LCD_write_char2(unsigned char X, unsigned char Y,unsigned char c){unsigned char line;LCD_set_XY(X,Y);c -= 32;for (line=0; line<6; line++){LCD_write_byte(font6x8[c][line], 1);}}/****************************************************************************** **************************************//*-----------------------------------------------------------------------LCD_write_english_String : 英文字符串显示函数输入参数:*s :英文字符串指针;X、Y : 显示字符串的位置,x 0-83 ,y 0-5-----------------------------------------------------------------------*/void LCD_write_english_string(unsigned char X,unsigned char Y,char *s){LCD_set_XY(X,Y);while (*s){LCD_write_char(*s);s++;}}/********************************************************************************************************************//*-----------------------------------------------------------------------LCD_write_chinese_string: 在LCD上显示汉字输入参数:X、Y :显示汉字的起始X、Y坐标;ch_with :汉字点阵的宽度num :显示汉字的个数;line :汉字点阵数组中的起始行数row :汉字显示的行间距-----------------------------------------------------------------------*//*void LCD_write_chinese_string(unsigned char X, unsigned char Y,unsigned char ch_with,unsigned char num,unsigned char line,unsigned char row){unsigned char i,n;LCD_set_XY(X,Y); //设置初始位置for (i=0;i<num;){for (n=0; n<ch_with*2; n++) //写一个汉字{if (n==ch_with) //写汉字的下半部分{if (i==0) LCD_set_XY(X,Y+1);else{LCD_set_XY((X+(ch_with+row)*i),Y+1);}}LCD_write_byte(HZK[line+i][n],1);}i++;LCD_set_XY((X+(ch_with+row)*i),Y);}}*//****************************************************************************** **************************************//*-----------------------------------------------------------------------LCD_draw_map : 位图绘制函数输入参数:X、Y :位图绘制的起始X、Y坐标;*map :位图点阵数据;Pix_x :位图像素(长)Pix_y :位图像素(宽)-----------------------------------------------------------------------*/void LCD_draw_bmp_pixel(unsigned char X,unsigned char Y,unsigned char *map,unsigned char Pix_x,unsigned char Pix_y){unsigned int i,n;unsigned char row;if (Pix_y%8==0){row=Pix_y/8; //计算位图所占行数}else{row=Pix_y/8+1;}for (n=0;n<row;n++){LCD_set_XY(X,Y);for(i=0; i<Pix_x; i++){LCD_write_byte(map[i+n*Pix_x], 1);}Y++; //换行}}/****************************************************************************** **************************************//*-----------------------------------------------------------------------LCD_write_byte : 写数据到LCD输入参数:data :写入的数据;command :写数据/命令选择;-----------------------------------------------------------------------*/void LCD_write_byte(unsigned char dat, unsigned char command){unsigned char i;CLEARBIT(LCD_PORT,LCD_CE);// 使能LCD_CE = 0if (command == 0){CLEARBIT(LCD_PORT,LCD_DC);// 传送命令LCD_DC = 0;}else{SETBIT(LCD_PORT,LCD_DC);// 传送数据LCD_DC = 1;}for(i=0;i<8;i++){//delay_1us();if(dat&0x80){SETBIT(LCD_PORT,SDIN);//SDIN = 1;}else{CLEARBIT(LCD_PORT,SDIN);//SDIN = 0;}CLEARBIT(LCD_PORT,SCLK);//SCLK = 0;dat = dat << 1;SETBIT(LCD_PORT,SCLK);//SCLK = 1;}SETBIT(LCD_PORT,LCD_CE);//LCD_CE = 1;}void LCD_Show_Number (unsigned char X,unsigned char Y,unsigned int number) {LCD_set_XY(X,Y);LCD_write_char2(X,Y,number/1000+48);LCD_write_char2(X+6,Y,number%1000/100+48);LCD_write_char2(X+12,Y,number%100/10+48);LCD_write_char2(X+18,Y,number%10+48);}。

飞思卡尔 所有的算法

飞思卡尔  所有的算法

第1章电机控制1.1. 直流电机控制策略:针对本文所研究的智能车来说,车体速度是大惯性的被控对象。

算法输出的控制量只能对电机输出力进行控制。

而有一定负载时电机的输出力无论对车轮的转速还是车体的形式速度都是不成正比的,车在刚开始启动的时候速度是零,而电机的输出可能很大;车在匀速行驶的时候速度很快,而电机的输出可能并不是很大。

而且电池电量、车体重量都会对车速造成影响。

因此只有用闭环才能对车速进行良好的控制。

在车轮对地面不打滑的情况下车体的速度和后轮的转动速度是成正比的。

因此我们可以直接用光电码盘对后轮的转速进行控制。

对于这样一个大惯性系统,我们选用PID和鲁棒相结合的办法进行速度控制。

回路的设定值由经验值确定。

考虑到速度控制通道的时间滞后比较小,因此采用PID 控制方案,并在进行加减速控制时,引入了“棒棒控制”。

U(k + 1) = U(K) + P1 * e(k) + P2 * (e(k) – e(k - 1)) + P3 * ((e(k) – e(k-1) – (e(k-1) – e(k - 2)));公式1-1 PID的公式其中第一项为积分项;第二项为比例项;第三项为微分项。

考虑到被控对象(车体速度)本身是一个大的积分环节,公式中可以将第一项省略,即采用PD控制。

E 为误差。

同时设定误差门限,在误差比较大的时候采用大输出控制电机,将误差在最短时间内减小到所要求的范围,这就是鲁棒控制的思想。

电机控制策略,其实就是对模型车速度的控制策略,它是继路径识别之后非常重要的策略,直接关系到整个模型车比赛的性能。

速度控制得当,小车才能以最好的状态,在最短的时间完成比赛路程。

1.1.1.弯道速度控制在模型车入弯时刻出于稳定性考虑做减速控制。

减速原则是在原来直道速度设定值的基础上,减小速度设定值到低速挡,保证模型车可以安全入弯。

另一方面,入弯之后,为了过弯时模型车能够不明显的左右摆动并采用较好的姿态通过弯路,令车速与偏差成线性关系,偏差越大速度设定值越小。

飞思卡尔光电组程序

飞思卡尔光电组程序

/////////////////////////头文件////////////////////////////#include <hidef.h>#include "derivative.h"#include "mc9s12g128.h"#include "base.h"//#define idealspeed 12000#define SERVO_KP 31.5 //比例增益#define SERVO_KD 6.3 //微分增益////////////////////////////函数声明///////////////////////void base_Init(void);void sleep(int ms);void Time0_Init();void setspeed();void light();void turn();void CarControl(float measure);void setspeed1();////////////////////////////变量定义////////////////////////////////int k,sudu;int jiaodu=0;int m=0,i=0;int dushu6,dushu5,dushu4,dushu3,dushu2,dushu1,dushu7,dushu8,dushu9;float l_ser_error = 0; // e(t - 1)float p_ser_error = 0; // e(t - 2)float n_ser_error = 0; // e(t)float set_ser = 0;float inc_ser ;float servo_kp;///////////////////////////PID变量定义//////////////////////typedef struct{char sp_p;char sp_d;char sp_i;}sp_pid;sp_pid pid={11,3,42};/////////////////////////////主函数////////////////////////////////// void main(void) {DDRB=0XFF;DDRD=0X00;DDRC=0X00;EnableInterrupts;base_Init();core_Car_speed_set(750);for(;;){turn();}_FEED_COP();}///////////////////////定时测脉冲/////////////////////////////void Time0_Init(){TIOS=0x01; //定时器通道0设置为输出比较TC0=100000; //赋初值,当TCNT从0计数到此值时第一次进入中断TCTL2=0x01;TSCR2=0x07; //计一个数用5.33微秒TSCR1=0x80;TIE=0x01;}//中断:#pragma CODE_SEG __NEAR_SEG NON_BANKEDinterrupt 8 TIM0(void){TFLG1_C0F=1;//清中断标志位TIE=0x00;TC0=100000;sudu=PACNT ; //读取脉冲数//setspeed();PACNT =0;TIE=0x01;}#pragma CODE_SEG DEFAULT///////////////////////////////////////////////////////////////////////////////////初始化/////////////////////////////void base_Init(void){base_Pll_init();base_Pwm_init();base_Pulse_count_init();Time0_Init();}/////////////////////锁相环设置//////////////////////////////int base_Pll_init(void){CPMUCLKS=0x00;CPMUSYNR=0x00 | 0x02;CPMUREFDIV=0x80 | 0x01;CPMUPOSTDIV=0x00;CPMUOSC_OSCE=1;while(!(CPMUFLG_LOCK==1));CPMUCLKS_PLLSEL=1;_DISABLE_COP();EnableInterrupts;}///////////////////////pulse初始化////////////////////////////int base_Pulse_count_init(){PACTL=0x50;PACNT = 0x0000; //清0计数器}//////////////////////////////pwm设置//////////////////////////////int base_Pwm_init(void){PWME=0x00;PWMCLK=0xff;PWMPRCLK=0x30;PWMSCLA=0x01;PWMSCLB=0x03;PWMPOL=0x00;PWMCAE=0x00;PWMCTL=0xf0;}int base_Pwm_set(Pwm_Channel pchannel,int pper,int pdty){int *bpwm=(int*)0x00ac;uchar p_start=0x01;p_start = ~(p_start<<(pchannel*2+1));//PWME &=p_start;bpwm+=pchannel;//*bpwm=0x0000;bpwm+=4;*bpwm=pper;bpwm+=4;*bpwm=pdty;if(pper!=0){p_start=0x01;p_start=p_start<<(pchannel*2+1);PWME |=p_start;}}//////////////////////////速度设置///////////////////////////////////int core_car_speed_setting=0;int core_Car_speed_start(){base_Pwm_set(PWM_CHANNEL0,1200,1200);base_Pwm_set(PWM_CHANNEL2,1200,1200);}int core_Car_speed_set(int speed){base_Pwm_set(PWM_CHANNEL0,1200,1200);base_Pwm_set(PWM_CHANNEL2,1200,speed);}int core_Car_speed_close(){base_Pwm_set(PWM_CHANNEL0,0,0);base_Pwm_set(PWM_CHANNEL2,0,0);}/////////////////////////方向设置/////////////////////////int core_Car_direction_set(int size){if(size>=0){base_Pwm_set(PWM_CHANNEL3,10000,9250+250*size/45);} else{base_Pwm_set(PWM_CHANNEL3,10000,9250-250*abs(size)/45);}}void sleep(int ms){ int i,j;for(i=0;i<ms;i++)for(j=0;j<2003;j++){}}////////////////////////////调整速度PID///////////////////////////void setspeed(){int idealspeed=17750;static int speedpwm=700;static int error_sp=0,errorlast_sp=0,errord_sp=0,errordlast_sp=0,errordd_sp=0;int realspeed;realspeed=sudu; //实际速度error_sp=idealspeed-realspeed; //当前误差计算积分项Ierrord_sp=error_sp-errorlast_sp; //计算比例项Perrordd_sp=errord_sp-errordlast_sp; //计算微分项Derrorlast_sp=error_sp; //前一次误差errordlast_sp=errord_sp; //前两次误差speedpwm=speedpwm+pid.sp_p*errord_sp+pid.sp_d*errordd_sp/10+pid.sp_i*error_sp/10; if(speedpwm>=800)speedpwm=800;else if(speedpwm<=700)speedpwm=700;core_Car_speed_set(speedpwm);}void setspeed1(){int idealspeed=7600;static int speedpwm=950;static int error_sp=0,errorlast_sp=0,errord_sp=0,errordlast_sp=0,errordd_sp=0;int realspeed;realspeed=sudu; //实际速度error_sp=idealspeed-realspeed; //当前误差计算积分项Ierrord_sp=error_sp-errorlast_sp; //计算比例项Perrordd_sp=errord_sp-errordlast_sp; //计算微分项Derrorlast_sp=error_sp; //前一次误差errordlast_sp=errord_sp; //前两次误差speedpwm=speedpwm+pid.sp_p*errord_sp+pid.sp_d*errordd_sp/10+pid.sp_i*error_sp/10; if(speedpwm>=1000)speedpwm=1000;else if(speedpwm<=900)speedpwm=900;core_Car_speed_set(speedpwm);}//////////////////////激光头点亮流水灯/////////////////////void light(){PORTB=0x00;sleep(1);dushu4=PORTD_PD4;dushu9=PORTC_PC0;PORTB=0x11;sleep(1);dushu4=PORTD_PD4;dushu1=PORTD_PD1;PORTB=0x22;sleep(1);dushu5=PORTD_PD5;dushu2=PORTD_PD2;PORTB=0x33;sleep(1);dushu5=PORTD_PD5;dushu2=PORTD_PD2;PORTB=0x44;sleep(1);dushu6=PORTD_PD6;dushu3=PORTD_PD3;PORTB=0x55;sleep(1);dushu6=PORTD_PD6;dushu3=PORTD_PD3;PORTB=0x66;sleep(1);dushu7=PORTD_PD7;dushu8=PORTD_PD0;}///////////////////////////转弯判断////////////////////////////void turn(){ light();///////////////////////////直道/////////////////////////////////if(dushu8==1&&dushu7==1){ setspeed();CarControl(0);}//左转elseif(dushu4==1&&dushu7==1&&dushu1==0&&dushu2==0&&dushu3==0&&dushu5==0&&dush u6==0&&dushu8==0){ setspeed();//eft_direction(-11);CarControl(-9);}elseif(dushu4==1&&dushu7==1&&dushu5==1&&dushu1==0&&dushu2==0&&dushu3==0&&dush u6==0&&dushu8==0){ setspeed1();//left_direction(-13);CarControl(-12);}elseif(dushu4==1&&dushu7==1&&dushu5==1&&dushu6==1&&dushu1==0&&dushu2==0&&dush u3==0&&dushu8==0){ setspeed1();//left_direction(-14);CarControl(-14);}//右转elseif(dushu8==1&&dushu1==1&&dushu2==0&&dushu3==0&&dushu5==0&&dushu6==0&&dush u4==0&&dushu7==0){ setspeed();//right_direction(8);CarControl(7);}elseif(dushu1==1&&dushu2==1&&dushu8==1&&dushu3==0&&dushu5==0&&dushu6==0&&dush u4==0&&dushu7==0){ setspeed1();//right_direction(9);CarControl(8);}elseif(dushu1==1&&dushu2==1&&dushu3==1&&dushu8==1&&dushu5==0&&dushu6==0&&dush u4==0&&dushu7==0){ setspeed1();//right_direction(11);CarControl(11);}//////////////////////////弯道/////////////////////////////右转else if(dushu3==1&&dushu2==1&&dushu1==1&&dushu8==1){ setspeed1();//left_direction(-16);CarControl(20);}else if(dushu3==1&&dushu2==1&&dushu1==1&&dushu8==1&&dushu6==1){ setspeed1();//left_direction(-30);CarControl(30);}elseif(dushu3==1&&dushu2==1&&dushu1==1&&dushu8==1&&dushu6==1&&dushu5==1) { //setspeed1();core_Car_speed_set(1000);CarControl(30);}else if(dushu8==1&&dushu1==1){ setspeed1();//left_direction(-11);CarControl(11);}//左转else if(dushu4==1&&dushu5==1&&dushu6==1&&dushu7==1){ setspeed1();//right_direction(12);CarControl(-12);}else if(dushu4==1&&dushu5==1&&dushu6==1&&dushu7==1&&dushu3==1){ setspeed1();//right_direction(22);CarControl(-22);}elseif(dushu4==1&&dushu5==1&&dushu6==1&&dushu7==1&&dushu3==1&&dushu2==1) { //setspeed1();core_Car_speed_set(1000);CarControl(-25);}elseif(dushu4==1&&dushu5==1&&dushu6==1&&dushu7==1&&dushu3==1&&dushu2==1&&dush u1==1){ //setspeed1();core_Car_speed_set(1000);CarControl(-28);}else if(dushu6==1&&dushu7==1){ setspeed1();// right_direction(12);CarControl(-12);}//elseif(dushu1==0&&dushu2==0&&dushu3==0&&dushu8==0&&dushu5==0&&dushu6==0&&dush u4==0&&dushu7==0){ setspeed();CarControl(0);}}void CarControl(float measure){//舵机输出增量float inc_ser;//舵机上一次的输出值,初始化为1500static float out_pwm = 9250;//舵机变增益控制系数float servo_kp = 0.4;float servo_kd = 0.2;n_ser_error = measure - set_ser; //这里是测量值- 设定值//变增益控制inc_ser = servo_kp * SERVO_KP * (n_ser_error - l_ser_error)+ servo_kd * SERVO_KD * (n_ser_error - 2 * l_ser_error +p_ser_error);out_pwm += inc_ser; // 初始就为9250p_ser_error = l_ser_error;l_ser_error = n_ser_error;//防止超限,阈值到时要重新测一测if(out_pwm <= 9000)out_pwm = 9000;if(out_pwm >= 9500)out_pwm = 9500;base_Pwm_set(PWM_CHANNEL3,10000,out_pwm);}。

飞思卡尔小车PID控制的通俗理解

飞思卡尔小车PID控制的通俗理解

很多同学都不清楚PID是个什么东西,因为很多不是自动化的学生。

他们开口就要资料,要程序。

这是明显的学习方法不对,起码,首先,你要理解PID是个什么东西。

本文以通俗的理解,以小车纵向控制举例说明PID的一些理解。

首先,为什么要做PID?由于外界原因,小车的实际速度有时不稳定,这是其一,要让小车以最快的时间达达到既定的目标速度,这是其二。

速度控制系统是闭环,才能满足整个系统的稳定要求,必竟速度是系统参数之一,这是其三.小车调速肯定不是线性的,外界因素那么多,没人能证明是线性的。

如果是线性的,直接用P就可以了。

比如在PWM=60%时,速度是2M/S,那么你要它3M/S,就把PWM提高到90%。

因为90/60=3/2,这样一来太完美了。

完美是不可能的。

那么不是线性的,要怎么怎么控制PWM使速度达到即定的速度呢?即要快,又要准,又要狠。

(即快准狠)系统这个速度的调整过程就必须通过某个算法调整,一般PID就是这个所用的算法。

可能你会想到,如果通过编码器测得现在的速度是2.0m/s,要达到2.3m/s的速度,那么我把pwm增大一点不就行了吗?是的,增大pwm多少呢?必须要通过算法,因为PWM 和速度是个什么关系,对于整个系统来说,谁也不知道。

要一点一点的试,加个1%,不够,再加1%还是不够,那么第三次你还会加1%吗?很有可能就加2%了。

通过PID三个参数得到一个表达式:△PWM=a *△V1+b *△V2+c *△V3,a b c是通过PID的那个长长的公式展开,然后约简后的数字,△V1 ,△V2 ,△V3 此前第一次调整后的速度差,第二次调整后的速度差,第三次。

一句话,PID要使当前速度达到目标速度最快,需要建立如何调整pwm和速度之间的关系。

输入输出是什么:输入就是前次速度,前前次速度,前前前次速度。

输出就是你的PWM应该增加或减小多少。

为了避免教科书公式化的说明,本文用口语化和通俗的语言描述。

虽然不一定恰当,但意思差不多,就是那个事。

PID控制算法及流程图

PID控制算法及流程图

1,PID是一个闭环控制算法.因此要实现PID算法,必须在硬件上具有闭环控制,就是得有反馈。

比如控制一个电机的转速,就得有一个测量转速的传感器,并将结果反馈到控制路线上,下面也将以转速控制为例。

2,PID是比例(P)、积分(I)、微分(D)控制算法。

但并不是必须同时具备这三种算法,也可以是PD,PI,甚至只有P算法控制。

我以前对于闭环控制的一个最朴素的想法就只有P控制,将当前结果反馈回来,再与目标相减,为正的话,就减速,为负的话就加速.现在知道这只是最简单的闭环控制算法。

3,比例(P)、积分(I)、微分(D)控制算法各有作用:比例,反应系统的基本(当前)偏差e(t),系数大,可以加快调节,减小误差,但过大的比例使系统稳定性下降,甚至造成系统不稳定;积分,反应系统的累计偏差,使系统消除稳态误差,提高无差度,因为有误差,积分调节就进行,直至无误差;微分,反映系统偏差信号的变化率e(t)—e(t—1),具有预见性,能预见偏差变化的趋势,产生超前的控制作用,在偏差还没有形成之前,已被微分调节作用消除,因此可以改善系统的动态性能.但是微分对噪声干扰有放大作用,加强微分对系统抗干扰不利.积分和微分都不能单独起作用,必须与比例控制配合。

4,控制器的P,I,D项选择。

下面将常用的各种控制规律的控制特点简单归纳一下:1、比例控制规律P:采用P控制规律能较快地克服扰动的影响,它的作用于输出值较快,但不能很好稳定在一个理想的数值,不良的结果是虽较能有效的克服扰动的影响,但有余差出现。

它适用于控制通道滞后较小、负荷变化不大、控制要求不高、被控参数允许在一定范围内有余差的场合.如:金彪公用工程部下设的水泵房冷、热水池水位控制;油泵房中间油罐油位控制等。

2、比例积分控制规律(PI):在工程中比例积分控制规律是应用最广泛的一种控制规律。

积分能在比例的基础上消除余差,它适用于控制通道滞后较小、负荷变化不大、被控参数不允许有余差的场合。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
{
}
}
#pragma CODE_SEG __NEAR_SEG NON_BANKED
void interrupt 66 timer0(void) //1ms执行函数程序
{
PITTF_PTF0 = 1; //PIT中断标志位清零
count++;
if(count>9) //10MS一次中断,用来读取编码器脉冲值
}
void main(void)
{
DisableInterrupts;
DDRP=0xFF;
DDRB=0xFF;
DDRA=0x00;
PORTB=0x24;
Init_PLL();
PIT_Init();
Init_PWMB();
Init_Event_Count();
EnableInterrupts;
for(;;)
volatile int count;
volatile int pulse;
//时钟初始化
void Init_PLL(void)
{
CLKSEL = 0X00;//disengage PLL to system
PLLCTL_PLLON = 1;//turn on PLL
SYNR = (0xc0|0x18); //SYDIV=0X18=24
{
PORTB |=(1<<5);
PORTB &= ~(1<<4);
PWMDTY23 = M_PWM;
}
void Moto_PID()
{
volatile static int err=0,last_err=0,derr=0;
volatile static int M_PWM=0;
err=think_speed-pulse;// err
PWMDTY23 = 1800; //占空比1/20
PWMPER23 = 2778; //周期20ms
PWME_PWME3 = 1; //enable pwm3
}
//PIT定时中断
void PIT_Init(void)
{
INT_CFADDR = 0x70;
INT_CFDATA5 = 0x07; //设置为最高级
}
void Init_PWMB(void) //控制后轮电机
{
PWMCTL_CON23 = 1; //级联2,3通道
PWME_PWME3 = 0;//关闭3通道
PWMPRCLK =0x00; //选择时钟B,50MHZ
PWMPOL_PPOL3 = 1; //起始波为高电平
PWMCNT23 = 0; //计数器从零开始计数
derr=err-last_err;
M_PWM+=err*10+derr*15; //15 5
if(M_PWM<=0)
M_PWM=0;
if(M_PWM>=2777)
M_PWM=2777;
last_err=err; //记录上次偏差值
Start_Moto(M_PWM);//电机前进的控制函数,换成自己的就行了
#include <hidef.h> /* common defines and macros */
#include "derivative.h" /* derivative-specific definitions */
#define think_speed 30 // think_speed是用来控制电机轮子的转速的,给定他们不同的值,轮子就不同的转速,
{
count=0;
pulse=PACNT; //读取脉冲值
Moto_PID();
//进行电机的PID控制
PACNT=0; //脉冲累加器计数器清零
}
}
#pragma CODE_SEG DEFAULT
REFDV = (0x40|0x07); //REFDIV=0X07=7
POSTDIV = 0x00; //pllclock=2*osc*(1+SYDIV)/(1+REFDIV)=100MHz;
_asm(nop); //BUS CLOCK=50M
_asm(nop);
_asm(nop);
_asm(nop);
PITCFLMT_PITE = 0; //PIT is disabled.
PITCE_PCE0 = 1; //0 Chanel is enabled.
PITMUX_PMUX0 = 0; //使用子定时器0
PITMTLD0 = 200; //子定时器0设置为4us
PITLD0 = 250; // 1ms
{
DDRT=0x00;
PERT=0xC0;//编码器脉冲累加器口为输入,上拉有效。其他口没作用。
PACTL = (1<<6);//脉冲累加器启动,外部发生一次下降沿就计数一次。外部编码器连接到IOC7,IOC6.
//在中断里读取PACNT的值就是脉冲个数。读取后清零PACNT。
}Байду номын сангаас
void Start_Moto(uint M_PWM) //第一路电机
PITCFLMT_PFLMT = 1; //使能计数器0
PITFLT_PFLT0 = 1; //使能计数器1
PITINTE_PINTE0 = 1; //通道0中断打开
PITTF_PTF0 = 1; //清中断标志位
PITCFLMT_PITE = 1; // PIT is enabled
}
void Init_Event_Count(void)
_asm(nop);
_asm(nop);
_asm(nop);
_asm(nop);
_asm(nop);
while(!(CRGFLG_LOCK==1));//when pll is steady ,then use it;
CLKSEL_PLLSEL = 1;//engage PLL to system;
相关文档
最新文档