Category :Tutorials

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文件,下面对部分代码做简要说明。

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

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

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

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

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

编码器引脚初始化,左右电机编码的A相输出分别使用arduino外部中断0和外部中断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--;
}

编码器中断服务函数。当有跳变沿到来时候,会执行中断服务函数,对脉冲加1或减1

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;
}

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

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
}

10ms到达时候会执行定时器中断服务函数,在定时器中断服务函数中,将PI得到的误差补给作用到右边电机上。

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

坦克智能小车第六课:蓝牙/wifi控制

概述

在前面几课中我们把esp8266 uart wifi shield仅仅作为arduino uno的扩展板使用,并没有用到它的串口转wifi功能,都只是红外控制小车运动,在本课中,将介绍如何使用esp8266 uart wifi shield的串口转wifi功能,手机连接esp8266 uart wifi shield的wifi热点,用APP控制小车运动。此外,esp8266 uart wifi shield具备蓝牙接口,将蓝牙模块插到对应接口上,连接蓝牙,同样可以用手机app控制小车运动。

原理

esp8266 uart wifi shield在工作的时候会发射一个wifi热点,wifi名称默认叫”DoitWIFI_Config”,打开手机wifi,无需密码就能连接这个热点,将esp8266 uart wifi shield上拨码开关SW1都拨到ON的位置,表示esp8266与arduino uno串口已连接在一起,这样arduino的信息可以通过串口传给esp8266,然后esp8266再将arduino的串口信息通过wifi发送到手机app;同样,手机app可以将控制指令通过wifi发送给esp8266,esp8266通过串口发送arduino,最后达到控制目的。

蓝牙也是一样的原理,将蓝牙模块插到esp8266 uart wifi shield对应的接口上,把拨码开关SW1都拨到OFF(即12)的位置,表示arduino串口与esp8266断开连接,而已蓝牙模块连接在一起。打开手机蓝牙搜索并连接蓝牙,打开手机app,选择蓝牙连接,连接蓝牙。arduino就可以将信息通过串口发送到蓝牙模块,蓝牙模块再通过蓝牙传输到手机app;同样,也可以将控制指令通过蓝牙发送到蓝牙模块,蓝牙模块在通过串口发送到arduino,最终达到控制目的。

关于esp8266 uart wifi shiel更多信息,请看这里。

ESP8266 UART WIFI Shield use guide

软件

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

//WiFi / Bluetooth through the serial control
void do_Uart_Tick()
{

  char Uart_Date=0;
  if(Serial.available()) 
  {
    size_t len = Serial.available();
    uint8_t sbuf[len + 1];
    sbuf[len] = 0x00;
    Serial.readBytes(sbuf, len);
    //parseUartPackage((char*)sbuf);
    memcpy(buffUART + buffUARTIndex, sbuf, len);//ensure that the serial port can read the entire frame of data
    buffUARTIndex += len;
    preUARTTick = millis();
    if(buffUARTIndex >= MAX_PACKETSIZE - 1) 
    {
      buffUARTIndex = MAX_PACKETSIZE - 2;
      preUARTTick = preUARTTick - 200;
    }
  }
  if(buffUARTIndex > 0 && (millis() - preUARTTick >= 100))//APP send flag to modify the obstacle avoidance parameters
  { //data ready
    buffUART[buffUARTIndex] = 0x00;
    if(buffUART[0]=='C') 
    {
      Serial.println(buffUART);
      Serial.println("You have modified the parameters!");//indicates that the obstacle avoidance distance parameter has been modified
      sscanf(buffUART,"CMD%d,%d,%d",&distancelimit,&sidedistancelimit,&turntime);
    }
    else  Uart_Date=buffUART[0];
    buffUARTIndex = 0;
  }
  switch (Uart_Date)    //serial control instructions
  {
    case '2':
            Drive_Status=MANUAL_DRIVE; Drive_Num=GO_ADVANCE;Serial.println("forward"); break;
    case '4':
            Drive_Status=MANUAL_DRIVE; Drive_Num=GO_LEFT; Serial.println("turn left");break;
    case '6':
            Drive_Status=MANUAL_DRIVE; Drive_Num=GO_RIGHT; Serial.println("turn right");break;
    case '8':
            Drive_Status=MANUAL_DRIVE; Drive_Num=GO_BACK; Serial.println("go back");break;
    case '5':
            Drive_Status=MANUAL_DRIVE; Drive_Num=STOP_STOP;buzz_off();Serial.println("stop");break;
    case '3':
            Drive_Status=AUTO_DRIVE_UO; Serial.println("avoid obstacles...");break;
    case '1':
          Drive_Status=AUTO_DRIVE_LF; Serial.println("line follow...");break;
    default:break;
  }
}

上面的程序用于接收app发送的控制命令。

测试

step 1 烧录程序:用usb线把坦克下车与pc连接起来,选择正确的板子型号和端口号,将esp8266 uart wifi shield上SW1拨到off,如果插了蓝牙模块,需要拔掉蓝牙模块。把程序烧录到arduino后,如果用wifi控制就把SW1拨到ON位置;若用蓝牙控制,就把SW1拨到OFF位置,把蓝牙模块插到对应接口。

