Category :Arduino Projects

Byamber

坦克智能小车第八课:编码器

概述

这是坦克智能小车的最后一课,在前面已经提到过,由于电机之间存在一定误差,即使给两个电机相同的电压,其转速一般是不一样的,这样坦克小车就无法行走直线。要想小车走直线就需要用编码器调节两个电机速度,使其速度一样。

编码器原理

编码器分为光电式编码器和霍尔编码器,我们使用的是霍尔式编码器。霍尔编码器是一种通过磁电转换将输出轴上机械几何位移转换成脉冲或数字量的传感器。霍尔编码器由霍尔码盘和霍尔元件组成。霍尔码盘是在一定直径的直板上等分地布置有不同的磁极,霍尔码盘与电机同轴,电机旋转时,霍尔元件检测输出若干脉冲信号,为判定转向,一般输出两组存在一定相位差的脉冲信号。

编码器接线说明

电机一共有6pin,其中VM和GM是控制电机的,接到L298N上,这在之前已经讲过,剩下的4pin分别是

V:霍尔编码器电源,一般接5V

G:霍尔编码器地,接GND

S1:编码器的A相输出

S2:编码器B相输出

motor

拧下亚克力面板上的四颗螺帽,将电机上编码器的四条线穿过金属面板和亚克力面板,按照下表接到esp8266 uart wifi shield上(翻译的时候把表变成连线图)

左边电机
编码器 esp8266 uart wifi shield
V 5V
G GND
S1 D2
S2 D4
右边电机
编码器 esp8266 uart wifi shield
V 5V
G GND
S1 D3
S2 D7

采集脉冲

因为编码器输出的是方波信号,可以用arduino直接读取,在上面的接线图中我们分别将编码器的A相输出接到arduino的外部中断引脚,用中断的方式采集脉冲;B相接到普通GPIO口,B相的电平用来判断正反转。通过arduino定时器把采样周期设定为10ms,采集完两个电机的脉冲后,需要用PID算法来调节电机速度。所谓PID就是对偏差进行比例、积分、微分,PID由3个单元组成,分别是比例(P)单元、积分(I)单元和微分(D)单元。在工程实践中,比例单元是必须的,所以衍生出许多组合的PID控制器,如PD、PI、PID,更多关于PID算法详细介绍请看这里。在本课中我才用增量式PI算法。在这个PI算法中把左边电机的速度作为目标速度,通过PI算法调节右边电机速度使其与左边电机速度一致。

软件

下载http://osoyoo.com/driver/tank_robot_lesson7.zip并解压文件,用arduino IDE打开tank_robot_lesson7.ino文件,下面对部分代码做简要说明。

第一步:上面四行代码分别定义了左右两个电机A、B相接口

const byte encoder0pinA = 2;//A pin -> the interrupt pin 0
const byte encoder0pinB = 4;//B pin -> the digital pin 4
const byte rencodPinA = 3;  //rencodPinA -> the interrupt pin 1
const byte rencodPinB = 7;  //rencodPinB -> the digital pin 11

第二步:设定采样周期为10ms,10ms到达后,进入定时器中断服务函数control中

 MsTimer2::set(10, control);  //use timer2 to set the 10ms timer interrupt
 MsTimer2::start();          //enable interrupt

第三步:编码器接到arduino uno外部中断引脚上。(编码器引脚初始化,左右电机编码的A相输出分别使用arduino外部中断0和外部中断1,使用跳变沿(上升沿和下降沿))。

  l_direction = true;//default -> Forward  
  r_direction = true;//default -> Forward  
  pinMode(encoder0pinB,INPUT);  
  pinMode(rencodPinB,INPUT);  
  attachInterrupt(0, lwheelSpeed, CHANGE);
  attachInterrupt(1, rwheelSpeed, CHANGE);

第四步:电机转动时候对脉冲计数。(编码器中断服务函数。当有跳变沿到来时候,会执行中断服务函数,对脉冲加1或减1)

