极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

楼主: wujingyu

自平衡小车的入门

  [复制链接]
发表于 2015-4-13 22:48:13 | 显示全部楼层
wujingyu 发表于 2015-4-13 20:23
譬如,在自平衡小车控制中,u(t)就是计算出来的PID输出值,这个值转变为对电机的控制量,在直流电机中,就 ...

那么从u(t)到PWM占空比的这一过程中,u(t)又是通过怎样的数学关系与占空比对应起来的呢?需要知道电机的数学模型吗?
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-4-13 23:19:21 来自手机 | 显示全部楼层
四叔第一 发表于 2015-4-13 22:48
那么从u(t)到PWM占空比的这一过程中,u(t)又是通过怎样的数学关系与占空比对应起来的呢?需要知道电机的数 ...

线性的关系,譬如,0~255对应占空比0~100%
不需要知道电机的数学模型
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-4-14 08:11:37 | 显示全部楼层
晒晒做自平衡小车过程中我所花费的清单:
费用表.jpg
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-4-14 08:22:39 | 显示全部楼层
2、自平衡小车供电

本想讲控制板输出后的电机驱动模块,后来一想,没有电,这个模块怎么驱动呀,所以接下来先说说自平衡小车的供电吧。
我们这里因为选用的是TT马达,它的工作电压网上给出的是DC3~6V,6V时的空载电流小于200mA,为了不频繁的充电,我们选用容量大一点的7.4V锂电池,其容量为2200mAh。在网上搜了一家性价比还不错的淘宝店铺,链接如下(注意,东西最好一次买齐,有备份的更好):

http://item.taobao.com/item.htm? ... &_u=e79shmu3446
电池.jpg

充电器:
http://item.taobao.com/item.htm? ... &_u=e79shmu521d
充电器.jpg

连接线:
充电线.jpg

下面给出这个自平衡小车电池供电的电路原理图。
供电原理图.jpg

BT为7.4V锂电池,CB为充电接口。电池通过开关S1分别给Arduino Nano模块和L298N电机驱动模块供电。这个原理图没什么可说明的,照着连接,别接错了,正负别接反了就没问题。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-4-14 09:28:01 | 显示全部楼层
3、电机驱动模块

电机驱动模块,我们选择最常用的,价格低廉的L298N电机驱动模块,这个模块可以同时驱动两个电机,正好适用我们的需求。直接给出淘宝链接如下:

http://item.taobao.com/item.htm? ... &_u=e79shmu3209

你们可能会发现,有很多东西,你怎么都推荐这家呢,首先声明,我跟他们一点关系都没有,我之所以选这家,是在价格合理的情况下,尽量在这一家把东西买齐,这样你们就会少花费运费了,可以节约点小钱。

L298N模块.jpg

L298N模块说明.jpg

L298N接线端子.jpg

该模块是2路的H桥驱动,所以可以同时驱动两个电机,在自平衡小车中通常利用ENA、ENB使能端输入控制两个电机的PWM信号,分别控制两个电机的转速;利用IN1、IN2输入控制电机1的方向; 利用IN3、IN4输入控制电机2的方向。其控制逻辑表如下:

L298N控制逻辑表.jpg

电路原理图如下:

L298N电路原理图.jpg

这个电路原理其实也没什么可说的,但有些新手凭自己的想当然,要么用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("\t"); Serial.println(Right_PWM);//左电机加速
      }
      if(val == 'b') {
        Left_PWM --; Serial.print(Left_PWM); Serial.print("\t"); Serial.println(Right_PWM);//左电机减速
      }
      if(val == 'C') {
        Right_PWM ++; Serial.print(Left_PWM); Serial.print("\t"); Serial.println(Right_PWM);//右电机加速
      }
      if(val == 'c') {
        Right_PWM --; Serial.print(Left_PWM); Serial.print("\t"); Serial.println(Right_PWM);//右电机减速
      }
    }
  }
}
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-4-14 09:56:31 | 显示全部楼层
4、蓝牙串口模块