step2 下载app并安装。

app下载链接:http://osoyoo.com/driver/car.apk.

app源码链接:http://osoyoo.com/driver/BTcar-master.zip

目前,手机app只支持安卓,并且,提供手机APP源码,可以根据自己需要,修改源码,个性化定制app。

step3 打开电池盒电源,如果想用wifi控制,打开手机wifi,找到名叫“DoitWIFI_Config”的热点并连接

step4 Open app>> select WiFi mode>> then you can controller the robot car through wifi

step 5 If you want to control the robot car through Bluetooth, please turn on bluetooth of your Android phone which you have installed APP and scan bluetooth(different bluetooth module will scan different bluetooth name), Click connect and enter password “1234” or “0000” if no change (You can change wifi or bluetooth settings in Android phone to switch to control car through wifi or bluetooth):

Step 6) Open app>> select bluetooth mode>> then you can controller the robot car through bluetooth:

There are three working mode: manual control, obstacle avoidance and tracking. Users can switch freely among three working mode.
1) In manual control mode, you can click buttons (^) (V) (<) (>) to control the Robot car to move forward and backward, turn right and left. Meanwhile, the APP can observe the car real time movement.

2) Click “tracking” button of App to switch the current mode to tracking mode. The Robot car will move forward along the black line in white background. Meanwhile, the APP can observe the car real time movement. Press “||” button to stop moving and click other button to change Robot car working mode. To learn more about this mode, please review our lesson 4.

3) Click “Obstacle” button to switch the current mode to obstacle avoidance mode. The Robot car can be driven forward continuously and stopped and steered away once any obstacle in its way. Press “||” button to stop moving and then click other button to change Robot car working mode. To learn more about this mode, please review our lesson 5.

Byamber

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

概述

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

超声波原理

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

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

软件

下载http://osoyoo.com/driver/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://osoyoo.com/driver/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

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

概述

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

工作原理

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

软件

下载http://osoyoo.com/driver/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://osoyoo.com/driver/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,最后停止。如果不能得到这样的实验结果,请检查接线是否正确。

Byamber

坦克智能小车第一课:底盘安装

第一部分:硬件安装

坦克智能小车底盘组成图

1.安装电池盒

所需器件

电池盒 x1

一号车板 x1

M3*6十字螺丝 x2

M3螺帽 x2

把电池盒滑盖打开,用M3*6十字螺丝把电池盒靠左侧固定在一号车板活动卡槽里面

2.安装LED

将2个LED灯珠从外侧放到二号车板圆孔中,在内测用塑料螺帽锁紧

3.安装循迹模块

所需器件

M3*12双通铜柱 x2

M3*6十字螺丝 x4

循迹传感器模块 x2

铜柱一端用M3*6十字螺丝固定在4号车板活动卡槽中,另一端将循迹传感器也用M3*6十字螺丝固定在铜柱上

 

4.安装电机

所需器件

左右侧板 x2

电机 x2

M3*6内六角螺丝 x4(不要用M3*8内六角螺丝,这样可能会顶坏电机转子)

将在侧板上寻找合适孔位,使电机接线端子朝前,电机用M3*6内六角螺丝固定在左右侧板上

5.安装车架

用4颗M3*8内六角螺丝将一号车板和左右侧边偏接起来

用4颗M3*8内六角螺丝将四号车板和左右侧边偏接起来

用2颗M3*8内六角螺丝将二号车板和左右侧边偏接起来

注意:为了使led灯光能够向前照射,二号车板需要竖直安装,与左右侧边之间只需要固定2颗螺丝即可。

用4颗M3*8内六角螺丝将三号车板和左右侧边偏接起来

将M3*6+6铜柱母口一端放在五号车板四角螺丝孔上,再用M3*8内六角螺丝从底盘底部穿过螺丝孔固定到铜柱上。

 

6.驱动轮安装

驱动轮所用器件

轮片 x4

M3*17双通铜柱 x6

M3*8 内六角螺丝 x12

联轴器 x2

M6*10 x2

 

将铜柱与轮片用M3*8内六角螺丝固定,两轮片孔位要对其。

将联轴器安图示样子插入驱动轮中,另一侧用M6*10内六角螺丝固定

用黑色小螺丝将联轴器和电机轴固定(再放一张驱动轮装到电机轴上后的照片)

7.安装承重轮

将轴承卡在塑料轮子中,用M6长螺丝穿过螺丝孔中,另一端用M6螺帽固定在侧板上,使用M6内六角扳手和M6扳手将螺丝拧紧。

8.安装履带

履带长度可以随意拼接,本款坦克小车约需要70节履带即可,安装履带时候需要注意驱动轮和承重轮对其,如果没有对齐,可以调节驱动轮使其对齐(这里最好加一个拆装履带的动态图和调节动态图)

9.安装舵机

用两颗M2.5*8十字螺丝和螺帽将舵机固定在金属面板上。