void lwheelSpeed()
{
  int Lstate = digitalRead(encoder0pinA);
  if((encoder0PinALast == LOW) && Lstate==HIGH)
  {
    int val = digitalRead(encoder0pinB);
    if(val == LOW && l_direction)
    {
      l_direction = false; //Reverse
    }
    else if(val == HIGH && !l_direction)
    {
      l_direction = true;  //Forward
    }
  }
  encoder0PinALast = Lstate;
 
  if(!l_direction)  duration++;
  else  duration--;
}

void rwheelSpeed()
{
  int Lstate = digitalRead(rencodPinA);
  if((encoder0PinALast1 == LOW) && Lstate==HIGH)
  {
    int val = digitalRead(rencodPinB);
    if(val == LOW && r_direction)
    {
      r_direction = false; //Reverse
    }
    else if(val == HIGH && !r_direction)
    {
      r_direction = true;  //Forward
    }
  }
  encoder0PinALast1 = Lstate;
 
  if(!r_direction)  duration1++;
  else  duration1--;
}

第五步:通过PI算法得到一个误差补给量power,将这个power作用于电机上,调节电机速度。(上面的函数就是增量式PI算法的C语言实现,左右电机脉冲相减作为误差,误差的累积作为积分项,误差为0表示右边电机速度和左边电机速度一致;大于0说明右边电机比左边电机慢;小于0表示右边电机速度比左边电机快。通过PI算法会得到一个误差补给power,将这个power作用与右边电机上,就能达到调节速度的目的。)

int PID_controller(int master,int slave)
{ 
  static float power,error,integralerror,lasterror;
  if(master < 0) master = -master;
  if(slave < 0) slave = -slave;
  error = master - slave;
  integralerror += error;
  power += Kp *(error-lasterror) + Ki * error;
  lasterror = error;
  return power;
}

第六步:每10ms执行一次control()函数。10ms到达时候会执行定时器中断服务函数,在定时器中断服务函数中,将PI得到的误差补给作用到右边电机上。

void control()
{
   sei();//enable global interrupts
   if(++i >=4)//20ms
   {
   master_pulse = duration ,duration = 0;
   slave_pulse = duration1, duration1 = 0;
   pwm = PID_controller(master_pulse,slave_pulse);
   i = 0;
   }
   int newpower1 = motorspeed+pwm;
   constrain(newpower1,0,255);
   analogWrite(ENB,newpower1),analogWrite(ENA,motorspeed);
   cli();//disenable global interrupts
}

 

const float Kp =20;
const float Ki =1;

测试

step 1 烧录程序:用usb线把坦克小车与pc连接起来,选择正确的板子型号和端口号,将esp8266 uart wifi shield上SW1拨到off,把程序烧录到arduino中。

step 2 在两边履带相同位置绑一条红线之类的绳子。

step 3 用手拿着安装电池盒的金属车板,打开电池盒电源,观察2个电机上绳子转的快慢是否一致。如果不一致可以通过调节Kp、Ki两个参数。

step 4 将小车放在相对粗糙的地板上,打开电源开关,小车就能走直线了。(注意:如果地板光滑,会因为摩擦过小导致小车无法走直线)

Byamber

坦克智能小车第7课:wifi和蓝牙控制

Overview

在这个例程中将介绍如何用Arduino UNO、 ESP8266串口WIFIArduino UNO扩展板、L298N电机驱动模块以及银色坦克底盘设计一辆智能坦克。同时,在坦克上挂载一些常用传感器模块,如光敏电阻、DS18B20温度传感器模块、红外避障传感器、超声波测距模块、舵机等。可以用手机APP手动控制坦克前进、后退、左转、右转以及停止;还能根据超声波模块和避障模块检测到的数据判断后自行运动;并向APP端反馈光照值、温度值。

DSC_5488

Parts
UNO R3
Arduino UNO x1
DBAD200700-2
ESP8266串口WIFI Arduino UNO扩展板 x1
L298N-0
L298N x1
EASM101700
红外避障模块 x2
9
DS18B20 x1
14
光敏电阻模块 x1
HC-SR04
超声波测距模块 x1
q
银色底盘套件 x1
SG90
舵机 x1