蓝牙串口模块相对比较简单,按照给的资料就能使用了,之所以选择这款蓝牙模块,是因为连接过程中不出任何信息,这样就不会产生各种干扰你程序的信息了。

http://item.taobao.com/item.htm? ... &_u=e79shmu9f3e

蓝牙串口模块.jpg

卖家介绍也很详细,我这里就不啰嗦了。卖家提供的资料和配置软件(很好用)。
4 蓝牙.zip (1.38 MB, 下载次数: 317)
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-4-14 10:12:51 | 显示全部楼层
5、材料清单

材料清单.jpg

超声自平衡小车材料清单.zip (10.49 KB, 下载次数: 116)
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-4-14 10:18:25 | 显示全部楼层
6、完整原理图

原理图.jpg

PCB图.jpg
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-4-14 14:25:09 | 显示全部楼层
本帖最后由 wujingyu 于 2015-4-14 14:39 编辑

五、结构装配

自平衡小车的装配实际上很简单,但关键是小车的结构设计,如果小车的本身结构设计得好,自身就很容易平衡在某个角度,那么自平衡小车的平衡控制效果也就好,如果本身极不容易平衡,那么其控制效果也就要差一截,也就是网上很多人抱怨,在设定的平衡点不能稳定不动的保持平衡,总在晃动或抖动。

新手关心的都是些电路、程序、算法、参数(程序里的参数)之类的东西,小车的结构也有很多参数,为什么就不关心呢?譬如重心、机械平衡点(这个词我也不知道专业点怎么称呼,意思是在没有施加控制的情况下,小车平衡时的位置)。还有就是传感器安装的位置,因为传感器安装位置不同,它对平衡感知的精确度和灵敏性也不同。

这里先贴上几张我最新版的蓝牙超声自平衡小车装配过程中和完成后的几张照片,供大家参考一下,这也没有什么设计,只是凭着感觉做的,我这方面的知识几乎是零,没有设计能力,但我知道有一些因素是很重要的。网络上这方面的介绍也很少,希望学机械的同学们在这方面多思考一些,给大家提供一套设计思路和方案。

蓝牙版超声自平衡小车底板PCB.jpg

蓝牙版超声自平衡小车电路部分照.jpg

背面图.jpg

蓝牙版超声自平衡小车完整照.jpg

我这个加电的情况下,在某个角度是能勉强短时间内保持平衡的。

下面发两张群里网友装配的两张照片,我不知道他这个平衡情况如何,我问他机械平衡角度大概是多少,他也不知道,有没有人知道更通俗或更准确的这个术语,我也不知道是不是我表达得不准确,造成别人不理解。

1.jpg

2.jpg
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-4-14 18:53:33 | 显示全部楼层
本帖最后由 wujingyu 于 2015-4-17 10:15 编辑

六、软件设计

软件这里直接上程序吧,很多参数值我并没有给出我调试好的参数,其目的是希望你们不要囫囵吞枣式的干这件事,你们要根据你们自己搭建的小车平台来确定自己程序的参数。整个程序除了前面的宏定义,不到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("\t");
      Serial.print(Kp); Serial.print("\t"); Serial.println(Kd); //查看设置参数
    }
    if(val == 0x08) {
      Serial.print(Len_filter); Serial.print("\t"); Serial.println(PWM_Out); //
    }
  }
}

源代码下载:
v3.zip (3.04 KB, 下载次数: 199)
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-4-14 18:57:07 | 显示全部楼层
本帖最后由 wujingyu 于 2015-4-14 19:02 编辑

七、调试

有些人急着等我帖子发完,现在把主要的内容都发上来了,但剩下的却是最为关键的调试,在调试之前你们一定要把前面的东西都消化吸收了,再进行调试。这一部分我先不急着写,希望跟大家互动着一起来写,这样内容才丰富,才有更针对性。

平衡调试完成的,请大家上照片和视频,做完的,我提供蓝牙超声自平衡小车的遥控版源代码,这个代码暂时不在这里给出了。

回复 支持 0 反对 1

使用道具 举报

 楼主| 发表于 2015-4-14 18:59:45 | 显示全部楼层
