一、引言
2014年10月18日开始接触到自平衡小车,于是就有了DIY自平衡小车的冲动了,于是在网上看到很多有关自平衡小车的帖子,在淘宝上也发现有很多现成的套件或相应的部件,这些丰富的资源极为凌乱,让新入行的人很难决策、不知如何下手。正如当下的社会一样,专家太多,而且各种专家的见解相同,甚至意见相左,弄得新入行的人更不知道怎么办了。
首先声明,我不是什么专家,只是一个过来人,走过的路多一些、时间长一些,遇到的挫折也多一些而已,所以有点自己的体会。特别是接触到现在的很多年轻人,再加上我自己也是刚刚接触自平衡小车,就有些想要说的话了,但确没有要说的具体对象,于是就在此瞎说一通,有不对的地方,请广大的“xx友”予以斧正!
做自平衡小车是要花钱、花精力的,很多新人还是学生,还没有收入,所以在花钱这方面就更犹豫了,特别是淘宝上介绍的什么价位的东西都有,好的东西贵,便宜的东西又怕不靠谱。其实,对于真正的发烧友来说,钱是次要的,他们的经验都是靠前期花费的银子积累起来的,别看他们有了经验之后,往往花点小钱就能解决大问题。关于花钱我也是一样,换个手机、吃顿饭很随便,钱花得多了去了,但是要买点这些东西就算计来算计去,一点小钱都要花费几个小时来回比较,哪怕运费贵两块钱都不愿意。我虽然做了一个这样不起眼的小东西,现在来看直接成本能控制在100元以内,但我前期来回折腾的钱统计了一下有1121.15元。所以这里介绍一些东西的目的,也是让还未有收入来源的学生们花点小钱积累更多一些的经验,从而提高“投入产出”比,我就当作你们前面的探路者之一吧。
想做自平衡小车的我接触的有下面几类人群:
1、好奇,看到这个很神奇,而且有那么多人都做成了,我也是学了这么多年了,也会不少东西了,所以我也要做一个;
2、想通过这个自平衡小车学单片机;
3、自己学的专业与此相关,所以想拿他开刀,来练练手;
4、还有就是我这样的人,没事干,又有点“经验”,拿它来消磨时间,填补自己的空虚。
无论是哪类人群,如果是第一次上手,请都不要轻敌,当然也不排除一次就蒙成功了的,东西是做出来了,但我想从中学到的东西是不会太多的。
还有很多新人都认为算法最复杂,也是最为困难的部分,其实我的看法是这部分恰恰是很简单的部分,如果前期障碍都解决了(譬如,买了一套现成的小车底盘,和一些参考资料),剩下的还真就是简单的编写(其实大部分也是抄来的)程序、调整一下参数,就成功了,其结果就是照葫芦画了个瓢!
如果,没解决前期问题,就像很多人一样,怎么调参数都调不好,因为他们只知道程序和算法,不知道的就不去分析和想办法知道,想办法去解决,就在没问题的部分瞎折腾。这是我想起一个寓言:就是灯下找钥匙,一个人看到另外一个人晚上在路灯下找东西,就问他,你找什么东西啊?那个人说,我找钥匙。你的钥匙是掉在这儿吗?他说不是掉在这儿。那你为什么要在这儿找呢,他说因为这儿有灯,看得见,别的地放没亮光,我看不见。
想做还没做的你们有些什么样的想法和看法呢?
下面给新人如何交流技术问题提个建议:
技术问题交流不能像日常生活中大妈们对话那样(这也是网络聊天的模式),简短的几个词就能表达的,就像我们单位的年轻人说话方式一样,问他某项工作的情况,他就会说一句,没问题或者说不行,话要是能这样简单说下就能很好交流的,要么是相当的高手,要么是在一起生活了几十年的两口子。
你们说行和不行,都要说清楚(注意这里的清楚二字,很多人话是说不清楚的),做了哪些工作,是怎么做的,现象是怎样的,最好是有图有数据,不要自己就给出一个结论来,因为之前的有些工作不到位,甚至有错误,这个结论是不靠谱的,结论是由听者自己来下的,而不是由说者告诉听者!!!
有些人,想问的问题也说不出来(的确有人知道,说不出来,还有些人能说出来,却写不出来),这时候你们最好上照片,上图吧,图文并茂的表达。
二、PID那点事
关于PID的算法,网络上资料很多,也有各种通俗易懂的解释,我这里想给大家一个只要具有初中数学、物理基础的人,就能明白的一种不甚严谨的,但容易理解的一种解释方法。
先给出一个典型的PID算法框图,如下图:
我这里先将此图简化为仅剩P控制部分的框图,至于其他的I和D部分,最后仅用两句话解释一下就行了,再也无需太多的解释了。
比例调节的公式是:u(t) = Kp * e(t),e(t) = r(t) – c(t)
其中:r(t) 是设定值,就是你想让被控系统某个参数所要保持的状态值; c(t)是系统的这个参数的实际状态值。
比例调节的过程就是即时成比例地反应控制系统的偏差信号e(t),偏差一旦产生,通过 Kp * e(t) 产生控制作用以减小偏差。理想的情况是有多大的误差,通过这个调节作用之后,就能将误差消除。但实际情况并非都是那么理想,Kp小了,修正不到位,Kp大了就会出现矫枉过正的现象。
对于自平衡小车来说,要控制的这个参数就是小车的倾斜角度,就是想办法让这个小车停在你所设定的角度上,这样小车就能稳定平衡了。
这样我们就知道了,控制的作用就是想让被控系统稳定在你所设定的某个值上。拿小车的平衡来说就是让小车的倾斜角度与其物理(就是小车不控制时,能够自然稳定)平衡角度一致,始终保持在这个倾斜状态。
对于有些结构比较好的小车,仅比例这一项,在没有大的扰动的情况下,的确就能稳定的控制小车平衡。但往往情况并非这么理想,所以还要用到积分项I或微分项D。那么实际会出现小车来回摆动,或者始终往某个方向倾斜,造成小车往一边跑,最后控制不住就倒地了。
先说说来回摆动的问题吧,来回摆动是不是就是小车有一定的倾斜转动角速度,角速度是什么呢?角速度是不是就是角度的微分(有点超出初中的知识范围了,还是改成初中能理解的语言吧,也就是说速度是不是在单位时间内的位置差)。好了,我要不想让他摆动,是不是控制这个角速度为0,是不是就不摆动了。那么,我们增加D项,就能达到这个目的,虽然不是绝对的解决,但还是明显的改善了很多的。
下面接着说始终往一边偏的问题,如果能不往一边偏,仅来回摆动,也就是这个角度一会大、一会小,一会正、一会负,经过积分(又超出范围了,长时间的角度求平均),这个角度平均值几乎是0,如果往一边偏的话,这个平均值就是某个不为0的值了,这是我们加上I项就能克服这个问题了。
啰里啰嗦的说多了,打字也打累了,赶紧总结一下结束吧。
PID控制:对于角度环来说:P是消除角度的误差,I是消除角度累积的误差,D是消除角度变化率(角速度)的误差;同理,对于速度环来说:P是消除速度的误差,I是消除速度累积(位置)的误差,D是消除速度变化率(加速度)的误差。
三、方案选择
经历过项目开发的人员都知道,第一个首要任务就是要进行需求分析,这个需求是要认真分析的,因为需求不是一个单一不变的变量,更不是一个不变的常量。他是在一定的范围和一段时间内都要符合你的需求,满足你的需要。在做这个小车时,个人的需求也符合马斯洛的需求层次理论的。在需求分析中最重要的是要列出那些相互矛盾的方面,并且要根据自己的核心需求进行合理和有效的舍取。
那么我这里提出的自平衡小车入门,也是要满足一组特定的需求,现将其罗列如下:
1、投入的经费要低;
2、小车要能很好的实现平衡,而且是要在一定的控制下实现的自平衡,而不是那种不倒翁式的平衡(结构本身就具有的能力);
3、尽量像那些大神们一样,也能控制它前后运动和左右转动;
4、门槛要低,就是容易成功,而不是折腾得“要死的心都有了”(有些网友在调试过程中发出的感慨);
5、从中能提高自己的动手能力、提高分析和解决问题的能力;
6、能对大家觉得神奇的PID有深刻的体会。
自平衡小车无论什么方案都有以下几个部分:一是检测平衡状态所用的传感器;二是控制核心的处理器;三是执行控制动作的电机。
传感器有加速度、陀螺组合的,有用超声波测距的,还有用红外测距的;
处理器流行的有用STM32系列的,有用Arduino开源的,也还有人用最传统的51系列的;
电机有用带AB相测速输出的强动力的电机,也有用步进电机,还有用舵机的,也有用低廉的TT马达(俗称香蕉电机)。
根据上述的入门需求,我这里提供的入门方案配置如下:超声波测距传感器 + Arduino Nano控制模块 + TT马达(L298N电机驱动模块) + 7.4V/2200mAh锂电池 + 蓝牙串口无线模块。
这个方案的核心优点(除了成本低之外)是超声波测距模块,抗干扰强,不像MPU6050极容易受干扰(电磁干扰和安装位置敏感性的机械干扰),关于MPU6050的问题,大家可以在网络上看看一些新手们的烦恼(死机、数据不稳定等等)。
这个方案遭人诟病的是,“超声波测距的自平衡小车不能爬坡、不能在斜坡上平衡”,首先这里所说的不能爬坡和不能在斜坡上平衡说法本身就极为不准确,这是网络上说话不靠谱的通病,其实他们想要表达的是在坡度变化的地方,超声波测距方式的自平衡小车不是实现平衡控制。这种说法的人只是凭自己想当然的一种臆断,没有任何实际的根据,根据我的实践,这个问题通过速度环的控制是完全能够解决的。其实爬坡的关键点,是看你的电机性能如何,而不是别的什么。
在这里补充说明一点,有很多人想用这个作为学习单片机的平台,这个想法我个人觉得有点反了,要学单片机,这个平台太局限了,选择别的可能要更合适一些。
前面这三节都是务虚的,从下面开始逐渐深入到实处,有些东西因为涉及到入门,可能写得也啰嗦一些了,因为有些网友真的是一点基础(概念)也没有、从未动过手,但还是很执着的想做这个,为了照顾他们,会的人一是忍忍,另一方面也帮助帮助那些需要帮助的人吧!
四、硬件设计
根据方案的框图,首先分别介绍各模块,由于这里主要是讨论自平衡小车,而不是学习单片机,所以与自平衡小车关系不大的单片机使用以及程序部分就不拟讨论了。按照框图顺序和硬件调试步骤,首先介绍的是超声波测距模块。
4.1、超声波测距模块
我们选择的超声波测距模块型号是:新款HC-SR04超声波测距模块。
这个模块的淘宝链接是:
推荐用这种
不推荐用这种,就是图中红色区域有个4MHz的晶体
它的特点,我从卖家那里摘抄部分信息如下:
新款提升了IC性能,因晶振受低温环境影响,频率容易发生漂移。所以去掉了晶振。比带晶振的稳定很多,此型号为原厂原装型号,市场上大部分4块多钱的HC-SR04带晶振的那种,都是仿品性能不稳定!(通过我买的几种对比,情况的确如此,有些精度更高的,近距离运用时,效果更差)
(1)主要技术参数
工作电压:DC5V
静态电流:小于2mA
电平输出:高电平5V、低电平0V
感应角度:不大于15度
探测距离:2cm ~ 450cm
精度:可达0.3cm
(2)接线方式
VCC(电源正端)可用杜邦线接Arduino Nano模块的5V端;
GND(地)接Arduino Nano模块的GND;
Trig(控制端)接Arduino Nano模块的D4;
Echo(接收端)接Arduino Nano模块的D5。
(3)工作原理:
采用IO触发测距,给Trip控制端至少10us的高电平信号;模块自动发送8个40khz的方波,并自动检测是否有信号返回;如有信号返回,通过Echo输出一高电平,高电平持续的时间就是超声波从发射到返回的时间。
测试距离 =(高电平时间 * 声速)/ 2。
测试原理图
测试接线照片
//超声波测距模块测试程序
char val='z'; //调节与控制命令字
unsigned int TrigPin = 4, EchoPin = 5, Len_Echo = 0; //HC-SR04触发信号,回波检测,回波时间
unsigned long systime0; //上次系统时间,当前时间
//初始化
void setup() {
Serial.begin(115200);
pinMode(EchoPin, INPUT); //超声波测距
pinMode(TrigPin, OUTPUT);
digitalWrite(TrigPin, LOW);
systime0 = millis(); //读取系统时间
}
//主循环程序
void loop() {
if(millis() - systime0 >= 5){ //系统循环周期为5ms
systime0 = millis();
digitalWrite(TrigPin, HIGH); //发送超声波测量触发脉冲
delayMicroseconds(10);
digitalWrite(TrigPin, LOW);
Len_Echo = pulseIn(EchoPin, HIGH); //回波时间测量
if (Serial.available() > 0) {
val = Serial.read();
if(val == 'A') {
Serial.println(Len_Echo); //超声波测距输出
}
}
}
}
使用串口调试助手(sscom42.exe)发送字符“A”命令读取超声波的测距值。
sscom42.zip
(338.41 KB, 下载次数: 25)
程序中超声波的测量周期是5ms,一般超声波测距的测量周期远远大于这个值,但在小车平衡中,这个值不能太大,否则是不能稳定控制住小车平衡的。
串口测试界面如下图所示:
注意:串口号选择要正确,比特率要与程序中的一致(此处为115200),这里为了方便,串口输出的是字符串,发送的命令是“A”,图中用了100ms间隔的定时发送。
晒晒做自平衡小车过程中我所花费的清单:
4.2、自平衡小车供电
本想讲控制板输出后的电机驱动模块,后来一想,没有电,这个模块怎么驱动呀,所以接下来先说说自平衡小车的供电吧。
我们这里因为选用的是TT马达,它的工作电压网上给出的是DC3~6V,6V时的空载电流小于200mA,为了不频繁的充电,我们选用容量大一点的7.4V锂电池,其容量为2200mAh。在网上搜了一家性价比还不错的淘宝店铺,链接如下(注意,东西最好一次买齐,有备份的更好):
充电器:
连接线:
下面给出这个自平衡小车电池供电的电路原理图。
BT为7.4V锂电池,CB为充电接口。电池通过开关S1分别给Arduino Nano模块和L298N电机驱动模块供电。这个原理图没什么可说明的,照着连接,别接错了,正负别接反了就没问题。
4.3、电机驱动模块
电机驱动模块,我们选择最常用的,价格低廉的L298N电机驱动模块,这个模块可以同时驱动两个电机,正好适用我们的需求。直接给出淘宝链接如下:
你们可能会发现,有很多东西,你怎么都推荐这家呢,首先声明,我跟他们一点关系都没有,我之所以选这家,是在价格合理的情况下,尽量在这一家把东西买齐,这样你们就会少花费运费了,可以节约点小钱。
该模块是2路的H桥驱动,所以可以同时驱动两个电机,在自平衡小车中通常利用ENA、ENB使能端输入控制两个电机的PWM信号,分别控制两个电机的转速;利用IN1、IN2输入控制电机1的方向; 利用IN3、IN4输入控制电机2的方向。其控制逻辑表如下:
电路原理图如下:
这个电路原理其实也没什么可说的,但有些新手凭自己的想当然,要么用Arduino Nano模块的5V接到L298N模块的5V(看清楚,L298N的5V是输出,不是输入)。有明白不能接这里的,他接到L298N模块的VIN,Arduino Nano模块的5V提供不了大电流,这种接法如果是负载重点(电机工作电流比较大时),无异于将Arduino Nano模块的5V短路(效果差不多,就是烧掉了)。再明白一点的人将L298N的Vin和GND接到7.4V的电池或其他外部独立供电的电源上,但告诉我程序控制不了电机,电机不转,其原因是什么呢?他的Arduino Nano模块是通过USB接口供电的,Arduino Nano模块与L298N模块没有共地,这一切看似简单的问题,在有些新手那里就是百思不得其解,这些问题他们因为不知道原因,所以也提不出问题,好在看到现场接线的照片,还能帮着分析分析,有些问题你如果不在现场真是你想不到的状况。
还有的人也会检查,用电压表测输出给电机的电压,但是怎么测的呢?他是分别测量OUT1~OUT4对GND的电压。这个说明他们不知道H桥是怎么回事,也不知道电机上的电压是什么。
L298N模块拿到手后,在用程序测试之前,先直接加电测试确定模块是否正常。测试方法是给VIN与GND之间加上工作电压,IN1~IN4、ENA、ENB按照控制逻辑表加信号,看看OUT1-OUT2和OUT3-OUT4之间的电压是否正常,不同的控制情况下,这个电压的极性是否会反转。如果一切正常进入程序测试阶段。
下面给出测试程序,包含了前面的超声测距的程序。
//蓝牙遥控无码盘,TT马达超声自平衡小车硬件单元测试程序
char val='z'; //调节与控制命令字
int Left_PWM, Right_PWM; //左右电机PWM输出
unsigned int TrigPin = 4, EchoPin = 5, Len_Echo = 0; //HC-SR04触发信号,回波检测,回波时间
unsigned int M_IN1 = 6, M_IN2 = 7, M_IN3 = 8, M_IN4 = 9; // L298:IN1-IN4
unsigned int M_ENA = 10, M_ENB = 11; // L298:ENA-ENB
unsigned long systime0; //上次系统时间,当前时间
//电机输出
void SetMotorVoltage(int Left_MotorVol, int Right_MotorVol) {
if(Left_MotorVol >= 0) {
digitalWrite(M_IN1, LOW);
digitalWrite(M_IN2, HIGH);
}else {
digitalWrite(M_IN1, HIGH);
digitalWrite(M_IN2, LOW);
Left_MotorVol = -Left_MotorVol;
}
if(Right_MotorVol >= 0) {
digitalWrite(M_IN3, LOW);
digitalWrite(M_IN4, HIGH);
}else {
digitalWrite(M_IN3, HIGH);
digitalWrite(M_IN4, LOW);
Right_MotorVol = -Right_MotorVol;
}
if(Left_MotorVol > 255) Left_MotorVol = 255; //防止PWM值超过255
if(Right_MotorVol > 255) Right_MotorVol = 255; //防止PWM值超过255
analogWrite(M_ENA, Left_MotorVol);
analogWrite(M_ENB, Right_MotorVol);
}
//初始化
void setup() {
Serial.begin(115200);
pinMode(M_ENA, OUTPUT); //电机控制
pinMode(M_IN1, OUTPUT);
pinMode(M_IN2, OUTPUT);
pinMode(M_ENB, OUTPUT);
pinMode(M_IN3, OUTPUT);
pinMode(M_IN4, OUTPUT);
pinMode(EchoPin, INPUT); //超声波测距
pinMode(TrigPin, OUTPUT);
digitalWrite(TrigPin, LOW);
systime0 = millis(); //读取系统时间
}
//主循环程序
void loop() {
if(millis() - systime0 >= 5){ //系统循环周期为5ms
systime0 = millis();
digitalWrite(TrigPin, HIGH); //发送超声波测量触发脉冲
delayMicroseconds(10);
digitalWrite(TrigPin, LOW);
Len_Echo = pulseIn(EchoPin, HIGH); //回波时间测量
SetMotorVoltage(Left_PWM, Right_PWM);
if (Serial.available() > 0) {
val = Serial.read();
if(val == 'A') {
Serial.println(Len_Echo); //超声波测距输出
}
if(val == 'B') {
Left_PWM ++; Serial.print(Left_PWM); Serial.print(" "); Serial.println(Right_PWM);//左电机加速
}
if(val == 'b') {
Left_PWM --; Serial.print(Left_PWM); Serial.print(" "); Serial.println(Right_PWM);//左电机减速
}
if(val == 'C') {
Right_PWM ++; Serial.print(Left_PWM); Serial.print(" "); Serial.println(Right_PWM);//右电机加速
}
if(val == 'c') {
Right_PWM --; Serial.print(Left_PWM); Serial.print(" "); Serial.println(Right_PWM);//右电机减速
}
}
}
}
4.4、蓝牙串口模块
蓝牙串口模块相对比较简单,按照给的资料就能使用了,之所以选择这款蓝牙模块,是因为连接过程中不出任何信息,这样就不会产生各种干扰你程序的信息了。
卖家介绍也很详细,我这里就不啰嗦了。卖家提供的资料和配置软件(很好用)。
4 蓝牙.zip
(1.38 MB, 下载次数: 14)
下面给出与Arduino Nano模块的接线原理图。
这里要说明的一点是,如果要用Arduino Nano模块USB的串口,蓝牙串口就不能用,二者只能用其一。所以蓝牙串口也是用插座的,这样不用时,就可拔下来。因为这两者在硬件是用了单片机的同一个串口。
5、材料清单
超声自平衡小车材料清单.zip
(10.49 KB, 下载次数: 16)
这个材料清单不含手动遥控部分,如果简单的控制,直接用手机就能控制,想做点复杂的控制可以用摇杆+Arduino模块+蓝牙+供电,自制一个两通道比例遥控器,有需要的,以后再展开讨论吧。
4.6、完整原理图
五、结构装配
自平衡小车的装配实际上很简单,但关键是小车的结构设计,如果小车的本身结构设计得好,自身就很容易平衡在某个角度,那么自平衡小车的平衡控制效果也就好,如果本身极不容易平衡,那么其控制效果也就要差一截,也就是网上很多人抱怨,在设定的平衡点不能稳定不动的保持平衡,总在晃动或抖动。
新手关心的都是些电路、程序、算法、参数(程序里的参数)之类的东西,小车的结构也有很多参数,为什么就不关心呢?譬如重心、机械平衡点(这个词我也不知道专业点怎么称呼,意思是在没有施加控制的情况下,小车平衡时的位置)。还有就是传感器安装的位置,因为传感器安装位置不同,它对平衡感知的精确度和灵敏性也不同。
这里先贴上几张我最新版的蓝牙超声自平衡小车装配过程中和完成后的几张照片,供大家参考一下,这也没有什么设计,只是凭着感觉做的,我这方面的知识几乎是零,没有设计能力,但我知道有一些因素是很重要的。网络上这方面的介绍也很少,希望学机械的同学们在这方面多思考一些,给大家提供一套设计思路和方案。
我这个加电的情况下,在某个角度是能勉强短时间内保持平衡的。
下面发两张群里网友装配的两张照片,我不知道他这个平衡情况如何,我问他机械平衡角度大概是多少,他也不知道,有没有人知道更通俗或更准确的这个术语,我也不知道是不是我表达得不准确,造成别人不理解。
六、软件设计
软件这里直接上程序吧,很多参数值我并没有给出我调试好的参数,其目的是希望你们不要囫囵吞枣式的干这件事,你们要根据你们自己搭建的小车平台来确定自己程序的参数。整个程序除了前面的宏定义,不到100行,这些程序你们先看,弄明白了,再去调试。
//利用超声波测距传感器实现小车平衡
#define L_max 200
#define L_min 150
#define L_a 0.5
#define filter_init 10
#define L_t 20
byte val = 0x00; //调节与控制命令字
int i, LoopCount = 0; //平衡点调整,PID各调整设定系数
int E_0 = 0, E_1 = 0, PWM_Out, Left_PWM, Right_PWM; //误差,PWM输出,左右电机PWM输出
double Kp = 0.0, Kd = 0.0; //PID系数
double Len_filter = 0, Len_0 = 180; //测距滤波,机械平衡距离
unsigned int TrigPin = 4, EchoPin = 5, Len_Echo = 0; //HC-SR04触发信号,回波检测,回波时间
unsigned int M_IN1 = 6, M_IN2 = 7, M_IN3 = 8, M_IN4 = 9; // L298:IN1-IN4
unsigned int M_ENA = 10, M_ENB = 11; // L298:ENA-ENB
unsigned long systime0; //系统时间
//电机输出
void SetMotorVoltage(int Left_MotorVol, int Right_MotorVol) {
if(Left_MotorVol >= 0) {
digitalWrite(M_IN1, LOW);
digitalWrite(M_IN2, HIGH);
}else {
digitalWrite(M_IN1, HIGH);
digitalWrite(M_IN2, LOW);
Left_MotorVol = -Left_MotorVol;
}
if(Right_MotorVol >= 0) {
digitalWrite(M_IN3, LOW);
digitalWrite(M_IN4, HIGH);
}else {
digitalWrite(M_IN3, HIGH);
digitalWrite(M_IN4, LOW);
Right_MotorVol = -Right_MotorVol;
}
if(Left_MotorVol > 255) Left_MotorVol = 255; //防止PWM值超过255
if(Right_MotorVol > 255) Right_MotorVol = 255; //防止PWM值超过255
analogWrite(M_ENA, Left_MotorVol);
analogWrite(M_ENB, Right_MotorVol);
}
//初始化
void setup() {
Serial.begin(115200);
pinMode(M_ENA, OUTPUT); //电机控制
pinMode(M_IN1, OUTPUT);
pinMode(M_IN2, OUTPUT);
pinMode(M_ENB, OUTPUT);
pinMode(M_IN3, OUTPUT);
pinMode(M_IN4, OUTPUT);
pinMode(EchoPin, INPUT); //超声波测距
pinMode(TrigPin, OUTPUT);
digitalWrite(TrigPin, LOW);
i = 0;
systime0 = millis();
}
//主循环程序
void loop() {
if(millis() - systime0 >= L_t) {
systime0 = millis();
digitalWrite(TrigPin, HIGH); //发送超声波测量触发脉冲
delayMicroseconds(15);
digitalWrite(TrigPin, LOW);
Len_Echo = pulseIn(EchoPin, HIGH); //回波时间测量
if((Len_Echo < L_max) && (Len_Echo > L_min)) {
Len_filter *= L_a; //一阶滤波
Len_filter += (1 - L_a) * Len_Echo;
i ++;
if(i > filter_init){
i = 100;
LoopCount ++;
E_0 = Len_0 - Len_filter;
PWM_Out = Kp * E_0 + Kd * (E_0 - E_1);
E_1 = E_0;
Left_PWM = PWM_Out;
Right_PWM = PWM_Out;
SetMotorVoltage(Left_PWM, Right_PWM);
}
}else {
SetMotorVoltage(0, 0); //超出平衡范围,停止PWM输出
i = 0; Len_filter = 0;
}
}
//处理串口指令,发送相应数据
if (Serial.available() > 0) {
val = Serial.read();
//参数调节
if(val == 0x01) Kp += 0.01;
if(val == 0x02) Kp -= 0.01;
if(val == 0x03) Kd += 0.01;
if(val == 0x04) Kd -= 0.01;
if(val == 0x05) Len_0 ++;
if(val == 0x06) Len_0 --;
if(val == 0x07) {
Serial.print(Len_0); Serial.print(" ");
Serial.print(Kp); Serial.print(" "); Serial.println(Kd); //查看设置参数
}
if(val == 0x08) {
Serial.print(Len_filter); Serial.print(" "); Serial.println(PWM_Out); //
}
}
}
源代码下载:
v3.zip
(3.04 KB, 下载次数: 25)
七、调试
有些人急着等我帖子发完,现在把主要的内容都发上来了,但剩下的却是最为关键的调试,在调试之前你们一定要把前面的东西都消化吸收了,再进行调试。这一部分我先不急着写,希望跟大家互动着一起来写,这样内容才丰富,才有更针对性。
平衡调试完成的,请大家上照片和视频,做完的,我提供蓝牙超声自平衡小车的遥控版源代码,这个代码暂时不在这里给出了。
7.1 接地问题
很多网友在做自平衡车时都遇到各种干扰,无法解决,同样的原理图和程序,怎么就不行呢?!用人家现成的电路板没问题,自己用模块搭建就不行了。
今天就讲讲接地问题,网上有现成的,我直接抄过来(http://wenku.baidu.com/link?url= ... a_zHzlfXLHOrvhCXKDm)。
单点接地有两种类型,一种是串联单点接地,另一种是并联单点接地。
串联单点接地中,许多电路之间有公共阻抗,因此相互之间由公共阻抗耦合产生的干扰十分严重。
串联单点接地的干扰:
A点的电位是:VA = ( I1 + I2 + I3 ) R1
A点的电位是:VB = ( I1 + I2 + I3 ) R1 + ( I2 + I3 ) R2
C点的电位是: VC = ( I1 + I2 + I3 ) R1 + ( I2 + I3 ) R2 + I3 R3 从公式中可以看出,A、B、C各点的电位是受电路工作电流影响的,随各电路的地线电流而变化。尤其是C点的电位,十分不稳定。
这种接地方式虽然有很大的问题,却是实际中最常见的,因为它十分简单。但在大功率和小功率电路混合的系统中,切忌使用,因为大功率电路中的地线电流会影响小功率电路的正常工作。另外,最敏感的电路要放在A点,这点电位是最稳定的。另外,从前面讨论的放大器情况知道,功率输出级要放在A点,前置放大器放在B、C点。
以上是网络上直接复制的内容,下面说几句多余的话,没有动过手的新人,接触实际的东西很少,这个时代更是如此,从小就在虚拟环境下成长,教育也是如此的一个虚拟环境,初中学习物理时,很多例子、练习题都有一个括号,(……忽略不计),这些忽略的经常有电池内阻、灯泡电阻不变、导线电阻忽略不计以及力学中一些摩擦力忽略不计等等,这些都是严重的误导,导致现在很多大学生毕业工作多少年了,还问灯泡为什么不能串起来接(当然,你串起来接也不会死人的,也出不了什么大事)……
有些人还很固执,你告诉他原因了,他还不信,对于这种人你就自己接着折腾吧!
所以,在此告诉那些使用现成模块的新人,确实很方便,但整体的(不是模块单独本身)电磁兼容方面是有很大隐患的。
回到做自平衡小车上来,电机的启动以及正反转的切换都会带来很强的脉冲干扰(电机线圈的感应电动势),对于那些高速器件,或者时序要求很严的器件来说就是一个很主要的干扰源。
蓝牙串口调试助手,怎么使用,自己摸索!!!
蓝牙串口 5.4.2.zip
(1.49 MB, 下载次数: 19)
蓝牙串口调试助手的使用与Arduino怎么编程没有关系,只与你程序用了什么样的命令有关系,这些命令集就是最简单的一种通信协议。
八、测试总结
总结这部分,我就写个说明,这个说明就是希望总结由实践者们来写吧!!! |