Hardware

1)底盘安装

坦克底盘具体安装步骤请参照

注意:在进行固定电路板,如arduino uno 、l298n电机驱动以及各传感器模块到底盘时候,要注意做绝缘处理,最好在底盘上垫一层塑料或者用垫子将电路板与底盘隔开,达到绝缘目的。

2)控制部分

坦克用Arduino UNO作为核心控制单元,同时在Arduino UNO上搭载一个 ESP8266串口WIFI Arduino UNO扩展板实现wifi控制。在使用时候需要把 ESP8266串口WIFI Arduino UNO扩展板插在Arduino UNO上去,坦克在使用时候需要把 ESP8266串口WIFI Arduino UNO扩展板上的两个拨码开关拨到”ON”的位置,表示将 ESP8266串口WIFI Arduino UNO扩展板和Arduino UNO的串口接在一起,这样Arduino UNO与手机APP就能进行数据交互了。如图

arduino+uarttowifi

3)电源及电机部分

坦克采用2节18650电池供电,如图

power

小车左右两边各一个电机,分别把左右电机接到L298N电机驱动模块的两个输出端上,如图(这个图你最好拍个照片后用ps把两个模块对应口P在一起,我没时间搞)
电机
L298N
左边电机:VM: Power for Motor OUT1
左边电机:GM:GND for Motor OUT2
右边电机:VM: Power for Motor OUT3
右边电机:GM:GND for Motor OUT4

注意:只需要将电机上VM: Power for Motor和GM:GND for Motor接到L298N电机驱动板就行了,电机上的其他线不用接。

motor

(把L298N的图片放上,标上OUT1-OUT4)

4)传感器接线

各传感器都是接到esp8266串口wifi模块上,ESP8266串口WIFI Arduino UNO扩展板引出了Arduino UNO所有的GPIO口,将传感器接到ESP8266串口WIFI Arduino UNO扩展板上Arduino UNO的GPIO口上。

A.超声波模块

超声波模块的VCC、trig、echo、GND分别接到ESP8266 串口WIFI模块的5V、D4、D8、GND上,如图

sr-hc04

B.舵机

舵机的供电不要从ESP8266 串口WIFI模块,因为在舵机转动的瞬间会把电压拉得比较,导致ESP8266 串口WIFI模块重启,为了避免这种情况,将L298N上面的5V电压输出作为舵机的供电口,如图:

servo

C.L298N

L298N是一个电机驱动模块,该模块地上有4个控制引脚,分别是IN1—IN4,将这四个脚分别接到ESP8266 串口WIFI模块的D5、D6、D3、D11上,如图

l298n

D.红外避障

红外避障模块固定底盘前端,左右各一个。左边红外避障模块接到ESP8266 串口WIFI模块A0,右边红外避障模块接到ESP8266 串口WIFI模块A1.如图

Infrared obstruction1

E.光敏电阻模块

光敏电阻模块的信号脚接到ESP8266 串口WIFI模块的A2口,如图

lightsensor

F.LED接线

在坦克底盘上两个LED灯,在光照度很暗的时候,led会自动打开

LED Light-1

LED Light Installation

LED灯有两个脚,一个脚长一些,一个脚短一些,长的是正极,短的是负极,分别将左右两个灯长的引脚接到ESP8266 串口WIFI模块的D2和D13脚上;短的引脚接到ESP8266 串口WIFI模块的GND上。 接线如图所示

led

至此,硬件部分组装完成。

DSC_5492

Software

软件分为 下位机和上位机两部分,下位机主要是Arduino UNO里面的小车控制部分;上位机即手机APP。

下位机:yinse

安卓APP:BTcar
APP使用

安装好,将下位机软件烧录到Arduino UNO里,给小车上电,打开手机无线网络,会看到一个”DoitWIFI_Config”的wifi热点,这是一个免密连接的热点,连接这个热点后,打开小车控制APP选择”WIFI模式”,如图

Screenshot_2017-01-20-11-01-28-572_

进入小车控制界面,如图

Screenshot_2017-01-20-11-02-02-651