本帖最后由 wujingyu 于 2015-4-14 21:10 编辑

八、测试总结

总结这部分,我就写个说明,这个说明就是希望总结由实践者们来写吧!!!
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-4-15 10:07:56 | 显示全部楼层
本帖最后由 wujingyu 于 2015-4-15 10:55 编辑

7.1 接地问题

很多网友在做自平衡车时都遇到各种干扰,无法解决,同样的原理图和程序,怎么就不行呢?!用人家现成的电路板没问题,自己用模块搭建就不行了。

今天就讲讲接地问题,网上有现成的,我直接抄过来(http://wenku.baidu.com/link?url= ... a_zHzlfXLHOrvhCXKDm)。

单点接地有两种类型,一种是串联单点接地,另一种是并联单点接地。

串联单点接地中,许多电路之间有公共阻抗,因此相互之间由公共阻抗耦合产生的干扰十分严重。

接地.jpg

串联单点接地的干扰:&#160;

A点的电位是:VA&#160;=&#160;(&#160;I1&#160;+&#160;I2&#160;+&#160;I3&#160;)&#160;R1&#160;

A点的电位是:VB&#160;=&#160;(&#160;I1&#160;+&#160;I2&#160;+&#160;I3&#160;)&#160;R1&#160;+&#160;(&#160;I2&#160;+&#160;I3&#160;)&#160;R2&#160;&#160;

C点的电位是:&#160;VC&#160;=&#160;(&#160;I1&#160;+&#160;I2&#160;+&#160;I3&#160;)&#160;R1&#160;+&#160;(&#160;I2&#160;+&#160;I3&#160;)&#160;R2&#160;+&#160;I3&#160;R3&#160;从公式中可以看出,A、B、C各点的电位是受电路工作电流影响的,随各电路的地线电流而变化。尤其是C点的电位,十分不稳定。
&#160;
这种接地方式虽然有很大的问题,却是实际中最常见的,因为它十分简单。但在大功率和小功率电路混合的系统中,切忌使用,因为大功率电路中的地线电流会影响小功率电路的正常工作。另外,最敏感的电路要放在A点,这点电位是最稳定的。另外,从前面讨论的放大器情况知道,功率输出级要放在A点,前置放大器放在B、C点。

以上是网络上直接复制的内容,下面说几句多余的话,没有动过手的新人,接触实际的东西很少,这个时代更是如此,从小就在虚拟环境下成长,教育也是如此的一个虚拟环境,初中学习物理时,很多例子、练习题都有一个括号,(……忽略不计),这些忽略的经常有电池内阻、灯泡电阻不变、导线电阻忽略不计以及力学中一些摩擦力忽略不计等等,这些都是严重的误导,导致现在很多大学生毕业工作多少年了,还问灯泡为什么不能串起来接(当然,你串起来接也不会死人的,也出不了什么大事)……

有些人还很固执,你告诉他原因了,他还不信,对于这种人你就自己接着折腾吧!

所以,在此告诉那些使用现成模块的新人,确实很方便,但整体的(不是模块单独本身)电磁兼容方面是有很大隐患的。

回到做自平衡小车上来,电机的启动以及正反转的切换都会带来很强的脉冲干扰(电机线圈的感应电动势),对于那些高速器件,或者时序要求很严的器件来说就是一个很主要的干扰源。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-4-16 10:55:54 | 显示全部楼层
本帖最后由 wujingyu 于 2015-4-16 10:57 编辑

蓝牙串口调试助手,怎么使用,自己摸索!!!
蓝牙串口 5.4.2.zip (1.49 MB, 下载次数: 198)
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-4-16 14:48:13 | 显示全部楼层
“世界单片机菜鸟组织” —— 51版超声自平衡小车项目

一、小车底盘

1.jpg

2.jpg

3.jpg

小车挺精致的吧!
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|联系我们|极客工坊 ( 浙ICP备09023225号 )

GMT+8, 2020-7-4 00:31 , Processed in 0.184101 second(s), 24 queries .

Powered by Discuz! X3.4 Licensed

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表