10.安装亚克力

将所有控制电路板和一些传感器按照图示样子安装在亚克力面板上,亚克力面板兼容arduino UNO、Mega 2560、raspberry Pi三块常用开源主板螺丝孔位。用M3*10十字螺丝和螺帽将arduino uno,L298N,电压表,蜂鸣器亚克力面板上,用M2.5*8十字螺丝和螺帽将红外接收器按照图示样子安装在亚克力上。(注意:最好用PS做一张图,标明那些孔位是UNO的,那些是2560的,那些是树莓派的。)

第二部分:接线

1.电机

取出6pin电机线,带6pin端子一端插在电机上,把其中带2pin接线端子穿过金属面板和亚克力面板,剩余4pin是编码器电源线和信号线,暂时不使用,在后面的课程中会使用到,先将它们用尼龙扎带绑在电机上。将左边电机红黑线接到L298N的K1或K2接口;右边电机接到K3或K4接口。

 

2.esp8266 uart wifi shield

将esp8266 uart wifi shield插到arduino uno板上,esp8266 uart wifi shield引出了UNO的所有GPIO口,可以作为UNO的扩展板使用,同时,esp8266 uart wifi shield还具有wifi功能,支持AP/STA模式,默认工作在AP模式。esp8266 uart wifi shield与arduino之间通过串口进行通讯,默认波特率为9600,也就是说esp8266 uart wifi shield也就是一个串口wifi模块。关于esp8266 uart wifi shield的详细介绍请看下面链接。

ESP8266 UART WIFI Shield use guide

 

3.L298N

L298N是电机驱动器,能接4路直流电机,板上引出了5V输出口和12V输出口,在我们的坦克小车中,5V用于给舵机供电。

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

4.电压表

L298N 电压表
GND GND
VCC 12V
Vd V0

5.电源

坦克小车通过2节18650电池供电,将18650电池放到电池盒中(注意方向),将电池盒,uno,L298N按照图示接线。

6.循迹

esp8266 uart wifi shield 左循迹
5V VCC
GND GND
A0 DO
esp8266 uart wifi shield 右循迹
5V VCC
GND GND
A1 DO

7.蜂鸣器

esp8266 uart wifi shield 蜂鸣器
5V VCC
GND GND
D7 IO

8.红外接收器

ESP8266 UNO SHIELD 红外接收器
5V VCC
GND GND
D13 S

9.LED

 

10.舵机

舵机有三条线,分别为VCC、GND、S,电机再转动瞬间会把电压拉的比较低,为了不影响arduino uno正常工作,将舵机电源L298N上的5V输出供电,同时将控制信号引到L298N上

舵机 L298N esp8266 uart wifi shield
GND GND
VCC 5V
S S D11

esp8266 uart wifi shield与uno之间通过UART连接通讯,将esp8266 uart wifi shield上两位拨码开关拨到”12″位置,使esp8266 uart wifi shield与uno断开连接,向arduino uno中烧录一个程序使舵机转到90度位置。

11.超声波

取出舵机配套的一字叶片,按照图示样子套在舵机旋转轴上

然后将L型超声波支架用M2自攻螺丝固定在叶片上。超声波模块有4pin,分别是VCC、Trig、Echo、GND,按照下表接线

esp8266 uart wifi shield 超声波模块
5V VCC
GND GND
A2 Trig
A3 Echo

12.测试

下载http://osoyoo.com/driver/tank_robot_lesson1.zip,解压文件并烧录到arduino中,在进行测试之前,先调节一下循迹传感器的灵敏度。在白色地板上贴一条10mm左右的黑色电工胶,把坦克小车上的2个循迹传感器放在黑色电工胶上,用十字螺丝刀调节可调电位器,使循迹模块信号指示灯刚好熄灭,再将循迹传感器离开黑色区域,使信号指示灯刚好亮起,这表示循迹传感器灵敏度调节好了。

用usb线将坦克小车和pc连接起来,打开电池盒开关打开arduino IDE的Serial Monitor将波特率设置为9600,Serial Monitor会向终端打印出如下信息:

welcome to use osoyoo tank robot car…
send :test line follow sensor
send :turn on LED
send :turn off LED
send : test servo
send : test HC-SR04
send : test buzzer
send : test robot go ahead
send : test robot go back
send : test robot stop
—————————————————>>

串口发送”line follow”会测试循迹传感器,终端将会打印出是2个循迹传感器是否在黑线上;

串口发送”led on”会打开LED;

串口发送”led off”会关闭LED;

串口发送”servo”会使servo旋转,舵机会从0度转到180度,再从180度转到0度,最后回到90度;

串口发送”hc-sr04″会获取到超声波与障碍物之间的距离;

串口发送”buzzer”会使蜂鸣器响一下;

串口发送”go”会使坦克小车前进;

串口发送”back”会使坦克小车后退;

串口发送”stop”会使坦克小车停止;

用遥控器对着红外接收器按遥控器上按键,终端会打印出每个按键的红外编码。

至于详细原理在后面的课程中会详细讲解。