按钮功能解释

连接:表示连接WIFI

修改参数:修改超声波测距的阈值

避障模式:小车会根据传感器参数自己选择路径移动

循迹模式:小车沿着黑白轨道运动

^:前进

V:后退

>:右转

<:左转 ||:停止

Byamber

坦克智能小车第6课:超声波避障

概述

在这一课中,将会介绍如何用超声波模块和舵机实现坦克小车避障功能。

超声波原理

坦克小车上安装有一个超声波模块,该模块由两部分组成:超声波发射器和接收器。 超声波发射器向某一方向发射超声波,在发射时刻开始计时,超声波在空气中传播,途中碰到障碍物就立即返回来,超声波接收器收到反射波就立即停止计时,通过时间差来算出超声波与障碍物之间的距离。

超声波模块是安装在SG90舵机旋转轴上的,SG90舵机可以旋转0-180,因此小车可以检测0-180范围内的障碍物,当小车检测到障碍物后,小车先停止运动并报警,舵机旋转检测左右距离,如果左边或右边无障碍物,小车将转向左边或右边,同时舵机回到90度位置(使超声波朝正前方)。

软件

下载http://www.kookye.com/download/car/tank_robot_lesson5.zip并解压文件,用arduino IDE打开tank_robot_lesson5.ino文件,下面对部分代码做简要说明。

#define SERVO     11  //servo connect to D11
#define IRPIN  13 //IR receiver Signal pin connect to Arduino pin 13
#define echo    A3 // Ultrasonic Echo pin connect to A2
#define trig    A2  // Ultrasonic Trig pin connect to A3
#define buzzer     7 //buzzer connect to D7

上面5行代码定义了舵机、红外接收器、超声波和蜂鸣器所接的GPIO口

int leftscanval, centerscanval, rightscanval, ldiagonalscanval, rdiagonalscanval;
const int distancelimit = 30; //distance limit for obstacles in front           
const int sidedistancelimit = 18; //minimum distance in cm to obstacles at both sides (the car will allow a shorter distance sideways)

定义几个变量用于存储各个方向距离以及小车与障碍物的极限距离。

/*detection of ultrasonic distance*/
int watch() {
  long howfar;
  digitalWrite(trig, LOW);
  delayMicroseconds(5);
  digitalWrite(trig, HIGH);
  delayMicroseconds(15);
  digitalWrite(trig, LOW);
  howfar = pulseIn(echo, HIGH);
  howfar = howfar * 0.01657; //how far away is the object in cm
  Serial.println((int)howfar);
  return round(howfar);
}

上面的watch()函数用于测量小车与障碍物之间的距离。

void auto_avoidance() {
  head.write(90); 
  delay(100);
  centerscanval = watch();
  if (centerscanval >= distancelimit) {
    set_motorspeed(LSPEED, RSPEED);
    go_ahead();
  }
  else {
    go_stop();
    alarm();
    head.write(120);
    delay(150);
    ldiagonalscanval = watch();

    head.write(180);
    delay(150);
    leftscanval = watch();

    head.write(90);
    delay(150);

    head.write(60);
    delay(150);
    rdiagonalscanval = watch();

    head.write(0);
    delay(150);
    rightscanval = watch();

    head.write(90);
    if (ldiagonalscanval >= sidedistancelimit && leftscanval >= sidedistancelimit) {
      set_motorspeed(LSPEED, RSPEED);
      go_back();
      delay(200);
      turn_left();
      delay(500);
    }
    else if (rdiagonalscanval >= sidedistancelimit && rightscanval >= sidedistancelimit) {
      set_motorspeed(LSPEED, RSPEED);
      go_back();
      delay(200);
      turn_right();
      delay(500);
    }
  }
}

在auto_avoidance()函数中,转动舵机并调用watch()函数,就能检测左右及前方障碍物距离,通过测量距离与允许距离比较选择合理路径,实现超声波避障。

测试

step 1 用usb线把坦克下车与pc连接起来,选择正确的板子型号和端口号,将程序烧录到arduino中

step 2 打开电池盒电源,将坦克小车放到地上上

step 3 遥控器对着红外接收头,按下”OK”键,小车将开始避障;按下”0″小车停止。

注意:若无法避障,请看考第一课参考第一课检查超声波及舵机安装时否正确并检查接线。

Byamber

坦克智能小车第五课:循迹小车

概述

在本课中将介绍用循迹模块让坦克小车循迹,当按下遥控器某个按键,小车开始循迹;按下另一个按键,小车停止。

循迹原理

循迹传感器模块上有2个探头,一个是红外发射二极管,一个是红外接收管。红外发射二极管不断向外发射红外线,若循迹模块不在黑色轨道上,红外发射管发射的红外线就会被反射回来,反射回来的红外线会被红外接收管接收到,循迹模块输出低电平;如果循迹模块在黑色轨道上,红外发射管发射的红外线不能被反射,红外接收管无法检测到红外线或检测到的红外线信号比较弱,模块输出高电平。

坦克底盘上一共有2个循迹传感器,左右各一个。若左边循迹传感器模块位于黑线上,坦克小车左转;若右边循迹传感器模块位于黑线上,坦克小车右转;若左右两个循迹模块位于黑色轨道两侧,则坦克小车直行;若左右循迹模块均在黑线上,坦克小车停止运动。如图所示

软件

下载http://www.kookye.com/download/car/tank_robot_lesson4.zip并解压文件,用arduino IDE打开tank_robot_lesson4.ino文件,下面对部分代码做简要说明。

#define LFSensor_1 A0 //line follow sensor1
#define LFSensor_2 A1 //line follow sensor2

上面两行代码定义了左右两个循迹传感器所接的端口

void read_sensor_values()
{
  sensor[0]=digitalRead(LFSensor_1);
  sensor[1]=digitalRead(LFSensor_2);
}

read_sensor_values()函数会读取左右两个循迹模块信号,并将左边模块信号存储在sensor[0]中;右边模块结果存储在sensor[1]中。

void auto_tarcking(){
  read_sensor_values();
  if((sensor[0]==LOW)&&(sensor[1]==HIGH)){ //The right sensor is on the black line.The left sensor is on the white line
    set_motorspeed(M_SPEED1,M_SPEED1);
    turn_right(250);
  }
  else if((sensor[0]==HIGH)&&(sensor[1]==LOW)){//The right sensor is on the white line.The left sensor is on the black line
    set_motorspeed(M_SPEED1,M_SPEED1);
    turn_left(250);
  }
  else if((sensor[0]==LOW)&&(sensor[1]==LOW)){//The left an right sensor are on the white line.
    set_motorspeed(M_SPEED2,M_SPEED2);
    go_ahead();
  }
  else if((sensor[0]==HIGH)&&(sensor[1]==HIGH)){//The left an right sensor are on the blac

在auto_tarcking()中先调用read_sensor_values()函数,获取到左右循迹模块信号,接着通过if语句判断左右循迹模块信号,控制坦克小车运动,实现循迹。

测试

step 1 用usb线把坦克下车与pc连接起来,选择正确的板子型号和端口号,将程序烧录到arduino中

step 2 打开电池盒电源,将坦克小车放到黑色轨道上

step 3 遥控器对着红外接收头,按下”OK”键,小车将沿着黑色轨道行驶;按下”0″小车停止。

注意:若无法循迹,请看考第一课调节循迹模块灵敏度,并检查接线。

Byamber

坦克智能小车第4课:红外控制

概述

在第二课中介绍了如何控制电机,这一课中我们会简介如何用红外遥控器控制坦克小车运动。

工作原理

坦克小车上有一个红外接收器,当遥控器按下按键,红外接收器会接收红外信号,arduino会把这个红外信号解码,每个按键对应一个不同的红外信号,当arduino接收到不同的红外信号后执行不同的操作,实现不同的功能。例如,arduino接收到遥控器上“1”对应的红外信号后坦克小车前进;接收到“2”对应的红外信号小车后退。

软件

下载http://www.kookye.com/download/car/tank_robot_lesson3.zip并解压文件,用arduino IDE打开tank_robot_lesson3.ino文件,下面对部分代码做简要说明。

#define IR_ADVANCE       0x00FF18E7       //code from IR controller "▲" button
#define IR_BACK          0x00FF4AB5       //code from IR controller "▼" button
#define IR_RIGHT         0x00FF5AA5       //code from IR controller ">" button
#define IR_LEFT          0x00FF10EF       //code from IR controller "<" button
#define IR_SERVO         0x00FF38C7       //code from IR controller "OK" button
#define IR_OPENLED       0x00FFB04F       //code from IR controller "#" button
#define IR_CLOSELED      0x00FF6897       //code from IR controller "*" button
#define IR_BEEP          0x00FF9867       //code from IR controller "0" button

上面的代码,把要用到按键的红外编码在软件中做如下定义,每个按键的红外编码可以烧录第一课中的代码后,对着红外接收器按遥控器按键,打开arduino IDE Serial Monitor就会打印出对应按键的红外编码。

在本课中我们用到的按键和按键功能如下表所示

按键名 对应功能
前进
后退
> 右转
< 左转
OK 旋转舵机
# 打开LED
* 关闭LED
0 蜂鸣器响

 

enum DN
{ 
  GO_ADVANCE, //go ahead
  GO_LEFT, //left turn
  GO_RIGHT,//right turn
  GO_BACK,//go back
  MOVE_SERVO,//move servo
  OPEN_LED,//open led
  CLOSE_LED,//close led
  BEEP,//control buzzer
  DEF
}Drive_Num=DEF;

为了增加代码的可读性,把每个按键的功能定义在枚举变量中。

void do_IR_Tick()
{
  if(IR.decode(&IRresults))
  {
    if(IRresults.value==IR_ADVANCE)
    {
      Drive_Num=GO_ADVANCE;
    }
    else if(IRresults.value==IR_RIGHT)
    {
       Drive_Num=GO_RIGHT;
    }
    else if(IRresults.value==IR_LEFT)
    {
       Drive_Num=GO_LEFT;
    }
    else if(IRresults.value==IR_BACK)
    {
        Drive_Num=GO_BACK;
    }
    else if(IRresults.value==IR_SERVO)
    {
        Drive_Num=MOVE_SERVO;
    }
    else if(IRresults.value==IR_OPENLED)
    {
      Drive_Num=OPEN_LED;
    }
    else if(IRresults.value==IR_CLOSELED)
    {
      Drive_Num=CLOSE_LED;
    }
    else if(IRresults.value==IR_BEEP)
    {
      Drive_Num=BEEP;
    }
    IRresults.value = 0;
    IR.resume();
  }
}

上面的函数用于解码红外信号,通过调用IR.decode(&IRresults)将红外信号解码结果存储在IRresults.value变量中,比较IRresults.value变量与预定义按键红外编码,如果相等,就把对应的功能代码赋值给枚举变量Drive_Num。

void do_Drive_Tick()
{
    switch (Drive_Num) 
    {
      case GO_ADVANCE:
            go_ahead(10);JogFlag = true;JogTimeCnt = 1;JogTime=millis();break;//if GO_ADVANCE code is detected, then go advance
      case GO_LEFT:
            turn_left(10);JogFlag = true;JogTimeCnt = 1;JogTime=millis();break;//if GO_LEFT code is detected, then turn left
      case GO_RIGHT:
            turn_right(10);JogFlag = true;JogTimeCnt = 1;JogTime=millis();break;//if GO_RIGHT code is detected, then turn right
      case GO_BACK:
            go_back(10);JogFlag = true;JogTimeCnt = 1;JogTime=millis();break;//if GO_BACK code is detected, then backward
      case MOVE_SERVO:
            move_servo();JogFlag = true;JogTimeCnt = 1;JogTime=millis();break;//move servo
      case OPEN_LED:
            open_led(1),open_led(2);JogTime = 0;break;//open led
      case CLOSE_LED:
            close_led(1),close_led(2);JogTime = 0;break;//close led
      case BEEP:
            control_beep();JogTime = 0;break;//control beep
      default:break;
    }
    Drive_Num=DEF;
   //keep current moving mode for  200 millis seconds
    if(millis()-JogTime>=200)
    {
      JogTime=millis();
      if(JogFlag == true) 
      {
        stopFlag = false;
        if(JogTimeCnt <= 0) 
        {
          JogFlag = false; stopFlag = true;
        }
        JogTimeCnt--;
      }
      if(stopFlag == true) 
      {
        JogTimeCnt=0;
        go_stop();
      }
    }
}

在do_Drive_Tick()函数中,判断Drive_Num变量的值并执行对应的功能函数。

void open_led(int led_num)
{
  if (led_num == 1)  digitalWrite(LED1,LOW);
  else digitalWrite(LED2,LOW);
}
void close_led(int led_num)
{
   if (led_num == 1)  digitalWrite(LED1,HIGH);
   else digitalWrite(LED2,HIGH);
}
/*******control buzzer*******/
void control_beep()
{
  digitalWrite(BUZZER,LOW),delay(100);
  digitalWrite(BUZZER,HIGH),delay(100);
}
/***move servo***/
void move_servo()
{
  int i;
   for(i = 0;i<180;i++){ head.write(i); delay(5); } for(i = 180;i>=0;i--){
     head.write(i);
     delay(5);
  }
  head.write(90);
}

上面的4个函数分别用于控制LED的打开、关闭、控制蜂鸣器响以及让舵机从0度转到180度,再从180度转到0度,最后回到90度。

测试

step 1 用usb线把坦克下车与pc连接起来,选择正确的板子型号和端口号,将程序烧录到arduino中

step 2 打开电池盒电源

step 3 将遥控器对着红外接收器按按键,如果所按按键是程序预先定义好的,小车将执行相应的功能函数;如果所按按键是程序未定义的,小车不做任何操作。

 

Byamber

坦克智能小车第三课:电机基本控制

概述

在第一课中,我们介绍坦克底盘如何安装,各传感器如何与控制板连接。本课将在前一课的基础上,讲解如何驱动电机,如何实现坦克小车前进、后退、左右转、停止等基本功能。

原理

我们的坦克小车上用的是GM25直流减速电机,额定电压是9V,详细参数请看看下面链接。

GM25 motor

直流减速电机主要由两部分组成:直流电机和 减速器(图要重拍!!)。

直流电机有2个引脚,在这两个引脚上施加一个直流电压就能让电机转动,改变直流电压极性就可以改变电机的转向;改变电压大小可以改变电机转速。一般直流电机的转速很高,但是扭矩很小,在直流电机上增加一个减速器可以降低转速,增大扭矩。减速后的直流电机力矩增大,可控性增强。

除此之外,我们所用的电机上还有一个霍尔编码器,霍尔编码器上有6pin,其中2pin直接连接到直流电机的2个引脚上,因此,只需向霍尔编码器上这2pin上施加一个直流电压就可以控制电机了。由于制造工艺产生的误差,即使参数完全相同的两个直流减速电机给其施加完全相同的电压信号,其转速一般是不同的,所以坦克小车不能走直线属于正常现象。关于编码器的使用会在后面的课程中会详细讲解。(加一张电机图片,标注清楚编码器各条线含义!!)

(放一张L298N图片!!!)我们用L298N电机驱动器驱动电机,L298N电机驱动器本身可以驱动2路直流电机,经过扩展后可以驱动4路直流电机,其中K1、K2是一样的,K3、K4是一样的,左右电机如何与L298N连接前面已经介绍过了。向L298N上的ENA和ENB输入PWM信号就可以调节左右电机速度,L298N上的ENA和ENB原本是用2个跳线帽接到5V上去的,如果你不想调节电机速度,可以不用拔掉跳线帽;如果想调节电机速度需要拔掉跳线帽,将ENA、ENB接到arduino的PWM输出引脚上去。电机的正反转通过L298N上的IN1、IN2和IN3、IN4控制,其中,IN1、IN2控制左边电机;IN3、IN4控制右边电机,具体如下

左边电机 右边电机
ENA IN1 IN2 DC motor status ENB IN3 IN4 DC motor status
0 x x stop 0 x x stop
1 0 1 rotate clockwise 1 0 1 rotate clockwise
1 1 0 rotate counterclockwise 1 1 0 rotate counterclockwise
1 1 1 brake 1 1 1 brake
1 0 0 brake 1 0 0 brake

软件

下载http://www.kookye.com/download/car/tank_robot_lesson2.zip 并解压文件,用arduino IDE打开tank_robot_lesson2.ino文件,下面对代码做简要说明。

1.接口定义

在第一课中我们将L298N与esp8266 uart wifi shield按照如下方式连接

L298N esp8266 uart wifi shield
ENA D5
ENB D6
IN1 D8
IN2 D9
IN3 D10
IN4 D12

首先,在arduino IDE中按照上表顺序定义号各个接口

#define IN1  8    //K1、K2 motor direction
#define IN2  9    //K1、K2 motor direction
#define IN3  10    //K3、K4 motor direction
#define IN4  12   //K3、K4 motor direction
#define ENA  5    //needs to be a PWM pin to be able to control motor speed ENA
#define ENB  6   //needs to be a PWM pin to be able to control motor speed ENB

2.各功能函数

void go_ahead() //motor rotate clockwise -->robot go ahead
{
  digitalWrite(IN1, LOW);
  digitalWrite(IN2, HIGH);
  digitalWrite(IN3, LOW);
  digitalWrite(IN4,HIGH);
}
void go_back()  //motor rotate counterclockwise -->robot go back
{
  digitalWrite(IN1, HIGH);
  digitalWrite(IN2, LOW);
  digitalWrite(IN3, HIGH);
  digitalWrite(IN4,LOW); 
}
void go_stop()   //motor brake  -->robot stop
{
  digitalWrite(IN1, LOW);
  digitalWrite(IN2, LOW);
  digitalWrite(IN3, LOW);
  digitalWrite(IN4,LOW); 
}
void turn_left()  //left motor rotate counterclockwise and right motor rotate clockwise -->robot turn left
{
  digitalWrite(IN1, HIGH);
  digitalWrite(IN2, LOW);
  digitalWrite(IN3, LOW);
  digitalWrite(IN4, HIGH);
}
void turn_right() //left motor rotate clockwise and right motor rotate counterclockwise -->robot turn right
{
  digitalWrite(IN1, LOW);
  digitalWrite(IN2, HIGH);
  digitalWrite(IN3, HIGH);
  digitalWrite(IN4, LOW);
}
/*set motor speed */
void set_motorspeed(int lspeed,int rspeed)  //change motor speed
{
  analogWrite(ENA,lspeed);//lspeed:0-255
  analogWrite(ENB,rspeed);//rspeed:0-255  
}

3.初始化

 void setup() {
  pinMode(IN1, OUTPUT); 
  pinMode(IN2, OUTPUT); 
  pinMode(IN3, OUTPUT);
  pinMode(IN4, OUTPUT); 
  pinMode(ENA, OUTPUT); 
  pinMode(ENB, OUTPUT);  
  set_motorspeed(255,255);//maximum speed
  go_ahead(),delay(5000),go_stop();  //robot forward 5s
  go_back(),delay(5000),go_stop();  //robot go back 5s
  turn_left(),delay(5000),go_stop();//robot turn left 5s
  turn_right(),delay(5000),go_stop();//robot turn right 5s
  go_stop();//stop
}

在setup()函数中,先将L298N各个引脚设置成正确的工作模式,然后调用上一步中编写的各个功能子函数,使坦克以最大速度前进5s->后退5s->左转5s->右转5s->停止

用usb线把坦克下车与pc连接起来,选择正确的板子型号和端口号,将程序烧录到arduino中,打开电池盒电源,正常情况坦克小车会先向前移动5s,在后退5s,接着左转5s,再右转5s,最后停止。如果不能得到这样的实验结果,请检查接线是否正确。